migrate.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. <?php
  2. /**
  3. * ownCloud
  4. *
  5. * @author Tom Needham
  6. * @copyright 2012 Tom Needham tom@owncloud.com
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  10. * License as published by the Free Software Foundation; either
  11. * version 3 of the License, or any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public
  19. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. /**
  23. * provides an interface to migrate users and whole ownclouds
  24. */
  25. class OC_Migrate{
  26. // Array of OC_Migration_Provider objects
  27. static private $providers=array();
  28. // User id of the user to import/export
  29. static private $uid=false;
  30. // Holds the ZipArchive object
  31. static private $zip=false;
  32. // Stores the type of export
  33. static private $exporttype=false;
  34. // Array of temp files to be deleted after zip creation
  35. static private $tmpfiles=array();
  36. // Holds the db object
  37. static private $MDB2=false;
  38. // Schema db object
  39. static private $schema=false;
  40. // Path to the sqlite db
  41. static private $dbpath=false;
  42. // Holds the path to the zip file
  43. static private $zippath=false;
  44. // Holds the OC_Migration_Content object
  45. static private $content=false;
  46. /**
  47. * register a new migration provider
  48. * @param OC_Migrate_Provider $provider
  49. */
  50. public static function registerProvider($provider){
  51. self::$providers[]=$provider;
  52. }
  53. /**
  54. * @brief finds and loads the providers
  55. */
  56. static private function findProviders(){
  57. // Find the providers
  58. $apps = OC_App::getAllApps();
  59. foreach($apps as $app){
  60. $path = OC::$SERVERROOT . '/apps/' . $app . '/appinfo/migrate.php';
  61. if( file_exists( $path ) ){
  62. include( $path );
  63. }
  64. }
  65. }
  66. /**
  67. * @brief exports a user, or owncloud instance
  68. * @param optional $uid string user id of user to export if export type is user, defaults to current
  69. * @param ootional $type string type of export, defualts to user
  70. * @param otional $path string path to zip output folder
  71. * @return false on error, path to zip on success
  72. */
  73. public static function export( $uid=null, $type='user', $path=null ){
  74. $datadir = OC_Config::getValue( 'datadirectory' );
  75. // Validate export type
  76. $types = array( 'user', 'instance', 'system', 'userfiles' );
  77. if( !in_array( $type, $types ) ){
  78. OC_Log::write( 'migration', 'Invalid export type', OC_Log::ERROR );
  79. return json_encode( array( array( 'success' => false ) ) );
  80. }
  81. self::$exporttype = $type;
  82. // Userid?
  83. if( self::$exporttype == 'user' ){
  84. // Check user exists
  85. if( !is_null($uid) ){
  86. $db = new OC_User_Database;
  87. if( !$db->userExists( $uid ) ){
  88. OC_Log::write('migration', 'User: '.$uid.' is not in the database and so cannot be exported.', OC_Log::ERROR);
  89. return json_encode( array( 'success' => false ) );
  90. }
  91. self::$uid = $uid;
  92. } else {
  93. self::$uid = OC_User::getUser();
  94. }
  95. }
  96. // Calculate zipname
  97. if( self::$exporttype == 'user' ){
  98. $zipname = 'oc_export_' . self::$uid . '_' . date("y-m-d_H-i-s") . '.zip';
  99. } else {
  100. $zipname = 'oc_export_' . self::$exporttype . '_' . date("y-m-d_H-i-s") . '.zip';
  101. }
  102. // Calculate path
  103. if( self::$exporttype == 'user' ){
  104. self::$zippath = $datadir . '/' . self::$uid . '/' . $zipname;
  105. } else {
  106. if( !is_null( $path ) ){
  107. // Validate custom path
  108. if( !file_exists( $path ) || !is_writeable( $path ) ){
  109. OC_Log::write( 'migration', 'Path supplied is invalid.', OC_Log::ERROR );
  110. return json_encode( array( 'success' => false ) );
  111. }
  112. self::$zippath = $path . $zipname;
  113. } else {
  114. // Default path
  115. self::$zippath = get_temp_dir() . '/' . $zipname;
  116. }
  117. }
  118. // Create the zip object
  119. if( !self::createZip() ){
  120. return json_encode( array( 'success' => false ) );
  121. }
  122. // Do the export
  123. self::findProviders();
  124. $exportdata = array();
  125. switch( self::$exporttype ){
  126. case 'user':
  127. // Connect to the db
  128. self::$dbpath = $datadir . '/' . self::$uid . '/migration.db';
  129. if( !self::connectDB() ){
  130. return json_encode( array( 'success' => false ) );
  131. }
  132. self::$content = new OC_Migration_Content( self::$zip, self::$MDB2 );
  133. // Export the app info
  134. $exportdata = self::exportAppData();
  135. // Add the data dir to the zip
  136. self::$content->addDir( $datadir . '/' . self::$uid, true, '/' );
  137. break;
  138. case 'instance':
  139. self::$content = new OC_Migration_Content( self::$zip );
  140. // Creates a zip that is compatable with the import function
  141. $dbfile = tempnam( get_temp_dir(), "owncloud_export_data_" );
  142. OC_DB::getDbStructure( $dbfile, 'MDB2_SCHEMA_DUMP_ALL');
  143. // Now add in *dbname* and *dbprefix*
  144. $dbexport = file_get_contents( $dbfile );
  145. $dbnamestring = "<database>\n\n <name>" . OC_Config::getValue( "dbname", "owncloud" );
  146. $dbtableprefixstring = "<table>\n\n <name>" . OC_Config::getValue( "dbtableprefix", "oc_" );
  147. $dbexport = str_replace( $dbnamestring, "<database>\n\n <name>*dbname*", $dbexport );
  148. $dbexport = str_replace( $dbtableprefixstring, "<table>\n\n <name>*dbprefix*", $dbexport );
  149. // Add the export to the zip
  150. self::$content->addFromString( $dbexport, "dbexport.xml" );
  151. // Add user data
  152. foreach(OC_User::getUsers() as $user){
  153. self::$content->addDir( $datadir . '/' . $user . '/', true, "/userdata/" );
  154. }
  155. break;
  156. case 'userfiles':
  157. self::$content = new OC_Migration_Content( self::$zip );
  158. // Creates a zip with all of the users files
  159. foreach(OC_User::getUsers() as $user){
  160. self::$content->addDir( $datadir . '/' . $user . '/', true, "/" );
  161. }
  162. break;
  163. case 'system':
  164. self::$content = new OC_Migration_Content( self::$zip );
  165. // Creates a zip with the owncloud system files
  166. self::$content->addDir( OC::$SERVERROOT . '/', false, '/');
  167. foreach (array(".git", "3rdparty", "apps", "core", "files", "l10n", "lib", "ocs", "search", "settings", "tests") as $dir) {
  168. self::$content->addDir( OC::$SERVERROOT . '/' . $dir, true, "/");
  169. }
  170. break;
  171. }
  172. if( !$info = self::getExportInfo( $exportdata ) ){
  173. return json_encode( array( 'success' => false ) );
  174. }
  175. // Add the export info json to the export zip
  176. self::$content->addFromString( $info, 'export_info.json' );
  177. if( !self::$content->finish() ){
  178. return json_encode( array( 'success' => false ) );
  179. }
  180. return json_encode( array( 'success' => true, 'data' => self::$zippath ) );
  181. }
  182. /**
  183. * @brief imports a user, or owncloud instance
  184. * @param $path string path to zip
  185. * @param optional $type type of import (user or instance)
  186. * @param optional $uid userid of new user
  187. */
  188. public static function import( $path, $type='user', $uid=null ){
  189. $datadir = OC_Config::getValue( 'datadirectory' );
  190. // Extract the zip
  191. if( !$extractpath = self::extractZip( $path ) ){
  192. return json_encode( array( 'success' => false ) );
  193. }
  194. // Get export_info.json
  195. $scan = scandir( $extractpath );
  196. // Check for export_info.json
  197. if( !in_array( 'export_info.json', $scan ) ){
  198. OC_Log::write( 'migration', 'Invalid import file, export_info.json note found', OC_Log::ERROR );
  199. return json_encode( array( 'success' => false ) );
  200. }
  201. $json = json_decode( file_get_contents( $extractpath . 'export_info.json' ) );
  202. if( $json->exporttype != $type ){
  203. OC_Log::write( 'migration', 'Invalid import file', OC_Log::ERROR );
  204. return json_encode( array( 'success' => false ) );
  205. }
  206. self::$exporttype = $type;
  207. $currentuser = OC_User::getUser();
  208. // Have we got a user if type is user
  209. if( self::$exporttype == 'user' ){
  210. self::$uid = !is_null($uid) ? $uid : $currentuser;
  211. }
  212. // We need to be an admin if we are not importing our own data
  213. if(($type == 'user' && self::$uid != $currentuser) || $type != 'user' ){
  214. if( !OC_Group::inGroup( OC_User::getUser(), 'admin' )){
  215. // Naughty.
  216. OC_Log::write( 'migration', 'Import not permitted.', OC_Log::ERROR );
  217. return json_encode( array( 'success' => false ) );
  218. }
  219. }
  220. // Handle export types
  221. switch( self::$exporttype ){
  222. case 'user':
  223. // Check user availability
  224. if( !OC_User::userExists( self::$uid ) ){
  225. OC_Log::write( 'migration', 'User doesn\'t exist', OC_Log::ERROR );
  226. return json_encode( array( 'success' => false ) );
  227. }
  228. // Copy data
  229. if( !self::copy_r( $extractpath . $json->exporteduser, $datadir . '/' . self::$uid ) ){
  230. return json_encode( array( 'success' => false ) );
  231. }
  232. // Import user app data
  233. if( !$appsimported = self::importAppData( $extractpath . $json->exporteduser . '/migration.db', $json, self::$uid ) ){
  234. return json_encode( array( 'success' => false ) );
  235. }
  236. // All done!
  237. if( !self::unlink_r( $extractpath ) ){
  238. OC_Log::write( 'migration', 'Failed to delete the extracted zip', OC_Log::ERROR );
  239. }
  240. return json_encode( array( 'success' => true, 'data' => $appsimported ) );
  241. break;
  242. case 'instance':
  243. /*
  244. * EXPERIMENTAL
  245. // Check for new data dir and dbexport before doing anything
  246. // TODO
  247. // Delete current data folder.
  248. OC_Log::write( 'migration', "Deleting current data dir", OC_Log::INFO );
  249. if( !self::unlink_r( $datadir, false ) ){
  250. OC_Log::write( 'migration', 'Failed to delete the current data dir', OC_Log::ERROR );
  251. return json_encode( array( 'success' => false ) );
  252. }
  253. // Copy over data
  254. if( !self::copy_r( $extractpath . 'userdata', $datadir ) ){
  255. OC_Log::write( 'migration', 'Failed to copy over data directory', OC_Log::ERROR );
  256. return json_encode( array( 'success' => false ) );
  257. }
  258. // Import the db
  259. if( !OC_DB::replaceDB( $extractpath . 'dbexport.xml' ) ){
  260. return json_encode( array( 'success' => false ) );
  261. }
  262. // Done
  263. return json_encode( 'success' => true );
  264. */
  265. break;
  266. }
  267. }
  268. /**
  269. * @brief recursively deletes a directory
  270. * @param $dir string path of dir to delete
  271. * $param optional $deleteRootToo bool delete the root directory
  272. * @return bool
  273. */
  274. private static function unlink_r( $dir, $deleteRootToo=true ){
  275. if( !$dh = @opendir( $dir ) ){
  276. return false;
  277. }
  278. while (false !== ($obj = readdir($dh))){
  279. if($obj == '.' || $obj == '..') {
  280. continue;
  281. }
  282. if (!@unlink($dir . '/' . $obj)){
  283. self::unlink_r($dir.'/'.$obj, true);
  284. }
  285. }
  286. closedir($dh);
  287. if ( $deleteRootToo ) {
  288. @rmdir($dir);
  289. }
  290. return true;
  291. }
  292. /**
  293. * @brief copies recursively
  294. * @param $path string path to source folder
  295. * @param $dest string path to destination
  296. * @return bool
  297. */
  298. private static function copy_r( $path, $dest ){
  299. if( is_dir($path) ){
  300. @mkdir( $dest );
  301. $objects = scandir( $path );
  302. if( sizeof( $objects ) > 0 ){
  303. foreach( $objects as $file ){
  304. if( $file == "." || $file == ".." )
  305. continue;
  306. // go on
  307. if( is_dir( $path . '/' . $file ) ){
  308. self::copy_r( $path .'/' . $file, $dest . '/' . $file );
  309. } else {
  310. copy( $path . '/' . $file, $dest . '/' . $file );
  311. }
  312. }
  313. }
  314. return true;
  315. }
  316. elseif( is_file( $path ) ){
  317. return copy( $path, $dest );
  318. } else {
  319. return false;
  320. }
  321. }
  322. /**
  323. * @brief tries to extract the import zip
  324. * @param $path string path to the zip
  325. * @return string path to extract location (with a trailing slash) or false on failure
  326. */
  327. static private function extractZip( $path ){
  328. self::$zip = new ZipArchive;
  329. // Validate path
  330. if( !file_exists( $path ) ){
  331. OC_Log::write( 'migration', 'Zip not found', OC_Log::ERROR );
  332. return false;
  333. }
  334. if ( self::$zip->open( $path ) != TRUE ) {
  335. OC_Log::write( 'migration', "Failed to open zip file", OC_Log::ERROR );
  336. return false;
  337. }
  338. $to = get_temp_dir() . '/oc_import_' . self::$exporttype . '_' . date("y-m-d_H-i-s") . '/';
  339. if( !self::$zip->extractTo( $to ) ){
  340. return false;
  341. }
  342. self::$zip->close();
  343. return $to;
  344. }
  345. /**
  346. * @brief connects to a MDB2 database scheme
  347. * @returns bool
  348. */
  349. static private function connectScheme(){
  350. // We need a mdb2 database connection
  351. self::$MDB2->loadModule( 'Manager' );
  352. self::$MDB2->loadModule( 'Reverse' );
  353. // Connect if this did not happen before
  354. if( !self::$schema ){
  355. require_once('MDB2/Schema.php');
  356. self::$schema=MDB2_Schema::factory( self::$MDB2 );
  357. }
  358. return true;
  359. }
  360. /**
  361. * @brief creates a migration.db in the users data dir with their app data in
  362. * @return bool whether operation was successfull
  363. */
  364. private static function exportAppData( ){
  365. $success = true;
  366. $return = array();
  367. // Foreach provider
  368. foreach( self::$providers as $provider ){
  369. // Check if the app is enabled
  370. if( OC_App::isEnabled( $provider->getID() ) ){
  371. $success = true;
  372. // Does this app use the database?
  373. if( file_exists( OC::$SERVERROOT.'/apps/'.$provider->getID().'/appinfo/database.xml' ) ){
  374. // Create some app tables
  375. $tables = self::createAppTables( $provider->getID() );
  376. if( is_array( $tables ) ){
  377. // Save the table names
  378. foreach($tables as $table){
  379. $return['apps'][$provider->getID()]['tables'][] = $table;
  380. }
  381. } else {
  382. // It failed to create the tables
  383. $success = false;
  384. }
  385. }
  386. // Run the export function?
  387. if( $success ){
  388. // Set the provider properties
  389. $provider->setData( self::$uid, self::$content );
  390. $return['apps'][$provider->getID()]['success'] = $provider->export();
  391. } else {
  392. $return['apps'][$provider->getID()]['success'] = false;
  393. $return['apps'][$provider->getID()]['message'] = 'failed to create the app tables';
  394. }
  395. // Now add some app info the the return array
  396. $appinfo = OC_App::getAppInfo( $provider->getID() );
  397. $return['apps'][$provider->getID()]['version'] = OC_App::getAppVersion($provider->getID());
  398. }
  399. }
  400. return $return;
  401. }
  402. /**
  403. * @brief generates json containing export info, and merges any data supplied
  404. * @param optional $array array of data to include in the returned json
  405. * @return bool
  406. */
  407. static private function getExportInfo( $array=array() ){
  408. $info = array(
  409. 'ocversion' => OC_Util::getVersion(),
  410. 'exporttime' => time(),
  411. 'exportedby' => OC_User::getUser(),
  412. 'exporttype' => self::$exporttype
  413. );
  414. // Add hash if user export
  415. if( self::$exporttype == 'user' ){
  416. $query = OC_DB::prepare( "SELECT password FROM *PREFIX*users WHERE uid = ?" );
  417. $result = $query->execute( array( self::$uid ) );
  418. $row = $result->fetchRow();
  419. $hash = $row ? $row['password'] : false;
  420. if( !$hash ){
  421. OC_Log::write( 'migration', 'Failed to get the users password hash', OC_log::ERROR);
  422. return false;
  423. }
  424. $info['hash'] = $hash;
  425. $info['exporteduser'] = self::$uid;
  426. }
  427. if( !is_array( $array ) ){
  428. OC_Log::write( 'migration', 'Supplied $array was not an array in getExportInfo()', OC_Log::ERROR );
  429. }
  430. // Merge in other data
  431. $info = array_merge( $info, (array)$array );
  432. // Create json
  433. $json = json_encode( $info );
  434. return $json;
  435. }
  436. /**
  437. * @brief connects to migration.db, or creates if not found
  438. * @param $db optional path to migration.db, defaults to user data dir
  439. * @return bool whether the operation was successful
  440. */
  441. static private function connectDB( $path=null ){
  442. // Has the dbpath been set?
  443. self::$dbpath = !is_null( $path ) ? $path : self::$dbpath;
  444. if( !self::$dbpath ){
  445. OC_Log::write( 'migration', 'connectDB() was called without dbpath being set', OC_Log::ERROR );
  446. return false;
  447. }
  448. // Already connected
  449. if(!self::$MDB2){
  450. require_once('MDB2.php');
  451. $datadir = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" );
  452. // DB type
  453. if( class_exists( 'SQLite3' ) ){
  454. $dbtype = 'sqlite3';
  455. } else if( is_callable( 'sqlite_open' ) ){
  456. $dbtype = 'sqlite';
  457. } else {
  458. OC_Log::write( 'migration', 'SQLite not found', OC_Log::ERROR );
  459. return false;
  460. }
  461. // Prepare options array
  462. $options = array(
  463. 'portability' => MDB2_PORTABILITY_ALL & (!MDB2_PORTABILITY_FIX_CASE),
  464. 'log_line_break' => '<br>',
  465. 'idxname_format' => '%s',
  466. 'debug' => true,
  467. 'quote_identifier' => true
  468. );
  469. $dsn = array(
  470. 'phptype' => $dbtype,
  471. 'database' => self::$dbpath,
  472. 'mode' => '0644'
  473. );
  474. // Try to establish connection
  475. self::$MDB2 = MDB2::factory( $dsn, $options );
  476. // Die if we could not connect
  477. if( PEAR::isError( self::$MDB2 ) ){
  478. die( self::$MDB2->getMessage() );
  479. OC_Log::write( 'migration', 'Failed to create/connect to migration.db', OC_Log::FATAL );
  480. OC_Log::write( 'migration', self::$MDB2->getUserInfo(), OC_Log::FATAL );
  481. OC_Log::write( 'migration', self::$MDB2->getMessage(), OC_Log::FATAL );
  482. return false;
  483. }
  484. // We always, really always want associative arrays
  485. self::$MDB2->setFetchMode(MDB2_FETCHMODE_ASSOC);
  486. }
  487. return true;
  488. }
  489. /**
  490. * @brief creates the tables in migration.db from an apps database.xml
  491. * @param $appid string id of the app
  492. * @return bool whether the operation was successful
  493. */
  494. static private function createAppTables( $appid ){
  495. if( !self::connectScheme() ){
  496. return false;
  497. }
  498. // There is a database.xml file
  499. $content = file_get_contents( OC::$SERVERROOT . '/apps/' . $appid . '/appinfo/database.xml' );
  500. $file2 = 'static://db_scheme';
  501. // TODO get the relative path to migration.db from the data dir
  502. // For now just cheat
  503. $path = pathinfo( self::$dbpath );
  504. $content = str_replace( '*dbname*', self::$uid.'/migration', $content );
  505. $content = str_replace( '*dbprefix*', '', $content );
  506. $xml = new SimpleXMLElement($content);
  507. foreach($xml->table as $table){
  508. $tables[] = (string)$table->name;
  509. }
  510. file_put_contents( $file2, $content );
  511. // Try to create tables
  512. $definition = self::$schema->parseDatabaseDefinitionFile( $file2 );
  513. unlink( $file2 );
  514. // Die in case something went wrong
  515. if( $definition instanceof MDB2_Schema_Error ){
  516. OC_Log::write( 'migration', 'Failed to parse database.xml for: '.$appid, OC_Log::FATAL );
  517. OC_Log::write( 'migration', $definition->getMessage().': '.$definition->getUserInfo(), OC_Log::FATAL );
  518. return false;
  519. }
  520. $definition['overwrite'] = true;
  521. $ret = self::$schema->createDatabase( $definition );
  522. // Die in case something went wrong
  523. if( $ret instanceof MDB2_Error ){
  524. OC_Log::write( 'migration', 'Failed to create tables for: '.$appid, OC_Log::FATAL );
  525. OC_Log::write( 'migration', $ret->getMessage().': '.$ret->getUserInfo(), OC_Log::FATAL );
  526. return false;
  527. }
  528. return $tables;
  529. }
  530. /**
  531. * @brief tries to create the zip
  532. * @param $path string path to zip destination
  533. * @return bool
  534. */
  535. static private function createZip(){
  536. self::$zip = new ZipArchive;
  537. // Check if properties are set
  538. if( !self::$zippath ){
  539. OC_Log::write('migration', 'createZip() called but $zip and/or $zippath have not been set', OC_Log::ERROR);
  540. return false;
  541. }
  542. if ( self::$zip->open( self::$zippath, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE ) !== TRUE ) {
  543. OC_Log::write('migration', 'Failed to create the zip with error: '.self::$zip->getStatusString(), OC_Log::ERROR);
  544. return false;
  545. } else {
  546. return true;
  547. }
  548. }
  549. /**
  550. * @brief returns an array of apps that support migration
  551. * @return array
  552. */
  553. static public function getApps(){
  554. $allapps = OC_App::getAllApps();
  555. foreach($allapps as $app){
  556. $path = OC::$SERVERROOT . '/apps/' . $app . '/lib/migrate.php';
  557. if( file_exists( $path ) ){
  558. $supportsmigration[] = $app;
  559. }
  560. }
  561. return $supportsmigration;
  562. }
  563. /**
  564. * @brief imports a new user
  565. * @param $db string path to migration.db
  566. * @param $info object of migration info
  567. * @param $uid optional uid to use
  568. * @return array of apps with import statuses, or false on failure.
  569. */
  570. public static function importAppData( $db, $info, $uid=null ){
  571. // Check if the db exists
  572. if( file_exists( $db ) ){
  573. // Connect to the db
  574. if(!self::connectDB( $db )){
  575. OC_Log::write('migration','Failed to connect to migration.db',OC_Log::ERROR);
  576. return false;
  577. }
  578. } else {
  579. OC_Log::write('migration','Migration.db not found at: '.$db, OC_Log::FATAL );
  580. return false;
  581. }
  582. // Find providers
  583. self::findProviders();
  584. // Generate importinfo array
  585. $importinfo = array(
  586. 'olduid' => $info->exporteduser,
  587. 'newuid' => self::$uid
  588. );
  589. foreach( self::$providers as $provider){
  590. // Is the app in the export?
  591. $id = $provider->getID();
  592. if( isset( $info->apps->$id ) ){
  593. // Is the app installed
  594. if( !OC_App::isEnabled( $id ) ){
  595. OC_Log::write( 'migration', 'App: ' . $id . ' is not installed, can\'t import data.', OC_Log::INFO );
  596. $appsstatus[$id] = 'notsupported';
  597. } else {
  598. // Did it succeed on export?
  599. if( $info->apps->$id->success ){
  600. // Give the provider the content object
  601. if( !self::connectDB( $db ) ){
  602. return false;
  603. }
  604. $content = new OC_Migration_Content( self::$zip, self::$MDB2 );
  605. $provider->setData( self::$uid, $content, $info );
  606. // Then do the import
  607. if( !$appsstatus[$id] = $provider->import( $info->apps->$id, $importinfo ) ){
  608. // Failed to import app
  609. OC_Log::write( 'migration', 'Failed to import app data for user: ' . self::$uid . ' for app: ' . $id, OC_Log::ERROR );
  610. }
  611. } else {
  612. // Add to failed list
  613. $appsstatus[$id] = false;
  614. }
  615. }
  616. }
  617. }
  618. return $appsstatus;
  619. }
  620. /*
  621. * @brief creates a new user in the database
  622. * @param $uid string user_id of the user to be created
  623. * @param $hash string hash of the user to be created
  624. * @return bool result of user creation
  625. */
  626. public static function createUser( $uid, $hash ){
  627. // Check if userid exists
  628. if(OC_User::userExists( $uid )){
  629. return false;
  630. }
  631. // Create the user
  632. $query = OC_DB::prepare( "INSERT INTO `*PREFIX*users` ( `uid`, `password` ) VALUES( ?, ? )" );
  633. $result = $query->execute( array( $uid, $hash));
  634. if( !$result ){
  635. OC_Log::write('migration', 'Failed to create the new user "'.$uid."");
  636. }
  637. return $result ? true : false;
  638. }
  639. }