/** * Update or append the requested file with the supplied contents. * * @since 1.15.0 * * @param string $file Full path to config file to update. * @param string $contents Contents to write to the file. * @param bool $append Optional. Set to true to append contents to the file. Defaults to false. * @return bool|WP_Error Boolean true on success, WP_Error object otherwise. */ public static function write($file, $contents, $append = false) { $callable = array(); if (ITSEC_Lib_Utility::is_callable_function('fopen') && ITSEC_Lib_Utility::is_callable_function('fwrite') && ITSEC_Lib_Utility::is_callable_function('flock')) { $callable[] = 'fopen'; } if (ITSEC_Lib_Utility::is_callable_function('file_put_contents')) { $callable[] = 'file_put_contents'; } if (empty($callable)) { return new WP_Error('itsec-lib-file-write-no-callable-functions', sprintf(__('%s could not be written. Both the fopen/fwrite/flock and file_put_contents functions are disabled on the server. This is a server configuration issue that must be resolved before iThemes Security can write files.', 'it-l10n-better-wp-security'), $file)); } if (ITSEC_Lib_Directory::is_dir($file)) { return new WP_Error('itsec-lib-file-write-path-exists-as-directory', sprintf(__('%s could not be written as a file. The requested path already exists as a directory. The directory must be removed or a new file name must be chosen before the file can be written.', 'it-l10n-better-wp-security'), $file)); } if (!ITSEC_Lib_Directory::is_dir(dirname($file))) { $result = ITSEC_Lib_Directory::create(dirname($file)); if (is_wp_error($result)) { return $result; } } $file_existed = self::is_file($file); $success = false; // Different permissions to try in case the starting set of permissions are prohibiting write. $trial_perms = array(false, 0644, 0664, 0666); foreach ($trial_perms as $perms) { if (false !== $perms) { if (!isset($original_file_perms)) { $original_file_perms = self::get_permissions($file); } self::chmod($file, $perms); } if (in_array('fopen', $callable)) { if ($append) { $mode = 'ab'; } else { $mode = 'wb'; } if (false !== ($fh = @fopen($file, $mode))) { flock($fh, LOCK_EX); mbstring_binary_safe_encoding(); $data_length = strlen($contents); $bytes_written = @fwrite($fh, $contents); reset_mbstring_encoding(); @flock($fh, LOCK_UN); @fclose($fh); if ($data_length === $bytes_written) { $success = true; } } } if (!$success && in_array('file_put_contents', $callable)) { if ($append) { $flags = FILE_APPEND; } else { $flags = 0; } mbstring_binary_safe_encoding(); $data_length = strlen($contents); $bytes_written = @file_put_contents($file, $contents, $flags); reset_mbstring_encoding(); if ($data_length === $bytes_written) { $success = true; } } if ($success) { if (!$file_existed) { // Set default file permissions for the new file. self::chmod($file, self::get_default_permissions()); } else { if (isset($original_file_perms) && !is_wp_error($original_file_perms)) { // Reset the original file permissions if they were modified. self::chmod($file, $original_file_perms); } } return true; } if (!$file_existed) { // If the file is new, there is no point attempting different permissions. break; } } return new WP_Error('itsec-lib-file-write-file-put-contents-failed', sprintf(__('%s could not be written. This could be due to a permissions issue. Ensure that PHP runs as a user that has permission to write to this location.', 'it-l10n-better-wp-security'), $file)); }
public function process_directory() { if ($this->is_custom_directory()) { $this->show_error(__('The <code>wp-content</code> directory has already been renamed. No Directory Name changes have been made.', 'it-l10n-better-wp-security')); $this->show_network_admin_notice(); return; } $dir_name = sanitize_file_name($_POST['name']); if (empty($dir_name)) { $this->show_error(__('The Directory Name cannot be empty.', 'it-l10n-better-wp-security')); $this->show_network_admin_notice(); return; } if ('wp-content' === $dir_name) { $this->show_error(__('You have not chosen a new name for wp-content. Nothing was saved.', 'it-l10n-better-wp-security')); $this->show_network_admin_notice(); return; } if (preg_match('{^(?:/|\\|[a-z]:)}i', $dir_name)) { $this->show_error(sprintf(__('The Directory Name cannot be an absolute path. Please supply a path that is relative to <code>ABSPATH</code> (<code>%s</code>).', 'it-l10n-better-wp-security'), ABSPATH)); $this->show_network_admin_notice(); return; } $dir = ABSPATH . $dir_name; if (file_exists($dir)) { $this->show_error(sprintf(__('A file or directory already exists at <code>%s</code>. No Directory Name changes have been made. Please choose a new Directory Name or remove the existing file or directory and try again.', 'it-l10n-better-wp-security'), $dir)); $this->show_network_admin_notice(); return; } require_once trailingslashit($GLOBALS['itsec_globals']['plugin_dir']) . 'core/lib/class-itsec-lib-config-file.php'; $old_permissions = ITSEC_Lib_Directory::get_permissions(WP_CONTENT_DIR); $result = rename(WP_CONTENT_DIR, $dir); if (!$result) { $this->show_error(sprintf(__('Unable to rename the <code>wp-content</code> directory to <code>%s</code>. This could indicate a file permission issue or that your server does not support the supplied name as a valid directory name. No config file or directory changes have been made.', 'it-l10n-better-wp-security'), $dir_name)); $this->show_network_admin_notice(); return; } $new_permissions = ITSEC_Lib_Directory::get_permissions($dir); if (is_int($old_permissions) && is_int($new_permissions) && $old_permissions != $new_permissions) { $result = ITSEC_Lib_Directory::chmod($dir, $old_permissions); if (is_wp_error($result)) { $this->show_error(sprintf(__('Unable to set the permissions of the new Directory Name (<code>%1$s</code>) to match the permissions of the old Directory Name. You may have to manually change the permissions of the directory to <code>%2$s</code> in order for your site to function properly.', 'it-l10n-better-wp-security'), $dir_name, $old_permissions)); } } $php_content_dir = str_replace("'", "\\'", $dir); $php_content_url = str_replace("'", "\\'", get_option('siteurl') . "/{$dir_name}"); $modification = "define( 'WP_CONTENT_DIR', '{$php_content_dir}' ); // " . __('Do not remove. Removing this line could break your site. Added by Security > Settings > Change Content Directory.', 'it-l10n-better-wp-security') . "\n"; $modification .= "define( 'WP_CONTENT_URL', '{$php_content_url}' ); // " . __('Do not remove. Removing this line could break your site. Added by Security > Settings > Change Content Directory.', 'it-l10n-better-wp-security') . "\n"; $append_result = ITSEC_Lib_Config_File::append_wp_config($modification, true); if (is_wp_error($append_result)) { $rename_result = rename($dir, WP_CONTENT_DIR); if ($rename_result) { ITSEC_Lib_Directory::chmod(WP_CONTENT_DIR, $old_permissions); $this->show_error(sprintf(__('Unable to update the <code>wp-config.php</code> file. No directory or config file changes have been made. %1$s (%2$s)', 'it-l10n-better-wp-security'), $append_result->get_error_message(), $append_result->get_error_code())); $this->show_error(sprintf(__('In order to change the content directory on your server, you will have to manually change the configuration and rename the directory. Details can be found <a href="%s">here</a>.', 'it-l10n-better-wp-security'), 'https://codex.wordpress.org/Editing_wp-config.php#Moving_wp-content_folder')); } else { $this->show_error(sprintf(__('CRITICAL ERROR: The <code>wp-content</code> directory was successfully renamed to the new name (<code>%1$s</code>). However, an error occurred when updating the <code>wp-config.php</code> file to configure WordPress to use the new content directory. iThemes Security attempted to rename the directory back to its original name, but an unknown error prevented the rename from working as expected. In order for your site to function properly, you will either need to rename the <code>%1$s</code> directory back to <code>wp-content</code> or manually update the <code>wp-config.php</code> file with the necessary modifications. Instructions for making this modification can be found <a href="%2$s">here</a>.', 'it-l10n-better-wp-security'), $dir_name, 'https://codex.wordpress.org/Editing_wp-config.php#Moving_wp-content_folder')); $this->show_error(sprintf(__('Details on the error that prevented the <code>wp-config.php</code> file from updating is as follows: %1$s (%2$s)', 'it-l10n-better-wp-security'), $append_result->get_error_message(), $append_result->get_error_code())); } return; } $backup = get_site_option('itsec_backup'); if ($backup !== false && isset($backup['location'])) { $backup['location'] = str_replace(WP_CONTENT_DIR, $dir, $backup['location']); update_site_option('itsec_backup', $backup); } $global = get_site_option('itsec_global'); if ($global !== false && (isset($global['log_location']) || isset($global['nginx_file']))) { if (isset($global['log_location'])) { $global['log_location'] = str_replace(WP_CONTENT_DIR, $dir, $global['log_location']); } if (isset($global['nginx_file'])) { $global['nginx_file'] = str_replace(WP_CONTENT_DIR, $dir, $global['nginx_file']); } update_site_option('itsec_global', $global); } $this->show_network_admin_notice(); }
/** * Release the lock. * * Releases a file lock to allow others to use it. * * @since 4.0.0 * * @param string $lock_file file name of lock * * @return bool true if released, false otherwise */ public function release_file_lock($lock_file) { if (ITSEC_Modules::get_setting('global', 'lock_file')) { return true; } require_once ITSEC_Core::get_core_dir() . '/lib/class-itsec-lib-directory.php'; $lock_file = ITSEC_Core::get_storage_dir() . '/' . sanitize_text_field($lock_file) . '.lock'; $result = ITSEC_Lib_Directory::remove($lock_file); if (is_wp_error($result)) { return false; } return true; }
public static function get_storage_dir($dir = '') { $self = self::get_instance(); require_once self::get_core_dir() . '/lib/class-itsec-lib-directory.php'; if (!isset($self->storage_dir)) { $wp_upload_dir = self::get_wp_upload_dir(); $self->storage_dir = $wp_upload_dir['basedir'] . '/ithemes-security/'; } $dir = $self->storage_dir . $dir; $dir = rtrim($dir, '/'); ITSEC_Lib_Directory::create($dir); return $dir; }
/** * Executes backup function. * * Handles the execution of database backups. * * @since 4.0.0 * * @param bool $one_time whether this is a one-time backup * * @return void */ private function execute_backup($one_time = false) { global $wpdb, $itsec_globals, $itsec_logger; //get all of the tables if (isset($this->settings['all_sites']) && true === $this->settings['all_sites']) { $tables = $wpdb->get_results('SHOW TABLES', ARRAY_N); //retrieve a list of all tables in the DB } else { $tables = $wpdb->get_results('SHOW TABLES LIKE "' . $wpdb->base_prefix . '%"', ARRAY_N); //retrieve a list of all tables for this WordPress installation } $return = ''; //cycle through each table foreach ($tables as $table) { $num_fields = sizeof($wpdb->get_results('DESCRIBE `' . $table[0] . '`;')); $return .= 'DROP TABLE IF EXISTS `' . $table[0] . '`;'; $row2 = $wpdb->get_row('SHOW CREATE TABLE `' . $table[0] . '`;', ARRAY_N); $return .= PHP_EOL . PHP_EOL . $row2[1] . ";" . PHP_EOL . PHP_EOL; if (!in_array(substr($table[0], strlen($wpdb->prefix)), $this->settings['exclude'])) { $result = $wpdb->get_results('SELECT * FROM `' . $table[0] . '`;', ARRAY_N); foreach ($result as $row) { $return .= 'INSERT INTO `' . $table[0] . '` VALUES('; for ($j = 0; $j < $num_fields; $j++) { $row[$j] = addslashes($row[$j]); $row[$j] = preg_replace('#' . PHP_EOL . '#', "\n", $row[$j]); if (isset($row[$j])) { $return .= '"' . $row[$j] . '"'; } else { $return .= '""'; } if ($j < $num_fields - 1) { $return .= ','; } } $return .= ");" . PHP_EOL; } } $return .= PHP_EOL . PHP_EOL; } $return .= PHP_EOL . PHP_EOL; //save file $file = 'backup-' . substr(sanitize_title(get_bloginfo('name')), 0, 20) . '-' . current_time('Ymd-His') . '-' . wp_generate_password(30, false); require_once ITSEC_Core::get_core_dir() . 'lib/class-itsec-lib-directory.php'; $dir = $this->settings['location']; ITSEC_Lib_Directory::create($dir); $fileext = '.sql'; $handle = @fopen($dir . '/' . $file . '.sql', 'w+'); @fwrite($handle, $return); @fclose($handle); //zip the file if (true === $this->settings['zip']) { if (!class_exists('PclZip')) { require ABSPATH . 'wp-admin/includes/class-pclzip.php'; } $zip = new PclZip($dir . '/' . $file . '.zip'); if (0 != $zip->create($dir . '/' . $file . '.sql', PCLZIP_OPT_REMOVE_PATH, $dir)) { //delete .sql and keep zip @unlink($dir . '/' . $file . '.sql'); $fileext = '.zip'; } } if (2 !== $this->settings['method'] || true === $one_time) { require_once ITSEC_Core::get_core_dir() . 'lib/class-itsec-mailer.php'; $mail = new ITSEC_Mail(); $mail->add_header(esc_html__('Database Backup', 'better-wp-security'), sprintf(wp_kses(__('Site Database Backup for <b>%s</b>', 'better-wp-security'), array('b' => array())), date_i18n(get_option('date_format')))); $mail->add_info_box(esc_html__('Attached is the database backup file for your site.', 'better-wp-security'), 'attachment'); $mail->add_section_heading(esc_html__('Website', 'better-wp-security')); $mail->add_text(esc_html(network_home_url())); $mail->add_section_heading(esc_html__('Date', 'better-wp-security')); $mail->add_text(esc_html(date_i18n(get_option('date_format')))); $mail->add_footer(); $raw_recipients = ITSEC_Modules::get_setting('global', 'backup_email'); $recipients = array(); foreach ($raw_recipients as $recipient) { $recipient = trim($recipient); if (is_email($recipient)) { $recipients[] = $recipient; } } $subject = sprintf(esc_html__('[%s] Database Backup', 'better-wp-security'), esc_url(network_home_url())); $subject = apply_filters('itsec_backup_email_subject', $subject); $attachment = array("{$dir}/{$file}{$fileext}"); $mail_success = $mail->send($recipients, $subject, $attachment); } if (1 === $this->settings['method']) { @unlink($dir . '/' . $file . $fileext); } else { $retain = isset($this->settings['retain']) ? absint($this->settings['retain']) : 0; //delete extra files if (0 < $retain) { $files = scandir($dir, 1); $count = 0; if (is_array($files) && 0 < count($files)) { foreach ($files as $file) { if (strstr($file, 'backup')) { if ($count >= $retain) { @unlink(trailingslashit($dir) . $file); } $count++; } } } } } if (false === $one_time) { ITSEC_Modules::set_setting('backup', 'last_run', ITSEC_Core::get_current_time_gmt()); } switch ($this->settings['method']) { case 0: if (false === $mail_success) { $status = array('status' => __('Error', 'better-wp-security'), 'details' => __('saved locally but email to backup recipients could not be sent.', 'better-wp-security')); } else { $status = array('status' => __('Success', 'better-wp-security'), 'details' => __('emailed to backup recipients and saved locally', 'better-wp-security')); } break; case 1: if (false === $mail_success) { $status = array('status' => __('Error', 'better-wp-security'), 'details' => __('email to backup recipients could not be sent.', 'better-wp-security')); } else { $status = array('status' => __('Success', 'better-wp-security'), 'details' => __('emailed to backup recipients', 'better-wp-security')); } break; default: $status = array('status' => __('Success', 'better-wp-security'), 'details' => __('saved locally', 'better-wp-security')); break; } $itsec_logger->log_event('backup', 3, array($status)); }
/** * Uninstall execution * * @since 4.0 * * @return void * */ private function uninstall_execute() { global $itsec_globals, $wpdb; $this->deactivate_execute(); require_once $itsec_globals['plugin_dir'] . 'core/class-itsec-modules.php'; ITSEC_Modules::run_uninstall(); $itsec_files = ITSEC_Core::get_itsec_files(); $itsec_files->do_deactivate(); delete_site_option('itsec-storage'); delete_site_option('itsec_global'); delete_site_option('itsec_data'); delete_site_option('itsec_initials'); delete_site_option('itsec_jquery_version'); delete_site_option('itsec_message_queue'); $wpdb->query("DROP TABLE IF EXISTS " . $wpdb->base_prefix . "itsec_log;"); $wpdb->query("DROP TABLE IF EXISTS " . $wpdb->base_prefix . "itsec_lockouts;"); $wpdb->query("DROP TABLE IF EXISTS " . $wpdb->base_prefix . "itsec_temp;"); if (is_dir(ITSEC_Core::get_storage_dir())) { require_once ITSEC_Core::get_core_dir() . '/lib/class-itsec-lib-directory.php'; ITSEC_Lib_Directory::remove(ITSEC_Core::get_storage_dir()); } ITSEC_Lib::clear_caches(); }
protected function change_content_directory($dir_name) { if ('wp-content' == $dir_name) { $undo = true; } else { $undo = false; } if (0 === strpos(WP_CONTENT_DIR, ABSPATH)) { $old_name = substr(WP_CONTENT_DIR, strlen(ABSPATH)); $new_name = $dir_name; } else { $old_name = WP_CONTENT_DIR; $new_name = ABSPATH . $dir_name; } $old_dir = WP_CONTENT_DIR; $new_dir = ABSPATH . $dir_name; if (file_exists($new_dir)) { if ($undo) { $this->show_error(sprintf(__('A file or directory already exists at <code>%s</code>. The Content Directory change has not been undone. Please remove the existing file or directory and try again.', 'better-wp-security'), $new_dir)); } else { $this->show_error(sprintf(__('A file or directory already exists at <code>%s</code>. No Directory Name changes have been made. Please choose a new Directory Name or remove the existing file or directory and try again.', 'better-wp-security'), $new_dir)); } $this->show_network_admin_notice(); return false; } require_once trailingslashit($GLOBALS['itsec_globals']['plugin_dir']) . 'core/lib/class-itsec-lib-config-file.php'; $old_permissions = ITSEC_Lib_Directory::get_permissions($old_dir); $result = rename($old_dir, $new_dir); if (!$result) { $this->show_error(sprintf(__('Unable to rename the <code>%1$s</code> directory to <code>%2$s</code>. This could indicate a file permission issue or that your server does not support the supplied name as a valid directory name. No config file or directory changes have been made.', 'better-wp-security'), $old_name, $new_name)); $this->show_network_admin_notice(); return; } $new_permissions = ITSEC_Lib_Directory::get_permissions($new_dir); if (is_int($old_permissions) && is_int($new_permissions) && $old_permissions != $new_permissions) { $result = ITSEC_Lib_Directory::chmod($new_dir, $old_permissions); if (is_wp_error($result)) { $this->show_error(sprintf(__('Unable to set the permissions of the new Directory Name (<code>%1$s</code>) to match the permissions of the old Directory Name. You may have to manually change the permissions of the directory to <code>%2$s</code> in order for your site to function properly.', 'better-wp-security'), $new_name, $old_permissions)); } } if ($undo) { $expression = $this->get_wp_config_define_expression(); $expression = substr($expression, 0, -1); $expression .= "[\r\n]*|"; $modification_result = ITSEC_Lib_Config_File::remove_from_wp_config($expression); } else { $modification = $this->get_wp_config_modification($new_dir, get_option('siteurl') . "/{$dir_name}"); $modification_result = ITSEC_Lib_Config_File::append_wp_config($modification, true); } if (is_wp_error($modification_result)) { $rename_result = rename($new_dir, $old_dir); if ($rename_result) { ITSEC_Lib_Directory::chmod($old_dir, $old_permissions); $this->show_error(sprintf(__('Unable to update the <code>wp-config.php</code> file. No directory or config file changes have been made. %1$s (%2$s)', 'better-wp-security'), $modification_result->get_error_message(), $modification_result->get_error_code())); $this->show_error(sprintf(__('In order to change the content directory on your server, you will have to manually change the configuration and rename the directory. Details can be found <a href="%s">here</a>.', 'better-wp-security'), 'https://codex.wordpress.org/Editing_wp-config.php#Moving_wp-content_folder')); } else { $this->show_error(sprintf(__('CRITICAL ERROR: The <code>%1$s</code> directory was successfully renamed to the new name (<code>%2$s</code>). However, an error occurred when updating the <code>wp-config.php</code> file to configure WordPress to use the new content directory. iThemes Security attempted to rename the directory back to its original name, but an unknown error prevented the rename from working as expected. In order for your site to function properly, you will either need to manually rename the <code>%2$s</code> directory back to <code>%1$s</code> or manually update the <code>wp-config.php</code> file with the necessary modifications. Instructions for making this modification can be found <a href="%3$s">here</a>.', 'better-wp-security'), $old_name, $new_name, 'https://codex.wordpress.org/Editing_wp-config.php#Moving_wp-content_folder')); $this->show_error(sprintf(__('Details on the error that prevented the <code>wp-config.php</code> file from updating is as follows: %1$s (%2$s)', 'better-wp-security'), $modification_result->get_error_message(), $modification_result->get_error_code())); } return; } $backup = get_site_option('itsec_backup'); if ($backup !== false && isset($backup['location'])) { $backup['location'] = str_replace($old_dir, $new_dir, $backup['location']); update_site_option('itsec_backup', $backup); } $global = get_site_option('itsec_global'); if ($global !== false && (isset($global['log_location']) || isset($global['nginx_file']))) { if (isset($global['log_location'])) { $global['log_location'] = str_replace($old_dir, $new_dir, $global['log_location']); } if (isset($global['nginx_file'])) { $global['nginx_file'] = str_replace($old_dir, $new_dir, $global['nginx_file']); } update_site_option('itsec_global', $global); } $this->show_network_admin_notice(); if ($undo) { wp_redirect(admin_url("admin.php?page={$_GET['page']}&message=undo-success")); } else { wp_redirect(admin_url("admin.php?page={$_GET['page']}&message=change-success" . urlencode("|{$dir_name}"))); } exit; }
protected final function sanitize_setting($type, $var, $name, $prevent_save_on_error = true, $trim_value = true) { $id = $this->get_id(); if (!isset($this->settings[$var])) { $this->add_error(new WP_Error("itsec-validator-missing-var-{$id}-{$var}", sprintf(__('A validation check for %1$s failed. The %2$s value is missing. This could be due to a problem with the iThemes Security installation or an invalid modification. Please reinstall iThemes Security and try again.', 'better-wp-security'), $id, $name))); return false; } if ($trim_value && is_string($this->settings[$var])) { $this->settings[$var] = trim($this->settings[$var]); } $error = false; if ('string' === $type) { $this->settings[$var] = (string) $this->settings[$var]; } else { if ('non-empty-string' === $type) { $this->settings[$var] = (string) $this->settings[$var]; if (empty($this->settings[$var])) { $error = sprintf(__('The %1$s value cannot be empty.', 'better-wp-security'), $name); } } else { if ('title' === $type) { $this->settings[$var] = sanitize_title($this->settings[$var]); } else { if ('non-empty-title' === $type) { $this->settings[$var] = sanitize_title($this->settings[$var]); if (empty($this->settings[$var])) { $error = sprintf(__('The %1$s value cannot be empty.', 'better-wp-security'), $name); } } else { if ('array' === $type) { if (!is_array($this->settings[$var])) { if (empty($this->settings[$var])) { $this->settings[$var] = array(); } else { $this->settings[$var] = array($this->settings[$var]); } } } else { if ('bool' === $type) { if ('false' === $this->settings[$var]) { $this->settings[$var] = false; } else { if ('true' === $this->settings[$var]) { $this->settings[$var] = true; } else { $this->settings[$var] = (bool) $this->settings[$var]; } } } else { if ('int' === $type) { $test_val = intval($this->settings[$var]); if ((string) $test_val === (string) $this->settings[$var]) { $this->settings[$var] = $test_val; } else { $error = sprintf(__('The %1$s value must be an integer.', 'better-wp-security'), $name); } } else { if ('positive-int' === $type) { $test_val = intval($this->settings[$var]); if ((string) $test_val === (string) $this->settings[$var] && $test_val >= 0) { $this->settings[$var] = $test_val; } else { $error = sprintf(__('The %1$s value must be a positive integer.', 'better-wp-security'), $name); } } else { if ('email' === $type) { $this->settings[$var] = sanitize_text_field($this->settings[$var]); if (empty($this->settings[$var]) || !is_email($this->settings[$var])) { $error = sprintf(__('The %1$s value must be a valid email address.', 'better-wp-security'), $name); } } else { if ('valid-username' === $type) { $this->settings[$var] = sanitize_text_field($this->settings[$var]); if (!empty($this->settings[$var]) && !validate_username($this->settings[$var])) { $error = sprintf(__('The %1$s value is not a valid username.', 'better-wp-security'), $name); } } else { if ('date' === $type) { $val = $this->settings[$var]; $separator = '[\\-/\\. ]'; if (preg_match("|^(\\d\\d\\d\\d){$separator}(\\d\\d?){$separator}(\\d\\d?)\$|", $val, $match)) { $year = intval($match[1]); $month = intval($match[2]); $day = intval($match[3]); if (!checkdate($month, $day, $year)) { $error = sprintf(__('The %1$s value must be a valid date.', 'better-wp-security'), $name); } } else { $error = sprintf(__('The %1$s value must be a valid date in the format of YYYY-MM-DD.', 'better-wp-security'), $name); } } else { if ('writable-directory' === $type) { if (!is_string($this->settings[$var])) { $error = sprintf(__('The %1$s value must be a string.', 'better-wp-security'), $name); } else { require_once ITSEC_Core::get_core_dir() . 'lib/class-itsec-lib-directory.php'; $this->settings[$var] = rtrim($this->settings[$var], DIRECTORY_SEPARATOR); if (!ITSEC_Lib_Directory::is_dir($this->settings[$var])) { $result = ITSEC_Lib_Directory::create($this->settings[$var]); if (is_wp_error($result)) { $error = sprintf(_x('The directory supplied in %1$s cannot be used as a valid directory. %2$s', '%1$s is the input name. %2$s is the error message.', 'better-wp-security'), $name, $result->get_error_message()); } } if (empty($error) && !ITSEC_Lib_Directory::is_writable($this->settings[$var])) { $error = sprintf(__('The directory supplied in %1$s is not writable. Please select a directory that can be written to.', 'better-wp-security'), $name); } if (empty($error)) { ITSEC_Lib_Directory::add_file_listing_protection($this->settings[$var]); } } } else { if ('writable-file' === $type) { if (!is_string($this->settings[$var])) { $error = sprintf(__('The %1$s value must be a string.', 'better-wp-security'), $name); } else { require_once ITSEC_Core::get_core_dir() . 'lib/class-itsec-lib-directory.php'; if (!ITSEC_Lib_File::is_file($this->settings[$var]) && ITSEC_Lib_File::exists($this->settings[$var])) { $error = sprintf(__('The file path supplied in %1$s cannot be used as it already exists but is not a file. Please supply a valid file path.', 'better-wp-security'), $name); } else { $result = ITSEC_Lib_Directory::create(dirname($this->settings[$var])); if (is_wp_error($result)) { $error = sprintf(_x('The file path supplied in %1$s cannot be used as the parent directory cannot be created. %2$s', '%1$s is the input name. %2$s is the error message.', 'better-wp-security'), $name, $result->get_error_message()); } else { if (!ITSEC_Lib_File::exists($this->settings[$var])) { $result = ITSEC_Lib_File::write($this->settings[$var], ''); if (is_wp_error($result)) { $error = sprintf(__('The file path supplied in %1$s could not be created. Please supply a file path that can be written to.', 'better-wp-security'), $name); } else { if (!is_writable($this->settings[$var])) { $error = sprintf(__('The file path supplied in %1$s was successfully created, but it cannot be updated. Please supply a file path that can be written to.', 'better-wp-security'), $name); } } } else { if (!is_writable($this->settings[$var])) { $error = sprintf(__('The file path supplied in %1$s is not writable. Please supply a file path that can be written to.', 'better-wp-security'), $name); } } } } } } else { if (is_array($type) && 2 === count($type) && $this === $type[0]) { $this->settings[$var] = $this->convert_string_to_array($this->settings[$var]); if (!is_array($this->settings[$var])) { $error = sprintf(__('The %1$s value must be a string with each entry separated by a new line.', 'better-wp-security'), $name); } else { $invalid_entries = array(); foreach ($this->settings[$var] as $index => $entry) { $entry = sanitize_text_field(trim($entry)); $this->settings[$var][$index] = $entry; if (empty($entry)) { unset($this->settings[$var][$index]); } else { $result = call_user_func($type, $entry); if (false === $result) { $invalid_entries[] = $entry; } else { $this->settings[$var][$index] = $result; } } } $this->settings[$var] = array_unique($this->settings[$var]); if (!empty($invalid_entries)) { $error = wp_sprintf(_n('The following entry in %1$s is invalid: %2$l', 'The following entries in %1$s are invalid: %2$l', count($invalid_entries), 'better-wp-security'), $name, $invalid_entries); } } } else { if (is_array($type)) { if (is_array($this->settings[$var])) { $invalid_entries = array(); foreach ($this->settings[$var] as $index => $entry) { $entry = sanitize_text_field(trim($entry)); $this->settings[$var][$index] = $entry; if (empty($entry)) { unset($this->settings[$var][$index]); } else { if (!in_array($entry, $type, true)) { $invalid_entries[] = $entry; } } } $this->settings[$var] = array_unique($this->settings[$var]); if (!empty($invalid_entries)) { $error = wp_sprintf(_n('The following entry in %1$s is invalid: %2$l', 'The following entries in %1$s are invalid: %2$l', count($invalid_entries), 'better-wp-security'), $name, $invalid_entries); } } else { if (!in_array($this->settings[$var], $type, true)) { $error = wp_sprintf(_n('The valid value for %1$s is: %2$l.', 'The valid values for %1$s are: %2$l.', count($type), 'better-wp-security'), $name, $type); $type = 'array'; } } } else { if ('newline-separated-array' === $type) { $this->settings[$var] = $this->convert_string_to_array($this->settings[$var]); if (!is_array($this->settings[$var])) { $error = sprintf(__('The %1$s value must be a string with each entry separated by a new line.', 'better-wp-security'), $name); } } else { if ('newline-separated-emails' === $type) { $this->settings[$var] = $this->convert_string_to_array($this->settings[$var]); if (!is_array($this->settings[$var])) { $error = sprintf(__('The %1$s value must be a string with each entry separated by a new line.', 'better-wp-security'), $name); } else { $invalid_emails = array(); foreach ($this->settings[$var] as $index => $email) { $email = sanitize_text_field(trim($email)); $this->settings[$var][$index] = $email; if (empty($email)) { unset($this->settings[$var][$index]); } else { if (!is_email($email)) { $invalid_emails[] = $email; } } } $this->settings[$var] = array_unique($this->settings[$var]); if (!empty($invalid_emails)) { $error = wp_sprintf(_n('The following email in %1$s is invalid: %2$l', 'The following emails in %1$s are invalid: %2$l', count($invalid_emails), 'better-wp-security'), $name, $invalid_emails); } } } else { if ('newline-separated-ips' === $type) { $this->settings[$var] = $this->convert_string_to_array($this->settings[$var]); if (!is_array($this->settings[$var])) { $error = sprintf(__('The %1$s value must be a string with each entry separated by a new line.', 'better-wp-security'), $name); } else { require_once ITSEC_Core::get_core_dir() . 'lib/class-itsec-lib-ip-tools.php'; $invalid_ips = array(); foreach ($this->settings[$var] as $index => $ip) { $ip = trim($ip); if ('' === $ip) { unset($this->settings[$var][$index]); } else { $validated_ip = ITSEC_Lib_IP_Tools::ip_wild_to_ip_cidr($ip); if (false === $validated_ip) { $invalid_ips[] = $ip; } else { $this->settings[$var][$index] = $validated_ip; } } } $this->settings[$var] = array_unique($this->settings[$var]); if (!empty($invalid_ips)) { $error = wp_sprintf(_n('The following IP in %1$s is invalid: %2$l', 'The following IPs in %1$s are invalid: %2$l', count($invalid_ips), 'better-wp-security'), $name, $invalid_ips); } } } else { if ('newline-separated-extensions' === $type) { $this->settings[$var] = $this->convert_string_to_array($this->settings[$var]); if (!is_array($this->settings[$var])) { $error = sprintf(__('The %1$s value must be a string with each entry separated by a new line.', 'better-wp-security'), $name); } else { $invalid_extensions = array(); foreach ($this->settings[$var] as $index => $extension) { if (!preg_match('/^(\\.[^.]+)+$/', $extension)) { $invalid_extensions[] = $extension; } } $this->settings[$var] = array_unique($this->settings[$var]); if (!empty($invalid_extensions)) { $error = wp_sprintf(_n('The following extension in %1$s is invalid: %2$l', 'The following extensions in %1$s are invalid: %2$l', count($invalid_extensions), 'better-wp-security'), $name, $invalid_extensions); } } } else { /* translators: 1: sanitize type, 2: input name */ $error = sprintf(__('An invalid sanitize type of "%1$s" was received for the %2$s input.', 'better-wp-security'), $type, $name); } } } } } } } } } } } } } } } } } } } if (false !== $error) { $this->add_error(new WP_Error("itsec-validator-{$id}-invalid-type-{$var}-{$type}", $error)); $this->vars_to_skip_validate_matching_types[] = $var; if ($prevent_save_on_error) { $this->set_can_save(false); } return false; } return true; }
public static function change_content_directory($dir_name) { $dir_name = sanitize_file_name($dir_name); if (empty($dir_name)) { return new WP_Error('itsec-content-directory-utility-change-content-directory-empty-directory-name', __('The content directory cannot be changed to a blank directory name.', 'better-wp-security')); } if (preg_match('{^(?:/|\\|[a-z]:)}i', $dir_name)) { return new WP_Error('itsec-content-diraectory-utility-change-content-directory-received-absolute-path', sprintf(__('The new directory name cannot be an absolute path. Please supply a path that is relative to <code>ABSPATH</code> (<code>%s</code>).', 'better-wp-security'), esc_html(ABSPATH))); } if (0 === strpos(WP_CONTENT_DIR, ABSPATH)) { $old_name = substr(WP_CONTENT_DIR, strlen(ABSPATH)); $new_name = $dir_name; } else { $old_name = WP_CONTENT_DIR; $new_name = ABSPATH . $dir_name; } $old_dir = WP_CONTENT_DIR; $new_dir = ABSPATH . $dir_name; if ($old_dir === $new_dir) { return new WP_Error('itsec-content-directory-utility-change-content-directory-received-same-directory', __('The new directory name cannot be the same as the current directory name. Please supply a new directory name.', 'better-wp-security')); } if (file_exists($new_dir)) { return new WP_Error('itsec-content-directory-utility-change-content-directory-path-already-exists', sprintf(__('A file or directory already exists at <code>%s</code>. No Directory Name changes have been made. Please choose a new Directory Name or remove the existing file or directory and try again.', 'better-wp-security'), esc_html($new_dir))); } require_once ITSEC_Core::get_core_dir() . '/lib/class-itsec-lib-config-file.php'; $old_permissions = ITSEC_Lib_Directory::get_permissions($old_dir); $result = rename($old_dir, $new_dir); if (!$result) { /* translators: 1: Old directory path, 2: New directory path */ return new WP_Error('itsec-content-directory-utility-change-content-directory-cannot-rename-directory', sprintf(__('Unable to rename the <code>%1$s</code> directory to <code>%2$s</code>. This could indicate a file permission issue or that your server does not support the supplied name as a valid directory name. No config file or directory changes have been made.', 'better-wp-security'), esc_html($old_name), esc_html($new_name))); } // Make sure ITSEC_Core knows it's in a different place $plugin_file = str_replace($old_dir, $new_dir, ITSEC_Core::get_plugin_file()); ITSEC_Core::set_plugin_file($plugin_file); ITSEC_Core::update_wp_upload_dir($old_dir, $new_dir); ITSEC_Modules::update_module_paths($old_dir, $new_dir); $new_permissions = ITSEC_Lib_Directory::get_permissions($new_dir); if (is_int($old_permissions) && is_int($new_permissions) && $old_permissions != $new_permissions) { $result = ITSEC_Lib_Directory::chmod($new_dir, $old_permissions); if (is_wp_error($result)) { /* translators: 1: Directory path, 2: Directory permissions */ return new WP_Error('itsec-content-directory-utility-change-content-directory-unable-to-change-permissions', sprintf(__('Unable to set the permissions of the new Directory Name (<code>%1$s</code>) to match the permissions of the old Directory Name. You may have to manually change the permissions of the directory to <code>%2$s</code> in order for your site to function properly.', 'better-wp-security'), esc_html($new_name), esc_html($old_permissions))); } } if ('wp-content' === $dir_name) { // We're undoing the change. $expression = self::get_wp_config_define_expression(); $expression = substr($expression, 0, -1); $expression .= "[\r\n]*|"; $modification_result = ITSEC_Lib_Config_File::remove_from_wp_config($expression); } else { $modification = self::get_wp_config_modification($new_dir, get_option('siteurl') . "/{$dir_name}"); $modification_result = ITSEC_Lib_Config_File::append_wp_config($modification, true); } if (is_wp_error($modification_result)) { $rename_result = rename($new_dir, $old_dir); if ($rename_result) { // Reset the ITSEC_Core plugin file back to its old setting. $plugin_file = str_replace($new_dir, $old_dir, ITSEC_Core::get_plugin_file()); ITSEC_Core::set_plugin_file($plugin_file); ITSEC_Core::update_wp_upload_dir($new_dir, $old_dir); ITSEC_Modules::update_module_paths($new_dir, $old_dir); ITSEC_Lib_Directory::chmod($old_dir, $old_permissions); /* translators: 1: Specific error details */ return new WP_Error($modification_result->get_error_code(), sprintf(__('Unable to update the <code>wp-config.php</code> file. No directory or config file changes have been made. The error that prevented the file from updating is as follows: %1$s', 'better-wp-security'), $modification_result->get_error_message())); } else { /* translators: 1: Old directory path, 2: New directory path, 3: Specific error details */ return new WP_Error($modification_result->get_error_code(), sprintf(__('CRITICAL ERROR: The <code>%1$s</code> directory was successfully renamed to the new name (<code>%2$s</code>). However, an error occurred when updating the <code>wp-config.php</code> file to configure WordPress to use the new content directory. iThemes Security attempted to rename the directory back to its original name, but an unknown error prevented the rename from working as expected. In order for your site to function properly, you will either need to manually rename the <code>%2$s</code> directory back to <code>%1$s</code> or manually update the <code>wp-config.php</code> file with the necessary modifications. The error that prevented the file from updating is as follows: %3$s', 'better-wp-security'), $old_name, $new_name, $modification_result->get_error_message())); } } $backups_location = ITSEC_Modules::get_setting('backup', 'location'); $backups_location = str_replace($old_dir, $new_dir, $backups_location); ITSEC_Modules::set_setting('backup', 'location', $backups_location); $log_location = ITSEC_Modules::get_setting('global', 'log_location'); $log_location = str_replace($old_dir, $new_dir, $log_location); ITSEC_Modules::set_setting('global', 'log_location', $log_location); $nginx_file = ITSEC_Modules::get_setting('global', 'nginx_file'); $nginx_file = str_replace($old_dir, $new_dir, $nginx_file); ITSEC_Modules::set_setting('global', 'nginx_file', $nginx_file); return $dir_name; }
/** * Executes backup function. * * Handles the execution of database backups. * * @since 4.0.0 * * @param bool $one_time whether this is a one-time backup * * @return void */ private function execute_backup($one_time = false) { global $wpdb, $itsec_globals, $itsec_logger; //get all of the tables if (isset($this->settings['all_sites']) && true === $this->settings['all_sites']) { $tables = $wpdb->get_results('SHOW TABLES', ARRAY_N); //retrieve a list of all tables in the DB } else { $tables = $wpdb->get_results('SHOW TABLES LIKE "' . $wpdb->base_prefix . '%"', ARRAY_N); //retrieve a list of all tables for this WordPress installation } $return = ''; //cycle through each table foreach ($tables as $table) { $num_fields = sizeof($wpdb->get_results('DESCRIBE `' . $table[0] . '`;')); $return .= 'DROP TABLE IF EXISTS `' . $table[0] . '`;'; $row2 = $wpdb->get_row('SHOW CREATE TABLE `' . $table[0] . '`;', ARRAY_N); $return .= PHP_EOL . PHP_EOL . $row2[1] . ";" . PHP_EOL . PHP_EOL; if (!in_array(substr($table[0], strlen($wpdb->prefix)), $this->settings['exclude'])) { $result = $wpdb->get_results('SELECT * FROM `' . $table[0] . '`;', ARRAY_N); foreach ($result as $row) { $return .= 'INSERT INTO `' . $table[0] . '` VALUES('; for ($j = 0; $j < $num_fields; $j++) { $row[$j] = addslashes($row[$j]); $row[$j] = preg_replace('#' . PHP_EOL . '#', "\n", $row[$j]); if (isset($row[$j])) { $return .= '"' . $row[$j] . '"'; } else { $return .= '""'; } if ($j < $num_fields - 1) { $return .= ','; } } $return .= ");" . PHP_EOL; } } $return .= PHP_EOL . PHP_EOL; } $return .= PHP_EOL . PHP_EOL; //save file $file = 'backup-' . substr(sanitize_title(get_bloginfo('name')), 0, 20) . '-' . current_time('Ymd-His') . '-' . wp_generate_password(30, false); require_once ITSEC_Core::get_core_dir() . 'lib/class-itsec-lib-directory.php'; $dir = $this->settings['location']; ITSEC_Lib_Directory::create($dir); $fileext = '.sql'; $handle = @fopen($dir . '/' . $file . '.sql', 'w+'); @fwrite($handle, $return); @fclose($handle); //zip the file if (true === $this->settings['zip']) { if (!class_exists('PclZip')) { require ABSPATH . 'wp-admin/includes/class-pclzip.php'; } $zip = new PclZip($dir . '/' . $file . '.zip'); if (0 != $zip->create($dir . '/' . $file . '.sql', PCLZIP_OPT_REMOVE_PATH, $dir)) { //delete .sql and keep zip @unlink($dir . '/' . $file . '.sql'); $fileext = '.zip'; } } if (2 !== $this->settings['method'] || true === $one_time) { $attachment = array($dir . '/' . $file . $fileext); $body = __('Attached is the backup file for the database powering', 'better-wp-security') . ' ' . get_option('siteurl') . __(' taken', 'better-wp-security') . ' ' . date('l, F jS, Y \\a\\t g:i a', $itsec_globals['current_time']); //Setup the remainder of the email $recipients = ITSEC_Modules::get_setting('global', 'backup_email'); $subject = __('Site Database Backup', 'better-wp-security') . ' ' . date('l, F jS, Y \\a\\t g:i a', $itsec_globals['current_time']); $subject = apply_filters('itsec_backup_email_subject', $subject); $headers = 'From: ' . get_bloginfo('name') . ' <' . get_option('admin_email') . '>' . "\r\n"; $mail_success = false; //Use HTML Content type add_filter('wp_mail_content_type', array($this, 'set_html_content_type')); //Send emails to all recipients foreach ($recipients as $recipient) { if (is_email(trim($recipient))) { if (defined('ITSEC_DEBUG') && true === ITSEC_DEBUG) { $body .= '<p>' . __('Debug info (source page): ' . esc_url($_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"])) . '</p>'; } $mail_success = wp_mail(trim($recipient), $subject, '<html>' . $body . '</html>', $headers, $attachment); } } //Remove HTML Content type remove_filter('wp_mail_content_type', array($this, 'set_html_content_type')); } if (1 === $this->settings['method']) { @unlink($dir . '/' . $file . $fileext); } else { $retain = isset($this->settings['retain']) ? absint($this->settings['retain']) : 0; //delete extra files if (0 < $retain) { $files = scandir($dir, 1); $count = 0; if (is_array($files) && 0 < count($files)) { foreach ($files as $file) { if (strstr($file, 'backup')) { if ($count >= $retain) { @unlink(trailingslashit($dir) . $file); } $count++; } } } } } if (false === $one_time) { ITSEC_Modules::set_setting('backup', 'last_run', ITSEC_Core::get_current_time_gmt()); } switch ($this->settings['method']) { case 0: if (false === $mail_success) { $status = array('status' => __('Error', 'better-wp-security'), 'details' => __('saved locally but email to backup recipients could not be sent.', 'better-wp-security')); } else { $status = array('status' => __('Success', 'better-wp-security'), 'details' => __('emailed to backup recipients and saved locally', 'better-wp-security')); } break; case 1: if (false === $mail_success) { $status = array('status' => __('Error', 'better-wp-security'), 'details' => __('email to backup recipients could not be sent.', 'better-wp-security')); } else { $status = array('status' => __('Success', 'better-wp-security'), 'details' => __('emailed to backup recipients', 'better-wp-security')); } break; default: $status = array('status' => __('Success', 'better-wp-security'), 'details' => __('saved locally', 'better-wp-security')); break; } $itsec_logger->log_event('backup', 3, array($status)); }