summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorGeorg Ehrke <dev@georgswebsite.de>2012-04-10 22:44:13 -0400
committerGeorg Ehrke <dev@georgswebsite.de>2012-04-10 22:44:13 -0400
commit613e15035e3f02a212c9f3ec11ae98fc3ef682c8 (patch)
tree4b6b93ceb338ae8abd7253faf41526e41ae72d74 /lib
parentef1e359c7c10f4ebd8230b4fa79bd0b284b5186e (diff)
parent9f547a1b3987838fda8db238a8999c9f474bb542 (diff)
downloadnextcloud-server-613e15035e3f02a212c9f3ec11ae98fc3ef682c8.tar.gz
nextcloud-server-613e15035e3f02a212c9f3ec11ae98fc3ef682c8.zip
Merge branch 'master' into sabredav_1.6
Diffstat (limited to 'lib')
-rwxr-xr-xlib/app.php12
-rw-r--r--lib/base.php87
-rw-r--r--lib/db.php25
-rw-r--r--lib/eventsource.php3
-rw-r--r--lib/filecache.php25
-rw-r--r--lib/files.php4
-rw-r--r--lib/filestorage/local.php4
-rw-r--r--lib/filesystem.php13
-rw-r--r--lib/filesystemview.php17
-rw-r--r--lib/log.php71
-rw-r--r--lib/log/owncloud.php79
-rw-r--r--lib/log/syslog.php37
-rw-r--r--lib/migrate.php714
-rw-r--r--lib/migration/content.php252
-rw-r--r--lib/migration/provider.php52
-rw-r--r--lib/mimetypes.fixlist.php3
-rw-r--r--lib/updater.php1
-rw-r--r--lib/util.php8
18 files changed, 1299 insertions, 108 deletions
diff --git a/lib/app.php b/lib/app.php
index 6c882963a02..1c81fbd4242 100755
--- a/lib/app.php
+++ b/lib/app.php
@@ -55,7 +55,7 @@ class OC_App{
// Our very own core apps are hardcoded
foreach( array('files', 'settings') as $app ){
- if(is_null($types) or self::isType($app,$types)){
+ if(is_null($types)){
require( $app.'/appinfo/app.php' );
}
}
@@ -103,9 +103,9 @@ class OC_App{
*/
public static function getEnabledApps(){
$apps=array();
- $query = OC_DB::prepare( 'SELECT appid FROM *PREFIX*appconfig WHERE configkey = "enabled" AND configvalue="yes"' );
- $query->execute();
- while($row=$query->fetchRow()){
+ $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;
@@ -319,7 +319,7 @@ class OC_App{
$file=OC::$APPSROOT.'/apps/'.$appid.'/appinfo/info.xml';
}
$data=array();
- $content=file_get_contents($file);
+ $content=@file_get_contents($file);
if(!$content){
return;
}
@@ -452,7 +452,7 @@ class OC_App{
*/
public static function getAppVersions(){
$versions=array();
- $query = OC_DB::prepare( 'SELECT appid, configvalue FROM *PREFIX*appconfig WHERE configkey = "installed_version"' );
+ $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'];
diff --git a/lib/base.php b/lib/base.php
index b031572f177..83dd0c98f45 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -229,6 +229,39 @@ class OC{
}
}
+ 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();
+ }
+ // allow manual override via GET parameter
+ if(isset($_GET['formfactor'])){
+ $_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" );
+ OC_Util::addScript( "jquery-showpassword" );
+ OC_Util::addScript( "jquery.infieldlabel.min" );
+ OC_Util::addScript( "jquery-tipsy" );
+ OC_Util::addScript( "oc-dialogs" );
+ OC_Util::addScript( "js" );
+ OC_Util::addScript( "eventsource" );
+ OC_Util::addScript( "config" );
+ //OC_Util::addScript( "multiselect" );
+ OC_Util::addScript('search','result');
+ OC_Util::addStyle( "styles" );
+ 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'));
@@ -244,6 +277,24 @@ class OC{
date_default_timezone_set('Europe/Berlin');
ini_set('arg_separator.output','&amp;');
+ //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))
{
@@ -270,37 +321,10 @@ class OC{
self::checkInstalled();
self::checkSSL();
- self::checkUpgrade();
- ini_set('session.cookie_httponly','1;');
- session_start();
-
- // 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();
- }
- // allow manual override via GET parameter
- if(isset($_GET['formfactor'])){
- $_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" );
- OC_Util::addScript( "jquery-showpassword" );
- OC_Util::addScript( "jquery.infieldlabel.min" );
- OC_Util::addScript( "jquery-tipsy" );
- OC_Util::addScript( "oc-dialogs" );
- OC_Util::addScript( "js" );
- OC_Util::addScript( "eventsource" );
- OC_Util::addScript( "config" );
- //OC_Util::addScript( "multiselect" );
- OC_Util::addScript('search','result');
- OC_Util::addStyle( "styles" );
- OC_Util::addStyle( "multiselect" );
- OC_Util::addStyle( "jquery-ui-1.8.16.custom" );
- OC_Util::addStyle( "jquery-tipsy" );
+ self::initSession();
+ self::initTemplateEngine();
+ self::checkUpgrade();
$errors=OC_Util::checkServer();
if(count($errors)>0) {
@@ -341,6 +365,9 @@ class OC{
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/db.php b/lib/db.php
index a0fb6c385d8..9c46a40addb 100644
--- a/lib/db.php
+++ b/lib/db.php
@@ -483,6 +483,30 @@ class OC_DB {
}
/**
+ * @breif 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(){
@@ -586,3 +610,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 a8c48e3f144..cdd91dcbfa4 100644
--- a/lib/filecache.php
+++ b/lib/filecache.php
@@ -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{
@@ -469,6 +469,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 +486,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));
+ }
}
}
}
@@ -637,6 +642,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 e7bfbbc19bb..a68c29ad989 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';
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..b6909f5acdf 100644
--- a/lib/filesystem.php
+++ b/lib/filesystem.php
@@ -298,6 +298,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 39e47975b28..9d530c7ad63 100644
--- a/lib/filesystemview.php
+++ b/lib/filesystemview.php
@@ -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){
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..dff3abe9e93
--- /dev/null
+++ b/lib/migrate.php
@@ -0,0 +1,714 @@
+<?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;
+ }
+
+ /**
+ * @breif 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 );
+ }
+ }
+ }
+
+ /**
+ * @breif 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) ){
+ if( !OC_User_Database::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 ) );
+ }
+
+ /**
+ * @breif 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;
+ }
+
+ }
+
+ /**
+ * @breif 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;
+ }
+
+ /**
+ * @breif 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;
+ }
+ }
+
+ /**
+ * @breif 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;
+ }
+
+ /**
+ * @breif 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'] = $appinfo['version'];
+
+ }
+
+ return $return;
+
+ }
+
+
+ /**
+ * @breif 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;
+ }
+
+ /**
+ * @breif 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;
+
+ }
+
+ /**
+ * @breif 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;
+
+ }
+
+ /**
+ * @breif 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;
+ }
+ }
+
+ /**
+ * @breif 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;
+ }
+
+ /**
+ * @breif 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;
+
+ }
+
+ /*
+ * @breif 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..d304051f3e6
--- /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;
+
+ /**
+ * @breif 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;
+ }
+
+ }
+
+ // @breif 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;
+ }
+
+ }
+
+ /**
+ * @breif 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;
+
+ }
+
+ /**
+ * @breif 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;
+ }
+
+ /**
+ * @breif 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;
+ }
+
+ /**
+ * @breif 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;
+ }
+
+ /**
+ * @breif 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;
+ }
+
+ /**
+ * @breif cleans up after the zip
+ */
+ private function cleanup(){
+ // Delete tmp files
+ foreach($this->tmpfiles as $i){
+ unlink( $i );
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/migration/provider.php b/lib/migration/provider.php
new file mode 100644
index 00000000000..feae29f1354
--- /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 );
+ }
+
+ /**
+ * @breif exports data for apps
+ * @return array appdata to be exported
+ */
+ abstract function export( );
+
+ /**
+ * @breif imports data for the app
+ * @return void
+ */
+ abstract function import( );
+
+ /**
+ * @breif 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;
+ }
+ }
+
+ /**
+ * @breif 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 51f12dbcc29..a40fbd9e228 100644
--- a/lib/mimetypes.fixlist.php
+++ b/lib/mimetypes.fixlist.php
@@ -16,5 +16,6 @@ return array(
'xls'=>'application/msexcel',
'xlsx'=>'application/msexcel',
'ppt'=>'application/mspowerpoint',
- 'pptx'=>'application/mspowerpoint'
+ 'pptx'=>'application/mspowerpoint',
+ 'sgf' => 'application/sgf'
);
diff --git a/lib/updater.php b/lib/updater.php
index 57623797ae5..196822ac35d 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
diff --git a/lib/util.php b/lib/util.php
index 529b6d958fb..722b7404d0c 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -77,6 +77,14 @@ class OC_Util {
return '3';
}
+ /**
+ * 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
*