diff --git a/admin/actions.php b/admin/actions.php index 532d7c35..e8f191e3 100755 --- a/admin/actions.php +++ b/admin/actions.php @@ -57,6 +57,52 @@ function request_delete_schedule() { } add_action( 'admin_post_hmbkp_request_delete_schedule', 'HM\BackUpWordPress\request_delete_schedule' ); +add_action( 'admin_post_hmbkp_request_credentials', function() { + + global $wp_filesystem; + + ob_start(); + $creds = request_filesystem_credentials( '' ); + ob_end_clean(); + + // Default to showing an error if we're not able to connect. + $url = add_query_arg( 'connection_error', 1, get_settings_url() ); + + /** + * If we have valid filesystem credentials then let's attempt + * to use them to create the backups directory. If we can't create it in + * WP_CONTENT_DIR then we fallback to trying in uploads. + */ + if ( WP_Filesystem( $creds ) ) { + + // If we're able to connect then no need to redirect with an error. + $url = get_settings_url(); + + // If the backup path exists then let's just try to chmod it to the correct permissions. + if ( + is_dir( Path::get_instance()->get_default_path() ) && + ! $wp_filesystem->chmod( Path::get_instance()->get_default_path(), FS_CHMOD_DIR ) + ) { + $url = add_query_arg( 'creation_error', 1, get_settings_url() ); + } else { + + // If the path doesn't exist then try to correct the permission for the parent directory and create it. + $wp_filesystem->chmod( dirname( Path::get_instance()->get_default_path() ), FS_CHMOD_DIR ); + + if ( + ! $wp_filesystem->mkdir( Path::get_instance()->get_default_path(), FS_CHMOD_DIR ) && + ! $wp_filesystem->mkdir( Path::get_instance()->get_fallback_path(), FS_CHMOD_DIR ) + ) { + $url = add_query_arg( 'creation_error', 1, get_settings_url() ); + } + } + } + + wp_safe_redirect( $url , 303 ); + die; + +} ); + /** * Perform a manual backup * diff --git a/admin/filesystem-credentials.php b/admin/filesystem-credentials.php new file mode 100644 index 00000000..ea570305 --- /dev/null +++ b/admin/filesystem-credentials.php @@ -0,0 +1,8 @@ + - + -

', '' ); ?>

+ - +

', '' ); ?>

+ + + + + + + + diff --git a/classes/class-path.php b/classes/class-path.php index 47bfc5f9..4d94b8e6 100644 --- a/classes/class-path.php +++ b/classes/class-path.php @@ -275,6 +275,29 @@ public function get_existing_path() { */ public function calculate_path() { + $paths = $this->get_possible_paths(); + + // Loop through possible paths, use the first one that exists/can be created and is writable. + foreach ( $paths as $path ) { + // Also handles fixing perms / directory already exists. + if ( wp_mkdir_p( $path ) && wp_is_writable( $path ) ) { + break; + } + } + + /** + * If we managed to create a writable path then use that, + * otherwise just return the unwritable path. + */ + if ( file_exists( $path ) && wp_is_writable( $path ) ) { + $this->path = $path; + } else { + $this->path = reset( $paths ); + } + } + + public function get_possible_paths() { + $paths = array(); // If we have a custom path then try to use it. @@ -293,13 +316,7 @@ public function calculate_path() { // If that didn't work then fallback to a new directory in uploads. $paths[] = $this->get_fallback_path(); - // Loop through possible paths, use the first one that exists/can be created and is writable. - foreach ( $paths as $path ) { - if ( wp_mkdir_p( $path ) && file_exists( $path ) && wp_is_writable( $path ) ) { // Also handles fixing perms / directory already exists. - $this->path = $path; - break; - } - } + return $paths; } /** @@ -410,7 +427,6 @@ public function move_old_backups( $from ) { if ( false !== strpos( $from, WP_CONTENT_DIR ) && Path::get_path() !== $from ) { rmdirtree( $from ); } - } /** diff --git a/classes/class-requirement.php b/classes/class-requirement.php index a7959ab2..c9b47bca 100644 --- a/classes/class-requirement.php +++ b/classes/class-requirement.php @@ -281,7 +281,10 @@ class Requirement_Backup_Path_Permissions extends Requirement { * @return string */ public static function test() { - return substr( sprintf( '%o', fileperms( Path::get_path() ) ), - 4 ); + if ( is_readable( PATH::get_path() ) ) { + return substr( sprintf( '%o', fileperms( Path::get_path() ) ), - 4 ); + } + return 'Unreadable'; } } Requirements::register( 'HM\BackUpWordPress\Requirement_Backup_Path_Permissions', 'Site' ); diff --git a/classes/class-site-size.php b/classes/class-site-size.php index f34b6e53..94b8d89d 100644 --- a/classes/class-site-size.php +++ b/classes/class-site-size.php @@ -8,7 +8,7 @@ /** * Site Size class * - * Use to calculate the total or partial size of the sites database and files. + * Use to calculate the total or partial size of the site's database and files. */ class Site_Size { diff --git a/functions/core.php b/functions/core.php index 8201614f..ab94bdf7 100755 --- a/functions/core.php +++ b/functions/core.php @@ -393,17 +393,17 @@ function rmdirtree( $dir ) { @rmdir( $dir ); return true; + } /** - * Check if a backup is possible with regards to file - * permissions etc. + * Check if we have read and write permission on the server * * @return bool */ -function is_backup_possible() { +function has_server_permissions() { - if ( ! wp_is_writable( Path::get_path() ) || ! is_dir( Path::get_path() ) ) { + if ( ! wp_is_writable( Path::get_path() ) ) { return false; } @@ -411,6 +411,21 @@ function is_backup_possible() { return false; } + return true; +} + +/** + * Check if a backup is possible with regards to file + * permissions etc. + * + * @return bool + */ +function is_backup_possible() { + + if ( ! has_server_permissions() || ! is_dir( Path::get_path() ) ) { + return false; + } + if ( ! Requirement_Mysqldump_Command_Path::test() && ! Requirement_PDO::test() ) { return false; } diff --git a/functions/interface.php b/functions/interface.php index 57b512bf..3b69425a 100644 --- a/functions/interface.php +++ b/functions/interface.php @@ -33,7 +33,19 @@ function get_backup_row( $file, Scheduled_Backup $schedule ) { | - + + + @@ -42,8 +54,7 @@ function get_backup_row( $file, Scheduled_Backup $schedule ) { -
  • - @@ -97,7 +106,12 @@ function admin_notices() { -
  • +
  • + +
  • @@ -139,65 +153,110 @@ function admin_notices() { function set_server_config_notices() { - $notices = Notices::get_instance(); - + $notices = Notices::get_instance(); $messages = array(); - if ( ! is_dir( Path::get_path() ) ) { - $messages[] = sprintf( __( 'The backups directory can\'t be created because your %s directory isn\'t writable. Please create the folder manually.', 'backupwordpress' ), '' . esc_html( dirname( Path::get_path() ) ) . '' ); - } - - if ( is_dir( Path::get_path() ) && ! wp_is_writable( Path::get_path() ) ) { - $messages[] = __( 'The backups directory isn\'t writable. Please fix the permissions.', 'backupwordpress' ); - } - if ( Backup_Utilities::is_safe_mode_on() ) { - $messages[] = sprintf( __( '%1$s is running in %2$s, please contact your host and ask them to disable it. BackUpWordPress may not work correctly whilst %3$s is on.', 'backupwordpress' ), 'PHP', sprintf( '%2$s', __( 'http://php.net/manual/en/features.safe-mode.php', 'backupwordpress' ), __( 'Safe Mode', 'backupwordpress' ) ), '' . __( 'Safe Mode', 'backupwordpress' ) . '' ); + + $messages[] = sprintf( + /* translators: 1: The `PHP` abbreviation. */ + __( '%1$s is running in Safe Mode, please contact your host and ask them to disable it. BackUpWordPress may not work correctly whilst Safe Mode is on.', 'backupwordpress' ), + 'PHP' + ); } if ( defined( 'HMBKP_PATH' ) && HMBKP_PATH ) { // Suppress open_basedir warning https://bugs.php.net/bug.php?id=53041 if ( ! path_in_php_open_basedir( HMBKP_PATH ) ) { - $messages[] = sprintf( __( 'Your server has an %1$s restriction in effect and your custom backups directory (%2$s) is not within the allowed path(s): (%3$s).', 'backupwordpress' ), 'open_basedir', '' . esc_html( HMBKP_PATH ) . '', '' . esc_html( @ini_get( 'open_basedir' ) ) . '' ); - } elseif ( ! file_exists( HMBKP_PATH ) ) { - $messages[] = sprintf( __( 'Your custom path does not exist', 'backupwordpress' ) ); + $messages[] = sprintf( + __( 'Your server has an %1$s restriction in effect and your custom backups directory (%2$s) is not within the allowed path(s): (%3$s).', 'backupwordpress' ), + 'open_basedir', + '' . esc_html( HMBKP_PATH ) . '', + '' . esc_html( @ini_get( 'open_basedir' ) ) . '' + ); - } else { + } elseif ( ! is_dir( HMBKP_PATH ) ) { - if ( ! is_dir( HMBKP_PATH ) ) { - $messages[] = sprintf( __( 'Your custom backups directory %1$s doesn\'t exist and can\'t be created, your backups will be saved to %2$s instead.', 'backupwordpress' ), '' . esc_html( HMBKP_PATH ) . '', '' . esc_html( Path::get_path() ) . '' ); - } + $messages[] = sprintf( + __( 'Your custom backups directory (%1$s) doesn't exist, your backups will be saved to %2$s instead.', 'backupwordpress' ), + '' . esc_html( HMBKP_PATH ) . '', + '' . esc_html( Path::get_path() ) . '' + ); - if ( is_dir( HMBKP_PATH ) && ! wp_is_writable( HMBKP_PATH ) ) { - $messages[] = sprintf( __( 'Your custom backups directory %1$s isn\'t writable, new backups will be saved to %2$s instead.', 'backupwordpress' ), '' . esc_html( HMBKP_PATH ) . '', '' . esc_html( Path::get_path() ) . '' ); + } elseif ( is_dir( HMBKP_PATH ) && ! wp_is_writable( HMBKP_PATH ) ) { - } + $messages[] = sprintf( + __( 'Your custom backups directory (%1$s) isn't writable, new backups will be saved to %2$s instead.', 'backupwordpress' ), + '' . esc_html( HMBKP_PATH ) . '', + '' . esc_html( Path::get_path() ) . '' + ); + } + } + + if ( ! is_dir( Path::get_path() ) || is_dir( Path::get_path() ) && ! wp_is_writable( Path::get_path() ) ) { + + if ( isset( $_GET['creation_error'] ) ) { + + $messages[] = sprintf( + /* translators: 1: URL to BackupWordPress docs. */ + __( 'We connected to your server successfully but still weren't able to automatically create the directory. You'll need to manually specify a valid directory', 'backupwordpress' ), + 'https://bwp.hmn.md/support-center/backupwordpress-faqs/#where' + ); + + } else { + + $messages[] = sprintf( + /* translators: 1: Path to backup directory. 2: URL to BackupWordPress docs. */ + __( 'We couldn't create the backups directory (%1$s). You'll need to manually specify a valid directory or you can have WordPress do it automatically by entering your server details below. This is a one time thing.', 'backupwordpress' ), + '' . esc_html( Path::get_path() ) . '', + 'https://bwp.hmn.md/support-center/backupwordpress-faqs/#where' + ); } } if ( ! is_readable( Path::get_root() ) ) { - $messages[] = sprintf( __( 'Your site root path %s isn\'t readable.', 'backupwordpress' ), '' . Path::get_root() . '' ); + + $messages[] = sprintf( + __( 'Your site's root path (%s) isn't readable. Please contact support.', 'backupwordpress' ), + '' . Path::get_root() . '' + ); } if ( ! Requirement_Mysqldump_Command_Path::test() && ! Requirement_PDO::test() ) { - $messages[] = sprintf( __( 'Your site cannot be backed up because your server doesn\'t support %1$s or %2$s. Please contact your host and ask them to enable them.', 'backupwordpress' ), 'mysqldump', 'PDO::mysql' ); + + $messages[] = sprintf( + /* translators: FYI: specified MySQL features. */ + __( 'Your site cannot be backed up because your server doesn't support %1$s or %2$s. Please contact your host and ask them to enable them.', 'backupwordpress' ), + 'mysqldump', + 'PDO::mysql' + ); } if ( ! Requirement_Zip_Command_Path::test() && ! Requirement_Zip_Archive::test() ) { - $messages[] = sprintf( __( 'Your site cannot be backed up because your server doesn\'t support %1$s or %2$s. Please contact your host and ask them to enable them.', 'backupwordpress' ), 'zip', 'ZipArchive' ); + + $messages[] = sprintf( + /* translators: FYI: specified zip archiving features. */ + __( 'Your site cannot be backed up because your server doesn't support %1$s or %2$s. Please contact your host and ask them to enable them.', 'backupwordpress' ), + 'zip', + 'ZipArchive' + ); } if ( disk_space_low() ) { - $messages[] = sprintf( __( 'Your server only has %s of disk space left which probably isn\'t enough to complete a backup. Try deleting some existing backups or other files to free up space.', 'backupwordpress' ), '' . size_format( disk_free_space( Path::get_path() ) ) . '' ); + + $messages[] = sprintf( + __( 'Your server only has %s of disk space left which probably isn't enough to complete a backup. Try deleting some existing backups or other files to free up space.', 'backupwordpress' ), + '' . size_format( disk_free_space( Path::get_path() ) ) . '' + ); } if ( count( $messages ) > 0 ) { $notices->set_notices( 'server_config', $messages, false ); } - } + add_action( 'admin_init', 'HM\BackUpWordPress\set_server_config_notices' ); /** @@ -217,7 +276,6 @@ function plugin_row( $plugins ) { return $plugins; } - add_filter( 'all_plugins', 'HM\BackUpWordPress\plugin_row', 10 ); /** @@ -460,6 +518,11 @@ function disk_space_low( $backup_size = false ) { } - return $backup_size >= $disk_space; + if ( ! is_readable( Path::get_path() ) ) { + return false; + } + + $disk_space = disk_free_space( Path::get_path() ); + return $disk_space && $backup_size >= $disk_space; } diff --git a/readme.txt b/readme.txt index 96aaf187..4b71bbb2 100644 --- a/readme.txt +++ b/readme.txt @@ -985,7 +985,7 @@ users should see major improvements to reliability. #### 2.0.6 -* Fix possible warning on plugin activation if the sites cron option is empty. +* Fix possible warning on plugin activation if the site's cron option is empty. * Don't show the version warning in the help for Constants as that comes from the current version. #### 2.0.5 diff --git a/tests/class-backup-engine/test-class-backup-engine-file-zip-archive.php b/tests/class-backup-engine/test-class-backup-engine-file-zip-archive.php index 3da6dae9..f7c71098 100644 --- a/tests/class-backup-engine/test-class-backup-engine-file-zip-archive.php +++ b/tests/class-backup-engine/test-class-backup-engine-file-zip-archive.php @@ -12,4 +12,4 @@ public function setUp() { } -} \ No newline at end of file +}