/[drupal]/contributions/modules/multisite_maintenance/multisite_maintenance.module
ViewVC logotype

Contents of /contributions/modules/multisite_maintenance/multisite_maintenance.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Fri Jan 25 06:28:39 2008 UTC (22 months ago) by dalin
Branch: MAIN
CVS Tags: DRUPAL-5--0-1, HEAD
Branch point for: DRUPAL-5, DRUPAL-6--1
Changes since 1.1: +565 -251 lines
File MIME type: text/x-php
- fixed issue with incorrectly reporting status of sites
- added bulk processing of update.php
1 <?php
2 // $Id: multisite_maintenance.module,v 1.1 2008/01/09 06:36:08 dalin Exp $
3
4 /**
5 * @subpackage HOOKS
6 */
7
8 /**
9 * Implementation of hook_help().
10 */
11 function multisite_maintenance_help($section) {
12 switch ($section) {
13 case 'admin/help#multisite_maintenance':
14 return '<p>'. t('Allows batch maintenance of multisites including taking sites offline, ' .
15 'and running update.php.') .'</p>';
16 case 'admin/multisite/multisite_maintenance/site_status':
17 return '<p>'. t('You can alter the status of any site below. Only those sites whose databases ' .
18 'can be reached can be changed (Other sites may be for use on another staging or production ' .
19 'server). Note that the cache will also be cleared for all sites that you take offline.') .'</p>';
20 case 'admin/multisite/multisite_maintenance/update':
21 return '<p>'. t('Choose the sites that you wish to run update.php for. Only those sites whose ' .
22 'databases can be reached can be taken offline (Other sites may be for use on another staging ' .
23 'or production server).') .'</p>' .
24 '<h3>'. t('Technique') .'</h3>'.
25 '<p>'. t('For each site to be updated, $db_url is changed on the fly, global variables are ' .
26 'rebuilt, caches are cleared, the update functions are run (with the default "latest version" ' .
27 'for each updated module), and then everything is restored to the original values.') .'</p>'.
28 '<h3>'. t('Challenges and Limitations') .'</h3>'.
29 '<p>'. t('The following globals cannot be rebuilt: base_url (if not explicitly set in each ' .
30 'settings.php file, therefore we recommend always explicitly setting this). Also be aware ' .
31 'that static variables cannot be reset (see conf_path() as an example). If an update is relying ' .
32 'on a static variable that would be different on each site the update will be completed in error ' .
33 'but without any indication of such. It should be noted that this edge case should be very rare, ' .
34 'in theory update.php will only be making changes to the database (perhaps modifying a module\'s ' .
35 'tables and using variable_set).') .'</p>';
36 case 'admin/multisite/multisite_maintenance':
37 return '<p>'. t('Multisite Maintenance can make multisite Drupal installations easier to manage ' .
38 'by providing tools to take selected sites off-line, and to update selected sites. Note that ' .
39 'by visiting the status and update tabs, the code in all of your settings.php files will be ' .
40 'evaluated. This should not be a problem unless you have some really unusual customization in ' .
41 'your settings.php files.') .'</p>';
42 }
43 }
44
45 /**
46 * Implementation of hook_perm().
47 */
48 function multisite_maintenance_perm() {
49 return array('perform maintenance on multisites');
50 }
51
52
53 /**
54 * Implementation of hook_menu().
55 */
56 function multisite_maintenance_menu($may_cache) {
57
58 $items = array();
59 $access = user_access('perform maintenance on multisites');
60
61 if ($may_cache) {
62 $items[] = array(
63 'path' => 'admin/multisite/multisite_maintenance',
64 'title' => t('Multisite maintenance'),
65 'callback' => 'drupal_get_form',
66 'callback arguments' => array('multisite_maintenance_info_form'),
67 'access' => $access,
68 'type' => MENU_NORMAL_ITEM,
69 );
70 $items[] = array(
71 'path' => 'admin/multisite/multisite_maintenance/info',
72 'title' => t('Info'),
73 'type' => MENU_DEFAULT_LOCAL_TASK,
74 );
75 $items[] = array(
76 'path' => 'admin/multisite/multisite_maintenance/site_status',
77 'title' => t('Site Status'),
78 'callback' => 'drupal_get_form',
79 'callback arguments' => array('multisite_maintenance_status_form'),
80 'access' => $access,
81 'type' => MENU_LOCAL_TASK,
82 );
83 $items[] = array(
84 'path' => 'admin/multisite/multisite_maintenance/update',
85 'title' => t('Update Sites'),
86 'callback' => 'drupal_get_form',
87 'callback arguments' => array('multisite_maintenance_update_form'),
88 'access' => $access,
89 'type' => MENU_LOCAL_TASK,
90 );
91 }
92
93 return $items;
94
95 }
96
97
98 /**
99 * @subpackage FORMS
100 */
101
102 /**
103 * multisite info page
104 */
105 function multisite_maintenance_info_form() {
106
107 // test for mysqldump
108 $form['mysql']['#value'] = '<strong>'. t('mysqldump') .':</strong> ';
109 if (_multisite_maintenance_test_shell_app('mysqldump')) {
110 $form['mysql']['#value'] .= t('Found');
111 }
112 else {
113 $form['mysql']['#value'] .= t('Not found. Your database(s) will not be backed up before you run the mutlisite update. To rectify this, make sure that the path for mysqldump is included in your system\'s $PATH variable.');
114 }
115
116 // test for gzip
117 $form['gzip']['#value'] = '<br /><strong>'. t('gzip') .':</strong> ';
118 if (_multisite_maintenance_test_shell_app('mysqldump')) {
119 $form['gzip']['#value'] .= t('Found');
120 }
121 else {
122 $form['gzip']['#value'] .= t('Not found. Your backups will not be compressed before you run the mutlisite update. To rectify this, make sure that the path for gzip is included in your system\'s $PATH variable.');
123 }
124
125 // backup dir
126 $form['multisite_maintenance_backup_dir'] = array(
127 '#type' => 'textfield',
128 '#title' => 'Backup Directory',
129 '#default_value' => variable_get('multisite_maintenance_backup_dir', ''),
130 '#description' => 'Enter the absolute path to the directory that you wish to store your backups to. It is recommended that you store backups outside of the webroot. The directory that you choose must be writable by the apache user.',
131 );
132
133 // check for devel
134 if (module_exists('devel') && variable_get('devel_error_handler', '1') == '2') {
135 drupal_set_message('You have the devel module enabled with error backtrace. You may see a series of mysql errors on the subsequent pages. Switching to the standard backtrace is recommended.');
136 }
137
138 return system_settings_form($form);
139 }
140
141 function multisite_maintenance_info_form_submit($form_id, $form_values) {
142 if (!file_check_directory($form_values['multisite_maintenance_backup_dir'], FILE_CREATE_DIRECTORY)) {
143 drupal_set_message(t('The directory is not writable. Your database(s) will not be backed up before you run the mutlisite update.'), 'error');
144 }
145 else{
146 variable_set('multisite_maintenance_backup_dir', $form_values['multisite_maintenance_backup_dir']);
147 }
148 }
149
150
151 /**
152 * abstracted form
153 */
154 function multisite_maintenance_form() {
155 $sites = multisite_api_site_list();
156
157 // create storage mechanism for all sites
158 $form['sites'] = array('#type' => 'value', '#value' => array());
159
160 // create storage mechanism for sites with unavailable DBs
161 $form['unavailable_sites'] = array('#type' => 'value', '#value' => array());
162
163 // set the timeout to be real low
164 if ($timeout_error = !_multisite_maintenance_mysql_timeout(3)) {
165 drupal_set_message('Unable to set the mysql timeout to a lower value. This means that the multisite maintenance page might take as much as 2mins * (the number of sites) to load.');
166 }
167
168 // Traverse the sites retrieved and build the form.
169 foreach ($sites as $site) {
170 $dir = $site['dir'];
171 $form['sites']['#value'][$dir] = $site;
172 $form['dir'][$dir] = array('#value' => $site['dir']);
173
174 // obfuscate passwords
175 $db_url = $site['db_url'];
176 $db_default_dsn = $site['db_default_dsn'];
177 $pass_star = str_repeat('*', strlen($db_default_dsn['pass']));
178 $db_url = str_replace($db_default_dsn['pass'], $pass_star, $db_url);
179 $db_default_dsn['pass'] = str_repeat('*', strlen($db_default_dsn['pass']));
180
181 // db information
182 $form['db_url'][$dir] = array('#value' => $db_url);
183 $form['db_prefix'][$dir] = array('#value' => print_r($site['db_prefix'], true));
184 $form['db_default_dsn'][$dir] = array('#value' => print_r($db_default_dsn, true));
185
186 // check if the DB can be accessed
187 if (!$available = _multisite_maintenance_dsn_check($site['db_default_dsn'])) {
188 $form['unavailable_sites']['#value'][$dir] = true;
189 $form['db_reachable'][$dir] = array('#value' => 'No');
190 }
191 else {
192 $form['db_reachable'][$dir] = array('#value' => 'Yes');
193 }
194 }
195
196 // reset timeout value
197 if (!$timeout_error) {
198 _multisite_maintenance_mysql_timeout();
199 }
200
201 return $form;
202 }
203
204
205 /**
206 * multisite status page
207 */
208 function multisite_maintenance_status_form() {
209 $sites = multisite_api_site_list();
210 $form = multisite_maintenance_form();
211
212 $form['status'] = array('#tree' => true);
213
214 // Traverse the sites retrieved and build the form.
215 foreach ($sites as $site) {
216 $dir = $site['dir'];
217
218 // site status
219 $form['status']['status.'. $dir] = array(
220 '#type' => 'radios',
221 '#options' => array('Off-line', 'Online'),
222 '#process' => array(
223 'expand_radios' => array(),
224 ),
225 );
226
227 // check if the DB can be accessed
228 if ($form['unavailable_sites']['#value'][$dir]) {
229 $form['status']['status.'. $dir]['#attributes']['disabled'] = 'disabled';
230 }
231 else {
232 // find out the current state of the site and adjust the radio accordingly
233 $status = _multisite_maintenance_is_site_online($site);
234 $form['sites']['#value'][$dir]['site_status'] = (int)$status;
235 $form['status']['status.'. $dir]['#default_value'] = (int)$status;
236 }
237 }
238
239 // session clear
240 $form['clear_sessions'] = array(
241 '#type' => 'checkbox',
242 '#default_value' => true,
243 '#title' => t('Clear sessions tables'),
244 '#description' => t('Clearing sessions will log out any users currently logged in. If this table is shared accross sites (likely situation) you will log users out of all sites. You will not logged out because your session is written back to the table after it is truncated. '),
245 );
246
247 // submit button
248 $form['submit'] = array(
249 '#type' => 'submit',
250 '#value' => t('Submit'),
251 );
252
253 return $form;
254 }
255
256 function multisite_maintenance_status_form_submit($form_id, $form_values) {
257
258 // clear any messages (such as "You are operating in offline mode", cause chances are we won't when we're done)
259 unset($_SESSION['messages']);
260
261 // update site status
262 foreach ($form_values['sites'] as $site => $site_info) {
263 if ($form_values['unavailable_sites'][$site] || $form_values['status']['status.'. $site] == $site_info['site_status']) {
264 continue;
265 }
266
267 $error = null;
268
269 // connect to the db, this time we can use drupal query functions
270 _multisite_maintenance_connect_to_db($site_info);
271
272 if (!count($error)) {
273
274 // update the variable
275 variable_set('site_offline', !$form_values['status']['status.'. $site]);
276
277 // truncate sessions if nec.
278 if ($form_values['clear_sessions'] && !db_query('TRUNCATE sessions')) {
279 drupal_set_message('sessions error', 'error');
280 $error[] = true;
281 }
282
283 // clear the cache
284 cache_clear_all('*', 'cache', TRUE);
285 cache_clear_all('*', 'cache_page', TRUE);
286 cache_clear_all('*', 'cache_menu', TRUE);
287 cache_clear_all('*', 'cache_filter', TRUE);
288 drupal_clear_css_cache();
289 }
290 else {
291 drupal_set_message('connection error', 'error');
292 }
293
294 // close the db
295 _multisite_maintenance_connect_to_db();
296
297 // give some feedback
298 $msg = $site .(count($error) ? ' could not be put ' : ' was taken ');
299 $msg .= ($form_values['status']['status.'. $site] ? 'on' : 'off-') .'line.';
300 $msg .= count($error) ? 'You\'ll need to do it manually.' : '';
301 drupal_set_message($msg, count($error) ? 'error' : 'status');
302 }
303
304 }
305
306 /**
307 * multisite update page
308 */
309 function multisite_maintenance_update_form() {
310 $sites = multisite_api_site_list();
311 $form = multisite_maintenance_form();
312
313 $form['update'] = array('#tree' => true);
314
315 // Traverse the sites retrieved and build the form.
316 foreach ($sites as $site) {
317 $dir = $site['dir'];
318
319 // site update
320 $form['update']['update.'. $dir] = array(
321 '#type' => 'checkbox',
322 );
323
324 // check if the DB can be accessed
325 if ($form['unavailable_sites']['#value'][$dir]) {
326 $form['update']['update.'. $dir]['#attributes']['disabled'] = 'disabled';
327 }
328 else {
329 $form['update']['update.'.$dir]['#default_value'] = true;
330 }
331 }
332
333 // backup
334 if (_multisite_maintenance_test_shell_app('mysqldump') && file_check_directory(variable_get('multisite_maintenance_backup_dir', ''))) {
335 $file = 'host_dbname_yyyy_mm_dd.mysql';
336 if (_multisite_maintenance_test_shell_app('gzip')) {
337 $file .= '.gz';
338 }
339 $form['backup'] = array(
340 '#type' => 'checkbox',
341 '#default_value' => true,
342 '#title' => t('Backup database(s) before updating.'),
343 '#description' => t('Backups of the database(s) will be stored in %files in the form %format.', array('%files' => variable_get('multisite_maintenance_backup_dir', ''), '%format' => 'host_dbname_yyyy_mm_dd.mysql.gz')),
344 );
345 }
346 else {
347 $form['backup'] = array(
348 '#type' => 'checkbox',
349 '#title' => t('Backup database(s) before updating.'),
350 '#attributes' => array('disabled' => 'disabled'),
351 '#description' => t('Your database(s) can not be backed up. See the info tab for more information'),
352 );
353 }
354
355 // submit button
356 $form['submit'] = array(
357 '#type' => 'submit',
358 '#value' => t('Submit'),
359 );
360
361 return $form;
362 }
363
364 function multisite_maintenance_update_form_submit($form_id, $form_values) {
365
366 // storage mechanism for backed up sites
367 $backed_up = array();
368
369 // switch to user1 so we pass the access check
370 global $user;
371 $old_user = $user;
372 $user = user_load(array('uid' =>1));
373
374 // update sites
375 foreach ($form_values['sites'] as $site => $site_info) {
376 if ($form_values['unavailable_sites'][$site] || !$form_values['update']['update.'.$site]) {
377 continue;
378 }
379
380 // give each site 5 mins to do its thing
381 set_time_limit(300);
382
383 $error = null;
384
385 // backup
386 if ($form_values['backup'] && _multisite_maintenance_test_shell_app('mysqldump') && file_check_directory(variable_get('multisite_maintenance_backup_dir', ''))) {
387
388 // db_url
389 $db_key = $site_info['db_dsn']['host'] . $site_info['db_dsn']['path'];
390 if (!array_key_exists($db_key, $backed_up)) {
391 $ret = check_plain(_multisite_maintenance_backup_db($site_info['db_dsn']));
392 if (strlen($ret)) {
393 $error[] = $ret;
394 watchdog('multisite_maintenance', $ret);
395 drupal_set_message($ret .'!', 'error');
396 }
397 else {
398 drupal_set_message($db_key .' has been backed up');
399 $backed_up[$db_key] = true;
400 }
401 }
402
403 // db_default_url
404 $db_key = $site_info['db_default_dsn']['host'] . $site_info['db_default_dsn']['path'];
405 if (!array_key_exists($db_key, $backed_up)) {
406 $ret = check_plain(_multisite_maintenance_backup_db($site_info['db_default_dsn']));
407 if (strlen($ret)) {
408 $error[] = $ret;
409 watchdog('multisite_maintenance', $ret);
410 drupal_set_message($ret .'!', 'error');
411 }
412 else {
413 drupal_set_message($db_key .' has been backed up');
414 $backed_up[$db_key] = true;
415 }
416 }
417 }
418
419 //run the update
420 if (!count($error)) {
421
422 // switch to the other db
423 _multisite_maintenance_connect_to_db($site_info);
424
425 // reset the page timer
426 timer_start('page');
427
428 // get the list of updated versions
429 include_once('update.php');
430 $update_form = update_script_selection_form();
431 $_POST['start'] = array();
432 foreach ($update_form['start'] as $name => $module) {
433 if (substr($name, 0, 1) == '#') {
434 continue;
435 }
436 $_POST['start'][$name] = $module['#default_value'];
437 }
438
439 /**
440 * the below code is stolen from update.php update_update_page()
441 */
442 // Set the installed version so updates start at the correct place.
443 foreach ($_POST['start'] as $module => $version) {
444 drupal_set_installed_schema_version($module, $version - 1);
445 $updates = drupal_get_schema_versions($module);
446 $max_version = max($updates);
447 if ($version <= $max_version) {
448 foreach ($updates as $update) {
449 if ($update >= $version) {
450 $_SESSION['update_remaining'][] = array('module' => $module, 'version' => $update);
451 }
452 }
453 }
454 }
455 // Keep track of total number of updates
456 if (isset($_SESSION['update_remaining'])) {
457 $_SESSION['update_total'] = count($_SESSION['update_remaining']);
458 }
459
460 /**
461 * the below code is stolen from update.php update_do_updates() and slightly modified
462 */
463 while (isset($_SESSION['update_remaining']) && ($update = reset($_SESSION['update_remaining']))) {
464 $update_finished = update_data($update['module'], $update['version']);
465 if ($update_finished == 1) {
466 // Dequeue the completed update.
467 unset($_SESSION['update_remaining'][key($_SESSION['update_remaining'])]);
468 $update_finished = 0; // Make sure this step isn't counted double
469 }
470 /** this has been lengthened so that each site update runs for 1 min before we give up **/
471 if (timer_read('page') > 1000 *3600) {
472 break;
473 }
474 }
475 if ($_SESSION['update_total']) {
476 $percentage = floor(($_SESSION['update_total'] - count($_SESSION['update_remaining']) + $update_finished) / $_SESSION['update_total'] * 100);
477 }
478 else {
479 $percentage = 100;
480 }
481
482 // When no updates remain, clear the caches in case the data has been updated.
483 if (!isset($update['module'])) {
484 cache_clear_all('*', 'cache', TRUE);
485 cache_clear_all('*', 'cache_page', TRUE);
486 cache_clear_all('*', 'cache_menu', TRUE);
487 cache_clear_all('*', 'cache_filter', TRUE);
488 drupal_clear_css_cache();
489 }
490
491 // close the db
492 _multisite_maintenance_connect_to_db();
493 }
494 else {
495 drupal_set_message('backup error', 'error');
496 }
497
498 // give some feedback
499 if (count($error)) {
500 $msg = $site .' could not be updated. You\'ll need to do it manually.';
501 }
502 else {
503 $msg = $percentage .'% of '. $site .' was updated. ';
504 }
505 drupal_set_message($msg, count($error) ? 'error' : 'status');
506 }
507
508 // set user back
509 $user = $old_user;
510 }
511
512 /**
513 * @subpackage THEME FUNCTIONS
514 */
515 function theme_multisite_maintenance_status_form($form) {
516
517 // Individual table headers.
518 $header = array(t('Site Online'), t('Sites Directory'), t('db_url'), t('db_prefix'), t('Default DSN'), t('DB is Reachable'));
519
520 // build table
521 $rows = array();
522 foreach($form['sites']['#value'] as $key => $site) {
523 if (substr($key, 0,1) == '#') {
524 continue;
525 }
526 $row = array();
527 $row[] = drupal_render($form['status']['status.'. $key]);
528 $row[] = '<strong>'. drupal_render($form['dir'][$key]) .'</strong>';
529 $row[] = drupal_render($form['db_url'][$key]);
530 $row[] = '<pre>'. drupal_render($form['db_prefix'][$key]) .'</pre>';
531 $row[] = '<pre>'. drupal_render($form['db_default_dsn'][$key]) .'</pre>';
532 $row[] = '<strong>'. drupal_render($form['db_reachable'][$key]) .'</strong>';
533 $rows[] = $row;
534 }
535 $output .= theme('table', $header, $rows, array('class' => 'package'));
536
537 // render remaining form objects and return
538 $output .= drupal_render($form);
539 return $output;
540 }
541
542 function theme_multisite_maintenance_update_form($form) {
543
544 // Individual table headers.
545 $header = array(t('Update Site'), t('Sites Directory'), t('db_url'), t('db_prefix'), t('Default DSN'), t('DB is Reachable'));
546
547 // build table
548 $rows = array();
549 foreach($form['sites']['#value'] as $key => $site) {
550 if (substr($key, 0,1) == '#') {
551 continue;
552 }
553 $row = array();
554 $row[] = drupal_render($form['update']['update.'. $key]);
555 $row[] = '<strong>'. drupal_render($form['dir'][$key]) .'</strong>';
556 $row[] = drupal_render($form['db_url'][$key]);
557 $row[] = '<pre>'. drupal_render($form['db_prefix'][$key]) .'</pre>';
558 $row[] = '<pre>'. drupal_render($form['db_default_dsn'][$key]) .'</pre>';
559 $row[] = '<strong>'. drupal_render($form['db_reachable'][$key]) .'</strong>';
560 $rows[] = $row;
561 }
562 $output .= theme('table', $header, $rows, array('class' => 'package'));
563
564 // render remaining form objects and return
565 $output .= drupal_render($form);
566 return $output;
567 }
568
569
570 /**
571 * @subpackage INTERNAL_FUNCTIONS
572 */
573
574 /**
575 * Checks a DSN array to see if connection to the db can be made
576 * @param array $dsn
577 * an associative array of the db connection info in the form returned by parse_url()
578 * @return boolean
579 * true on success else false
580 * @todo postgres
581 * unfortunately we can't use drupal db functions here. PostgreSQL users will need to patch this
582 */
583 function _multisite_maintenance_dsn_check($dsn) {
584
585 // test db connection
586 $link = @mysql_connect($dsn['host'] . ($dsn['port'] ? ':'. $dsn['port'] : ''), $dsn['user'], $dsn ['pass'], true)
587 or $error = true;
588 if (empty($link)) {
589 $error = true;
590 }
591 if (!$error) {
592 $db = substr($dsn['path'], 1);
593 $link_db = @mysql_select_db($db, $link)
594 or $error = true;
595 if (!$link_db) {
596 $error = true;
597 }
598 @mysql_close($link);
599 }
600
601
602 return !$error;
603 }
604
605
606 /**
607 * adjusts mysql.connect_timeout
608 * pass an int to set it, leave arg blank to reset it
609 */
610 function _multisite_maintenance_mysql_timeout($new_value = null) {
611 static $old_timeout;
612 if (!is_null($new_value)) {
613
614 // store the old value
615 if (is_null($old_timeout)) {
616 if (!($old_timeout = ini_get('mysql.connect_timeout'))) {
617 $error = true;
618 }
619
620 // set the new value
621 if (!$error && ini_set('mysql.connect_timeout', $new_value)) {
622 return true;
623 }
624 return false;
625 }
626 else {
627 // whoops! we tried to set the timeout a second time without reseting
628 return false;
629 }
630 }
631 else {
632
633 // reset the timer
634 // check for saved value
635 if (!is_null($old_timeout) && ini_set('mysql.connect_timeout', $old_timeout)) {
636 $old_timeout = null;
637 return true;
638 }
639 return false;
640 }
641 }
642
643
644 /**
645 * -adjusts $_GLOBALS['db_url'] and $_GLOBALS['db_prefix']
646 * -mounts the db
647 * -adjusts all other globals (if possible)
648 * -clear cache
649 * @param array
650 * $site in the form as created by multisite_api_site_list()
651 * or leave null to reset to the original values
652 */
653 function _multisite_maintenance_connect_to_db($site = null) {
654
655 global $db_url, $db_prefix, $base_url, $base_root, $base_path;
656
657 static $original_site;
658
659 if ($site) {
660
661 // store the old value
662 if (!isset($original_site)) {
663 $sites = multisite_api_site_list();
664 $original_site = $sites[substr(conf_path(), 6)];
665 }
666
667 // set the new value
668 if (is_array($db_url)) {
669 $db_url[$site['dir']] = $site['db_url'];
670 }
671 else {
672 $db_url = array('default' => $db_url);
673 $db_url[$site['dir']] = $site['db_url'];
674 }
675 $db_prefix = $site['db_prefix'];
676 if ($site['base_url']) {
677 $base_url = $site['base_url'];
678 }
679 else {
680 unset($base_url);
681 }
682 db_set_active($site['dir']);
683
684 }
685 else {
686
687 // reset the db stuff
688 // check for saved value
689 if (isset($original_site)) {
690 $db_url = $original_site['db_url'];
691 $db_prefix = $original_site['db_prefix'];
692 if ($original_site['base_url']) {
693 $base_url = $original_site['base_url'];
694 }
695 else {
696 unset($base_url);
697 }
698 db_set_active();
699 $site = $original_site;
700 unset($original_site);
701 }
702 else {
703 drupal_set_message('whoops! we tried to reset before we set', 'error');
704 return false;
705 }
706 }
707
708 // clear our cache for this site
709 cache_clear_all('*', 'cache', TRUE);
710 cache_clear_all('*', 'cache_page', TRUE);
711 cache_clear_all('*', 'cache_menu', TRUE);
712 cache_clear_all('*', 'cache_filter', TRUE);
713 drupal_clear_css_cache();
714
715 /** rebuild all important globals **/
716 // $base_url, $base_path, $base_root
717 // this code grabbed from bootsrtap.inc conf_init
718 if (isset($base_url)) {
719 // Parse fixed base URL from settings.php.
720 $parts = parse_url($base_url);
721 if (!isset($parts['path'])) {
722 $parts['path'] = '';
723 }
724 $base_path = $parts['path'] . '/';
725 // Build $base_root (everything until first slash after "scheme://").
726 $base_root = substr($base_url, 0, strlen($base_url) - strlen($parts['path']));
727 }
728 else {
729 // if $base_url is not passed to us, we cannot reverse engineer the others,
730 // unset them so that an error is thrown if they are used
731 unset ($base_root, $base_path);
732 }
733
734 // variables
735 cache_clear_all('*', 'cache', TRUE);
736
737 global $debug;
738 $debug = true;
739 unset($GLOBALS['conf']);
740 $GLOBALS['conf'] = variable_init((array)$site['conf']);
741
742 }
743
744 /**
745 * switches to the given site and asks whether it's online
746 */
747 function _multisite_maintenance_is_site_online($site) {
748
749 // switch to the given site
750 _multisite_maintenance_connect_to_db($site);
751
752 // are we online?
753 $offline = variable_get('site_offline', 'default');
754 // drupal_set_message('$offline:'. $offline);
755
756 // switch back
757 _multisite_maintenance_connect_to_db();
758
759 return !$offline;
760 }
761
762 /**
763 * tests if a shell application exists
764 * @param string $app
765 * either 'gzip' or 'mysqldump'
766 * @return boolean
767 * true if it exists, else false
768 */
769 function _multisite_maintenance_test_shell_app($app) {
770 static $gzip;
771 static $mysqldump;
772
773 if ($$app) {
774 return $app;
775 }
776 switch ($app) {
777 case 'gzip':
778 $info = shell_exec('gzip -L');
779 $gzip = strpos($info, 'WARRANTY') !== false;
780 return $gzip;
781 break;
782 case 'mysqldump':
783 $info = shell_exec('mysqldump -V');
784 $mysqldump = strpos($info, 'Ver') !== false;
785 return $mysqldump;
786 break;
787 }
788 }
789
790 /**
791 * backs up the given db.
792 * @param array
793 * $dsn must be in the form as returned by parse_url()
794 * @return string
795 * the output of the command
796 */
797 function _multisite_maintenance_backup_db($dsn) {
798 $db = substr($dsn['path'], 1);
799 $gzip = _multisite_maintenance_test_shell_app('gzip');
800
801 // build filename
802 $ext = '.mysql'. ($gzip ? '.gz' : '');
803 $file = variable_get('multisite_maintenance_backup_dir', '') .'/'. $dsn['host'] .'_'. $db .'_'. date('Y_m_d');
804 $inc = '';
805 $x = 1;
806
807 // test if exists
808 while (file_exists($file_name =($file . $inc . $ext))) {
809 $inc = "__$x";
810 $x ++;
811 }
812
813 // build command
814 $cmd = 'mysqldump -u'. $dsn['user'] .' -p'. $dsn['pass'] .' -h'. $dsn['host'] .' '. $db;
815 if ($gzip) {
816 $cmd .= ' | gzip';
817 }
818 $cmd .= ' > '. $file_name;
819
820 // execute command
821 $return = shell_exec($cmd);
822 return $return;
823 }

  ViewVC Help
Powered by ViewVC 1.1.2