Add OC_Migration_Content class to help app devs. Restructure OC_Migrate.
This commit is contained in:
parent
77f6872ea4
commit
145d6f3566
7 changed files with 593 additions and 660 deletions
|
@ -27,11 +27,10 @@ OC_Util::checkAppEnabled('admin_export');
|
|||
|
||||
define('DS', '/');
|
||||
|
||||
|
||||
// Export?
|
||||
if (isset($_POST['admin_export'])) {
|
||||
// Create the export zip
|
||||
if( !$path = OC_Migrate::createSysExportFile( $_POST['export_type'] ) ){
|
||||
if( !$path = OC_Migrate::export( $_POST['export_type'] ) ){
|
||||
// Error
|
||||
die('error');
|
||||
} else {
|
||||
|
@ -46,136 +45,11 @@ if (isset($_POST['admin_export'])) {
|
|||
// Import?
|
||||
} else if( isset($_POST['admin_import']) ){
|
||||
|
||||
$root = OC::$SERVERROOT . "/";
|
||||
$importname = "owncloud_import_" . date("y-m-d_H-i-s");
|
||||
|
||||
// Save data dir for later
|
||||
$datadir = OC_Config::getValue( 'datadirectory' );
|
||||
|
||||
// Copy the uploaded file
|
||||
$from = $_FILES['owncloud_import']['tmp_name'];
|
||||
$to = get_temp_dir().'/'.$importname.'.zip';
|
||||
if( !move_uploaded_file( $from, $to ) ){
|
||||
OC_Log::write('admin_export',"Failed to copy the uploaded file",OC_Log::INFO);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Extract zip
|
||||
$zip = new ZipArchive();
|
||||
if ($zip->open(get_temp_dir().'/'.$importname.'.zip') != TRUE) {
|
||||
OC_Log::write('admin_export',"Failed to open zip file",OC_Log::INFO);
|
||||
exit();
|
||||
}
|
||||
$zip->extractTo(get_temp_dir().'/'.$importname.'/');
|
||||
$zip->close();
|
||||
|
||||
// Delete uploaded file
|
||||
unlink( get_temp_dir() . '/' . $importname . '.zip' );
|
||||
|
||||
// Now we need to check if everything is present. Data and dbexport.xml
|
||||
|
||||
|
||||
// Delete current data folder.
|
||||
OC_Log::write('admin_export',"Deleting current data dir",OC_Log::INFO);
|
||||
unlinkRecursive( $datadir, false );
|
||||
|
||||
// Copy over data
|
||||
if( !copy_r( get_temp_dir() . '/' . $importname . '/data', $datadir ) ){
|
||||
OC_Log::write('admin_export',"Failed to copy over data directory",OC_Log::INFO);
|
||||
exit();
|
||||
}
|
||||
|
||||
OC_DB::replaceDB( get_temp_dir() . '/' . $importname . '/dbexport.xml' );
|
||||
// TODO
|
||||
// OC_Migrate::import( $pathtozipfile );
|
||||
|
||||
} else {
|
||||
// fill template
|
||||
$tmpl = new OC_Template('admin_export', 'settings');
|
||||
return $tmpl->fetchPage();
|
||||
}
|
||||
|
||||
function zipAddDir($dir, $zip, $recursive=true, $internalDir='') {
|
||||
$dirname = basename($dir);
|
||||
$zip->addEmptyDir($internalDir . $dirname);
|
||||
$internalDir.=$dirname.='/';
|
||||
|
||||
if ($dirhandle = opendir($dir)) {
|
||||
while (false !== ( $file = readdir($dirhandle))) {
|
||||
|
||||
if (( $file != '.' ) && ( $file != '..' )) {
|
||||
|
||||
if (is_dir($dir . '/' . $file) && $recursive) {
|
||||
zipAddDir($dir . '/' . $file, $zip, $recursive, $internalDir);
|
||||
} elseif (is_file($dir . '/' . $file)) {
|
||||
$zip->addFile($dir . '/' . $file, $internalDir . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($dirhandle);
|
||||
} else {
|
||||
OC_Log::write('admin_export',"Was not able to open directory: " . $dir,OC_Log::ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
function unlinkRecursive($dir, $deleteRootToo)
|
||||
{
|
||||
if(!$dh = @opendir($dir))
|
||||
{
|
||||
return;
|
||||
}
|
||||
while (false !== ($obj = readdir($dh)))
|
||||
{
|
||||
if($obj == '.' || $obj == '..')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!@unlink($dir . '/' . $obj))
|
||||
{
|
||||
unlinkRecursive($dir.'/'.$obj, true);
|
||||
}
|
||||
}
|
||||
|
||||
closedir($dh);
|
||||
|
||||
if ($deleteRootToo)
|
||||
{
|
||||
@rmdir($dir);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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.DS.$file ) )
|
||||
{
|
||||
copy_r( $path.DS.$file, $dest.DS.$file );
|
||||
}
|
||||
else
|
||||
{
|
||||
copy( $path.DS.$file, $dest.DS.$file );
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
elseif( is_file($path) )
|
||||
{
|
||||
return copy($path, $dest);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
<?php
|
||||
class OC_Migrate_Provider_Bookmarks extends OC_Migrate_Provider{
|
||||
class OC_Migration_Provider_Bookmarks extends OC_Migration_Provider{
|
||||
|
||||
// Create the xml for the user supplied
|
||||
function export( $uid ){
|
||||
function export( ){
|
||||
OC_Log::write('migration','starting export for bookmarks',OC_Log::INFO);
|
||||
$options = array(
|
||||
'table'=>'bookmarks',
|
||||
'matchcol'=>'user_id',
|
||||
'matchval'=>$uid,
|
||||
'matchval'=>$this->uid,
|
||||
'idcol'=>'id'
|
||||
);
|
||||
$ids = OC_Migrate::copyRows( $options );
|
||||
$ids = $this->content->copyRows( $options );
|
||||
|
||||
$options = array(
|
||||
'table'=>'bookmarks_tags',
|
||||
|
@ -19,7 +19,7 @@ class OC_Migrate_Provider_Bookmarks extends OC_Migrate_Provider{
|
|||
);
|
||||
|
||||
// Export tags
|
||||
$ids2 = OC_Migrate::copyRows( $options );
|
||||
$ids2 = $this->content->copyRows( $options );
|
||||
|
||||
// If both returned some ids then they worked
|
||||
if( is_array( $ids ) && is_array( $ids2 ) )
|
||||
|
@ -32,17 +32,17 @@ class OC_Migrate_Provider_Bookmarks extends OC_Migrate_Provider{
|
|||
}
|
||||
|
||||
// Import function for bookmarks
|
||||
function import( $app, $info ){
|
||||
switch( $app->version ){
|
||||
function import( ){
|
||||
switch( $this->appinfo->version ){
|
||||
default:
|
||||
// All versions of the app have had the same db structure, so all can use the same import function
|
||||
$query = OC_Migrate::prepare( "SELECT * FROM bookmarks WHERE user_id LIKE ?" );
|
||||
$results = $query->execute( array( $info['olduid'] ) );
|
||||
$results = $query->execute( array( $this->info['olduid'] ) );
|
||||
$idmap = array();
|
||||
while( $row = $data->fetchRow() ){
|
||||
// Import each bookmark, saving its id into the map
|
||||
$query = OC_DB::prepare( "INSERT INTO *PREFIX*bookmarks(url, title, user_id, public, added, lastmodified) VALUES (?, ?, ?, ?, ?, ?)" );
|
||||
$query->execute( array( $row['url'], $row['title'], $info['newuid'], $row['public'], $row['added'], $row['lastmodified'] ) );
|
||||
$query->execute( array( $row['url'], $row['title'], $this->info['newuid'], $row['public'], $row['added'], $row['lastmodified'] ) );
|
||||
// Map the id
|
||||
$idmap[$row['id']] = OC_DB::insertid();
|
||||
}
|
||||
|
@ -66,4 +66,4 @@ class OC_Migrate_Provider_Bookmarks extends OC_Migrate_Provider{
|
|||
}
|
||||
|
||||
// Load the provider
|
||||
new OC_Migrate_Provider_Bookmarks( 'bookmarks' );
|
||||
new OC_Migration_Provider_Bookmarks( 'bookmarks' );
|
|
@ -26,7 +26,7 @@ OC_Util::checkAppEnabled('user_migrate');
|
|||
|
||||
if (isset($_POST['user_export'])) {
|
||||
// Create the export zip
|
||||
if( !$path = OC_Migrate::createUserExportFile() ){
|
||||
if( !$path = OC_Migrate::export() ){
|
||||
// Error
|
||||
die('error');
|
||||
} else {
|
||||
|
|
781
lib/migrate.php
781
lib/migrate.php
|
@ -22,28 +22,31 @@
|
|||
|
||||
|
||||
/**
|
||||
* provides an interface to all search providers
|
||||
* provides an interface to migrate users and whole ownclouds
|
||||
*/
|
||||
class OC_Migrate{
|
||||
|
||||
// Holds the db object
|
||||
static private $MDB2=false;
|
||||
|
||||
// Array of OC_Migration_Provider objects
|
||||
static private $providers=array();
|
||||
// Schema db object
|
||||
static private $schema=false;
|
||||
// User id of the user to import/export
|
||||
static private $uid=false;
|
||||
// Path to the sqlite db
|
||||
static private $dbpath=false;
|
||||
// Holds the ZipArchive object
|
||||
static private $zip=false;
|
||||
// String path to export
|
||||
static private $zippath=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
|
||||
|
@ -69,99 +72,78 @@ class OC_Migrate{
|
|||
}
|
||||
|
||||
/**
|
||||
* @breif creates a migration.db in the users data dir with their app data in
|
||||
* @return bool whether operation was successfull
|
||||
* @breif exports a user, or owncloud instance
|
||||
* @param ootional $type string type of export, defualts to user
|
||||
* @param otional $path string path to zip output folder
|
||||
* @param optional $uid string user id of user to export if export type is user, defaults to current
|
||||
*/
|
||||
private static function exportAppData( ){
|
||||
|
||||
self::connectDB();
|
||||
$ok = true;
|
||||
$return = array();
|
||||
|
||||
// Find the providers
|
||||
self::findProviders();
|
||||
|
||||
// Foreach provider
|
||||
foreach( self::$providers as $provider ){
|
||||
$failed = false;
|
||||
|
||||
// Does this app use the database?
|
||||
if(file_exists(OC::$SERVERROOT.'/apps/'.$provider->id.'/appinfo/database.xml')){
|
||||
// Create some app tables
|
||||
$tables = self::createAppTables( $provider->id );
|
||||
if( is_array( $tables ) ){
|
||||
// Save the table names
|
||||
foreach($tables as $table){
|
||||
$return['apps'][$provider->id]['tables'][] = $table;
|
||||
}
|
||||
} else {
|
||||
// It failed to create the tables
|
||||
$failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Run the import function?
|
||||
if( !$failed ){
|
||||
$return['apps'][$provider->id]['success'] = $provider->export( self::$uid );
|
||||
} else {
|
||||
$return['apps'][$provider->id]['success'] = false;
|
||||
$return['apps'][$provider->id]['message'] = 'failed to create the app tables';
|
||||
}
|
||||
|
||||
// Now add some app info the the return array
|
||||
$appinfo = OC_App::getAppInfo( $provider->id );
|
||||
$return['apps'][$provider->id]['version'] = $appinfo['version'];
|
||||
|
||||
}
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @breif creates an export file for the whole system
|
||||
* @param optional $exporttype string export type ('instance','system' or 'userfiles')
|
||||
* @param optional $path string path to zip destination (with trailing slash)
|
||||
* @return path to the zip or false if there was a problem
|
||||
*/
|
||||
static public function createSysExportFile( $exporttype='instance', $path=null ){
|
||||
// Calculate zip name
|
||||
$zipname = "oc_export_" . date("y-m-d_H-i-s") . ".zip";
|
||||
// Get the data dir
|
||||
public static function export( $type='user', $path=null, $uid=null ){
|
||||
$datadir = OC_Config::getValue( 'datadirectory' );
|
||||
// Calculate destination
|
||||
if( !is_null( $path ) ){
|
||||
// Path given
|
||||
// Is a directory?
|
||||
if( !is_dir( $path ) ){
|
||||
OC_Log::write('migration', 'Path supplied to createSysExportFile() is not a directory', OC_Log::ERROR);
|
||||
return false;
|
||||
}
|
||||
// Is writeable
|
||||
if( !is_writeable( $path ) ){
|
||||
OC_Log::write('migration', 'Path supplied to createSysExportFile() is not writeable', OC_Log::ERROR);
|
||||
return false;
|
||||
}
|
||||
self::$zippath = $path . $zipname;
|
||||
} else {
|
||||
// Save in tmp dir
|
||||
self::$zippath = sys_get_temp_dir() . '/' . $zipname;
|
||||
}
|
||||
// Create the zip object
|
||||
self::$zip = new ZipArchive;
|
||||
// Try to create the zip
|
||||
if( !self::createZip() ){
|
||||
return false;
|
||||
}
|
||||
// Handle export types
|
||||
$exporttypes = array( 'userfiles', 'instance', 'system' );
|
||||
self::$exporttype = in_array( $exporttype, $exporttypes ) ? $exporttype : false;
|
||||
if( !self::$exporttype ){
|
||||
OC_Log::write( 'migration', 'Export type: '.$exporttype.' is not supported.', OC_Log::ERROR);
|
||||
return false;
|
||||
}
|
||||
switch( self::$exporttype ){
|
||||
case 'instance':
|
||||
// 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 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 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 false;
|
||||
}
|
||||
self::$zippath = $path . $zipname;
|
||||
} else {
|
||||
// Default path
|
||||
self::$zippath = get_temp_dir() . '/' . $zipname;
|
||||
}
|
||||
}
|
||||
// Create the zip object
|
||||
self::$zip = new ZipArchive;
|
||||
if( !self::createZip() ){
|
||||
return 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 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');
|
||||
|
@ -172,43 +154,112 @@ class OC_Migrate{
|
|||
$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 );
|
||||
// Write the new db export file
|
||||
file_put_contents( $dbfile, $dbexport );
|
||||
self::$zip->addFile( $dbfile, "dbexport.xml" );
|
||||
// Add the export to the zip
|
||||
self::$content->addFromString( $dbexport, "dbexport.xml" );
|
||||
// Add user data
|
||||
foreach(OC_User::getUsers() as $user){
|
||||
self::addDirToZip( $datadir . '/' . $user . '/', true, "/userdata/" );
|
||||
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::addDirToZip( $datadir . '/' . $user . '/', true, "/" );
|
||||
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::addDirToZip( OC::$SERVERROOT . '/', false, '/');
|
||||
self::$content->addDir( OC::$SERVERROOT . '/', false, '/');
|
||||
foreach (array(".git", "3rdparty", "apps", "core", "files", "l10n", "lib", "ocs", "search", "settings", "tests") as $dir) {
|
||||
self::addDirToZip( OC::$SERVERROOT . '/' . $dir, true, "/");
|
||||
self::$content->addDir( OC::$SERVERROOT . '/' . $dir, true, "/");
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
if( !$info = self::getExportInfo( $exportdata ) ){
|
||||
return false;
|
||||
}
|
||||
// Add the export info json to the export zip
|
||||
self::$content->addFromString( $info, 'export_info.json' );
|
||||
if( !self::$content->finish() ){
|
||||
return false;
|
||||
}
|
||||
return self::$zippath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 );
|
||||
}
|
||||
// Add export info
|
||||
self::addExportInfo();
|
||||
// Close the zip
|
||||
if( !self::closeZip() ){
|
||||
return false;
|
||||
}
|
||||
return self::$zippath;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @breif adds a json file with infomation on the export to the zips root (used on import)
|
||||
* @return bool
|
||||
*/
|
||||
static private function addExportInfo( $array=array() ){
|
||||
* @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(),
|
||||
|
@ -216,11 +267,12 @@ class OC_Migrate{
|
|||
'exporttype' => self::$exporttype
|
||||
);
|
||||
// Add hash if user export
|
||||
if( self::$exporttype = 'user' ){
|
||||
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;
|
||||
die(var_dump($hash));
|
||||
if( !$hash ){
|
||||
OC_Log::write( 'migration', 'Failed to get the users password hash', OC_log::ERROR);
|
||||
return false;
|
||||
|
@ -228,110 +280,122 @@ class OC_Migrate{
|
|||
$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 );
|
||||
$info = array_merge( $info, (array)$array );
|
||||
// Create json
|
||||
$json = json_encode( $info );
|
||||
$tmpfile = tempnam("/tmp", "oc_export_info_");
|
||||
self::$tmpfiles[] = $tmpfile;
|
||||
if( !file_put_contents( $tmpfile, $json ) ){
|
||||
return false;
|
||||
} else {
|
||||
self::$zip->addFile( $tmpfile, "/" . self::$uid . "/export_info.json" );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @breif tried to finalise the zip
|
||||
* @return bool
|
||||
*/
|
||||
static private function closeZip(){
|
||||
if( !self::$zip->close() ){
|
||||
OC_Log::write('migration', 'Failed to save the zip with error: '.self::$zip->getStatusString(), OC_Log::ERROR);
|
||||
self::cleanup();
|
||||
return false;
|
||||
} else {
|
||||
OC_Log::write('migration', 'Export zip created ok', OC_Log::INFO);
|
||||
self::cleanup();
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @breif cleans up after the zip
|
||||
*/
|
||||
static private function cleanup(){
|
||||
// Delete tmp files
|
||||
foreach(self::$tmpfiles as $i){
|
||||
unlink( $i );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @breif creates a zip user export
|
||||
* @param optional $uid string user id of the user to export (defaults to current)
|
||||
* @param optional $path string path to folder to create file in (with trailing slash) (defaults to current user's data dir)
|
||||
* @return false on failure | string path on success
|
||||
*/
|
||||
static public function createUserExportFile( $uid=null, $path=null ){
|
||||
// User passed?
|
||||
$uid = is_null( $uid ) ? OC_User::getUser() : $uid ;
|
||||
// Is a database user?
|
||||
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);
|
||||
* @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;
|
||||
}
|
||||
// Set the uid
|
||||
self::$uid = $uid;
|
||||
// Create the zip object
|
||||
self::$zip = new ZipArchive;
|
||||
// Set export type
|
||||
self::$exporttype = 'user';
|
||||
// Calculate users data dir
|
||||
$user = OC_User::getUser();
|
||||
$userdatadir = OC_Config::getValue( 'datadirectory' ) . '/' . $user . '/';
|
||||
// Calculate zip name
|
||||
$zipname = "oc_userexport_" . $user . '_' . date("y-m-d_H-i-s") . ".zip";
|
||||
// Calculate destination
|
||||
if( !is_null( $path ) ){
|
||||
// Path given
|
||||
// Is a directory?
|
||||
if( !is_dir( $path ) ){
|
||||
OC_Log::write('migration', 'Path supplied to createUserExportFile() is not a directory', OC_Log::ERROR);
|
||||
return false;
|
||||
}
|
||||
// Is writeable
|
||||
if( !is_writeable( $path ) ){
|
||||
OC_Log::write('migration', 'Path supplied to createUserExportFile() is not writeable', OC_Log::ERROR);
|
||||
// Already connected
|
||||
if(!self::$MDB2){
|
||||
require_once('MDB2.php');
|
||||
|
||||
$datadir = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" );
|
||||
|
||||
// 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' => 'sqlite3',
|
||||
'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;
|
||||
}
|
||||
self::$zippath = $path . $zipname;
|
||||
} else {
|
||||
// Save in users data dir
|
||||
self::$zippath = $userdatadir . $zipname;
|
||||
// We always, really always want associative arrays
|
||||
self::$MDB2->setFetchMode(MDB2_FETCHMODE_ASSOC);
|
||||
}
|
||||
// Try to create the zip
|
||||
if( !self::createZip() ){
|
||||
return false;
|
||||
}
|
||||
// Export the app info
|
||||
$appinfo = self::exportAppData();
|
||||
// Save the migration results
|
||||
self::addExportInfo( $appinfo );
|
||||
// Add the data dir to the zip
|
||||
self::addDirToZip( $userdatadir );
|
||||
// Close the zip
|
||||
if( !self::closeZip() ){
|
||||
return false;
|
||||
}
|
||||
// All good
|
||||
return self::$zippath;
|
||||
}
|
||||
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(){
|
||||
|
@ -340,45 +404,13 @@ class OC_Migrate{
|
|||
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 ) !== TRUE ) {
|
||||
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 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
|
||||
*/
|
||||
static private function addDirToZip($dir, $recursive=true, $internaldir='') {
|
||||
$dirname = basename($dir);
|
||||
self::$zip->addEmptyDir($internaldir . $dirname);
|
||||
$internaldir.=$dirname.='/';
|
||||
|
||||
if ($dirhandle = opendir($dir)) {
|
||||
while (false !== ( $file = readdir($dirhandle))) {
|
||||
|
||||
if (( $file != '.' ) && ( $file != '..' )) {
|
||||
|
||||
if (is_dir($dir . '/' . $file) && $recursive) {
|
||||
self::addDirToZip($dir . '/' . $file, $recursive, $internaldir);
|
||||
} elseif (is_file($dir . '/' . $file)) {
|
||||
self::$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 returns an array of apps that support migration
|
||||
|
@ -429,10 +461,17 @@ class OC_Migrate{
|
|||
|
||||
foreach( self::$providers as $provider){
|
||||
// Is the app in the export?
|
||||
$id = $provider->id;
|
||||
$id = $provider->getID();
|
||||
if( isset( $info->apps->$id ) ){
|
||||
// Did it succeed?
|
||||
if( $info->apps->$id->success ){
|
||||
// Give the provider the content object
|
||||
// TODO PASS THE PATH TO MIGRATION.DB
|
||||
if( !self::connectDB() ){
|
||||
return false;
|
||||
}
|
||||
$content = new OC_Migration_Content( self::$zip, self::$db );
|
||||
$provider->setObject( $content );
|
||||
// Then do the import
|
||||
$provider->import( $info->apps->$id, $importinfo );
|
||||
}
|
||||
|
@ -443,252 +482,12 @@ class OC_Migrate{
|
|||
|
||||
}
|
||||
|
||||
// @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
|
||||
private static function connectDB( $dbpath=null ){
|
||||
OC_Log::write('migration','connecting to migration.db for user: '.self::$uid,OC_Log::INFO);
|
||||
// Fail if no user is set
|
||||
if(!self::$uid){
|
||||
OC_Log::write('migration','connectDB() called without self::$uid being set',OC_Log::INFO);
|
||||
return false;
|
||||
}
|
||||
// Already connected
|
||||
if(!self::$MDB2){
|
||||
require_once('MDB2.php');
|
||||
|
||||
$datadir = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" );
|
||||
|
||||
self::$dbpath = $datadir.'/'.self::$uid.'/migration.db';//!is_null( $dbpath ) ? $dbpath : $datadir.'/'.self::$uid.'/migration.db';
|
||||
|
||||
// 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' => 'sqlite3',
|
||||
'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;
|
||||
} else {
|
||||
}
|
||||
// We always, really always want associative arrays
|
||||
self::$MDB2->setFetchMode(MDB2_FETCHMODE_ASSOC);
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// @breif prepares the db
|
||||
// @param $query the sql query to prepare
|
||||
public static function prepare( $query ){
|
||||
|
||||
// Optimize the query
|
||||
$query = self::processQuery( $query );
|
||||
|
||||
// Optimize the query
|
||||
$query = self::$MDB2->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 static function processQuery( $query ){
|
||||
|
||||
self::connectDB();
|
||||
$prefix = '';
|
||||
|
||||
$query = str_replace( '`', '\'', $query );
|
||||
$query = str_replace( 'NOW()', 'datetime(\'now\')', $query );
|
||||
$query = str_replace( 'now()', 'datetime(\'now\')', $query );
|
||||
|
||||
// replace table name prefix
|
||||
$query = str_replace( '*PREFIX*', $prefix, $query );
|
||||
|
||||
return $query;
|
||||
|
||||
}
|
||||
|
||||
// @brief copys rows to migration.db from the main database
|
||||
// @param $options array of options.
|
||||
// @return bool
|
||||
public static 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)
|
||||
$query = OC_DB::prepare( "SELECT * FROM *PREFIX*" . $options['table'] . " WHERE " . $options['matchcol'] . " LIKE ?" );
|
||||
$results = $query->execute( array( $matchval ) );
|
||||
$newreturns = self::insertData( $results, $options );
|
||||
$return = array_merge( $return, $newreturns );
|
||||
}
|
||||
|
||||
} else {
|
||||
// Just get everything
|
||||
$query = OC_DB::prepare( "SELECT * FROM *PREFIX*" . $options['table'] );
|
||||
$results = $query->execute();
|
||||
$return = self::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 static function insertData( $data, $options ){
|
||||
$return = array();
|
||||
while( $row = $data->fetchRow() ){
|
||||
// Now save all this to the migration.db
|
||||
$fields = array();
|
||||
$values = array();
|
||||
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 = self::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
// @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
|
||||
private static 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';
|
||||
$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 connects to a MDB2 database scheme
|
||||
* @returns true/false
|
||||
*
|
||||
* Connects to a MDB2 database scheme
|
||||
*/
|
||||
private static function connectScheme(){
|
||||
// We need a mdb2 database connection
|
||||
self::connectDB();
|
||||
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 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
|
||||
/*
|
||||
* @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
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* provides search functionalty
|
||||
*/
|
||||
abstract class OC_Migrate_Provider{
|
||||
|
||||
public $id;
|
||||
|
||||
public function __construct( $appid ){
|
||||
$this->id = $appid;
|
||||
OC_Migrate::registerProvider( $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* @breif exports data for apps
|
||||
* @param string $uid
|
||||
* @return array appdata to be exported
|
||||
*/
|
||||
abstract function export($uid);
|
||||
|
||||
/**
|
||||
* @breif imports data for the app
|
||||
* @param $appinfo object with the data that the app exported
|
||||
* @param $info array of info including exportinfo.json
|
||||
* @return void
|
||||
*/
|
||||
abstract function import( $appinfo, $info );
|
||||
}
|
239
lib/migration/content.php
Normal file
239
lib/migration/content.php
Normal file
|
@ -0,0 +1,239 @@
|
|||
<?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=false;
|
||||
// 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=false ){
|
||||
|
||||
$this->zip = $zip;
|
||||
$this->db = $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->MDB2->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)
|
||||
$query = OC_DB::prepare( "SELECT * FROM *PREFIX*" . $options['table'] . " WHERE " . $options['matchcol'] . " LIKE ?" );
|
||||
$results = $query->execute( array( $matchval ) );
|
||||
$newreturns = $this->insertData( $results, $options );
|
||||
$return = array_merge( $return, $newreturns );
|
||||
}
|
||||
|
||||
} else {
|
||||
// Just get everything
|
||||
$query = OC_DB::prepare( "SELECT * FROM *PREFIX*" . $options['table'] );
|
||||
$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();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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 ($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 );
|
||||
}
|
||||
}
|
||||
}
|
49
lib/migration/provider.php
Normal file
49
lib/migration/provider.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
/**
|
||||
* provides search functionalty
|
||||
*/
|
||||
abstract class OC_Migration_Provider{
|
||||
|
||||
protected $id=false;
|
||||
protected $content=false;
|
||||
protected $uid=false;
|
||||
protected $info=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=false, $appinfo=false ){
|
||||
$this->content = $content;
|
||||
$this->uid = $uid;
|
||||
$this->info = $info;
|
||||
$this->appinfo = $appinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @breif returns the appid of the provider
|
||||
* @return string
|
||||
*/
|
||||
public function getID(){
|
||||
return $this->id;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue