PageRenderTime 41ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/migrate.php

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