PageRenderTime 60ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-content/plugins/backupbuddy/classes/core.php

https://bitbucket.org/summitds/bloomsburgpa.org
PHP | 1988 lines | 1373 code | 318 blank | 297 comment | 246 complexity | b08e737a3a43b1207f915dacf2b7d0f7 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. // Helper functions for BackupBuddy.
  3. // TODO: Eventually break out of a lot of these from BB core. Migrating from old framework to new resulted in this mid-way transition but it's a bit messy...
  4. class pb_backupbuddy_core {
  5. /* is_network_activated()
  6. *
  7. * Returns a boolean indicating whether a plugin is network activated or not.
  8. *
  9. * @return boolean True if plugin is network activated, else false.
  10. */
  11. function is_network_activated() {
  12. if ( !function_exists( 'is_plugin_active_for_network' ) ) { // Function is not available on all WordPress pages for some reason according to codex.
  13. require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
  14. }
  15. if ( is_plugin_active_for_network( basename( pb_backupbuddy::plugin_path() ) . '/' . pb_backupbuddy::settings( 'init' ) ) ) { // Path relative to wp-content\plugins\ directory.
  16. return true;
  17. } else {
  18. return false;
  19. }
  20. } // End is_network_activated().
  21. /* backup_integrity_check()
  22. *
  23. * Scans a backup file and saves the result in data structure. Checks for key files & that .zip can be read properly. Stores results with details in data structure.
  24. *
  25. * @param string $file Full pathname & filename to backup file to check.
  26. * @return boolean True if integrity 100% passed, else false. ( Side note: Result details stored in pb_backupbuddy::$options['backups'][$serial]['integrity'] ).
  27. */
  28. function backup_integrity_check( $file ) {
  29. $serial = $this->get_serial_from_file( $file );
  30. // User selected to rescan a file.
  31. if ( pb_backupbuddy::_GET( 'reset_integrity' ) == $serial ) {
  32. pb_backupbuddy::alert( 'Rescanning backup integrity for backup file `' . basename( $file ) . '`' );
  33. }
  34. if ( isset( pb_backupbuddy::$options['backups'][$serial]['integrity'] ) && ( count( pb_backupbuddy::$options['backups'][$serial]['integrity'] ) > 0 ) && ( pb_backupbuddy::_GET( 'reset_integrity' ) != $serial ) ) { // Already have integrity data and NOT resetting this one.
  35. pb_backupbuddy::status( 'details', 'Integrity data for backup `' . $serial . '` is cached; not scanning again.' );
  36. return;
  37. } elseif ( pb_backupbuddy::_GET( 'reset_integrity' ) == $serial ) { // Resetting this one.
  38. pb_backupbuddy::status( 'details', 'Resetting backup integrity stats for backup with serial `' . $serial . '`.' );
  39. }
  40. if ( pb_backupbuddy::$options['integrity_check'] == '0' ) { // Integrity checking disabled.
  41. $file_stats = @stat( $file );
  42. if ( $file_stats === false ) { // stat failure.
  43. pb_backupbuddy::alert( 'Error #4539774. Unable to get file details ( via stat() ) for file `' . $file . '`. The file may be corrupt or too large for the server.' );
  44. $file_size = 0;
  45. $file_modified = 0;
  46. } else { // stat success.
  47. $file_size = $file_stats['size'];
  48. $file_modified = $file_stats['mtime'];
  49. }
  50. unset( $file_stats );
  51. $integrity = array(
  52. 'status' => 'Unknown',
  53. 'status_details' => __( 'Integrity checking disabled based on settings. This file has not been verified.', 'it-l10n-backupbuddy' ),
  54. 'scan_time' => 0,
  55. 'detected_type' => 'unknown',
  56. 'size' => $file_size,
  57. 'modified' => $file_modified,
  58. 'file' => basename( $file ),
  59. 'comment' => false,
  60. );
  61. pb_backupbuddy::$options['backups'][$serial]['integrity'] = array_merge( pb_backupbuddy::settings( 'backups_integrity_defaults' ), $integrity );
  62. pb_backupbuddy::save();
  63. return;
  64. }
  65. //***** BEGIN CALCULATING STATUS DETAILS.
  66. // Status defaults.
  67. $status_details = array(
  68. 'found_dat' => false,
  69. 'found_sql' => false,
  70. 'found_wpconfig' => false,
  71. 'scan_log' => '',
  72. );
  73. $backup_type = '';
  74. if ( !isset( pb_backupbuddy::$classes['zipbuddy'] ) ) {
  75. require_once( pb_backupbuddy::plugin_path() . '/lib/zipbuddy/zipbuddy.php' );
  76. pb_backupbuddy::$classes['zipbuddy'] = new pluginbuddy_zipbuddy( pb_backupbuddy::$options['backup_directory'] );
  77. }
  78. pb_backupbuddy::set_status_serial( 'zipbuddy_test' ); // Redirect logging output to a certain log file.
  79. // Look for comment.
  80. $comment = pb_backupbuddy::$classes['zipbuddy']->get_comment( $file );
  81. // Check for DAT file.
  82. if ( pb_backupbuddy::$classes['zipbuddy']->file_exists( $file, 'wp-content/uploads/backupbuddy_temp/' . $serial . '/backupbuddy_dat.php' ) === true ) { // Post 2.0 full backup
  83. $status_details['found_dat'] = true;
  84. $backup_type = 'full';
  85. }
  86. if ( pb_backupbuddy::$classes['zipbuddy']->file_exists( $file, 'wp-content/uploads/temp_' . $serial . '/backupbuddy_dat.php' ) === true ) { // Pre 2.0 full backup
  87. $status_details['found_dat'] = true;
  88. $backup_type = 'full';
  89. }
  90. if ( pb_backupbuddy::$classes['zipbuddy']->file_exists( $file, 'backupbuddy_dat.php' ) === true ) { // DB backup
  91. $status_details['found_dat'] = true;
  92. $backup_type = 'db';
  93. }
  94. // Check for DB SQL file.
  95. if ( pb_backupbuddy::$classes['zipbuddy']->file_exists( $file, 'wp-content/uploads/backupbuddy_temp/' . $serial . '/db_1.sql' ) === true ) { // post 2.0 full backup
  96. $status_details['found_sql'] = true;
  97. $backup_type = 'full';
  98. }
  99. if ( pb_backupbuddy::$classes['zipbuddy']->file_exists( $file, 'wp-content/uploads/temp_' . $serial . '/db.sql' ) === true ) { // pre 2.0 full backup
  100. $status_details['found_sql'] = true;
  101. $backup_type = 'full';
  102. }
  103. if ( pb_backupbuddy::$classes['zipbuddy']->file_exists( $file, 'db_1.sql' ) === true ) { // db only backup 2.0+
  104. $status_details['found_sql'] = true;
  105. $backup_type = 'db';
  106. }
  107. if ( pb_backupbuddy::$classes['zipbuddy']->file_exists( $file, 'db.sql' ) === true ) { // db only backup pre-2.0
  108. $status_details['found_sql'] = true;
  109. $backup_type = 'db';
  110. }
  111. // Check for WordPress config file.
  112. if ( pb_backupbuddy::$classes['zipbuddy']->file_exists( $file, 'wp-config.php' ) === true ) {
  113. $status_details['found_wpconfig'] = true;
  114. $backup_type = 'full';
  115. }
  116. if ( pb_backupbuddy::$classes['zipbuddy']->file_exists( $file, 'wp-content/uploads/backupbuddy_temp/' . $serial . '/wp-config.php' ) === true ) {
  117. $status_details['found_wpconfig'] = true;
  118. $backup_type = 'full';
  119. }
  120. // Get zip scan log details.
  121. $temp_details = pb_backupbuddy::get_status( 'zipbuddy_test' ); // Get zipbuddy scan log.
  122. foreach( $temp_details as $temp_detail ) {
  123. $status_details['scan_log'][] = $temp_detail[4];
  124. }
  125. pb_backupbuddy::set_status_serial( '' ); // Stop redirecting log to a specific file.
  126. // Calculate status descriptions.
  127. $integrity_status = 'pass'; // Default.
  128. if ( $status_details['found_dat'] !== true ) {
  129. $integrity_status = 'fail';
  130. $integrity_description .= __('Error #7843564: Missing DAT file.', 'it-l10n-backupbuddy' );
  131. }
  132. if ( $status_details['found_sql'] !== true ) {
  133. $integrity_status = 'fail';
  134. $integrity_description .= __('Error #4664236: Missing database SQL file.', 'it-l10n-backupbuddy' );
  135. }
  136. if ( ( $backup_type == 'full' ) && ( $status_details['found_wpconfig'] !== true ) ) {
  137. $integrity_status = 'fail';
  138. $integrity_description .= __('Error #47834674: Missing wp-config.php file.', 'it-l10n-backupbuddy' );
  139. }
  140. if ( $integrity_status == 'pass' ) { // All tests passed.
  141. $integrity_description = __( 'All tests passed.', 'it-l10n-backupbuddy' );
  142. }
  143. //$integrity_description .= '<br><br>' . __('Technical Details', 'it-l10n-backupbuddy' ) . ':<br />' . $integrity_zipresult_details;
  144. //***** END CALCULATING STATUS DETAILS.
  145. // Get file information from file system.
  146. $file_stats = @stat( $file );
  147. if ( $file_stats === false ) { // stat failure.
  148. pb_backupbuddy::alert( 'Error #4539774b. Unable to get file details ( via stat() ) for file `' . $file . '`. The file may be corrupt or too large for the server.' );
  149. $file_size = 0;
  150. $file_modified = 0;
  151. } else { // stat success.
  152. $file_size = $file_stats['size'];
  153. $file_modified = $file_stats['ctime']; // Created time.
  154. }
  155. unset( $file_stats );
  156. // Compile array of results for saving into data structure.
  157. $integrity = array(
  158. 'status' => $integrity_status,
  159. 'status_details' => $status_details, // $integrity_description,
  160. 'scan_time' => time(),
  161. 'detected_type' => $backup_type,
  162. 'size' => $file_size,
  163. 'modified' => $file_modified, // Actually created time now.
  164. 'file' => basename( $file ),
  165. 'comment' => $comment, // boolean false if no comment. string if comment.
  166. );
  167. pb_backupbuddy::$options['backups'][$serial]['integrity'] = array_merge( pb_backupbuddy::settings( 'backups_integrity_defaults' ), $integrity );
  168. pb_backupbuddy::save();
  169. //pb_backupbuddy::$classes['zipbuddy']->clear_status();
  170. if ( $integrity_status == 'pass' ) { // 100% success
  171. return true;
  172. } else {
  173. return false;
  174. }
  175. } // End backup_integrity_check().
  176. /* get_serial_from_file()
  177. *
  178. * Returns the backup serial based on the filename.
  179. *
  180. * @param string $file Filename containing a serial to extract.
  181. * @return string Serial found.
  182. */
  183. public function get_serial_from_file( $file ) {
  184. $serial = strrpos( $file, '-' ) + 1;
  185. $serial = substr( $file, $serial, ( strlen( $file ) - $serial - 4 ) );
  186. return $serial;
  187. } // End get_serial_from_file().
  188. /**
  189. * versions_confirm()
  190. *
  191. * Check the version of an item and compare it to the minimum requirements BackupBuddy requires.
  192. *
  193. * @param string $type Optional. If left blank '' then all tests will be performed. Valid values: wordpress, php, ''.
  194. * @param boolean $notify Optional. Whether or not to alert to the screen (and throw error to log) of a version issue.\
  195. * @return boolean True if the selected type is a bad version
  196. */
  197. function versions_confirm( $type = '', $notify = false ) {
  198. $bad_version = false;
  199. if ( ( $type == 'wordpress' ) || ( $type == '' ) ) {
  200. global $wp_version;
  201. if ( version_compare( $wp_version, pb_backupbuddy::settings( 'wp_minimum' ), '<=' ) ) {
  202. if ( $notify === true ) {
  203. pb_backupbuddy::alert( sprintf( __('ERROR: BackupBuddy requires WordPress version %1$s or higher. You may experience unexpected behavior or complete failure in this environment. Please consider upgrading WordPress.', 'it-l10n-backupbuddy' ), $this->_wp_minimum) );
  204. pb_backupbuddy::log( 'Unsupported WordPress Version: ' . $wp_version , 'error' );
  205. }
  206. $bad_version = true;
  207. }
  208. }
  209. if ( ( $type == 'php' ) || ( $type == '' ) ) {
  210. if ( version_compare( PHP_VERSION, pb_backupbuddy::settings( 'php_minimum' ), '<=' ) ) {
  211. if ( $notify === true ) {
  212. pb_backupbuddy::alert( sprintf( __('ERROR: BackupBuddy requires PHP version %1$s or higher. You may experience unexpected behavior or complete failure in this environment. Please consider upgrading PHP.', 'it-l10n-backupbuddy' ), PHP_VERSION ) );
  213. pb_backupbuddy::log( 'Unsupported PHP Version: ' . PHP_VERSION , 'error' );
  214. }
  215. $bad_version = true;
  216. }
  217. }
  218. return $bad_version;
  219. } // End versions_confirm().
  220. /* get_directory_exclusions()
  221. *
  222. * Get sanitized directory exclusions. See important note below!
  223. * IMPORTANT NOTE: Cannot exclude the temp directory here as this is where SQL and DAT files are stored for inclusion in the backup archive.
  224. *
  225. * @param bool $trim_suffix True (default) if trailing slash should be trimmed from directories
  226. * @return array Array of directories to exclude.
  227. */
  228. public static function get_directory_exclusions( $trim_suffix = true ) {
  229. // Get initial array.
  230. $exclusions = trim( pb_backupbuddy::$options['excludes'] ); // Trim string.
  231. $exclusions = preg_split('/\n|\r|\r\n/', $exclusions ); // Break into array on any type of line ending.
  232. $abspath = str_replace( '\\', '/', ABSPATH );
  233. // Add additional internal exclusions.
  234. $exclusions[] = str_replace( rtrim( $abspath, '\\\/' ), '', pb_backupbuddy::$options['backup_directory'] ); // Exclude backup directory.
  235. $exclusions[] = '/wp-content/uploads/pb_backupbuddy/'; // BackupBuddy logs and junk.
  236. $exclusions[] = '/importbuddy/'; // Exclude importbuddy directory in root.
  237. $exclusions[] = '/importbuddy.php'; // Exclude importbuddy.php script in root.
  238. // Clean up & sanitize array.
  239. if ( $trim_suffix ) {
  240. array_walk( $exclusions, create_function( '&$val', '$val = rtrim( trim( $val ), \'/\' );' ) ); // Apply trim to all items within.
  241. } else {
  242. array_walk( $exclusions, create_function( '&$val', '$val = trim( $val );' ) ); // Apply (whitespace-only) trim to all items within.
  243. }
  244. $exclusions = array_filter( $exclusions, 'strlen' ); // Remove any empty / blank lines.
  245. // IMPORTANT NOTE: Cannot exclude the temp directory here as this is where SQL and DAT files are stored for inclusion in the backup archive.
  246. return $exclusions;
  247. } // End get_directory_exclusions().
  248. /* mail_error()
  249. *
  250. * Sends an error email to the defined email address(es) on settings page.
  251. *
  252. * @param string $message Message to be included in the body of the email.
  253. * @return null
  254. */
  255. function mail_error( $message ) {
  256. if ( !isset( pb_backupbuddy::$options ) ) {
  257. pb_backupbuddy::load();
  258. }
  259. $subject = pb_backupbuddy::$options['email_notify_error_subject'];
  260. $body = pb_backupbuddy::$options['email_notify_error_body'];
  261. $replacements = array(
  262. '{site_url}' => site_url(),
  263. '{backupbuddy_version}' => pb_backupbuddy::settings( 'version' ),
  264. '{current_datetime}' => date(DATE_RFC822),
  265. '{message}' => $message
  266. );
  267. foreach( $replacements as $replace_key => $replacement ) {
  268. $subject = str_replace( $replace_key, $replacement, $subject );
  269. $body = str_replace( $replace_key, $replacement, $body );
  270. }
  271. $email = pb_backupbuddy::$options['email_notify_error'];
  272. pb_backupbuddy::status( 'error', 'Sending email error notification. Subject: `' . $subject . '`; body: `' . $body . '`; recipient(s): `' . $email . '`.' );
  273. if ( !empty( $email ) ) {
  274. wp_mail( $email, $subject, $body, 'From: '.$email."\r\n".'Reply-To: '.get_option('admin_email')."\r\n");
  275. }
  276. } // End mail_error().
  277. /* mail_notify_scheduled()
  278. *
  279. * Sends a message email to the defined email address(es) on settings page.
  280. *
  281. * @param string $start_or_complete Whether this is the notifcation for starting or completing. Valid values: start, complete
  282. * @param string $message Message to be included in the body of the email.
  283. * @return null
  284. */
  285. function mail_notify_scheduled( $serial, $start_or_complete, $message ) {
  286. if ( !isset( pb_backupbuddy::$options ) ) {
  287. pb_backupbuddy::load();
  288. }
  289. if ( $start_or_complete == 'start' ) {
  290. $email = pb_backupbuddy::$options['email_notify_scheduled_start'];
  291. $subject = pb_backupbuddy::$options['email_notify_scheduled_start_subject'];
  292. $body = pb_backupbuddy::$options['email_notify_scheduled_start_body'];
  293. $replacements = array(
  294. '{site_url}' => site_url(),
  295. '{backupbuddy_version}' => pb_backupbuddy::settings( 'version' ),
  296. '{current_datetime}' => date(DATE_RFC822),
  297. '{message}' => $message
  298. );
  299. } elseif ( $start_or_complete == 'complete' ) {
  300. $email = pb_backupbuddy::$options['email_notify_scheduled_complete'];
  301. $subject = pb_backupbuddy::$options['email_notify_scheduled_complete_subject'];
  302. $body = pb_backupbuddy::$options['email_notify_scheduled_complete_body'];
  303. $replacements = array(
  304. '{site_url}' => site_url(),
  305. '{backupbuddy_version}' => pb_backupbuddy::settings( 'version' ),
  306. '{current_datetime}' => date(DATE_RFC822),
  307. '{message}' => $message,
  308. '{backup_serial}' => $serial,
  309. '{download_link}' => pb_backupbuddy::ajax_url( 'download_archive' ) . '&backupbuddy_backup=' . basename( pb_backupbuddy::$options['backups'][$serial]['archive_file'] ),
  310. '{backup_file}' => basename( pb_backupbuddy::$options['backups'][$serial]['archive_file'] ),
  311. '{backup_size}' => pb_backupbuddy::$format->file_size( pb_backupbuddy::$options['backups'][$serial]['archive_size'] ),
  312. '{backup_type}' => pb_backupbuddy::$options['backups'][$serial]['type'],
  313. );
  314. } else {
  315. pb_backupbuddy::status( 'error', 'ERROR #54857845785: Fatally halted. Invalid schedule type. Expected `start` or `complete`. Got `' . $start_or_complete . '`.' );
  316. }
  317. foreach( $replacements as $replace_key => $replacement ) {
  318. $subject = str_replace( $replace_key, $replacement, $subject );
  319. $body = str_replace( $replace_key, $replacement, $body );
  320. }
  321. pb_backupbuddy::status( 'error', 'Sending email schedule notification. Subject: `' . $subject . '`; body: `' . $body . '`; recipient(s): `' . $email . '`.' );
  322. if ( !empty( $email ) ) {
  323. wp_mail( $email, $subject, $body, 'From: '.$email."\r\n".'Reply-To: '.get_option('admin_email')."\r\n");
  324. }
  325. } // End mail_notify_scheduled().
  326. /* backup_prefix()
  327. *
  328. * Strips all non-file-friendly characters from the site URL. Used in making backup zip filename.
  329. *
  330. * @return string The filename friendly converted site URL.
  331. */
  332. function backup_prefix() {
  333. $siteurl = site_url();
  334. $siteurl = str_replace( 'http://', '', $siteurl );
  335. $siteurl = str_replace( 'https://', '', $siteurl );
  336. $siteurl = str_replace( '/', '_', $siteurl );
  337. $siteurl = str_replace( '\\', '_', $siteurl );
  338. $siteurl = str_replace( '.', '_', $siteurl );
  339. $siteurl = str_replace( ':', '_', $siteurl ); // Alternative port from 80 is stored in the site url.
  340. $siteurl = str_replace( '~', '_', $siteurl ); // Strip ~.
  341. return $siteurl;
  342. } // End backup_prefix().
  343. /* send_remote_destination()
  344. *
  345. * function description
  346. *
  347. * @param int $destination_id ID number (index of the destinations array) to send it.
  348. * @param string $file Full file path of file to send.
  349. * @param string $trigger What triggered this backup. Valid values: scheduled, manual.
  350. * @param bool $send_importbuddy Whether or not importbuddy.php should also be sent with the file to destination.
  351. * @return bool Send status. true success, false failed.
  352. */
  353. function send_remote_destination( $destination_id, $file, $trigger = '', $send_importbuddy = false ) {
  354. pb_backupbuddy::status( 'details', 'Sending file `' . $file . '` to remote destination `' . $destination_id . '` triggered by `' . $trigger . '`.' );
  355. if ( defined( 'PB_DEMO_MODE' ) ) {
  356. return false;
  357. }
  358. if ( $file == '' ) {
  359. $backup_file_size = filesize( $file );
  360. } else {
  361. $backup_file_size = 50000; // not sure why anything current would be sending importbuddy but NOT sending a backup but just in case...
  362. }
  363. // Record some statistics.
  364. $identifier = pb_backupbuddy::random_string( 12 );
  365. pb_backupbuddy::$options['remote_sends'][$identifier] = array(
  366. 'destination' => $destination_id,
  367. 'file' => $file,
  368. 'file_size' => $backup_file_size,
  369. 'trigger' => $trigger, // What triggered this backup. Valid values: scheduled, manual.
  370. 'send_importbuddy' => $send_importbuddy,
  371. 'start_time' => time(),
  372. 'finish_time' => 0,
  373. 'status' => 'timeout', // success, failure, timeout (default assumption if this is not updated in this PHP load)
  374. );
  375. pb_backupbuddy::save();
  376. // Prepare variables to pass to remote destination handler.
  377. if ( '' == $file ) { // No file to send (blank string file typically happens when just sending importbuddy).
  378. $files = array();
  379. } else {
  380. $files = array( $file );
  381. }
  382. $destination_settings = &pb_backupbuddy::$options['remote_destinations'][$destination_id];
  383. // For Stash we will check the quota prior to initiating send.
  384. if ( pb_backupbuddy::$options['remote_destinations'][$destination_id]['type'] == 'stash' ) {
  385. // Pass off to destination handler.
  386. require_once( pb_backupbuddy::plugin_path() . '/destinations/bootstrap.php' );
  387. $send_result = pb_backupbuddy_destinations::get_info( 'stash' ); // Used to kick the Stash destination into life.
  388. $stash_quota = pb_backupbuddy_destination_stash::get_quota( pb_backupbuddy::$options['remote_destinations'][$destination_id], true );
  389. if ( $file != '' ) {
  390. $backup_file_size = filesize( $file );
  391. } else {
  392. $backip_file_size = 50000;
  393. }
  394. if ( ( $backup_file_size + $stash_quota['quota_used'] ) > $stash_quota['quota_total'] ) {
  395. $message = '';
  396. $message .= "You do not have enough Stash storage space to send this file. Please upgrade your Stash storage at http://ithemes.com/member/stash.php or delete files to make space.\n\n";
  397. $message .= 'Attempting to send file of size ' . pb_backupbuddy::$format->file_size( $backup_file_size ) . ' but you only have ' . $stash_quota['quota_available_nice'] . ' available. ';
  398. $message .= 'Currently using ' . $stash_quota['quota_used_nice'] . ' of ' . $stash_quota['quota_total_nice'] . ' (' . $stash_quota['quota_used_percent'] . '%).';
  399. pb_backupbuddy::status( 'error', $message );
  400. pb_backupbuddy::$classes['core']->mail_error( $message );
  401. pb_backupbuddy::$options['remote_sends'][$identifier]['status'] = 'Failure. Insufficient destination space.';
  402. pb_backupbuddy::save();
  403. return false;
  404. } else {
  405. if ( isset( $stash_quota['quota_warning'] ) && ( $stash_quota['quota_warning'] != '' ) ) {
  406. // We log warning of usage but dont send error email.
  407. $message = '';
  408. $message .= 'WARNING: ' . $stash_quota['quota_warning'] . "\n\nPlease upgrade your Stash storage at http://ithemes.com/member/stash.php or delete files to make space.\n\n";
  409. $message .= 'Currently using ' . $stash_quota['quota_used_nice'] . ' of ' . $stash_quota['quota_total_nice'] . ' (' . $stash_quota['quota_used_percent'] . '%).';
  410. pb_backupbuddy::status( 'details', $message );
  411. //pb_backupbuddy::$classes['core']->mail_error( $message );
  412. }
  413. }
  414. }
  415. if ( $send_importbuddy === true ) {
  416. pb_backupbuddy::status( 'details', 'Generating temporary importbuddy.php file for remote send.' );
  417. $importbuddy_temp = pb_backupbuddy::$options['temp_directory'] . 'importbuddy.php'; // Full path & filename to temporary importbuddy
  418. $this->importbuddy( $importbuddy_temp ); // Create temporary importbuddy.
  419. pb_backupbuddy::status( 'details', 'Generated temporary importbuddy.' );
  420. $files[] = $importbuddy_temp; // Add importbuddy file to the list of files to send.
  421. $send_importbuddy = true; // Track to delete after finished.
  422. } else {
  423. pb_backupbuddy::status( 'details', 'Not sending importbuddy.' );
  424. }
  425. // Pass off to destination handler.
  426. require_once( pb_backupbuddy::plugin_path() . '/destinations/bootstrap.php' );
  427. $send_result = pb_backupbuddy_destinations::send( $destination_settings, $files );
  428. $this->kick_db(); // Kick the database to make sure it didn't go away, preventing options saving.
  429. // Update stats.
  430. pb_backupbuddy::$options['remote_sends'][$identifier]['finish_time'] = time();
  431. if ( $send_result === true ) { // succeeded.
  432. pb_backupbuddy::$options['remote_sends'][$identifier]['status'] = 'success';
  433. pb_backupbuddy::status( 'details', 'Remote send SUCCESS.' );
  434. } elseif ( $send_result === false ) { // failed.
  435. pb_backupbuddy::$options['remote_sends'][$identifier]['status'] = 'failure';
  436. pb_backupbuddy::status( 'details', 'Remote send FAILURE.' );
  437. } elseif ( is_array( $send_result ) ) { // Array so multipart.
  438. pb_backupbuddy::$options['remote_sends'][$identifier]['status'] = 'multipart';
  439. pb_backupbuddy::$options['remote_sends'][$identifier]['finish_time'] = 0;
  440. pb_backupbuddy::$options['remote_sends'][$identifier]['_multipart_id'] = $send_result[0];
  441. pb_backupbuddy::$options['remote_sends'][$identifier]['_multipart_status'] = $send_result[1];
  442. pb_backupbuddy::status( 'details', 'Multipart send in progress.' );
  443. } else {
  444. pb_backupbuddy::status( 'error', 'Error #5485785576463. Invalid status send result: `' . $send_result . '`.' );
  445. }
  446. pb_backupbuddy::save();
  447. // If we sent importbuddy then delete the local copy to clean up.
  448. if ( $send_importbuddy !== false ) {
  449. @unlink( $importbuddy_temp ); // Delete temporary importbuddy.
  450. }
  451. return $send_result;
  452. } // End send_remote_destination().
  453. /* destination_send()
  454. *
  455. * Send file(s) to a destination. Pass full array of destination settings.
  456. *
  457. * @param array $destination_settings All settings for this destination for this action.
  458. * @param array $files Array of files to send (full path).
  459. * @return bool|array Bool true = success, bool false = fail, array = multipart transfer.
  460. */
  461. public function destination_send( $destination_settings, $files ) {
  462. // Pass off to destination handler.
  463. require_once( pb_backupbuddy::plugin_path() . '/destinations/bootstrap.php' );
  464. $send_result = pb_backupbuddy_destinations::send( $destination_settings, $files );
  465. return $send_result;
  466. } // End destination_send().
  467. /* backups_list()
  468. *
  469. * function description
  470. *
  471. * @param string $type Valid options: default, migrate
  472. * @param boolean $subsite_mode When in subsite mode only backups for that specific subsite will be listed.
  473. * @return
  474. */
  475. public function backups_list( $type = 'default', $subsite_mode = false ) {
  476. if ( pb_backupbuddy::_POST( 'bulk_action' ) == 'delete_backup' ) {
  477. $needs_save = false;
  478. pb_backupbuddy::verify_nonce( pb_backupbuddy::_POST( '_wpnonce' ) ); // Security check to prevent unauthorized deletions by posting from a remote place.
  479. $deleted_files = array();
  480. foreach( pb_backupbuddy::_POST( 'items' ) as $item ) {
  481. if ( file_exists( pb_backupbuddy::$options['backup_directory'] . $item ) ) {
  482. if ( @unlink( pb_backupbuddy::$options['backup_directory'] . $item ) === true ) {
  483. $deleted_files[] = $item;
  484. if ( count( pb_backupbuddy::$options['backups'] ) > 5 ) { // Keep a minimum number of backups in array for stats.
  485. $this_serial = $this->get_serial_from_file( $item );
  486. unset( pb_backupbuddy::$options['backups'][$this_serial] );
  487. $needs_save = true;
  488. }
  489. } else {
  490. pb_backupbuddy::alert( 'Error: Unable to delete backup file `' . $item . '`. Please verify permissions.', true );
  491. }
  492. } // End if file exists.
  493. } // End foreach.
  494. if ( $needs_save === true ) {
  495. pb_backupbuddy::save();
  496. }
  497. pb_backupbuddy::alert( __( 'Deleted backup(s):', 'it-l10n-backupbuddy' ) . ' ' . implode( ', ', $deleted_files ) );
  498. } // End if deleting backup(s).
  499. $backups = array();
  500. $backup_sort_dates = array();
  501. $files = glob( pb_backupbuddy::$options['backup_directory'] . 'backup*.zip' );
  502. if ( is_array( $files ) && !empty( $files ) ) { // For robustness. Without open_basedir the glob() function returns an empty array for no match. With open_basedir in effect the glob() function returns a boolean false for no match.
  503. $backup_prefix = $this->backup_prefix(); // Backup prefix for this site. Used for MS checking that this user can see this backup.
  504. foreach( $files as $file_id => $file ) {
  505. if ( ( $subsite_mode === true ) && is_multisite() ) { // If a Network and NOT the superadmin must make sure they can only see the specific subsite backups for security purposes.
  506. // Only allow viewing of their own backups.
  507. if ( !strstr( $file, $backup_prefix ) ) {
  508. unset( $files[$file_id] ); // Remove this backup from the list. This user does not have access to it.
  509. continue; // Skip processing to next file.
  510. }
  511. }
  512. $serial = pb_backupbuddy::$classes['core']->get_serial_from_file( $file );
  513. // Populate integrity data structure in options.
  514. pb_backupbuddy::$classes['core']->backup_integrity_check( $file );
  515. // Backup status.
  516. $pretty_status = array(
  517. 'pass' => '<span class="pb_label pb_label-success">Good</span>', //'Good',
  518. 'fail' => '<span class="pb_label pb_label-important">Bad</span>',
  519. );
  520. // Backup type.
  521. $pretty_type = array(
  522. 'full' => 'Full',
  523. 'db' => 'Database',
  524. );
  525. $step_times = array();
  526. if ( isset( pb_backupbuddy::$options['backups'][$serial]['steps'] ) ) {
  527. foreach( pb_backupbuddy::$options['backups'][$serial]['steps'] as $step ) {
  528. if ( isset( $step['finish_time'] ) && ( $step['finish_time'] != 0 ) ) {
  529. // Step time taken.
  530. $step_times[] = $step['finish_time'] - $step['start_time'];
  531. }
  532. } // End foreach.
  533. } else { // End if serial in array is set.
  534. $step_times[] = 'unknown';
  535. } // End if serial in array is NOT set.
  536. $step_times = implode( ', ', $step_times );
  537. // Calculate zipping step time to use later for calculating write speed.
  538. if ( isset( pb_backupbuddy::$options['backups'][$serial]['steps']['backup_zip_files'] ) ) {
  539. $zip_time = pb_backupbuddy::$options['backups'][$serial]['steps']['backup_zip_files'];
  540. } else {
  541. $zip_time = 0;
  542. }
  543. // Calculate write speed in MB/sec for this backup.
  544. if ( $zip_time == '0' ) { // Took approx 0 seconds to backup so report this speed.
  545. if ( !isset( $finish_time ) || ( $finish_time == '0' ) ) {
  546. $write_speed = 'unknown';
  547. } else {
  548. $write_speed = '> ' . pb_backupbuddy::$format->file_size( pb_backupbuddy::$options['backups'][$serial]['integrity']['size'] );
  549. }
  550. } else {
  551. $write_speed = pb_backupbuddy::$format->file_size( pb_backupbuddy::$options['backups'][$serial]['integrity']['size'] / $zip_time );
  552. }
  553. // Calculate start and finish.
  554. if ( isset( pb_backupbuddy::$options['backups'][$serial]['start_time'] ) && isset( pb_backupbuddy::$options['backups'][$serial]['finish_time'] ) && ( pb_backupbuddy::$options['backups'][$serial]['start_time'] >0 ) && ( pb_backupbuddy::$options['backups'][$serial]['finish_time'] > 0 ) ) {
  555. $start_time = pb_backupbuddy::$options['backups'][$serial]['start_time'];
  556. $finish_time = pb_backupbuddy::$options['backups'][$serial]['finish_time'];
  557. $total_time = $finish_time - $start_time;
  558. } else {
  559. $total_time = 'unknown';
  560. }
  561. // Figure out trigger.
  562. if ( isset( pb_backupbuddy::$options['backups'][$serial]['trigger'] ) ) {
  563. $trigger = pb_backupbuddy::$options['backups'][$serial]['trigger'];
  564. } else {
  565. $trigger = __( 'Unknown', 'it-l10n-backupbuddy' );
  566. }
  567. // HTML output for stats.
  568. $statistics = '';
  569. if ( $total_time != 'unknown' ) {
  570. $statistics .= "<span style='width: 80px; display: inline-block;'>Total time:</span>{$total_time} secs<br>";
  571. }
  572. if ( $step_times != 'unknown' ) {
  573. $statistics .= "<span style='width: 80px; display: inline-block;'>Step times:</span>{$step_times}<br>";
  574. }
  575. if ( $write_speed != 'unknown' ) {
  576. $statistics .= "<span style='width: 80px; display: inline-block;'>Write speed:</span>{$write_speed}/sec";
  577. }
  578. // Calculate time ago.
  579. $time_ago = '<span class="description">' . pb_backupbuddy::$format->time_ago( pb_backupbuddy::$options['backups'][$serial]['integrity']['modified'] ) . ' ago</span>';
  580. // Calculate main row string.
  581. if ( $type == 'default' ) { // Default backup listing.
  582. $main_string = '<a href="' . pb_backupbuddy::ajax_url( 'download_archive' ) . '&backupbuddy_backup=' . basename( $file ) . '">' . basename( $file ) . '</a>';
  583. } elseif ( $type == 'migrate' ) { // Migration backup listing.
  584. $main_string = '<a class="pb_backupbuddy_hoveraction_migrate" rel="' . basename( $file ) . '" href="' . pb_backupbuddy::page_url() . '&migrate=' . basename( $file ) . '&value=' . basename( $file ) . '">' . basename( $file ) . '</a>';
  585. } else {
  586. $main_string = '{Unknown type.}';
  587. }
  588. // Add comment to main row string if applicable.
  589. if ( isset( pb_backupbuddy::$options['backups'][$serial]['integrity']['comment'] ) && ( pb_backupbuddy::$options['backups'][$serial]['integrity']['comment'] !== false ) && ( pb_backupbuddy::$options['backups'][$serial]['integrity']['comment'] !== '' ) ) {
  590. $main_string .= '<br><span class="description">Note: <span class="pb_backupbuddy_notetext">' . htmlentities( pb_backupbuddy::$options['backups'][$serial]['integrity']['comment'] ) . '</span></span>';
  591. }
  592. if ( pb_backupbuddy::$options['backups'][$serial]['integrity']['status'] == 'pass' ) {
  593. $status_details = __( 'All tests passed.', 'it-l10n-backupbuddy' );
  594. } else {
  595. $status_details = pb_backupbuddy::$options['backups'][$serial]['integrity']['status_details'];
  596. }
  597. $backups[basename( $file )] = array(
  598. array( basename( $file ), $main_string ),
  599. pb_backupbuddy::$format->prettify( pb_backupbuddy::$options['backups'][$serial]['integrity']['detected_type'], $pretty_type ),
  600. pb_backupbuddy::$format->file_size( pb_backupbuddy::$options['backups'][$serial]['integrity']['size'] ),
  601. pb_backupbuddy::$format->date( pb_backupbuddy::$format->localize_time( pb_backupbuddy::$options['backups'][$serial]['integrity']['modified'] ) ) . '<br>' . $time_ago,
  602. $statistics,
  603. pb_backupbuddy::$format->prettify( pb_backupbuddy::$options['backups'][$serial]['integrity']['status'], $pretty_status ) .
  604. ' <a href="' . pb_backupbuddy::page_url() . '&reset_integrity=' . $serial . '" title="Rescan integrity. Last checked ' . pb_backupbuddy::$format->date( pb_backupbuddy::$options['backups'][$serial]['integrity']['scan_time'] ) . '."><img src="' . pb_backupbuddy::plugin_url() . '/images/refresh_gray.gif" style="vertical-align: -1px;"></a>' .
  605. '<div class="row-actions"><a title="' . __( 'Integrity Check Details', 'it-l10n-backupbuddy' ) . '" href="' . pb_backupbuddy::ajax_url( 'integrity_status' ) . '&serial=' . $serial . '&#038;TB_iframe=1&#038;width=640&#038;height=600" class="thickbox">' . __( 'View Details', 'it-l10n-backupbuddy' ) . '</a></div>',
  606. );
  607. $backup_sort_dates[basename( $file)] = pb_backupbuddy::$options['backups'][$serial]['integrity']['modified'];
  608. } // End foreach().
  609. } // End if.
  610. // Sort backup sizes.
  611. arsort( $backup_sort_dates );
  612. // Re-arrange backups based on sort dates.
  613. $sorted_backups = array();
  614. foreach( $backup_sort_dates as $backup_file => $backup_sort_date ) {
  615. $sorted_backups[$backup_file] = $backups[$backup_file];
  616. unset( $backups[$backup_file] );
  617. }
  618. unset( $backups );
  619. return $sorted_backups;
  620. } // End backups_list().
  621. // If output file not specified then outputs to browser as download.
  622. // IMPORTANT: If outputting to browser (no output file) must die() after outputting content if using AJAX. Do not output to browser anything after this function in this case.
  623. public static function importbuddy( $output_file = '', $importbuddy_pass_hash = '' ) {
  624. if ( defined( 'PB_DEMO_MODE' ) ) {
  625. echo 'Access denied in demo mode.';
  626. return;
  627. }
  628. pb_backupbuddy::set_greedy_script_limits(); // Some people run out of PHP memory.
  629. if ( $importbuddy_pass_hash == '' ) {
  630. if ( !isset( pb_backupbuddy::$options ) ) {
  631. pb_backupbuddy::load();
  632. }
  633. $importbuddy_pass_hash = pb_backupbuddy::$options['importbuddy_pass_hash'];
  634. }
  635. if ( $importbuddy_pass_hash == '' ) {
  636. $message = 'Error #9032: Warning only - You have not set a password to generate the ImportBuddy script yet on the BackupBuddy Settings page. If you are creating a backup, the importbuddy.php restore script will not be included in the backup. You can download it from the Restore page. If you were trying to download ImportBuddy then you may have a plugin confict preventing the page from prompting you to enter a password.';
  637. pb_backupbuddy::status( 'warning', $message );
  638. return false;
  639. }
  640. $output = file_get_contents( pb_backupbuddy::plugin_path() . '/_importbuddy/_importbuddy.php' );
  641. if ( $importbuddy_pass_hash != '' ) {
  642. $output = preg_replace('/#PASSWORD#/', $importbuddy_pass_hash, $output, 1 ); // Only replaces first instance.
  643. }
  644. $output = preg_replace('/#VERSION#/', pb_backupbuddy::settings( 'version' ), $output, 1 ); // Only replaces first instance.
  645. // PACK IMPORTBUDDY
  646. $_packdata = array( // NO TRAILING OR PRECEEDING SLASHES!
  647. '_importbuddy/importbuddy' => 'importbuddy',
  648. 'classes/_migrate_database.php' => 'importbuddy/classes/_migrate_database.php',
  649. 'classes/core.php' => 'importbuddy/classes/core.php',
  650. 'classes/import.php' => 'importbuddy/classes/import.php',
  651. 'images/working.gif' => 'importbuddy/images/working.gif',
  652. 'images/bullet_go.png' => 'importbuddy/images/bullet_go.png',
  653. 'images/favicon.png' => 'importbuddy/images/favicon.png',
  654. 'images/sort_down.png' => 'importbuddy/images/sort_down.png',
  655. 'lib/dbreplace' => 'importbuddy/lib/dbreplace',
  656. 'lib/dbimport' => 'importbuddy/lib/dbimport',
  657. 'lib/commandbuddy' => 'importbuddy/lib/commandbuddy',
  658. 'lib/zipbuddy' => 'importbuddy/lib/zipbuddy',
  659. 'lib/mysqlbuddy' => 'importbuddy/lib/mysqlbuddy',
  660. 'lib/textreplacebuddy' => 'importbuddy/lib/textreplacebuddy',
  661. 'lib/cpanel' => 'importbuddy/lib/cpanel',
  662. 'pluginbuddy' => 'importbuddy/pluginbuddy',
  663. 'controllers/pages/server_info' => 'importbuddy/controllers/pages/server_info',
  664. 'controllers/pages/server_info.php' => 'importbuddy/controllers/pages/server_info.php',
  665. // Stash
  666. 'destinations/stash/lib/class.itx_helper.php' => 'importbuddy/classes/class.itx_helper.php',
  667. 'destinations/_s3lib/aws-sdk/lib/requestcore' => 'importbuddy/lib/requestcore',
  668. );
  669. $output .= "\n<?php /*\n###PACKDATA,BEGIN\n";
  670. foreach( $_packdata as $pack_source => $pack_destination ) {
  671. $pack_source = '/' . $pack_source;
  672. if ( is_dir( pb_backupbuddy::plugin_path() . $pack_source ) ) {
  673. $files = pb_backupbuddy::$filesystem->deepglob( pb_backupbuddy::plugin_path() . $pack_source );
  674. } else {
  675. $files = array( pb_backupbuddy::plugin_path() . $pack_source );
  676. }
  677. foreach( $files as $file ) {
  678. if ( is_file( $file ) ) {
  679. $source = str_replace( pb_backupbuddy::plugin_path(), '', $file );
  680. $destination = $pack_destination . substr( $source, strlen( $pack_source ) );
  681. $output .= "###PACKDATA,FILE_START,{$source},{$destination}\n";
  682. $output .= base64_encode( file_get_contents( $file ) );
  683. $output .= "\n";
  684. $output .= "###PACKDATA,FILE_END,{$source},{$destination}\n";
  685. }
  686. }
  687. }
  688. $output .= "###PACKDATA,END\n*/";
  689. $output .= "\n\n\n\n\n\n\n\n\n\n";
  690. if ( $output_file == '' ) { // No file so output to browser.
  691. header( 'Content-Description: File Transfer' );
  692. header( 'Content-Type: text/plain; name=importbuddy.php' );
  693. header( 'Content-Disposition: attachment; filename=importbuddy.php' );
  694. header( 'Expires: 0' );
  695. header( 'Content-Length: ' . strlen( $output ) );
  696. flush();
  697. echo $output;
  698. flush();
  699. // BE SURE TO die() AFTER THIS AND NOT OUTPUT TO BROWSER!
  700. } else { // Write to file.
  701. file_put_contents( $output_file, $output );
  702. }
  703. } // End importbuddy().
  704. // If output file not specified then outputs to browser as download.
  705. // IMPORTANT: If outputting to browser (no output file) must die() after outputting content if using AJAX. Do not output to browser anything after this function in this case.
  706. public static function serverbuddy( $output_file = '', $serverbuddy_pass_hash = '' ) {
  707. if ( defined( 'PB_DEMO_MODE' ) ) {
  708. echo 'Access denied in demo mode.';
  709. return;
  710. }
  711. pb_backupbuddy::set_greedy_script_limits(); // Some people run out of PHP memory.
  712. if ( $serverbuddy_pass_hash == '' ) {
  713. if ( !isset( pb_backupbuddy::$options ) ) {
  714. pb_backupbuddy::load();
  715. }
  716. $serverbuddy_pass_hash = pb_backupbuddy::$options['importbuddy_pass_hash'];
  717. }
  718. if ( $serverbuddy_pass_hash == '' ) {
  719. $message = 'Error #9032c: Warning only - You have not set a password to generate the ServerBuddy script yet on the BackupBuddy Settings page. If you were trying to download ServerBuddy then you may have a plugin confict preventing the page from prompting you to enter a password.';
  720. pb_backupbuddy::status( 'warning', $message );
  721. return false;
  722. }
  723. $output = file_get_contents( pb_backupbuddy::plugin_path() . '/_serverbuddy/_serverbuddy.php' );
  724. if ( $serverbuddy_pass_hash != '' ) {
  725. $output = preg_replace('/#PASSWORD#/', $serverbuddy_pass_hash, $output, 1 ); // Only replaces first instance.
  726. }
  727. $output = preg_replace('/#VERSION#/', pb_backupbuddy::settings( 'version' ), $output, 1 ); // Only replaces first instance.
  728. // PACK SERVERBUDDY
  729. $_packdata = array( // NO TRAILING OR PRECEEDING SLASHES!
  730. '_serverbuddy/serverbuddy' => 'serverbuddy',
  731. 'classes/_migrate_database.php' => 'serverbuddy/classes/_migrate_database.php',
  732. 'classes/core.php' => 'serverbuddy/classes/core.php',
  733. 'images/working.gif' => 'serverbuddy/images/working.gif',
  734. 'images/bullet_go.png' => 'serverbuddy/images/bullet_go.png',
  735. 'images/favicon.png' => 'serverbuddy/images/favicon.png',
  736. 'images/sort_down.png' => 'serverbuddy/images/sort_down.png',
  737. 'lib/dbreplace' => 'serverbuddy/lib/dbreplace',
  738. 'lib/commandbuddy' => 'serverbuddy/lib/commandbuddy',
  739. 'lib/zipbuddy' => 'serverbuddy/lib/zipbuddy',
  740. 'lib/mysqlbuddy' => 'serverbuddyy/lib/mysqlbuddy',
  741. 'lib/textreplacebuddy' => 'serverbuddy/lib/textreplacebuddy',
  742. 'pluginbuddy' => 'serverbuddy/pluginbuddy',
  743. 'controllers/pages/server_info' => 'serverbuddy/controllers/pages/server_info',
  744. 'controllers/pages/server_info.php' => 'serverbuddy/controllers/pages/server_info.php',
  745. );
  746. $output .= "\n<?php /*\n###PACKDATA,BEGIN\n";
  747. foreach( $_packdata as $pack_source => $pack_destination ) {
  748. $pack_source = '/' . $pack_source;
  749. if ( is_dir( pb_backupbuddy::plugin_path() . $pack_source ) ) {
  750. $files = pb_backupbuddy::$filesystem->deepglob( pb_backupbuddy::plugin_path() . $pack_source );
  751. } else {
  752. $files = array( pb_backupbuddy::plugin_path() . $pack_source );
  753. }
  754. foreach( $files as $file ) {
  755. if ( is_file( $file ) ) {
  756. $source = str_replace( pb_backupbuddy::plugin_path(), '', $file );
  757. $destination = $pack_destination . substr( $source, strlen( $pack_source ) );
  758. $output .= "###PACKDATA,FILE_START,{$source},{$destination}\n";
  759. $output .= base64_encode( file_get_contents( $file ) );
  760. $output .= "\n";
  761. $output .= "###PACKDATA,FILE_END,{$source},{$destination}\n";
  762. }
  763. }
  764. }
  765. $output .= "###PACKDATA,END\n*/";
  766. $output .= "\n\n\n\n\n\n\n\n\n\n";
  767. if ( $output_file == '' ) { // No file so output to browser.
  768. header( 'Content-Description: File Transfer' );
  769. header( 'Content-Type: text/plain; name=importbuddy.php' );
  770. header( 'Content-Disposition: attachment; filename=importbuddy.php' );
  771. header( 'Expires: 0' );
  772. header( 'Content-Length: ' . strlen( $output ) );
  773. flush();
  774. echo $output;
  775. flush();
  776. // BE SURE TO die() AFTER THIS AND NOT OUTPUT TO BROWSER!
  777. } else { // Write to file.
  778. file_put_contents( $output_file, $output );
  779. }
  780. } // End serverbuddy().
  781. // TODO: RepairBuddy is not yet converted into new framework so just using pre-BB3.0 version for now.
  782. public function repairbuddy( $output_file = '' ) {
  783. if ( defined( 'PB_DEMO_MODE' ) ) {
  784. echo 'Access denied in demo mode.';
  785. return;
  786. }
  787. if ( !isset( pb_backupbuddy::$options ) ) {
  788. pb_backupbuddy::load();
  789. }
  790. $output = file_get_contents( pb_backupbuddy::plugin_path() . '/_repairbuddy.php' );
  791. if ( pb_backupbuddy::$options['repairbuddy_pass_hash'] != '' ) {
  792. $output = preg_replace('/#PASSWORD#/', pb_backupbuddy::$options['repairbuddy_pass_hash'], $output, 1 ); // Only replaces first instance.
  793. }
  794. $output = preg_replace('/#VERSION#/', pb_backupbuddy::settings( 'version' ), $output, 1 ); // Only replaces first instance.
  795. if ( $output_file == '' ) { // No file so output to browser.
  796. header( 'Content-Description: File Transfer' );
  797. header( 'Content-Type: text/plain; name=repairbuddy.php' );
  798. header( 'Content-Disposition: attachment; filename=repairbuddy.php' );
  799. header( 'Expires: 0' );
  800. header( 'Content-Length: ' . strlen( $output ) );
  801. flush();
  802. echo $output;
  803. flush();
  804. // BE SURE TO die() AFTER THIS AND NOT OUTPUT TO BROWSER!
  805. } else { // Write to file.
  806. file_put_contents( $output_file, $output );
  807. }
  808. } // End repairbuddy().
  809. function pretty_destination_type( $type ) {
  810. if ( $type == 'rackspace' ) {
  811. return 'Rackspace';
  812. } elseif ( $type == 'email' ) {
  813. return 'Email';
  814. } elseif ( $type == 's3' ) {
  815. return 'Amazon S3';
  816. } elseif ( $type == 'ftp' ) {
  817. return 'FTP';
  818. } elseif ( $type == 'dropbox' ) {
  819. return 'Dropbox';
  820. } else {
  821. return $type;
  822. }
  823. } // End pretty_destination_type().
  824. // $max_depth int Maximum depth of tree to display. Npte that deeper depths are still traversed for size calculations.
  825. function build_icicle( $dir, $base, $icicle_json, $max_depth = 10, $depth_count = 0, $is_root = true ) {
  826. $bg_color = '005282';
  827. $depth_count++;
  828. $bg_color = dechex( hexdec( $bg_color ) - ( $depth_count * 15 ) );
  829. $icicle_json = '{' . "\n";
  830. $dir_name = $dir;
  831. $dir_name = str_replace( ABSPATH, '', $dir );
  832. $dir_name = str_replace( '\\', '/', $dir_name );
  833. $dir_size = 0;
  834. $sub = opendir( $dir );
  835. $has_children = false;
  836. while( $file = readdir( $sub ) ) {
  837. if ( ( $file == '.' ) || ( $file == '..' ) ) {
  838. continue; // Next loop.
  839. } elseif ( is_dir( $dir . '/' . $file ) ) {
  840. $dir_array = '';
  841. $response = $this->build_icicle( $dir . '/' . $file, $base, $dir_array, $max_depth, $depth_count, false );
  842. if ( ( $max_depth-1 > 0 ) || ( $max_depth == -1 ) ) { // Only adds to the visual tree if depth isnt exceeded.
  843. if ( $max_depth > 0 ) {
  844. $max_depth = $max_depth - 1;
  845. }
  846. if ( $has_children === false ) { // first loop add children section
  847. $icicle_json .= '"children": [' . "\n";
  848. } else {
  849. $icicle_json .= ',';
  850. }
  851. $icicle_json .= $response[0];
  852. $has_children = true;
  853. }
  854. $dir_size += $response[1];
  855. unset( $response );
  856. unset( $file );
  857. } else {
  858. $stats = stat( $dir . '/' . $file );
  859. $dir_size += $stats['size'];
  860. unset( $file );
  861. }
  862. }
  863. closedir( $sub );
  864. unset( $sub );
  865. if ( $has_children === true ) {
  866. $icicle_json .= ' ]' . "\n";
  867. }
  868. if ( $has_children === true ) {
  869. $icicle_json .= ',';
  870. }
  871. $icicle_json .= '"id": "node_' . str_replace( '/', ':', $dir_name ) . ': ^' . str_replace( ' ', '~', pb_backupbuddy::$format->file_size( $dir_size ) ) . '"' . "\n";
  872. $dir_name = str_replace( '/', '', strrchr( $dir_name, '/' ) );
  873. if ( $dir_name == '' ) { // Set root to be /.
  874. $dir_name = '/';
  875. }
  876. $icicle_json .= ', "name": "' . $dir_name . ' (' . pb_backupbuddy::$format->file_size( $dir_size ) . ')"' . "\n";
  877. $icicle_json .= ',"data": { "$dim": ' . ( $dir_size + 10 ) . ', "$color": "#' . str_pad( $bg_color, 6, '0', STR_PAD_LEFT ) . '" }' . "\n";
  878. $icicle_json .= '}';
  879. if ( $is_root !== true ) {
  880. //$icicle_json .= ',x';
  881. }
  882. return array( $icicle_json, $dir_size );
  883. } // End build_icicle().
  884. // return array of tests and their results.
  885. public function preflight_check() {
  886. $tests = array();
  887. // MULTISITE BETA WARNING.
  888. if ( is_multisite() && pb_backupbuddy::$classes['core']->is_network_activated() && !defined( 'PB_DEMO_MODE' ) ) { // Multisite installation.
  889. $tests[] = array(
  890. 'test' => 'multisite_beta',
  891. 'success' => false,
  892. 'message' => 'WARNING: BackupBuddy Multisite functionality is not supported. Multiple issues are known. Usage of it is at your own risk and should not be relied upon. Standalone WordPress sites are suggested. You may use the "Export" feature to export your subsites into standalone WordPress sites. To enable experimental BackupBuddy Multisite functionality you must add the following line to your wp-config.php file: <b>define( \'PB_BACKUPBUDDY_MULTISITE_EXPERIMENT\', true );</b>
  893. '
  894. );
  895. /*
  896. $tests[] = array(
  897. 'test' => 'multisite_beta_35',
  898. 'success' => false,
  899. 'message' => 'WARNING: Multisite running on WordPress v3.5 may have introduced multiple issues with importing sites into a Network, possibly including problems with media, users, and URL migration. Only using BackupBuddy with standalone sites is highly recommended.'
  900. );
  901. */
  902. } // end network-activated multisite.
  903. // LOOPBACKS TEST.
  904. if ( ( $loopback_response = $this->loopback_test() ) === true ) {
  905. $success = true;
  906. $message = '';
  907. } else { // failed
  908. $success = false;
  909. if ( defined( 'ALTERNATE_WP_CRON' ) && ( ALTERNATE_WP_CRON == true ) ) {
  910. $message = __('Running in Alternate WordPress Cron mode. HTTP Loopback Connections are not enabled on this server but you have overridden this in the wp-config.php file (this is a good thing).', 'it-l10n-backupbuddy' ) . ' <a href="http://ithemes.com/codex/page/BackupBuddy:_Frequent_Support_Issues#HTTP_Loopback_Connections_Disabled" target="_new">' . __('Additional Information Here', 'it-l10n-backupbuddy' ) . '</a>.';
  911. } else {
  912. $message = __('HTTP Loopback Connections are not enabled on this server. You may encounter stalled, significantly delayed backups, or other difficulties.', 'it-l10n-backupbuddy' ) . ' <a href="http://ithemes.com/codex/page/BackupBuddy:_Frequent_Support_Issues#HTTP_Loopback_Connections_Disabled" target="_new">' . __('Click for instructions on how to resolve this issue.', 'it-l10n-backupbuddy' ) . '</a>';
  913. }
  914. }
  915. $tests[] = array(
  916. 'test' => 'loopbacks',
  917. 'success' => $success,
  918. 'message' => $message,
  919. );
  920. // POSSIBLE CACHING PLUGIN CONFLICT WARNING.
  921. $success = true;
  922. $message = '';
  923. if ( ! is_multisite() ) {
  924. $active_plugins = serialize( get_option( 'active…

Large files files are truncated, but you can click here to view the full file