backup_migrate.install 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. <?php
  2. /**
  3. * @file
  4. * Install hooks for Backup and Migrate.
  5. */
  6. /**
  7. * Implementation of 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. // if (empty($requirements)) {
  100. // $requirements['bmdest_' . $dest_name] = array(
  101. // 'severity' => REQUIREMENT_INFO,
  102. // 'title' => 'Backup Migrate',
  103. // 'value' => $t('Backup destinations are safe'),
  104. // 'description' => $t('The backup destinations were all checked and none of them were exposing files to the public. This is a good thing.'),
  105. // );
  106. // }
  107. }
  108. return $requirements;
  109. }
  110. /**
  111. * Implementation of hook_schema().
  112. */
  113. function backup_migrate_schema() {
  114. $schema['backup_migrate_profiles'] = array(
  115. 'export' => array(
  116. 'key' => 'machine_name',
  117. 'key name' => 'Profile ID',
  118. 'admin_title' => 'name',
  119. 'primary key' => 'profile_id',
  120. 'identifier' => 'item', // Exports will be defined as $preset
  121. 'default hook' => 'exportables_backup_migrate_profiles', // Function hook name.
  122. 'api' => array(
  123. 'owner' => 'backup_migrate',
  124. 'api' => 'backup_migrate_exportables', // Base name for api include files.
  125. 'minimum_version' => 1,
  126. 'current_version' => 1,
  127. ),
  128. ),
  129. 'fields' => array(
  130. 'profile_id' => array(
  131. 'type' => 'serial',
  132. 'unsigned' => TRUE,
  133. 'not null' => TRUE,
  134. 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
  135. 'no export' => TRUE, // Do not export database-only keys.
  136. ),
  137. 'machine_name' => array(
  138. 'type' => 'varchar',
  139. 'length' => 255,
  140. 'not null' => TRUE,
  141. 'default' => '0',
  142. 'description' => 'The primary identifier for a profile.',
  143. ),
  144. 'name' => array(
  145. 'description' => 'The name of the profile.',
  146. 'type' => 'varchar',
  147. 'length' => 255,
  148. 'not null' => TRUE
  149. ),
  150. 'filename' => array(
  151. 'description' => 'The name of the profile.',
  152. 'type' => 'varchar',
  153. 'length' => 255,
  154. 'not null' => TRUE
  155. ),
  156. 'append_timestamp' => array(
  157. 'description' => 'Append a timestamp to the filename.',
  158. 'type' => 'int',
  159. 'size' => 'tiny',
  160. 'unsigned' => TRUE,
  161. 'not null' => TRUE,
  162. 'default' => 0
  163. ),
  164. 'timestamp_format' => array(
  165. 'description' => 'The format of the timestamp.',
  166. 'type' => 'varchar',
  167. 'length' => 14,
  168. 'not null' => TRUE
  169. ),
  170. 'filters' => array(
  171. 'description' => 'The filter settings for the profile.',
  172. 'type' => 'text',
  173. 'not null' => TRUE,
  174. 'serialize' => TRUE,
  175. 'serialized default' => 'a:0:{}',
  176. ),
  177. ),
  178. 'primary key' => array('profile_id'),
  179. );
  180. $schema['backup_migrate_destinations'] = array(
  181. 'export' => array(
  182. 'key' => 'machine_name',
  183. 'key name' => 'Destination ID',
  184. 'admin_title' => 'name',
  185. 'primary key' => 'destination_id',
  186. 'identifier' => 'item', // Exports will be defined as $preset
  187. 'default hook' => 'exportables_backup_migrate_destinations', // Function hook name.
  188. 'api' => array(
  189. 'owner' => 'backup_migrate',
  190. 'api' => 'backup_migrate_exportables', // Base name for api include files.
  191. 'minimum_version' => 1,
  192. 'current_version' => 1,
  193. ),
  194. ),
  195. 'fields' => array(
  196. 'destination_id' => array(
  197. 'type' => 'serial',
  198. 'unsigned' => TRUE,
  199. 'not null' => TRUE,
  200. 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
  201. 'no export' => TRUE, // Do not export database-only keys.
  202. ),
  203. 'machine_name' => array(
  204. 'type' => 'varchar',
  205. 'length' => 255,
  206. 'not null' => TRUE,
  207. 'default' => '0',
  208. 'description' => 'The primary identifier for a destination.',
  209. ),
  210. 'name' => array(
  211. 'description' => 'The name of the destination.',
  212. 'type' => 'varchar',
  213. 'length' => 255,
  214. 'not null' => TRUE
  215. ),
  216. 'subtype' => array(
  217. 'description' => 'The type of the destination.',
  218. 'type' => 'varchar',
  219. 'length' => 32,
  220. 'not null' => TRUE
  221. ),
  222. 'location' => array(
  223. 'description' => 'The the location string of the destination.',
  224. 'type' => 'text',
  225. 'not null' => TRUE
  226. ),
  227. 'settings' => array(
  228. 'description' => 'Other settings for the destination.',
  229. 'type' => 'text',
  230. 'not null' => TRUE,
  231. 'serialize' => TRUE,
  232. 'serialized default' => 'a:0:{}',
  233. ),
  234. ),
  235. 'primary key' => array('destination_id'),
  236. );
  237. $schema['backup_migrate_sources'] = array(
  238. 'export' => array(
  239. 'key' => 'machine_name',
  240. 'key name' => 'Source ID',
  241. 'admin_title' => 'name',
  242. 'primary key' => 'source_id',
  243. 'identifier' => 'item', // Exports will be defined as $preset
  244. 'default hook' => 'exportables_backup_migrate_sources', // Function hook name.
  245. 'api' => array(
  246. 'owner' => 'backup_migrate',
  247. 'api' => 'backup_migrate_exportables', // Base name for api include files.
  248. 'minimum_version' => 1,
  249. 'current_version' => 1,
  250. ),
  251. ),
  252. 'fields' => array(
  253. 'source_id' => array(
  254. 'type' => 'serial',
  255. 'unsigned' => TRUE,
  256. 'not null' => TRUE,
  257. 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
  258. 'no export' => TRUE, // Do not export database-only keys.
  259. ),
  260. 'machine_name' => array(
  261. 'type' => 'varchar',
  262. 'length' => 255,
  263. 'not null' => TRUE,
  264. 'default' => '0',
  265. 'description' => 'The primary identifier for a source.',
  266. ),
  267. 'name' => array(
  268. 'description' => 'The name of the source.',
  269. 'type' => 'varchar',
  270. 'length' => 255,
  271. 'not null' => TRUE
  272. ),
  273. 'subtype' => array(
  274. 'description' => 'The type of the source.',
  275. 'type' => 'varchar',
  276. 'length' => 32,
  277. 'not null' => TRUE
  278. ),
  279. 'location' => array(
  280. 'description' => 'The the location string of the source.',
  281. 'type' => 'text',
  282. 'not null' => TRUE
  283. ),
  284. 'settings' => array(
  285. 'description' => 'Other settings for the source.',
  286. 'type' => 'text',
  287. 'not null' => TRUE,
  288. 'serialize' => TRUE,
  289. 'serialized default' => 'a:0:{}',
  290. ),
  291. ),
  292. 'primary key' => array('source_id'),
  293. );
  294. $schema['backup_migrate_schedules'] = array(
  295. 'export' => array(
  296. 'key' => 'machine_name',
  297. 'key name' => 'Source ID',
  298. 'admin_title' => 'name',
  299. 'primary key' => 'schedule_id',
  300. 'identifier' => 'item', // Exports will be defined as $preset
  301. 'default hook' => 'exportables_backup_migrate_schedules', // Function hook name.
  302. 'api' => array(
  303. 'owner' => 'backup_migrate',
  304. 'api' => 'backup_migrate_exportables', // Base name for api include files.
  305. 'minimum_version' => 1,
  306. 'current_version' => 1,
  307. ),
  308. ),
  309. 'fields' => array(
  310. 'schedule_id' => array(
  311. 'type' => 'serial',
  312. 'unsigned' => TRUE,
  313. 'not null' => TRUE,
  314. 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
  315. 'no export' => TRUE, // Do not export database-only keys.
  316. ),
  317. 'machine_name' => array(
  318. 'type' => 'varchar',
  319. 'length' => 255,
  320. 'not null' => TRUE,
  321. 'default' => '0',
  322. 'description' => 'The primary identifier for a profile.',
  323. ),
  324. 'name' => array(
  325. 'description' => 'The name of the profile.',
  326. 'type' => 'varchar',
  327. 'length' => 255,
  328. 'not null' => TRUE
  329. ),
  330. 'source_id' => array(
  331. 'description' => 'The {backup_migrate_destination}.destination_id of the source to backup from.',
  332. 'type' => 'varchar',
  333. 'length' => 255,
  334. 'default' => 'db',
  335. 'not null' => TRUE
  336. ),
  337. 'destination_id' => array(
  338. 'type' => 'varchar',
  339. 'length' => 255,
  340. 'not null' => TRUE,
  341. 'default' => '0',
  342. 'description' => 'The {backup_migrate_destination}.destination_id of the destination to back up to.',
  343. ),
  344. 'copy_destination_id' => array(
  345. 'type' => 'varchar',
  346. 'length' => 32,
  347. 'not null' => TRUE,
  348. 'default' => '0',
  349. 'description' => 'A second {backup_migrate_destination}.destination_id of the destination to copy the backup to.',
  350. ),
  351. 'profile_id' => array(
  352. 'type' => 'varchar',
  353. 'length' => 255,
  354. 'not null' => TRUE,
  355. 'default' => '0',
  356. 'description' => 'The primary identifier for a profile.',
  357. ),
  358. 'keep' => array(
  359. 'type' => 'int',
  360. 'not null' => TRUE,
  361. 'default' => 0,
  362. 'description' => 'The number of backups to keep.',
  363. ),
  364. 'period' => array(
  365. 'type' => 'int',
  366. 'not null' => TRUE,
  367. 'default' => 0,
  368. 'description' => 'The number of seconds between backups.',
  369. ),
  370. 'enabled' => array(
  371. 'description' => 'Whether the schedule is enabled.',
  372. 'type' => 'int',
  373. 'size' => 'tiny',
  374. 'unsigned' => TRUE,
  375. 'not null' => TRUE,
  376. 'default' => 0
  377. ),
  378. 'cron' => array(
  379. 'description' => 'Whether the schedule should be run during cron.',
  380. 'type' => 'varchar',
  381. 'length' => 32,
  382. 'not null' => TRUE,
  383. 'default' => 'builtin',
  384. ),
  385. 'cron_schedule' => array(
  386. 'description' => 'The cron schedule to run on.',
  387. 'type' => 'varchar',
  388. 'length' => 255,
  389. 'not null' => TRUE,
  390. 'default' => '0 4 * * *',
  391. ),
  392. ),
  393. 'primary key' => array('schedule_id'),
  394. );
  395. return $schema;
  396. }
  397. /**
  398. * Implementation of hook_install().
  399. */
  400. function backup_migrate_install() {
  401. }
  402. /**
  403. * Remove variables on uninstall.
  404. */
  405. function backup_migrate_uninstall() {
  406. db_query("DELETE FROM {variable} WHERE name LIKE 'backup_migrate_%'");
  407. db_query("DELETE FROM {variable} WHERE name LIKE 'nodesquirrel_%'");
  408. cache_clear_all('variables', 'cache');
  409. }
  410. /**
  411. * Update from 1.x to 2.x.
  412. */
  413. function backup_migrate_update_2000() {
  414. _backup_migrate_setup_database_defaults();
  415. return array();
  416. }
  417. /**
  418. * Adding filter field for dev release of 2009-01-28
  419. */
  420. function backup_migrate_update_2001() {
  421. $ret = array();
  422. $schema = drupal_get_schema_unprocessed('backup_migrate', 'backup_migrate_profiles');
  423. // Add the filters field to the db.
  424. if (!db_field_exists('backup_migrate_profiles', 'filters')) {
  425. db_add_field('backup_migrate_profiles', 'filters', array('description' => t('The filter settings for the profile.'),'type' => 'text', 'not null' => TRUE));
  426. }
  427. // Add the source field
  428. if (!db_field_exists('backup_migrate_profiles', 'source_id')) {
  429. db_add_field('backup_migrate_profiles', 'source_id', array('description' => t('The {backup_migrate_destination}.destination_id of the source to backup from.'), 'type' => 'varchar', 'length' => 255, 'default' => 'db', 'not null' => TRUE));
  430. }
  431. // Remove the compression field.
  432. if (db_field_exists('backup_migrate_profiles', 'compression')) {
  433. db_drop_field('backup_migrate_profiles', 'compression');
  434. }
  435. return $ret;
  436. }
  437. /**
  438. * Clearing the cache because there was a menu structure change in the dev of 2009-05-31
  439. */
  440. function backup_migrate_update_2002() {
  441. // Cache should clear automatically. Nothing to do here.
  442. return array();
  443. }
  444. /**
  445. * Allowing non-int profile ids in schedules 2009-05-31
  446. */
  447. function backup_migrate_update_2003() {
  448. $ret = array();
  449. $spec = array(
  450. 'type' => 'varchar',
  451. 'length' => 255,
  452. 'not null' => TRUE,
  453. 'default' => '0',
  454. 'description' => 'The primary identifier for a profile.',
  455. );
  456. db_change_field('backup_migrate_schedules', 'profile_id', 'profile_id', $spec);
  457. return $ret;
  458. }
  459. /**
  460. * Allowing non-int profile ids 2009-07-01
  461. */
  462. function backup_migrate_update_2004() {
  463. $ret = array();
  464. $spec = array(
  465. 'type' => 'varchar',
  466. 'length' => 255,
  467. 'not null' => TRUE,
  468. 'default' => '0',
  469. );
  470. $spec['description'] = 'The primary identifier for a destination.';
  471. db_change_field('backup_migrate_destinations', 'destination_id', 'destination_id', $spec);
  472. $spec['description'] = 'The primary identifier for a profile.';
  473. db_change_field('backup_migrate_profiles', 'profile_id', 'profile_id', $spec);
  474. $spec['description'] = 'The primary identifier for a schedule.';
  475. db_change_field('backup_migrate_schedules', 'schedule_id', 'schedule_id', $spec);
  476. // Drop the user/pass fields as they weren't being used.
  477. if (db_field_exists('backup_migrate_destinations', 'username')) {
  478. db_drop_field('backup_migrate_destinations', 'username');
  479. }
  480. if (db_field_exists('backup_migrate_destinations', 'password')) {
  481. db_drop_field('backup_migrate_destinations', 'password');
  482. }
  483. return $ret;
  484. }
  485. /**
  486. * Change the default database id to something friendlier 2009-08-08
  487. */
  488. function backup_migrate_update_2005() {
  489. require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/crud.inc';
  490. require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/profiles.inc';
  491. $ret = array();
  492. // Change the destination ids of the defined database sources mostly to make using them with drush friendlier.
  493. // Change the db_url:default id to simply 'db'
  494. $ret[] = db_query("UPDATE {backup_migrate_profiles} SET source_id = 'db' WHERE source_id = 'db_url:default'");
  495. $ret[] = db_query("UPDATE {backup_migrate_schedules} SET destination_id = 'db' WHERE destination_id = 'db_url:default'");
  496. // Change the defined db keys from db_url:key to db:key.
  497. $ret[] = db_query("UPDATE {backup_migrate_profiles} SET source_id = REPLACE(source_id, 'db_url:', 'db:')");
  498. $ret[] = db_query("UPDATE {backup_migrate_schedules} SET destination_id = REPLACE(destination_id, 'db_url:', 'db:')");
  499. // Add the source field to the schedule
  500. if (!db_field_exists('backup_migrate_schedules', 'source_id')) {
  501. db_add_field('backup_migrate_schedules', 'source_id', array('description' => t('The db source to backup from.'), 'type' => 'varchar', 'length' => 255, 'default' => 'db', 'not null' => TRUE));
  502. }
  503. // Copy source data from profiles to schedules.
  504. $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));
  505. foreach ($result as $schedule) {
  506. if (!$schedule['source_id']) {
  507. $schedule['source_id'] = 'db';
  508. }
  509. $ret[] = db_query("UPDATE {backup_migrate_schedules} SET source_id = '". $schedule['source_id'] ."' WHERE schedule_id = '". $schedule['profile_id'] ."'");
  510. }
  511. if (db_field_exists('backup_migrate_profiles', 'source_id')) {
  512. db_drop_field('backup_migrate_profiles', 'source_id');
  513. }
  514. // Copy the no-data and exclude tables settings into the 'filter' field.
  515. $result = db_query('SELECT * FROM {backup_migrate_profiles}', array(), array('fetch' => PDO::FETCH_ASSOC));
  516. foreach ($result as $item) {
  517. if (isset($item['nodata_tables']) && isset($item['exclude_tables'])) {
  518. $profile = backup_migrate_get_profile($item['profile_id']);
  519. $profile->filters['nodata_tables'] = unserialize($item['nodata_tables']);
  520. $profile->filters['exclude_tables'] = unserialize($item['exclude_tables']);
  521. $profile->save();
  522. }
  523. }
  524. if (db_field_exists('backup_migrate_profiles', 'nodata_tables')) {
  525. db_drop_field('backup_migrate_profiles', 'nodata_tables');
  526. }
  527. if (db_field_exists('backup_migrate_profiles', 'exclude_tables')) {
  528. db_drop_field('backup_migrate_profiles', 'exclude_tables');
  529. }
  530. return $ret;
  531. }
  532. /**
  533. * Move the backup and migrate directory to the private directory.
  534. */
  535. function backup_migrate_update_7200() {
  536. $from = 'public://backup_migrate';
  537. $to = 'private://backup_migrate';
  538. if (drupal_realpath($from) && !drupal_realpath($to)) {
  539. if (!rename($from, $to)) {
  540. 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');
  541. }
  542. }
  543. }
  544. /**
  545. * Change the filename field to support 255 characters.
  546. */
  547. function backup_migrate_update_7202() {
  548. $ret = array();
  549. db_change_field('backup_migrate_profiles', 'filename', 'filename', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE));
  550. return $ret;
  551. }
  552. /**
  553. * Update the schedule last run times to use variables instead of saving with the schedule.
  554. */
  555. function backup_migrate_update_7203() {
  556. $result = db_query('SELECT * FROM {backup_migrate_schedules}', array(), array('fetch' => PDO::FETCH_ASSOC));
  557. foreach ($result as $item) {
  558. if (isset($item['last_run'])) {
  559. variable_set('backup_migrate_schedule_last_run_' . $item['schedule_id'], $item['last_run']);
  560. }
  561. }
  562. if (db_field_exists('backup_migrate_schedules', 'last_run')) {
  563. db_drop_field('backup_migrate_schedules', 'last_run');
  564. }
  565. }
  566. /**
  567. * Uninstall backup migrate files if it's installed
  568. */
  569. function backup_migrate_update_7300() {
  570. if (module_exists('backup_migrate_files')) {
  571. module_disable(array('backup_migrate_files'));
  572. $ret[] = array(
  573. 'success' => true,
  574. 'query' => 'Disabled the Backup and Migrate Files module',
  575. );
  576. }
  577. if (module_exists('nodesquirrel')) {
  578. module_disable(array('nodesquirrel'));
  579. $ret[] = array(
  580. 'success' => true,
  581. 'query' => 'Disabled the NodeSquirrel module',
  582. );
  583. }
  584. // Add sources to the schema.
  585. $schema['backup_migrate_sources'] = array(
  586. 'fields' => array(
  587. 'source_id' => array(
  588. 'type' => 'varchar',
  589. 'length' => 32,
  590. 'not null' => TRUE,
  591. 'default' => '0',
  592. 'description' => t('The primary identifier for a source.'),
  593. ),
  594. 'name' => array(
  595. 'description' => t('The name of the source.'),
  596. 'type' => 'varchar',
  597. 'length' => 255,
  598. 'not null' => TRUE
  599. ),
  600. 'type' => array(
  601. 'description' => t('The type of the source.'),
  602. 'type' => 'varchar',
  603. 'length' => 32,
  604. 'not null' => TRUE
  605. ),
  606. 'location' => array(
  607. 'description' => t('The the location string of the source.'),
  608. 'type' => 'text',
  609. 'not null' => TRUE
  610. ),
  611. 'settings' => array(
  612. 'description' => t('Other settings for the source.'),
  613. 'type' => 'text',
  614. 'not null' => TRUE,
  615. 'serialize' => TRUE,
  616. 'serialized default' => 'a:0:{}',
  617. ),
  618. ),
  619. 'primary key' => array('source_id'),
  620. );
  621. if (!db_table_exists('backup_migrate_sources')) {
  622. db_create_table('backup_migrate_sources', $schema['backup_migrate_sources']);
  623. }
  624. // Move custom destinations to sources.
  625. $result = db_query("SELECT * FROM {backup_migrate_destinations} WHERE type in ('filesource', 'db')", array(), array('fetch' => PDO::FETCH_ASSOC));
  626. foreach ($result as $item) {
  627. $item['source_id'] = $item['destination_id'];
  628. drupal_write_record('backup_migrate_source', $item);
  629. }
  630. // Change 'destination' settings to 'source' settings
  631. $result = db_query('SELECT * FROM {backup_migrate_profiles}', array(), array('fetch' => PDO::FETCH_ASSOC));
  632. foreach ($result as $item) {
  633. $item['filters'] = unserialize($item['filters']);
  634. $item['filters']['sources'] = $item['filters']['destinations'];
  635. unset($item['filters']['destinations']);
  636. drupal_write_record('backup_migrate_profiles', $item, array('profile_id'));
  637. }
  638. }
  639. /**
  640. * Switch the cron switch to text.
  641. */
  642. function backup_migrate_update_7301() {
  643. db_change_field('backup_migrate_schedules', 'cron', 'cron', array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => 'builtin'));
  644. db_add_field('backup_migrate_schedules', 'cron_schedule', array('description' => 'The cron schedule to run on.', 'type' => 'varchar', 'length' => 255, 'default' => '0 4 * * *', 'not null' => TRUE));
  645. }
  646. /**
  647. * Add a second destination to schedules.
  648. */
  649. function backup_migrate_update_7302() {
  650. db_add_field('backup_migrate_schedules', 'copy_destination_id',
  651. array(
  652. 'type' => 'varchar',
  653. 'length' => 32,
  654. 'not null' => TRUE,
  655. 'default' => '0',
  656. 'description' => 'A second {backup_migrate_destination}.destination_id of the destination to copy the backup to.',
  657. )
  658. );
  659. }
  660. /**
  661. * Add a serial id field to all tables to allow them to be ctools exportable.
  662. */
  663. function backup_migrate_update_7303() {
  664. foreach (array('backup_migrate_sources' => 'source_id', 'backup_migrate_destinations' => 'destination_id', 'backup_migrate_schedules' => 'schedule_id', 'backup_migrate_profiles' => 'profile_id') as $table => $id) {
  665. // Take the primary key status from the machine name so it can be renamed
  666. // A serial field must be defined as a key, so make a temporary index.
  667. // See: https://www.drupal.org/node/190027
  668. db_add_index($table, 'temp', array($id));
  669. db_drop_primary_key($table);
  670. // Drop our temporary index.
  671. db_drop_index($table, 'temp');
  672. // Switch the name of the id to 'machine_name' to be more ctools standard
  673. db_change_field($table, $id, 'machine_name', array('type' => 'varchar', 'length' => 32, 'not null' => TRUE));
  674. // Add a serial ID
  675. db_add_field($table, $id,
  676. array(
  677. 'type' => 'serial',
  678. 'unsigned' => TRUE,
  679. 'not null' => TRUE,
  680. 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
  681. 'no export' => TRUE, // Do not export database-only keys.
  682. ),
  683. array('primary key' => array($id))
  684. );
  685. }
  686. foreach (array('backup_migrate_sources', 'backup_migrate_destinations') as $table) {
  687. db_change_field($table, 'type', 'subtype', array('type' => 'varchar', 'length' => 32, 'not null' => TRUE));
  688. }
  689. }
  690. /**
  691. * Update all schedules to use the built in cron if none is specified.
  692. */
  693. function backup_migrate_update_7304() {
  694. db_query("UPDATE {backup_migrate_schedules} SET cron = 'builtin' WHERE cron = '0'");
  695. }
  696. /**
  697. * Fix schema mismatch after upgrade.
  698. */
  699. function backup_migrate_update_7305() {
  700. foreach (array('backup_migrate_profiles', 'backup_migrate_destinations', 'backup_migrate_sources', 'backup_migrate_schedules') as $table) {
  701. db_change_field($table, 'machine_name', 'machine_name', array(
  702. 'type' => 'varchar',
  703. 'length' => 255,
  704. 'not null' => TRUE,
  705. 'default' => '0',
  706. ));
  707. }
  708. db_change_field('backup_migrate_schedules', 'cron', 'cron', array(
  709. 'type' => 'varchar',
  710. 'length' => 32,
  711. 'not null' => TRUE,
  712. 'default' => 'builtin',
  713. ));
  714. }
  715. /**
  716. * Leave a message to explain the mixup over the backup option.
  717. */
  718. function backup_migrate_update_7306() {
  719. 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');
  720. }