UpdraftPlus_Options::get_updraft_option('updraft_ftp_login'), 'pass' => UpdraftPlus_Options::get_updraft_option('updraft_ftp_pass'), 'host' => UpdraftPlus_Options::get_updraft_option('updraft_server_address'), 'path' => UpdraftPlus_Options::get_updraft_option('updraft_ftp_remote_path'), 'passive' => true ); UpdraftPlus_Options::update_updraft_option('updraft_ftp', $opts); UpdraftPlus_Options::delete_updraft_option('updraft_server_address'); UpdraftPlus_Options::delete_updraft_option('updraft_ftp_pass'); UpdraftPlus_Options::delete_updraft_option('updraft_ftp_remote_path'); UpdraftPlus_Options::delete_updraft_option('updraft_ftp_login'); } if (!class_exists('UpdraftPlus_BackupModule')) require_once(UPDRAFTPLUS_DIR.'/methods/backup-module.php'); class UpdraftPlus_BackupModule_ftp extends UpdraftPlus_BackupModule { /** * Get FTP object with parameters set * * @param string $server Specify Server * @param string $user Specify Username * @param string $pass Specify Password * @param boolean $disable_ssl Indicate whether to disable SSL * @param boolean $disable_verify Indicate whether to disable verifiction * @param boolean $use_server_certs Indicate whether to use server certificates * @param boolean $passive Indicate whether to use passive FTP mode * @return array */ private function getFTP($server, $user, $pass, $disable_ssl = false, $disable_verify = true, $use_server_certs = false, $passive = true) { if ('' == trim($server) || '' == trim($user) || '' == trim($pass)) return new WP_Error('no_settings', sprintf(__('No %s settings were found', 'updraftplus'), 'FTP')); if (!class_exists('UpdraftPlus_ftp_wrapper')) include_once(UPDRAFTPLUS_DIR.'/includes/ftp.class.php'); $port = 21; if (preg_match('/^(.*):(\d+)$/', $server, $matches)) { $server = $matches[1]; $port = $matches[2]; } $ftp = new UpdraftPlus_ftp_wrapper($server, $user, $pass, $port); if ($disable_ssl) $ftp->ssl = false; $ftp->use_server_certs = $use_server_certs; $ftp->disable_verify = $disable_verify; $ftp->passive = ($passive) ? true : false; return $ftp; } /** * WordPress options filter, sanitising the FTP options saved from the options page * * @param Array $settings - the options, prior to sanitisation * * @return Array - the sanitised options for saving */ public function options_filter($settings) { if (is_array($settings) && !empty($settings['version']) && !empty($settings['settings'])) { foreach ($settings['settings'] as $instance_id => $instance_settings) { if (!empty($instance_settings['host']) && preg_match('#ftp(es|s)?://(.*)#i', $instance_settings['host'], $matches)) { $settings['settings'][$instance_id]['host'] = rtrim($matches[2], "/ \t\n\r\0x0B"); } if (isset($instance_settings['pass'])) { $settings['settings'][$instance_id]['pass'] = trim($instance_settings['pass'], "\n\r\0\x0B"); } } } return $settings; } public function get_supported_features() { // The 'multi_options' options format is handled via only accessing options via $this->get_options() return array('multi_options', 'config_templates', 'multi_storage'); } public function get_default_options() { return array( 'host' => '', 'user' => '', 'pass' => '', 'path' => '', 'passive' => 1 ); } public function backup($backup_array) { global $updraftplus; $opts = $this->get_options(); $ftp = $this->getFTP( $opts['host'], $opts['user'], $opts['pass'], $updraftplus->get_job_option('updraft_ssl_nossl'), $updraftplus->get_job_option('updraft_ssl_disableverify'), $updraftplus->get_job_option('updraft_ssl_useservercerts'), $opts['passive'] ); if (is_wp_error($ftp) || !$ftp->connect()) { if (is_wp_error($ftp)) { $updraftplus->log_wp_error($ftp); } else { $updraftplus->log("FTP Failure: we did not successfully log in with those credentials."); } $updraftplus->log(sprintf(__("%s login failure", 'updraftplus'), 'FTP'), 'error'); return false; } // $ftp->make_dir(); we may need to recursively create dirs? TODO $updraft_dir = $updraftplus->backups_dir_location().'/'; $ftp_remote_path = trailingslashit($opts['path']); foreach ($backup_array as $file) { $fullpath = $updraft_dir.$file; $updraftplus->log("FTP upload attempt: $file -> ftp://".$opts['user']."@".$opts['host']."/${ftp_remote_path}${file}"); $timer_start = microtime(true); $size_k = round(filesize($fullpath)/1024, 1); // Note :Setting $resume to true unnecessarily is not meant to be a problem. Only ever (Feb 2014) seen one weird FTP server where calling SIZE on a non-existent file did create a problem. So, this code just helps that case. (the check for non-empty upload_status[p] is being cautious. $upload_status = $updraftplus->jobdata_get('uploading_substatus'); if (0 == $updraftplus->current_resumption || (is_array($upload_status) && !empty($upload_status['p']) && 0 == $upload_status['p'])) { $resume = false; } else { $resume = true; } if ($ftp->put($fullpath, $ftp_remote_path.$file, FTP_BINARY, $resume, $updraftplus)) { $updraftplus->log("FTP upload attempt successful (".$size_k."KB in ".(round(microtime(true)-$timer_start, 2)).'s)'); $updraftplus->uploaded_file($file); } else { $updraftplus->log("ERROR: FTP upload failed"); $updraftplus->log(sprintf(__("%s upload failed", 'updraftplus'), 'FTP'), 'error'); } } return array('ftp_object' => $ftp, 'ftp_remote_path' => $ftp_remote_path); } public function listfiles($match = 'backup_') { global $updraftplus; $opts = $this->get_options(); $ftp = $this->getFTP( $opts['host'], $opts['user'], $opts['pass'], $updraftplus->get_job_option('updraft_ssl_nossl'), $updraftplus->get_job_option('updraft_ssl_disableverify'), $updraftplus->get_job_option('updraft_ssl_useservercerts'), $opts['passive'] ); if (is_wp_error($ftp)) return $ftp; if (!$ftp->connect()) return new WP_Error('ftp_login_failed', sprintf(__("%s login failure", 'updraftplus'), 'FTP')); $ftp_remote_path = $opts['path']; if ($ftp_remote_path) $ftp_remote_path = trailingslashit($ftp_remote_path); $dirlist = $ftp->dir_list($ftp_remote_path); if (!is_array($dirlist)) return array(); $results = array(); foreach ($dirlist as $k => $path) { if ($ftp_remote_path) { // Feb 2015 - found a case where the directory path was not prefixed on if (0 !== strpos($path, $ftp_remote_path) && (false !== strpos('/', $ftp_remote_path) && false !== strpos('\\', $ftp_remote_path))) continue; if (0 === strpos($path, $ftp_remote_path)) $path = substr($path, strlen($ftp_remote_path)); // if (0 !== strpos($path, $ftp_remote_path)) continue; // $path = substr($path, strlen($ftp_remote_path)); if (0 === strpos($path, $match)) $results[]['name'] = $path; } else { if ('/' == substr($path, 0, 1)) $path = substr($path, 1); if (false !== strpos($path, '/')) continue; if (0 === strpos($path, $match)) $results[]['name'] = $path; } unset($dirlist[$k]); } // ftp_nlist() doesn't return file sizes. rawlist() does, but is tricky to parse. So, we get the sizes manually. foreach ($results as $ind => $name) { $size = $ftp->size($ftp_remote_path.$name['name']); if (0 === $size) { unset($results[$ind]); } elseif ($size>0) { $results[$ind]['size'] = $size; } } return $results; } public function delete($files, $ftparr = array(), $sizeinfo = array()) { global $updraftplus; if (is_string($files)) $files = array($files); $opts = $this->get_options(); if (is_array($ftparr) && isset($ftparr['ftp_object'])) { $ftp = $ftparr['ftp_object']; } else { $ftp = $this->getFTP( $opts['host'], $opts['user'], $opts['pass'], $updraftplus->get_job_option('updraft_ssl_nossl'), $updraftplus->get_job_option('updraft_ssl_disableverify'), $updraftplus->get_job_option('updraft_ssl_useservercerts'), $opts['passive'] ); if (is_wp_error($ftp) || !$ftp->connect()) { if (is_wp_error($ftp)) $updraftplus->log_wp_error($ftp); $updraftplus->log("FTP Failure: we did not successfully log in with those credentials (host=".$opts['host'].")."); return false; } } $ftp_remote_path = isset($ftparr['ftp_remote_path']) ? $ftparr['ftp_remote_path'] : trailingslashit($opts['path']); $ret = true; foreach ($files as $file) { if (@$ftp->delete($ftp_remote_path.$file)) { $updraftplus->log("FTP delete: succeeded (${ftp_remote_path}${file})"); } else { $updraftplus->log("FTP delete: failed (${ftp_remote_path}${file})"); $ret = false; } } return $ret; } public function download($file) { global $updraftplus; $opts = $this->get_options(); $ftp = $this->getFTP( $opts['host'], $opts['user'], $opts['pass'], $updraftplus->get_job_option('updraft_ssl_nossl'), $updraftplus->get_job_option('updraft_ssl_disableverify'), $updraftplus->get_job_option('updraft_ssl_useservercerts'), $opts['passive'] ); if (is_wp_error($ftp)) return $ftp; if (!$ftp->connect()) { $updraftplus->log("FTP Failure: we did not successfully log in with those credentials."); $updraftplus->log(sprintf(__("%s login failure", 'updraftplus'), 'FTP'), 'error'); return false; } // $ftp->make_dir(); we may need to recursively create dirs? TODO $ftp_remote_path = trailingslashit($opts['path']); $fullpath = $updraftplus->backups_dir_location().'/'.$file; $resume = false; if (file_exists($fullpath)) { $resume = true; $updraftplus->log("File already exists locally; will resume: size: ".filesize($fullpath)); } return $ftp->get($fullpath, $ftp_remote_path.$file, FTP_BINARY, $resume, $updraftplus); } private function ftp_possible() { $funcs_disabled = array(); foreach (array('ftp_connect', 'ftp_login', 'ftp_nb_fput') as $func) { if (!function_exists($func)) $funcs_disabled['ftp'][] = $func; } $funcs_disabled = apply_filters('updraftplus_ftp_possible', $funcs_disabled); return (0 == count($funcs_disabled)) ? true : $funcs_disabled; } /** * Get the pre configuration template * * @return String - the template */ public function get_pre_configuration_template() { global $updraftplus_admin; $classes = $this->get_css_classes(false); ?>