backup_migrate.install 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  1. <?php
  2. /**
  3. * @file
  4. * Install hooks for Backup and Migrate.
  5. */
  6. /**
  7. * Implements hook_requirements().
  8. */
  9. function backup_migrate_requirements($phase) {
  10. $requirements = array();
  11. // Ensure translations don't break during installation.
  12. $t = get_t();
  13. if ($phase == 'runtime') {
  14. // Get a list of all destinations, make sure none of them are publicly
  15. // accessible.
  16. // @todo Expand the API to add methods to specifically check this.
  17. backup_migrate_include('destinations');
  18. foreach (backup_migrate_get_destinations() as $dest_name => $destination) {
  19. if (method_exists($destination, 'get_display_location')) {
  20. $dest_path = $destination->get_display_location();
  21. if (!empty($dest_path) && file_valid_uri($dest_path)) {
  22. $scheme = file_uri_scheme($dest_path);
  23. // Support public and private storage and raw server paths.
  24. if ($scheme === 'private' || $scheme === 'public' || substr($dest_path, 0, 1) == '/') {
  25. // Check if the path exists.
  26. $path_exists = file_prepare_directory($dest_path, FILE_CREATE_DIRECTORY);
  27. if ($path_exists) {
  28. $real_path = drupal_realpath($dest_path);
  29. // See if the private path is somewhere inside the main Drupal
  30. // directory structure.
  31. if (strpos($real_path, DRUPAL_ROOT) === 0) {
  32. // Extract the relative path from the Drupal root path, and
  33. // then add the base URL, theoretically creating a fully
  34. // qualified URL to the storage directory.
  35. $url = substr($real_path, strlen(DRUPAL_ROOT) + 1);
  36. $url = url($url, array('absolute' => TRUE));
  37. $result = drupal_http_request($url);
  38. // If the HTTP request comes back as a status 200 that means
  39. // there is a directory listing of some sort; directory paths
  40. // should return a 503 error.
  41. if (!empty($result->code) && $result->code == 200) {
  42. // Get the human readable information for this destination.
  43. $dest_spec = $destination->get_list_row();
  44. // Display a warning message.
  45. $requirements['bmdest_' . $dest_name] = array(
  46. 'severity' => REQUIREMENT_ERROR,
  47. 'title' => 'Backup Migrate',
  48. 'value' => $t('Backup destination "%dest" is publicly accessible!', array('%dest' => $dest_spec['name'])),
  49. 'description' => $t('The backup destination, "%dest", stores its files in the "%path" directory. This directory is publicly available from the web server and urgently needs to be secured! Please see the Drupal manual on <a href="@manual">configuring the private directory path</a> on how to fix this problem.',
  50. array(
  51. '%dest' => $dest_spec['name'],
  52. '%path' => $real_path,
  53. '@manual' => 'https://www.drupal.org/docs/7/core/modules/file/overview',
  54. )),
  55. );
  56. }
  57. // Check an individual file.
  58. else {
  59. $files = scandir($real_path);
  60. if (!empty($files)) {
  61. foreach ($files as $file) {
  62. // Skip the base field pointers.
  63. if ($file == '.' || $file == '..') {
  64. continue;
  65. }
  66. $result = drupal_http_request($url . '/' . $file);
  67. // If the HTTP request comes back as a status 200 that
  68. // means the file is accessible.
  69. if (!empty($result->code) && $result->code == 200) {
  70. // Get the human readable information for this
  71. // destination.
  72. $dest_spec = $destination->get_list_row();
  73. // Display a warning message.
  74. $requirements['bmdest_' . $dest_name] = array(
  75. 'severity' => REQUIREMENT_ERROR,
  76. 'title' => 'Backup Migrate',
  77. 'value' => $t('Files in "%dest" are publicly accessible!', array('%dest' => $dest_spec['name'])),
  78. 'description' => $t('The backup destination, "%dest", stores its files in the "%path" directory. These file(s) are publicly available from the web server and urgently need to be secured! Please see the Drupal manual on <a href="@manual">configuring the private directory path</a> on how to fix this problem.',
  79. array(
  80. '%dest' => $dest_spec['name'],
  81. '%path' => $real_path,
  82. '@manual' => 'https://www.drupal.org/docs/7/core/modules/file/overview',
  83. )),
  84. );
  85. }
  86. // Only need to check one file.
  87. break;
  88. }
  89. }
  90. }
  91. }
  92. }
  93. }
  94. }
  95. }
  96. }
  97. // Leave a note if there were no problems.
  98. // @todo No point in displaying this until the API has been expanded.
  99. // @code
  100. // if (empty($requirements)) {
  101. // $requirements['bmdest_' . $dest_name] = array(
  102. // 'severity' => REQUIREMENT_INFO,
  103. // 'title' => 'Backup Migrate',
  104. // 'value' => $t('Backup destinations are safe'),
  105. // 'description' => $t('The backup destinations were all checked and none of them were exposing files to the public. This is a good thing.'),
  106. // );
  107. // }
  108. // @endcode
  109. if (variable_get('backup_migrate_disable_cron', FALSE)) {
  110. $requirements['bm_disable_cron'] = array(
  111. 'severity' => REQUIREMENT_INFO,
  112. 'title' => 'Backup Migrate',
  113. 'value' => $t('Cron tasks are disabled'),
  114. 'description' => $t('The cron tasks have been disabled, so scheduled backups will not run. See the Backup & Migrate module\'s README.txt file for further details.'),
  115. );
  116. }
  117. }
  118. return $requirements;
  119. }
  120. /**
  121. * Implements hook_schema().
  122. */
  123. function backup_migrate_schema() {
  124. $schema['backup_migrate_profiles'] = array(
  125. 'export' => array(
  126. 'key' => 'machine_name',
  127. 'key name' => 'Profile ID',
  128. 'admin_title' => 'name',
  129. 'primary key' => 'profile_id',
  130. // Exports will be defined as $preset.
  131. 'identifier' => 'item',
  132. // Function hook name.
  133. 'default hook' => 'exportables_backup_migrate_profiles',
  134. 'api' => array(
  135. 'owner' => 'backup_migrate',
  136. // Base name for api include files.
  137. 'api' => 'backup_migrate_exportables',
  138. 'minimum_version' => 1,
  139. 'current_version' => 1,
  140. ),
  141. ),
  142. 'fields' => array(
  143. 'profile_id' => array(
  144. 'type' => 'serial',
  145. 'unsigned' => TRUE,
  146. 'not null' => TRUE,
  147. 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
  148. // Do not export database-only keys.
  149. 'no export' => TRUE,
  150. ),
  151. 'machine_name' => array(
  152. 'type' => 'varchar',
  153. 'length' => 255,
  154. 'not null' => TRUE,
  155. 'default' => '0',
  156. 'description' => 'The primary identifier for a profile.',
  157. ),
  158. 'name' => array(
  159. 'description' => 'The name of the profile.',
  160. 'type' => 'varchar',
  161. 'length' => 255,
  162. 'not null' => TRUE,
  163. ),
  164. 'filename' => array(
  165. 'description' => 'The name of the profile.',
  166. 'type' => 'varchar',
  167. 'length' => 255,
  168. 'not null' => TRUE,
  169. ),
  170. 'append_timestamp' => array(
  171. 'description' => 'Append a timestamp to the filename.',
  172. 'type' => 'int',
  173. 'size' => 'tiny',
  174. 'unsigned' => TRUE,
  175. 'not null' => TRUE,
  176. 'default' => 0,
  177. ),
  178. 'timestamp_format' => array(
  179. 'description' => 'The format of the timestamp.',
  180. 'type' => 'varchar',
  181. 'length' => 14,
  182. 'not null' => TRUE,
  183. ),
  184. 'filters' => array(
  185. 'description' => 'The filter settings for the profile.',
  186. 'type' => 'text',
  187. 'not null' => TRUE,
  188. 'serialize' => TRUE,
  189. 'serialized default' => 'a:0:{}',
  190. ),
  191. ),
  192. 'primary key' => array('profile_id'),
  193. );
  194. $schema['backup_migrate_destinations'] = array(
  195. 'export' => array(
  196. 'key' => 'machine_name',
  197. 'key name' => 'Destination ID',
  198. 'admin_title' => 'name',
  199. 'primary key' => 'destination_id',
  200. // Exports will be defined as $preset.
  201. 'identifier' => 'item',
  202. // Function hook name.
  203. 'default hook' => 'exportables_backup_migrate_destinations',
  204. 'api' => array(
  205. 'owner' => 'backup_migrate',
  206. // Base name for api include files.
  207. 'api' => 'backup_migrate_exportables',
  208. 'minimum_version' => 1,
  209. 'current_version' => 1,
  210. ),
  211. ),
  212. 'fields' => array(
  213. 'destination_id' => array(
  214. 'type' => 'serial',
  215. 'unsigned' => TRUE,
  216. 'not null' => TRUE,
  217. 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
  218. // Do not export database-only keys.
  219. 'no export' => TRUE,
  220. ),
  221. 'machine_name' => array(
  222. 'type' => 'varchar',
  223. 'length' => 255,
  224. 'not null' => TRUE,
  225. 'default' => '0',
  226. 'description' => 'The primary identifier for a destination.',
  227. ),
  228. 'name' => array(
  229. 'description' => 'The name of the destination.',
  230. 'type' => 'varchar',
  231. 'length' => 255,
  232. 'not null' => TRUE,
  233. ),
  234. 'subtype' => array(
  235. 'description' => 'The type of the destination.',
  236. 'type' => 'varchar',
  237. 'length' => 32,
  238. 'not null' => TRUE,
  239. ),
  240. 'location' => array(
  241. 'description' => 'The the location string of the destination.',
  242. 'type' => 'text',
  243. 'not null' => TRUE,
  244. ),
  245. 'settings' => array(
  246. 'description' => 'Other settings for the destination.',
  247. 'type' => 'text',
  248. 'not null' => TRUE,
  249. 'serialize' => TRUE,
  250. 'serialized default' => 'a:0:{}',
  251. ),
  252. ),
  253. 'primary key' => array('destination_id'),
  254. );
  255. $schema['backup_migrate_sources'] = array(
  256. 'export' => array(
  257. 'key' => 'machine_name',
  258. 'key name' => 'Source ID',
  259. 'admin_title' => 'name',
  260. 'primary key' => 'source_id',
  261. // Exports will be defined as $preset.
  262. 'identifier' => 'item',
  263. // Function hook name.
  264. 'default hook' => 'exportables_backup_migrate_sources',
  265. 'api' => array(
  266. 'owner' => 'backup_migrate',
  267. // Base name for api include files.
  268. 'api' => 'backup_migrate_exportables',
  269. 'minimum_version' => 1,
  270. 'current_version' => 1,
  271. ),
  272. ),
  273. 'fields' => array(
  274. 'source_id' => array(
  275. 'type' => 'serial',
  276. 'unsigned' => TRUE,
  277. 'not null' => TRUE,
  278. 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
  279. // Do not export database-only keys.
  280. 'no export' => TRUE,
  281. ),
  282. 'machine_name' => array(
  283. 'type' => 'varchar',
  284. 'length' => 255,
  285. 'not null' => TRUE,
  286. 'default' => '0',
  287. 'description' => 'The primary identifier for a source.',
  288. ),
  289. 'name' => array(
  290. 'description' => 'The name of the source.',
  291. 'type' => 'varchar',
  292. 'length' => 255,
  293. 'not null' => TRUE,
  294. ),
  295. 'subtype' => array(
  296. 'description' => 'The type of the source.',
  297. 'type' => 'varchar',
  298. 'length' => 32,
  299. 'not null' => TRUE,
  300. ),
  301. 'location' => array(
  302. 'description' => 'The the location string of the source.',
  303. 'type' => 'text',
  304. 'not null' => TRUE,
  305. ),
  306. 'settings' => array(
  307. 'description' => 'Other settings for the source.',
  308. 'type' => 'text',
  309. 'not null' => TRUE,
  310. 'serialize' => TRUE,
  311. 'serialized default' => 'a:0:{}',
  312. ),
  313. ),
  314. 'primary key' => array('source_id'),
  315. );
  316. $schema['backup_migrate_schedules'] = array(
  317. 'export' => array(
  318. 'key' => 'machine_name',
  319. 'key name' => 'Source ID',
  320. 'admin_title' => 'name',
  321. 'primary key' => 'schedule_id',
  322. // Exports will be defined as $preset.
  323. 'identifier' => 'item',
  324. // Function hook name.
  325. 'default hook' => 'exportables_backup_migrate_schedules',
  326. 'api' => array(
  327. 'owner' => 'backup_migrate',
  328. // Base name for api include files.
  329. 'api' => 'backup_migrate_exportables',
  330. 'minimum_version' => 1,
  331. 'current_version' => 1,
  332. ),
  333. ),
  334. 'fields' => array(
  335. 'schedule_id' => array(
  336. 'type' => 'serial',
  337. 'unsigned' => TRUE,
  338. 'not null' => TRUE,
  339. 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
  340. // Do not export database-only keys.
  341. 'no export' => TRUE,
  342. ),
  343. 'machine_name' => array(
  344. 'type' => 'varchar',
  345. 'length' => 255,
  346. 'not null' => TRUE,
  347. 'default' => '0',
  348. 'description' => 'The primary identifier for a profile.',
  349. ),
  350. 'name' => array(
  351. 'description' => 'The name of the profile.',
  352. 'type' => 'varchar',
  353. 'length' => 255,
  354. 'not null' => TRUE,
  355. ),
  356. 'source_id' => array(
  357. 'description' => 'The {backup_migrate_destination}.destination_id of the source to backup from.',
  358. 'type' => 'varchar',
  359. 'length' => 255,
  360. 'default' => 'db',
  361. 'not null' => TRUE,
  362. ),
  363. 'destination_id' => array(
  364. 'type' => 'varchar',
  365. 'length' => 255,
  366. 'not null' => TRUE,
  367. 'default' => '0',
  368. 'description' => 'The {backup_migrate_destination}.destination_id of the destination to back up to.',
  369. ),
  370. 'copy_destination_id' => array(
  371. 'type' => 'varchar',
  372. 'length' => 32,
  373. 'not null' => TRUE,
  374. 'default' => '0',
  375. 'description' => 'A second {backup_migrate_destination}.destination_id of the destination to copy the backup to.',
  376. ),
  377. 'profile_id' => array(
  378. 'type' => 'varchar',
  379. 'length' => 255,
  380. 'not null' => TRUE,
  381. 'default' => '0',
  382. 'description' => 'The primary identifier for a profile.',
  383. ),
  384. 'keep' => array(
  385. 'type' => 'int',
  386. 'not null' => TRUE,
  387. 'default' => 0,
  388. 'description' => 'The number of backups to keep.',
  389. ),
  390. 'period' => array(
  391. 'type' => 'int',
  392. 'not null' => TRUE,
  393. 'default' => 0,
  394. 'description' => 'The number of seconds between backups.',
  395. ),
  396. 'enabled' => array(
  397. 'description' => 'Whether the schedule is enabled.',
  398. 'type' => 'int',
  399. 'size' => 'tiny',
  400. 'unsigned' => TRUE,
  401. 'not null' => TRUE,
  402. 'default' => 0,
  403. ),
  404. 'cron' => array(
  405. 'description' => 'Whether the schedule should be run during cron.',
  406. 'type' => 'varchar',
  407. 'length' => 32,
  408. 'not null' => TRUE,
  409. 'default' => 'builtin',
  410. ),
  411. 'cron_schedule' => array(
  412. 'description' => 'The cron schedule to run on.',
  413. 'type' => 'varchar',
  414. 'length' => 255,
  415. 'not null' => TRUE,
  416. 'default' => '0 4 * * *',
  417. ),
  418. ),
  419. 'primary key' => array('schedule_id'),
  420. );
  421. return $schema;
  422. }
  423. /**
  424. * Implements hook_uninstall().
  425. */
  426. function backup_migrate_uninstall() {
  427. variable_del('backup_migrate_backup_max_time');
  428. variable_del('backup_migrate_copy_destination_id');
  429. variable_del('backup_migrate_data_bytes_per_line');
  430. variable_del('backup_migrate_data_rows_per_line');
  431. variable_del('backup_migrate_data_rows_per_query');
  432. variable_del('backup_migrate_destination_id');
  433. variable_del('backup_migrate_disable_cron');
  434. variable_del('backup_migrate_memory_limit');
  435. variable_del('backup_migrate_profile_id');
  436. variable_del('backup_migrate_schedule_last_run_');
  437. variable_del('backup_migrate_source_id');
  438. variable_del('backup_migrate_timeout_buffer');
  439. variable_del('backup_migrate_verbose');
  440. variable_del('nodesquirrel_endpoint_urls');
  441. variable_del('nodesquirrel_schedule');
  442. variable_del('nodesquirrel_schedule_enabled');
  443. variable_del('nodesquirrel_schedule_source_id');
  444. variable_del('nodesquirrel_secret_key');
  445. }
  446. /**
  447. * Update from 1.x to 2.x.
  448. */
  449. function backup_migrate_update_2000() {
  450. _backup_migrate_setup_database_defaults();
  451. return array();
  452. }
  453. /**
  454. * Adding filter field for dev release of 2009-01-28.
  455. */
  456. function backup_migrate_update_2001() {
  457. $ret = array();
  458. $schema = drupal_get_schema_unprocessed('backup_migrate', 'backup_migrate_profiles');
  459. // Add the filters field to the db.
  460. if (!db_field_exists('backup_migrate_profiles', 'filters')) {
  461. db_add_field('backup_migrate_profiles', 'filters', array(
  462. 'description' => t('The filter settings for the profile.'),
  463. 'type' => 'text',
  464. 'not null' => TRUE,
  465. ));
  466. }
  467. // Add the source field.
  468. if (!db_field_exists('backup_migrate_profiles', 'source_id')) {
  469. db_add_field('backup_migrate_profiles', 'source_id', array(
  470. 'description' => t('The {backup_migrate_destination}.destination_id of the source to backup from.'),
  471. 'type' => 'varchar',
  472. 'length' => 255,
  473. 'default' => 'db',
  474. 'not null' => TRUE,
  475. ));
  476. }
  477. // Remove the compression field.
  478. if (db_field_exists('backup_migrate_profiles', 'compression')) {
  479. db_drop_field('backup_migrate_profiles', 'compression');
  480. }
  481. return $ret;
  482. }
  483. /**
  484. * Clear the cache because there was a menu structure change.
  485. */
  486. function backup_migrate_update_2002() {
  487. // Cache should clear automatically. Nothing to do here.
  488. return array();
  489. }
  490. /**
  491. * Allowing non-int profile ids in schedules 2009-05-31.
  492. */
  493. function backup_migrate_update_2003() {
  494. $ret = array();
  495. $spec = array(
  496. 'type' => 'varchar',
  497. 'length' => 255,
  498. 'not null' => TRUE,
  499. 'default' => '0',
  500. 'description' => 'The primary identifier for a profile.',
  501. );
  502. db_change_field('backup_migrate_schedules', 'profile_id', 'profile_id', $spec);
  503. return $ret;
  504. }
  505. /**
  506. * Allowing non-int profile ids 2009-07-01.
  507. */
  508. function backup_migrate_update_2004() {
  509. $ret = array();
  510. $spec = array(
  511. 'type' => 'varchar',
  512. 'length' => 255,
  513. 'not null' => TRUE,
  514. 'default' => '0',
  515. );
  516. $spec['description'] = 'The primary identifier for a destination.';
  517. db_change_field('backup_migrate_destinations', 'destination_id', 'destination_id', $spec);
  518. $spec['description'] = 'The primary identifier for a profile.';
  519. db_change_field('backup_migrate_profiles', 'profile_id', 'profile_id', $spec);
  520. $spec['description'] = 'The primary identifier for a schedule.';
  521. db_change_field('backup_migrate_schedules', 'schedule_id', 'schedule_id', $spec);
  522. // Drop the user/pass fields as they weren't being used.
  523. if (db_field_exists('backup_migrate_destinations', 'username')) {
  524. db_drop_field('backup_migrate_destinations', 'username');
  525. }
  526. if (db_field_exists('backup_migrate_destinations', 'password')) {
  527. db_drop_field('backup_migrate_destinations', 'password');
  528. }
  529. return $ret;
  530. }
  531. /**
  532. * Change the default database id to something friendlier 2009-08-08.
  533. */
  534. function backup_migrate_update_2005() {
  535. require_once './' . drupal_get_path('module', 'backup_migrate') . '/includes/crud.inc';
  536. require_once './' . drupal_get_path('module', 'backup_migrate') . '/includes/profiles.inc';
  537. $ret = array();
  538. // Change the destination ids of the defined database sources mostly to make
  539. // using them with drush friendlier.
  540. // Change the db_url:default id to simply 'db'.
  541. $ret[] = db_query("UPDATE {backup_migrate_profiles} SET source_id = 'db' WHERE source_id = 'db_url:default'");
  542. $ret[] = db_query("UPDATE {backup_migrate_schedules} SET destination_id = 'db' WHERE destination_id = 'db_url:default'");
  543. // Change the defined db keys from db_url:key to db:key.
  544. $ret[] = db_query("UPDATE {backup_migrate_profiles} SET source_id = REPLACE(source_id, 'db_url:', 'db:')");
  545. $ret[] = db_query("UPDATE {backup_migrate_schedules} SET destination_id = REPLACE(destination_id, 'db_url:', 'db:')");
  546. // Add the source field to the schedule.
  547. if (!db_field_exists('backup_migrate_schedules', 'source_id')) {
  548. db_add_field('backup_migrate_schedules', 'source_id', array(
  549. 'description' => t('The db source to backup from.'),
  550. 'type' => 'varchar',
  551. 'length' => 255,
  552. 'default' => 'db',
  553. 'not null' => TRUE,
  554. ));
  555. }
  556. // Copy source data from profiles to schedules.
  557. $result = db_query('SELECT p.source_id, s.schedule_id FROM {backup_migrate_schedules} s LEFT JOIN {backup_migrate_profiles} p ON s.profile_id = p.profile_id', array(), array('fetch' => PDO::FETCH_ASSOC));
  558. foreach ($result as $schedule) {
  559. if (!$schedule['source_id']) {
  560. $schedule['source_id'] = 'db';
  561. }
  562. $ret[] = db_query("UPDATE {backup_migrate_schedules} SET source_id = '" . $schedule['source_id'] . "' WHERE schedule_id = '" . $schedule['profile_id'] . "'");
  563. }
  564. if (db_field_exists('backup_migrate_profiles', 'source_id')) {
  565. db_drop_field('backup_migrate_profiles', 'source_id');
  566. }
  567. // Copy the no-data and exclude tables settings into the 'filter' field.
  568. $result = db_query('SELECT * FROM {backup_migrate_profiles}', array(), array('fetch' => PDO::FETCH_ASSOC));
  569. foreach ($result as $item) {
  570. if (isset($item['nodata_tables']) && isset($item['exclude_tables'])) {
  571. $profile = backup_migrate_get_profile($item['profile_id']);
  572. $profile->filters['nodata_tables'] = unserialize($item['nodata_tables']);
  573. $profile->filters['exclude_tables'] = unserialize($item['exclude_tables']);
  574. $profile->save();
  575. }
  576. }
  577. if (db_field_exists('backup_migrate_profiles', 'nodata_tables')) {
  578. db_drop_field('backup_migrate_profiles', 'nodata_tables');
  579. }
  580. if (db_field_exists('backup_migrate_profiles', 'exclude_tables')) {
  581. db_drop_field('backup_migrate_profiles', 'exclude_tables');
  582. }
  583. return $ret;
  584. }
  585. /**
  586. * Move the backup and migrate directory to the private directory.
  587. */
  588. function backup_migrate_update_7200() {
  589. $from = 'public://backup_migrate';
  590. $to = 'private://backup_migrate';
  591. if (drupal_realpath($from) && !drupal_realpath($to)) {
  592. if (!rename($from, $to)) {
  593. drupal_set_message(t('Unable to move the backups directory to your private folder, please check file permissions and move the directory %from to %to', array('%from' => drupal_realpath($from), '%to' => drupal_realpath($to))), 'warning');
  594. }
  595. }
  596. }
  597. /**
  598. * Change the filename field to support 255 characters.
  599. */
  600. function backup_migrate_update_7202() {
  601. $ret = array();
  602. db_change_field('backup_migrate_profiles', 'filename', 'filename', array(
  603. 'type' => 'varchar',
  604. 'length' => 255,
  605. 'not null' => TRUE,
  606. ));
  607. return $ret;
  608. }
  609. /**
  610. * Schedule last run times to use variables instead of saving with the schedule.
  611. */
  612. function backup_migrate_update_7203() {
  613. $result = db_query('SELECT * FROM {backup_migrate_schedules}', array(), array('fetch' => PDO::FETCH_ASSOC));
  614. foreach ($result as $item) {
  615. if (isset($item['last_run'])) {
  616. variable_set('backup_migrate_schedule_last_run_' . $item['schedule_id'], $item['last_run']);
  617. }
  618. }
  619. if (db_field_exists('backup_migrate_schedules', 'last_run')) {
  620. db_drop_field('backup_migrate_schedules', 'last_run');
  621. }
  622. }
  623. /**
  624. * Uninstall backup migrate files if it's installed.
  625. */
  626. function backup_migrate_update_7300() {
  627. if (module_exists('backup_migrate_files')) {
  628. module_disable(array('backup_migrate_files'));
  629. $ret[] = array(
  630. 'success' => TRUE,
  631. 'query' => 'Disabled the Backup and Migrate Files module',
  632. );
  633. }
  634. if (module_exists('nodesquirrel')) {
  635. module_disable(array('nodesquirrel'));
  636. $ret[] = array(
  637. 'success' => TRUE,
  638. 'query' => 'Disabled the NodeSquirrel module',
  639. );
  640. }
  641. // Add sources to the schema.
  642. $schema['backup_migrate_sources'] = array(
  643. 'fields' => array(
  644. 'source_id' => array(
  645. 'type' => 'varchar',
  646. 'length' => 32,
  647. 'not null' => TRUE,
  648. 'default' => '0',
  649. 'description' => t('The primary identifier for a source.'),
  650. ),
  651. 'name' => array(
  652. 'description' => t('The name of the source.'),
  653. 'type' => 'varchar',
  654. 'length' => 255,
  655. 'not null' => TRUE,
  656. ),
  657. 'type' => array(
  658. 'description' => t('The type of the source.'),
  659. 'type' => 'varchar',
  660. 'length' => 32,
  661. 'not null' => TRUE,
  662. ),
  663. 'location' => array(
  664. 'description' => t('The the location string of the source.'),
  665. 'type' => 'text',
  666. 'not null' => TRUE,
  667. ),
  668. 'settings' => array(
  669. 'description' => t('Other settings for the source.'),
  670. 'type' => 'text',
  671. 'not null' => TRUE,
  672. 'serialize' => TRUE,
  673. 'serialized default' => 'a:0:{}',
  674. ),
  675. ),
  676. 'primary key' => array('source_id'),
  677. );
  678. if (!db_table_exists('backup_migrate_sources')) {
  679. db_create_table('backup_migrate_sources', $schema['backup_migrate_sources']);
  680. }
  681. // Move custom destinations to sources.
  682. $result = db_query("SELECT * FROM {backup_migrate_destinations} WHERE type in ('filesource', 'db')", array(), array('fetch' => PDO::FETCH_ASSOC));
  683. foreach ($result as $item) {
  684. $item['source_id'] = $item['destination_id'];
  685. drupal_write_record('backup_migrate_source', $item);
  686. }
  687. // Change 'destination' settings to 'source' settings.
  688. $result = db_query('SELECT * FROM {backup_migrate_profiles}', array(), array('fetch' => PDO::FETCH_ASSOC));
  689. foreach ($result as $item) {
  690. $item['filters'] = unserialize($item['filters']);
  691. $item['filters']['sources'] = $item['filters']['destinations'];
  692. unset($item['filters']['destinations']);
  693. drupal_write_record('backup_migrate_profiles', $item, array('profile_id'));
  694. }
  695. }
  696. /**
  697. * Switch the cron switch to text.
  698. */
  699. function backup_migrate_update_7301() {
  700. db_change_field('backup_migrate_schedules', 'cron', 'cron', array(
  701. 'type' => 'varchar',
  702. 'length' => 32,
  703. 'not null' => TRUE,
  704. 'default' => 'builtin',
  705. ));
  706. db_add_field('backup_migrate_schedules', 'cron_schedule', array(
  707. 'description' => 'The cron schedule to run on.',
  708. 'type' => 'varchar',
  709. 'length' => 255,
  710. 'default' => '0 4 * * *',
  711. 'not null' => TRUE,
  712. ));
  713. }
  714. /**
  715. * Add a second destination to schedules.
  716. */
  717. function backup_migrate_update_7302() {
  718. db_add_field('backup_migrate_schedules', 'copy_destination_id',
  719. array(
  720. 'type' => 'varchar',
  721. 'length' => 32,
  722. 'not null' => TRUE,
  723. 'default' => '0',
  724. 'description' => 'A second {backup_migrate_destination}.destination_id of the destination to copy the backup to.',
  725. )
  726. );
  727. }
  728. /**
  729. * Add a serial id field to all tables to allow them to be ctools exportable.
  730. */
  731. function backup_migrate_update_7303() {
  732. foreach (array(
  733. 'backup_migrate_sources' => 'source_id',
  734. 'backup_migrate_destinations' => 'destination_id',
  735. 'backup_migrate_schedules' => 'schedule_id',
  736. 'backup_migrate_profiles' => 'profile_id',
  737. ) as $table => $id) {
  738. // Take the primary key status from the machine name so it can be renamed
  739. // A serial field must be defined as a key, so make a temporary index.
  740. // See: https://www.drupal.org/node/190027
  741. db_add_index($table, 'temp', array($id));
  742. db_drop_primary_key($table);
  743. // Drop our temporary index.
  744. db_drop_index($table, 'temp');
  745. // Switch the name of the id to 'machine_name' to be more ctools standard.
  746. db_change_field($table, $id, 'machine_name', array(
  747. 'type' => 'varchar',
  748. 'length' => 32,
  749. 'not null' => TRUE,
  750. ));
  751. // Add a serial ID.
  752. db_add_field($table, $id,
  753. array(
  754. 'type' => 'serial',
  755. 'unsigned' => TRUE,
  756. 'not null' => TRUE,
  757. 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
  758. // Do not export database-only keys.
  759. 'no export' => TRUE,
  760. ),
  761. array('primary key' => array($id))
  762. );
  763. }
  764. foreach (array('backup_migrate_sources', 'backup_migrate_destinations') as $table) {
  765. db_change_field($table, 'type', 'subtype', array(
  766. 'type' => 'varchar',
  767. 'length' => 32,
  768. 'not null' => TRUE,
  769. ));
  770. }
  771. }
  772. /**
  773. * Update all schedules to use the built in cron if none is specified.
  774. */
  775. function backup_migrate_update_7304() {
  776. db_query("UPDATE {backup_migrate_schedules} SET cron = 'builtin' WHERE cron = '0'");
  777. }
  778. /**
  779. * Fix schema mismatch after upgrade.
  780. */
  781. function backup_migrate_update_7305() {
  782. // Fix the 'machine_name' table fields.
  783. $field_spec = array(
  784. 'type' => 'varchar',
  785. 'length' => 255,
  786. 'not null' => TRUE,
  787. 'default' => '0',
  788. );
  789. foreach (array(
  790. 'backup_migrate_profiles',
  791. 'backup_migrate_destinations',
  792. 'backup_migrate_sources',
  793. 'backup_migrate_schedules',
  794. ) as $table) {
  795. if (!db_field_exists($table, $machine_name)) {
  796. try {
  797. db_add_field($table, 'machine_name', $field_spec);
  798. }
  799. catch (\Exception $e) {
  800. db_change_field($table, 'machine_name', 'machine_name', $field_spec);
  801. }
  802. }
  803. else {
  804. db_change_field($table, 'machine_name', 'machine_name', $field_spec);
  805. }
  806. }
  807. // Fix the 'cron' table field.
  808. $field_spec = array(
  809. 'type' => 'varchar',
  810. 'length' => 32,
  811. 'not null' => TRUE,
  812. 'default' => 'builtin',
  813. );
  814. if (!db_field_exists('backup_migrate_schedules', 'cron')) {
  815. try {
  816. db_add_field('backup_migrate_schedules', 'cron', $field_spec);
  817. }
  818. catch (\Exception $e) {
  819. db_change_field('backup_migrate_schedules', 'cron', 'cron', $field_spec);
  820. }
  821. }
  822. else {
  823. db_change_field('backup_migrate_schedules', 'cron', 'cron', $field_spec);
  824. }
  825. }
  826. /**
  827. * Leave a message to explain the mixup over the backup option.
  828. */
  829. function backup_migrate_update_7306() {
  830. drupal_set_message(t('Please note that release 7.x-3.4 had a bug which caused all backups to be overwritten instead of having a timestamp added. Please review all backup settings to ensure they work as intended.'), 'warning');
  831. }
  832. /**
  833. * 'backup_migrate_backup_memory_limit' vs 'backup_migrate_memory_limit'.
  834. */
  835. function backup_migrate_update_7307() {
  836. $limit = variable_get('backup_migrate_backup_memory_limit');
  837. if (!empty($limit)) {
  838. variable_set('backup_migrate_memory_limit', $limit);
  839. variable_del('backup_migrate_backup_memory_limit');
  840. }
  841. }