updraftplus
Last commit date
addons
13 years ago
images
11 years ago
includes
11 years ago
languages
11 years ago
methods
11 years ago
oc
11 years ago
admin.php
11 years ago
backup.php
11 years ago
class-zip.php
11 years ago
example-decrypt.php
11 years ago
index.html
12 years ago
options.php
11 years ago
readme.txt
11 years ago
restorer.php
11 years ago
updraftplus.php
11 years ago
restorer.php
1692 lines
| 1 | <?php |
| 2 | if (!defined ('ABSPATH')) die('No direct access allowed'); |
| 3 | |
| 4 | if(!class_exists('WP_Upgrader')) require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); |
| 5 | class Updraft_Restorer extends WP_Upgrader { |
| 6 | |
| 7 | public $ud_backup_is_multisite = -1; |
| 8 | |
| 9 | private $is_multisite; |
| 10 | |
| 11 | // This is just used so far for detecting whether we're on the second run for an entity or not. |
| 12 | public $been_restored = array(); |
| 13 | public $delete = false; |
| 14 | |
| 15 | private $created_by_version = false; |
| 16 | |
| 17 | private $ud_backup_info; |
| 18 | public $ud_foreign; |
| 19 | |
| 20 | public function __construct($skin = null, $info = null, $shortinit = false) { |
| 21 | |
| 22 | global $wpdb; |
| 23 | // Line up a wpdb-like object to use |
| 24 | $this->use_wpdb = ((!function_exists('mysql_query') && !function_exists('mysqli_query')) || !$wpdb->is_mysql || !$wpdb->ready) ? true : false; |
| 25 | |
| 26 | if (false == $this->use_wpdb) { |
| 27 | // We have our own extension which drops lots of the overhead on the query |
| 28 | $wpdb_obj = new UpdraftPlus_WPDB(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST); |
| 29 | // Was that successful? |
| 30 | if (!$wpdb_obj->is_mysql || !$wpdb_obj->ready) { |
| 31 | $this->use_wpdb = true; |
| 32 | } else { |
| 33 | $this->mysql_dbh = $wpdb_obj->updraftplus_getdbh(); |
| 34 | $this->use_mysqli = $wpdb_obj->updraftplus_use_mysqli(); |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | if ($shortinit) return; |
| 39 | $this->ud_backup_info = $info; |
| 40 | $this->ud_foreign = (empty($info['meta_foreign'])) ? false : $info['meta_foreign']; |
| 41 | parent::__construct($skin); |
| 42 | $this->init(); |
| 43 | $this->backup_strings(); |
| 44 | $this->is_multisite = is_multisite(); |
| 45 | } |
| 46 | |
| 47 | function backup_strings() { |
| 48 | $this->strings['not_possible'] = __('UpdraftPlus is not able to directly restore this kind of entity. It must be restored manually.','updraftplus'); |
| 49 | $this->strings['no_package'] = __('Backup file not available.','updraftplus'); |
| 50 | $this->strings['copy_failed'] = __('Copying this entity failed.','updraftplus'); |
| 51 | $this->strings['unpack_package'] = __('Unpacking backup...','updraftplus'); |
| 52 | $this->strings['decrypt_database'] = __('Decrypting database (can take a while)...','updraftplus'); |
| 53 | $this->strings['decrypted_database'] = __('Database successfully decrypted.','updraftplus'); |
| 54 | $this->strings['moving_old'] = __('Moving old data out of the way...','updraftplus'); |
| 55 | $this->strings['moving_backup'] = __('Moving unpacked backup into place...','updraftplus'); |
| 56 | $this->strings['restore_database'] = __('Restoring the database (on a large site this can take a long time - if it times out (which can happen if your web hosting company has configured your hosting to limit resources) then you should use a different method, such as phpMyAdmin)...','updraftplus'); |
| 57 | $this->strings['cleaning_up'] = __('Cleaning up rubbish...','updraftplus'); |
| 58 | $this->strings['old_move_failed'] = __('Could not move old files out of the way.','updraftplus').' '.__('You should check the file permissions in your WordPress installation', 'updraftplus'); |
| 59 | $this->strings['old_delete_failed'] = __('Could not delete old directory.','updraftplus'); |
| 60 | $this->strings['new_move_failed'] = __('Could not move new files into place. Check your wp-content/upgrade folder.','updraftplus'); |
| 61 | $this->strings['move_failed'] = __('Could not move the files into place. Check your file permissions.','updraftplus'); |
| 62 | $this->strings['delete_failed'] = __('Failed to delete working directory after restoring.','updraftplus'); |
| 63 | $this->strings['multisite_error'] = __('You are running on WordPress multisite - but your backup is not of a multisite site.', 'updraftplus'); |
| 64 | $this->strings['unpack_failed'] = __('Failed to unpack the archive', 'updraftplus'); |
| 65 | } |
| 66 | |
| 67 | # This function is copied from class WP_Upgrader (WP 3.8 - no significant changes since 3.2 at least); we only had to fork it because it hard-codes using the basename of the zip file as its unpack directory; which can be long; and then combining that with long pathnames in the zip being unpacked can overflow a 256-character path limit (yes, they apparently still exist - amazing!) |
| 68 | # Subsequently, we have also added the ability to unpack tarballs |
| 69 | private function unpack_package_archive($package, $delete_package = true) { |
| 70 | |
| 71 | if (!empty($this->ud_foreign) && !empty($this->ud_foreign_working_dir)) { |
| 72 | if (is_dir($this->ud_foreign_working_dir)) { |
| 73 | return $this->ud_foreign_working_dir; |
| 74 | } else { |
| 75 | global $updraftplus; |
| 76 | $updraftplus->log('Previously unpacked directory seems to have disappeared; will unpack again'); |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | global $wp_filesystem, $updraftplus; |
| 81 | |
| 82 | $packsize = round(filesize($package)/1048576, 1).' Mb'; |
| 83 | |
| 84 | $this->skin->feedback($this->strings['unpack_package'].' ('.basename($package).', '.$packsize.')'); |
| 85 | |
| 86 | $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/'; |
| 87 | |
| 88 | //Clean up contents of upgrade directory beforehand. |
| 89 | $upgrade_files = $wp_filesystem->dirlist($upgrade_folder); |
| 90 | if ( !empty($upgrade_files) ) { |
| 91 | foreach ( $upgrade_files as $file ) |
| 92 | $wp_filesystem->delete($upgrade_folder . $file['name'], true); |
| 93 | } |
| 94 | |
| 95 | //We need a working directory |
| 96 | #This is the only change from the WP core version - minimise path length |
| 97 | #$working_dir = $upgrade_folder . basename($package, '.zip'); |
| 98 | $working_dir = $upgrade_folder . substr(md5($package), 0, 8); |
| 99 | |
| 100 | // Clean up working directory |
| 101 | if ( $wp_filesystem->is_dir($working_dir) ) |
| 102 | $wp_filesystem->delete($working_dir, true); |
| 103 | |
| 104 | // Unzip package to working directory |
| 105 | if ('.zip' == substr($package, -4, 4)) { |
| 106 | $result = unzip_file( $package, $working_dir ); |
| 107 | } elseif ('.tar' == substr($package, -4, 4) || '.tar.gz' == substr($package, -7, 7) || '.tar.bz2' == substr($package, -8, 8)) { |
| 108 | if (!class_exists('UpdraftPlus_Archive_Tar')) { |
| 109 | if (false === strpos(get_include_path(), UPDRAFTPLUS_DIR.'/includes/PEAR')) set_include_path(UPDRAFTPLUS_DIR.'/includes/PEAR'.PATH_SEPARATOR.get_include_path()); |
| 110 | |
| 111 | require_once(UPDRAFTPLUS_DIR.'/includes/PEAR/Archive/Tar.php'); |
| 112 | $p_compress = null; |
| 113 | if ('.tar.gz' == substr($package, -7, 7)) { |
| 114 | $p_compress = 'gz'; |
| 115 | } elseif ('.tar.bz2' == substr($package, -8, 8)) { |
| 116 | $p_compress = 'bz2'; |
| 117 | } |
| 118 | |
| 119 | # It's not pretty. But it works. |
| 120 | if (is_a($wp_filesystem, 'WP_Filesystem_Direct')) { |
| 121 | $extract_dir = $working_dir; |
| 122 | } else { |
| 123 | $updraft_dir = $updraftplus->backups_dir_location(); |
| 124 | if (!$updraftplus->really_is_writable($updraft_dir)) { |
| 125 | $updraftplus->log_e("Backup directory (%s) is not writable, or does not exist.", $updraft_dir); |
| 126 | $result = new WP_Error('unpack_failed', $this->strings['unpack_failed'], $tar->extract); |
| 127 | } else { |
| 128 | $extract_dir = $updraft_dir.'/'.basename($working_dir).'-old'; |
| 129 | if (file_exists($extract_dir)) $updraftplus->remove_local_directory($extract_dir); |
| 130 | $updraftplus->log("Using a temporary folder to extract before moving over WPFS: $extract_dir"); |
| 131 | } |
| 132 | } |
| 133 | # Slightly hackish - rather than re-write Archive_Tar to use wp_filesystem, we instead unpack into the location that we already require to be directly writable for other reasons, and then move from there. |
| 134 | |
| 135 | if (empty($result)) { |
| 136 | |
| 137 | $this->ud_extract_count = 0; |
| 138 | $this->ud_working_dir = trailingslashit($working_dir); |
| 139 | $this->ud_extract_dir = untrailingslashit($extract_dir); |
| 140 | $this->ud_made_dirs = array(); |
| 141 | add_filter('updraftplus_tar_wrote', array($this, 'tar_wrote'), 10, 2); |
| 142 | $tar = new UpdraftPlus_Archive_Tar($package, $p_compress); |
| 143 | $result = $tar->extract($extract_dir, false); |
| 144 | if (!is_a($wp_filesystem, 'WP_Filesystem_Direct')) $updraftplus->remove_local_directory($extract_dir); |
| 145 | if (true != $result) { |
| 146 | $result = new WP_Error('unpack_failed', $this->strings['unpack_failed'], $result); |
| 147 | } else { |
| 148 | if (!is_a($wp_filesystem, 'WP_Filesystem_Direct')) { |
| 149 | $updraftplus->log('Moved unpacked tarball contents'); |
| 150 | } |
| 151 | } |
| 152 | remove_filter('updraftplus_tar_wrote', array($this, 'tar_wrote'), 10, 2); |
| 153 | } |
| 154 | |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | // Once extracted, delete the package if required. |
| 159 | if ( $delete_package ) |
| 160 | unlink($package); |
| 161 | |
| 162 | if ( is_wp_error($result) ) { |
| 163 | $wp_filesystem->delete($working_dir, true); |
| 164 | if ( 'incompatible_archive' == $result->get_error_code() ) { |
| 165 | return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], $result->get_error_data() ); |
| 166 | } |
| 167 | return $result; |
| 168 | } |
| 169 | |
| 170 | if (!empty($this->ud_foreign)) $this->ud_foreign_working_dir = $working_dir; |
| 171 | |
| 172 | return $working_dir; |
| 173 | } |
| 174 | |
| 175 | public function tar_wrote($result, $file) { |
| 176 | if (0 !== strpos($file, $this->ud_extract_dir)) return false; |
| 177 | global $wp_filesystem, $updraftplus; |
| 178 | if (!is_a($wp_filesystem, 'WP_Filesystem_Direct')) { |
| 179 | $modint = 100; |
| 180 | $leaf = substr($file, strlen($this->ud_extract_dir)); |
| 181 | $dirname = dirname($leaf); |
| 182 | $need_dirs = explode('/', $dirname); |
| 183 | if (empty($this->ud_made_dirs[$dirname])) { |
| 184 | $cdir = ''; |
| 185 | foreach ($need_dirs as $ndir) { |
| 186 | $cdir .= ($cdir) ? '/'.$ndir : $ndir; |
| 187 | if (empty($this->ud_made_dirs[$cdir])) { |
| 188 | if ( !$wp_filesystem->mkdir( $this->ud_working_dir.$cdir, FS_CHMOD_DIR) && ! $wp_filesystem->is_dir($this->ud_working_dir.$cdir) ) { |
| 189 | $updraftplus->log("Failed to create WPFS directory: ".$this->ud_working_dir.$cdir); |
| 190 | return false; |
| 191 | } else { |
| 192 | $this->ud_made_dirs[$cdir] = true; |
| 193 | } |
| 194 | } |
| 195 | } |
| 196 | } |
| 197 | $put = $wp_filesystem->put_contents($this->ud_working_dir.$leaf, file_get_contents($file)); |
| 198 | if (is_wp_error($put)) $updraftplus->log_wp_error($put); |
| 199 | @unlink($file); |
| 200 | } else { |
| 201 | $modint = 500; |
| 202 | $put = true; |
| 203 | } |
| 204 | if ($put) { |
| 205 | $this->ud_extract_count++; |
| 206 | if ($this->ud_extract_count % $modint == 0) { |
| 207 | $updraftplus->log_e("%s files have been extracted", $this->ud_extract_count); |
| 208 | } |
| 209 | } |
| 210 | return ($put == true); |
| 211 | } |
| 212 | |
| 213 | // This returns a wp_filesystem location (and we musn't change that, as we must retain compatibility with the class parent) |
| 214 | function unpack_package($package, $delete_package = true) { |
| 215 | |
| 216 | global $wp_filesystem, $updraftplus; |
| 217 | |
| 218 | $updraft_dir = $updraftplus->backups_dir_location(); |
| 219 | |
| 220 | // If not database, then it is a zip - unpack in the usual way |
| 221 | #if (!preg_match('/db\.gz(\.crypt)?$/i', $package)) return parent::unpack_package($updraft_dir.'/'.$package, $delete_package); |
| 222 | if (!preg_match('/db\.gz(\.crypt)?$/i', $package) && !preg_match('/\.sql(\.gz)?$/i', $package)) return $this->unpack_package_archive($updraft_dir.'/'.$package, $delete_package); |
| 223 | |
| 224 | $backup_dir = $wp_filesystem->find_folder($updraft_dir); |
| 225 | |
| 226 | // Unpack a database. The general shape of the following is copied from class-wp-upgrader.php |
| 227 | |
| 228 | @set_time_limit(1800); |
| 229 | |
| 230 | $this->skin->feedback('unpack_package'); |
| 231 | |
| 232 | $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/'; |
| 233 | @$wp_filesystem->mkdir($upgrade_folder, octdec($this->calculate_additive_chmod_oct(FS_CHMOD_DIR, 0775))); |
| 234 | |
| 235 | //Clean up contents of upgrade directory beforehand. |
| 236 | $upgrade_files = $wp_filesystem->dirlist($upgrade_folder); |
| 237 | if ( !empty($upgrade_files) ) { |
| 238 | foreach ( $upgrade_files as $file ) |
| 239 | $wp_filesystem->delete($upgrade_folder.$file['name'], true); |
| 240 | } |
| 241 | |
| 242 | //We need a working directory |
| 243 | $working_dir = $upgrade_folder . basename($package, '.crypt'); |
| 244 | # $working_dir_localpath = WP_CONTENT_DIR.'/upgrade/'. basename($package, '.crypt'); |
| 245 | |
| 246 | // Clean up working directory |
| 247 | if ($wp_filesystem->is_dir($working_dir)) $wp_filesystem->delete($working_dir, true); |
| 248 | |
| 249 | if (!$wp_filesystem->mkdir($working_dir, octdec($this->calculate_additive_chmod_oct(FS_CHMOD_DIR, 0775)))) return new WP_Error('mkdir_failed', __('Failed to create a temporary directory','updraftplus').' ('.$working_dir.')'); |
| 250 | |
| 251 | // Unpack package to working directory |
| 252 | if ($updraftplus->is_db_encrypted($package)) { |
| 253 | $this->skin->feedback('decrypt_database'); |
| 254 | $encryption = UpdraftPlus_Options::get_updraft_option('updraft_encryptionphrase'); |
| 255 | if (!$encryption) return new WP_Error('no_encryption_key', __('Decryption failed. The database file is encrypted, but you have no encryption key entered.', 'updraftplus')); |
| 256 | |
| 257 | $plaintext = $updraftplus->decrypt(false, $encryption, $wp_filesystem->get_contents($backup_dir.$package)); |
| 258 | |
| 259 | if ($plaintext) { |
| 260 | $this->skin->feedback('decrypted_database'); |
| 261 | if (!$wp_filesystem->put_contents($working_dir.'/backup.db.gz', $plaintext)) { |
| 262 | return new WP_Error('write_failed', __('Failed to write out the decrypted database to the filesystem','updraftplus')); |
| 263 | } |
| 264 | } else { |
| 265 | return new WP_Error('decryption_failed', __('Decryption failed. The most likely cause is that you used the wrong key.','updraftplus')); |
| 266 | } |
| 267 | } else { |
| 268 | |
| 269 | if (preg_match('/\.sql$/i', $package)) { |
| 270 | if (!$wp_filesystem->copy($backup_dir.$package, $working_dir.'/backup.db')) { |
| 271 | if ( $wp_filesystem->errors->get_error_code() ) { |
| 272 | foreach ( $wp_filesystem->errors->get_error_messages() as $message ) show_message($message); |
| 273 | } |
| 274 | return new WP_Error('copy_failed', $this->strings['copy_failed']); |
| 275 | } |
| 276 | } elseif (!$wp_filesystem->copy($backup_dir.$package, $working_dir.'/backup.db.gz')) { |
| 277 | if ( $wp_filesystem->errors->get_error_code() ) { |
| 278 | foreach ( $wp_filesystem->errors->get_error_messages() as $message ) show_message($message); |
| 279 | } |
| 280 | return new WP_Error('copy_failed', $this->strings['copy_failed']); |
| 281 | } |
| 282 | |
| 283 | } |
| 284 | |
| 285 | // Once extracted, delete the package if required (non-recursive, is a file) |
| 286 | if ($delete_package) $wp_filesystem->delete($backup_dir.$package, false, true); |
| 287 | |
| 288 | $updraftplus->log("Database successfully unpacked"); |
| 289 | |
| 290 | return $working_dir; |
| 291 | |
| 292 | } |
| 293 | |
| 294 | // For moving files out of a directory into their new location |
| 295 | // The purposes of the $type parameter are 1) to detect 'others' and apply a historical bugfix 2) to detect wpcore, and apply the setting for what to do with wp-config.php 3) to work out whether to delete the directory itself |
| 296 | // Must use only wp_filesystem |
| 297 | // $dest_dir must already have a trailing slash |
| 298 | // $preserve_existing: this setting only applies at the top level: 0 = overwrite with no backup; 1 = make backup of existing; 2 = do nothing if there is existing, 3 = do nothing to the top level directory, but do copy-in contents. Thus, on a multi-archive set where you want a backup, you'd do this: first call with $preserve_existing === 1, then on subsequent zips call with 3 |
| 299 | public function move_backup_in($working_dir, $dest_dir, $preserve_existing = 1, $do_not_overwrite = array('plugins', 'themes', 'uploads', 'upgrade'), $type = 'not-others', $send_actions = false, $force_local = false) { |
| 300 | |
| 301 | global $wp_filesystem, $updraftplus; |
| 302 | $updraft_dir = $updraftplus->backups_dir_location(); |
| 303 | |
| 304 | # && !is_a($wp_filesystem, 'WP_Filesystem_Direct') |
| 305 | if (true == $force_local) { |
| 306 | $wpfs = new UpdraftPlus_WP_Filesystem_Direct(true); |
| 307 | } else { |
| 308 | $wpfs = $wp_filesystem; |
| 309 | } |
| 310 | |
| 311 | # Get the content to be moved in. Include hidden files = true. Recursion is only required if we're likely to copy-in |
| 312 | $recursive = (3 == $preserve_existing) ? true : false; |
| 313 | $upgrade_files = $wpfs->dirlist($working_dir, true, $recursive); |
| 314 | |
| 315 | if (empty($upgrade_files)) return true; |
| 316 | |
| 317 | if (!$wpfs->is_dir($dest_dir)) { |
| 318 | return new WP_Error('no_such_dir', __('The directory does not exist', 'updraftplus')." ($dest_dir)"); |
| 319 | // $updraftplus->log_e("The directory does not exist, so will be created (%s).", $dest_dir); |
| 320 | // # Attempts to create the directory fail, as due to a core bug, $dest_dir will be the wrong value if it did not already exist (at least for themes - the value of it depends on an is_dir() check wrongly used to detect a relative path) |
| 321 | // if (!$wpfs->mkdir($dest_dir)) { |
| 322 | // return new WP_Error('create_failed', __('Failed to create directory', 'updraftplus')." ($dest_dir)"); |
| 323 | // } |
| 324 | } |
| 325 | |
| 326 | $wpcore_config_moved = false; |
| 327 | |
| 328 | foreach ( $upgrade_files as $file => $filestruc ) { |
| 329 | |
| 330 | if (empty($file)) continue; |
| 331 | |
| 332 | if ($dest_dir.$file == $updraft_dir) { |
| 333 | $updraftplus->log('Skipping attempt to replace updraft_dir whilst processing '.$type); |
| 334 | continue; |
| 335 | } |
| 336 | |
| 337 | // Correctly restore files in 'others' in no directory that were wrongly backed up in versions 1.4.0 - 1.4.48 |
| 338 | if (('others' == $type || 'wpcore' == $type) && preg_match('/^([\-_A-Za-z0-9]+\.php)$/', $file, $matches) && $wpfs->exists($working_dir . "/$file/$file")) { |
| 339 | if ('others' == $type) { |
| 340 | echo "Found file: $file/$file: presuming this is a backup with a known fault (backup made with versions 1.4.0 - 1.4.48, and sometimes up to 1.6.55 on some Windows servers); will rename to simply $file<br>"; |
| 341 | } else { |
| 342 | echo "Found file: $file/$file: presuming this is a backup with a known fault (backup made with versions before 1.6.55 in certain situations on Windows servers); will rename to simply $file<br>"; |
| 343 | } |
| 344 | $updraftplus->log("$file/$file: rename to $file"); |
| 345 | $file = $matches[1]; |
| 346 | $tmp_file = rand(0,999999999).'.php'; |
| 347 | // Rename directory |
| 348 | $wpfs->move($working_dir . "/$file", $working_dir . "/".$tmp_file, true); |
| 349 | $wpfs->move($working_dir . "/$tmp_file/$file", $working_dir ."/".$file, true); |
| 350 | $wpfs->rmdir($working_dir . "/$tmp_file", false); |
| 351 | } |
| 352 | |
| 353 | if ('wp-config.php' == $file && 'wpcore' == $type) { |
| 354 | if (empty($_POST['updraft_restorer_wpcore_includewpconfig'])) { |
| 355 | $updraftplus->log_e('wp-config.php from backup: will restore as wp-config-backup.php', 'updraftplus'); |
| 356 | $wpfs->move($working_dir . "/$file", $working_dir . "/wp-config-backup.php", true); |
| 357 | $file = "wp-config-backup.php"; |
| 358 | $wpcore_config_moved = true; |
| 359 | } else { |
| 360 | $updraftplus->log_e("wp-config.php from backup: restoring (as per user's request)", 'updraftplus'); |
| 361 | } |
| 362 | } elseif ('wpcore' == $type && 'wp-config-backup.php' == $file && $wpcore_config_moved) { |
| 363 | # The file is already gone; nothing to do |
| 364 | continue; |
| 365 | } |
| 366 | |
| 367 | # Sanity check (should not be possible as these were excluded at backup time) |
| 368 | if (in_array($file, $do_not_overwrite)) continue; |
| 369 | |
| 370 | if (('object-cache.php' == $file || 'advanced-cache.php' == $file) && 'others' == $type) { |
| 371 | if (false == apply_filters('updraftplus_restorecachefiles', true, $file)) { |
| 372 | $nfile = preg_replace('/\.php$/', '-backup.php', $file); |
| 373 | $wpfs->move($working_dir . "/$file", $working_dir . "/".$nfile, true); |
| 374 | $file=$nfile; |
| 375 | } |
| 376 | } elseif (('object-cache-backup.php' == $file || 'advanced-cache-backup.php' == $file) && 'others' == $type) { |
| 377 | $wpfs->delete($working_dir."/".$file); |
| 378 | continue; |
| 379 | } |
| 380 | |
| 381 | # First, move the existing one, if necessary (may not be present) |
| 382 | if ($wpfs->exists($dest_dir.$file)) { |
| 383 | if ($preserve_existing == 1) { |
| 384 | # Move existing to -old |
| 385 | if ( !$wpfs->move($dest_dir.$file, $dest_dir.$file.'-old', true) ) { |
| 386 | return new WP_Error('old_move_failed', $this->strings['old_move_failed']." ($dest_dir.$file)"); |
| 387 | } |
| 388 | } elseif ($preserve_existing == 0) { |
| 389 | # Over-write, no backup |
| 390 | if (!$wpfs->delete($dest_dir.$file, true)) { |
| 391 | return new WP_Error('old_delete_failed', $this->strings['old_delete_failed']." ($file)"); |
| 392 | } |
| 393 | } |
| 394 | } |
| 395 | |
| 396 | # Secondly, move in the new one |
| 397 | if (2 == $preserve_existing && $wpfs->exists($dest_dir.$file)) { |
| 398 | # Something exists - no move. Remove it from the temporary directory - so that it will be clean later |
| 399 | @$wpfs->delete($working_dir.'/'.$file, true); |
| 400 | } elseif (3 != $preserve_existing || !$wpfs->exists($dest_dir.$file)) { |
| 401 | $is_dir = $wpfs->is_dir($working_dir."/".$file); |
| 402 | # This method is broken due to https://core.trac.wordpress.org/ticket/26598 |
| 403 | #if (empty($chmod)) $chmod = $wpfs->getnumchmodfromh($wpfs->gethchmod($dest_dir)); |
| 404 | if (empty($chmod)) $chmod = octdec(sprintf("%04d", $this->get_current_chmod($dest_dir, $wpfs))); |
| 405 | if ($wpfs->move($working_dir."/".$file, $dest_dir.$file, true) ) { |
| 406 | if ($send_actions) do_action('updraftplus_restored_'.$type.'_one', $file); |
| 407 | # Make sure permissions are at least as great as those of the parent |
| 408 | if ($is_dir && !empty($chmod)) $this->chmod_if_needed($dest_dir.$file, $chmod, false, $wpfs); |
| 409 | } else { |
| 410 | return new WP_Error('move_failed', $this->strings['move_failed'], $working_dir."/".$file." -> ".$dest_dir.$file); |
| 411 | } |
| 412 | } elseif (3 == $preserve_existing && !empty($filestruc['files'])) { |
| 413 | # The directory ($dest_dir) already exists, and we've been requested to copy-in. We need to perform the recursive copy-in |
| 414 | # $filestruc['files'] is then a new structure like $upgrade_files |
| 415 | # First pass: create directory structure |
| 416 | # Get chmod value for the parent directory, and re-use it (instead of passing false) |
| 417 | |
| 418 | # This method is broken due to https://core.trac.wordpress.org/ticket/26598 |
| 419 | #if (empty($chmod)) $chmod = $wpfs->getnumchmodfromh($wpfs->gethchmod($dest_dir)); |
| 420 | if (empty($chmod)) $chmod = octdec(sprintf("%04d", $this->get_current_chmod($dest_dir, $wpfs))); |
| 421 | # Copy in the files. This also needs to make sure the directories exist, in case the zip file lacks entries |
| 422 | $delete_root = ('others' == $type || 'wpcore' == $type) ? false : true; |
| 423 | |
| 424 | $copy_in = $this->copy_files_in($working_dir.'/'.$file, $dest_dir.$file, $filestruc['files'], $chmod, $delete_root); |
| 425 | if (!empty($chmod)) $this->chmod_if_needed($dest_dir.$file, $chmod, false, $wpfs); |
| 426 | |
| 427 | if (is_wp_error($copy_in)) return $copy_in; |
| 428 | if (!$copy_in) return new WP_Error('move_failed', $this->strings['move_failed'], "(2) ".$working_dir.'/'.$file." -> ".$dest_dir.$file); |
| 429 | |
| 430 | $wpfs->rmdir($working_dir.'/'.$file); |
| 431 | } else { |
| 432 | $wpfs->rmdir($working_dir.'/'.$file); |
| 433 | } |
| 434 | } |
| 435 | |
| 436 | return true; |
| 437 | |
| 438 | } |
| 439 | |
| 440 | # $dest_dir must already exist |
| 441 | function copy_files_in($source_dir, $dest_dir, $files, $chmod = false, $deletesource = false) { |
| 442 | global $wp_filesystem, $updraftplus; |
| 443 | foreach ($files as $rname => $rfile) { |
| 444 | if ('d' != $rfile['type']) { |
| 445 | # Delete it if it already exists (or perhaps WP does it for us) |
| 446 | if (!$wp_filesystem->move($source_dir.'/'.$rname, $dest_dir.'/'.$rname, true)) { |
| 447 | $updraftplus->log_e('Failed to move file (check your file permissions and disk quota): %s', $source_dir.'/'.$rname." -> ".$dest_dir.'/'.$rname); |
| 448 | return false; |
| 449 | } |
| 450 | } else { |
| 451 | # Directory |
| 452 | if ($wp_filesystem->is_file($dest_dir.'/'.$rname)) @$wp_filesystem->delete($dest_dir.'/'.$rname, false, 'f'); |
| 453 | # No such directory yet: just move it |
| 454 | if (!$wp_filesystem->is_dir($dest_dir.'/'.$rname)) { |
| 455 | if (!$wp_filesystem->move($source_dir.'/'.$rname, $dest_dir.'/'.$rname, false)) { |
| 456 | $updraftplus->log_e('Failed to move directory (check your file permissions and disk quota): %s', $source_dir.'/'.$rname." -> ".$dest_dir.'/'.$rname); |
| 457 | return false; |
| 458 | } |
| 459 | } elseif (!empty($rfile['files'])) { |
| 460 | # There is a directory - and we want to to copy in |
| 461 | $docopy = $this->copy_files_in($source_dir.'/'.$rname, $dest_dir.'/'.$rname, $rfile['files'], $chmod, false); |
| 462 | if (is_wp_error($docopy)) return $docopy; |
| 463 | if (false === $docopy) { |
| 464 | return false; |
| 465 | } |
| 466 | } else { |
| 467 | # There is a directory: but nothing to copy in to it |
| 468 | @$wp_filesystem->rmdir($source_dir.'/'.$rname); |
| 469 | } |
| 470 | } |
| 471 | } |
| 472 | # We are meant to leave the working directory empty. Hence, need to rmdir() once a directory is empty. But not the root of it all in case of others/wpcore. |
| 473 | if ($deletesource || strpos($source_dir, '/') !== false) { |
| 474 | $wp_filesystem->rmdir($source_dir, false); |
| 475 | } |
| 476 | |
| 477 | return true; |
| 478 | |
| 479 | } |
| 480 | |
| 481 | // Pre-flight check: chance to complain and abort before anything at all is done |
| 482 | public function pre_restore_backup($backup_files, $type, $info) { |
| 483 | |
| 484 | if (is_string($backup_files)) $backup_files=array($backup_files); |
| 485 | |
| 486 | if ('more' == $type) { |
| 487 | $this->skin->feedback('not_possible'); |
| 488 | return; |
| 489 | } |
| 490 | |
| 491 | // Ensure access to the indicated directory - and to WP_CONTENT_DIR (in which we use upgrade/) |
| 492 | $need_these = array(WP_CONTENT_DIR); |
| 493 | if (!empty($info['path'])) $need_these[] = $info['path']; |
| 494 | |
| 495 | $res = $this->fs_connect($need_these); |
| 496 | if (false === $res || is_wp_error($res)) return $res; |
| 497 | |
| 498 | # Check upgrade directory is writable (instead of having non-obvious messages when we try to write) |
| 499 | # In theory, this is redundant (since we already checked for access to WP_CONTENT_DIR); but in practice, this extra check has been needed |
| 500 | |
| 501 | global $wp_filesystem, $updraftplus, $updraftplus_admin, $updraftplus_addons_migrator; |
| 502 | |
| 503 | if (empty($this->pre_restore_updatedir_writable)) { |
| 504 | $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/'; |
| 505 | @$wp_filesystem->mkdir($upgrade_folder, octdec($this->calculate_additive_chmod_oct(FS_CHMOD_DIR, 0775))); |
| 506 | if (!$wp_filesystem->is_dir($upgrade_folder)) { |
| 507 | return new WP_Error('no_dir', sprintf(__('UpdraftPlus needed to create a %s in your content directory, but failed - please check your file permissions and enable the access (%s)', 'updraftplus'), __('folder', 'updraftplus'), $upgrade_folder)); |
| 508 | } |
| 509 | $rand_file = 'testfile_'.rand(0,9999999).md5(microtime(true)).'.txt'; |
| 510 | if ($wp_filesystem->put_contents($upgrade_folder.$rand_file, 'testing...')) { |
| 511 | @$wp_filesystem->delete($upgrade_folder.$rand_file); |
| 512 | $this->pre_restore_updatedir_writable = true; |
| 513 | } else { |
| 514 | return new WP_Error('no_file', sprintf(__('UpdraftPlus needed to create a %s in your content directory, but failed - please check your file permissions and enable the access (%s)', 'updraftplus'), __('file', 'updraftplus'), $upgrade_folder.$rand_file)); |
| 515 | } |
| 516 | } |
| 517 | |
| 518 | # Code below here assumes that we're dealing with file-based entities |
| 519 | if ('db' == $type) return true; |
| 520 | |
| 521 | $wp_filesystem_dir = $this->get_wp_filesystem_dir($info['path']); |
| 522 | if ($wp_filesystem_dir === false) return false; |
| 523 | |
| 524 | // $this->maintenance_mode(true); |
| 525 | // |
| 526 | // $updraftplus->log_e('Testing file permissions...'); |
| 527 | |
| 528 | $ret_val = true; |
| 529 | |
| 530 | $updraft_dir = $updraftplus->backups_dir_location(); |
| 531 | |
| 532 | if (('plugins' == $type || 'uploads' == $type || 'themes' == $type) && (!is_multisite() || $this->ud_backup_is_multisite !== 0 || ('uploads' != $type || empty($updraftplus_addons_migrator->new_blogid )))) { |
| 533 | // if ($wp_filesystem->exists($wp_filesystem_dir.'-old')) { |
| 534 | if (file_exists($updraft_dir.'/'.basename($wp_filesystem_dir)."-old")) { |
| 535 | $ret_val = new WP_Error('already_exists', sprintf(__('Existing unremoved folders from a previous restore exist (please use the "Delete Old Directories" button to delete them before trying again): %s', 'updraftplus'), $wp_filesystem_dir.'-old')); |
| 536 | |
| 537 | } else { |
| 538 | // No longer used - since we now do not move the directories themselves |
| 539 | // # File permissions test; see if we can move the directory back and forth |
| 540 | // if (!$wp_filesystem->move($wp_filesystem_dir, $wp_filesystem_dir."-old", false)) { |
| 541 | // $ret_val = new WP_Error('old_move_failed', $this->strings['old_move_failed']); |
| 542 | // } else { |
| 543 | // $wp_filesystem->move($wp_filesystem_dir."-old", $wp_filesystem_dir, false); |
| 544 | // } |
| 545 | } |
| 546 | } |
| 547 | |
| 548 | // $this->maintenance_mode(false); |
| 549 | |
| 550 | if (!empty($this->ud_foreign)) { |
| 551 | $known_foreigners = apply_filters('updraftplus_accept_archivename', array()); |
| 552 | if (!is_array($known_foreigners) || empty($known_foreigners[$this->ud_foreign])) { |
| 553 | return new WP_Error('uk_foreign', __('This version of UpdraftPlus does not know how to handle this type of foreign backup', 'updraftplus').' ('.$this->ud_foreign.')'); |
| 554 | } |
| 555 | } |
| 556 | |
| 557 | return $ret_val; |
| 558 | } |
| 559 | |
| 560 | function get_wp_filesystem_dir($path) { |
| 561 | global $wp_filesystem; |
| 562 | // Get the wp_filesystem location for the folder on the local install |
| 563 | switch ($path) { |
| 564 | case ABSPATH: |
| 565 | case ''; |
| 566 | $wp_filesystem_dir = $wp_filesystem->abspath(); |
| 567 | break; |
| 568 | case WP_CONTENT_DIR: |
| 569 | $wp_filesystem_dir = $wp_filesystem->wp_content_dir(); |
| 570 | break; |
| 571 | case WP_PLUGIN_DIR: |
| 572 | $wp_filesystem_dir = $wp_filesystem->wp_plugins_dir(); |
| 573 | break; |
| 574 | case WP_CONTENT_DIR . '/themes': |
| 575 | $wp_filesystem_dir = $wp_filesystem->wp_themes_dir(); |
| 576 | break; |
| 577 | default: |
| 578 | $wp_filesystem_dir = $wp_filesystem->find_folder($path); |
| 579 | break; |
| 580 | } |
| 581 | if ( ! $wp_filesystem_dir ) return false; |
| 582 | return untrailingslashit($wp_filesystem_dir); |
| 583 | } |
| 584 | |
| 585 | // $backup_file is just the basename, and must be a string; we expect the caller to deal with looping over an array (multi-archive sets). We do, however, record whether we have already unpacked an entity of the same type - so that we know to add (not replace). |
| 586 | public function restore_backup($backup_file, $type, $info, $last_one = false) { |
| 587 | |
| 588 | if ('more' == $type) { |
| 589 | $this->skin->feedback('not_possible'); |
| 590 | return; |
| 591 | } |
| 592 | |
| 593 | global $wp_filesystem, $updraftplus_addons_migrator, $updraftplus; |
| 594 | |
| 595 | $updraftplus->log("restore_backup(backup_file=$backup_file, type=$type, info=".serialize($info).", last_one=$last_one)"); |
| 596 | |
| 597 | $updraft_dir = $updraftplus->backups_dir_location(); |
| 598 | |
| 599 | $get_dir = (empty($info['path'])) ? '' : $info['path']; |
| 600 | $wp_filesystem_dir = $this->get_wp_filesystem_dir($get_dir); |
| 601 | if ($wp_filesystem_dir === false) return false; |
| 602 | |
| 603 | if (empty($this->abspath)) $this->abspath = trailingslashit($wp_filesystem->abspath()); |
| 604 | |
| 605 | @set_time_limit(1800); |
| 606 | |
| 607 | // This returns the wp_filesystem path |
| 608 | $working_dir = $this->unpack_package($backup_file, $this->delete); |
| 609 | |
| 610 | if (is_wp_error($working_dir)) return $working_dir; |
| 611 | |
| 612 | $working_dir_localpath = WP_CONTENT_DIR.'/upgrade/'.basename($working_dir); |
| 613 | @set_time_limit(1800); |
| 614 | |
| 615 | // We copy the variable because we may be importing with a different prefix (e.g. on multisite imports of individual blog data) |
| 616 | $import_table_prefix = $updraftplus->get_table_prefix(false); |
| 617 | |
| 618 | if (is_multisite() && $this->ud_backup_is_multisite === 0 && ( ( 'plugins' == $type || 'themes' == $type ) || ( 'uploads' == $type && !empty($updraftplus_addons_migrator->new_blogid)) )) { |
| 619 | |
| 620 | # Migrating a single site into a multisite |
| 621 | if ('plugins' == $type || 'themes' == $type) { |
| 622 | |
| 623 | $move_from = $this->get_first_directory($working_dir, array(basename($info['path']), $type)); |
| 624 | |
| 625 | $this->skin->feedback('moving_backup'); |
| 626 | |
| 627 | // Only move in entities that are not already there (2) |
| 628 | $new_move_failed = (false === $move_from) ? true : false; |
| 629 | if (false === $new_move_failed) { |
| 630 | $move_in = $this->move_backup_in($move_from, trailingslashit($wp_filesystem_dir), 2, array(), $type, true); |
| 631 | if (is_wp_error($move_in)) return $move_in; |
| 632 | if (!$move_in) $new_move_failed = true; |
| 633 | } |
| 634 | if ($new_move_failed) return new WP_Error('new_move_failed', $this->strings['new_move_failed']); |
| 635 | @$wp_filesystem->delete($move_from); |
| 636 | |
| 637 | } else { |
| 638 | // Uploads |
| 639 | |
| 640 | $this->skin->feedback('moving_old'); |
| 641 | |
| 642 | switch_to_blog($updraftplus_addons_migrator->new_blogid); |
| 643 | |
| 644 | $ud = wp_upload_dir(); |
| 645 | $wpud = $ud['basedir']; |
| 646 | $fsud = trailingslashit($wp_filesystem->find_folder($wpud)); |
| 647 | restore_current_blog(); |
| 648 | |
| 649 | // TODO: What is below will move the entire uploads directory if blog id is 1. Detect this situation. (Can that happen? We created a new blog, so should not be possible). |
| 650 | |
| 651 | // TODO: the upload dir is not necessarily reachable through wp_filesystem - try ordinary method instead |
| 652 | if (is_string($fsud)) { |
| 653 | // This is not expected to exist, since we created a new blog |
| 654 | |
| 655 | if ( $wp_filesystem->exists($fsud) && !$wp_filesystem->move($fsud, untrailingslashit($fsud)."-old", true) ) { |
| 656 | return new WP_Error('old_move_failed', $this->strings['old_move_failed']); |
| 657 | } |
| 658 | |
| 659 | $this->skin->feedback('moving_backup'); |
| 660 | |
| 661 | $move_from = $this->get_first_directory($working_dir, array(basename($info['path']), $type)); |
| 662 | |
| 663 | if ( !$wp_filesystem->move($move_from, $fsud, true) ) { |
| 664 | return new WP_Error('new_move_failed', $this->strings['new_move_failed']); |
| 665 | } |
| 666 | |
| 667 | @$wp_filesystem->delete($move_from); |
| 668 | |
| 669 | } else { |
| 670 | return new WP_Error('new_move_failed', $this->strings['new_move_failed']); |
| 671 | } |
| 672 | |
| 673 | } |
| 674 | } elseif ('db' == $type) { |
| 675 | |
| 676 | // $import_table_prefix is received as a reference |
| 677 | $rdb = $this->restore_backup_db($working_dir, $working_dir_localpath, $import_table_prefix); |
| 678 | if (false === $rdb || is_wp_error($rdb)) return $rdb; |
| 679 | |
| 680 | } elseif ('others' == $type) { |
| 681 | |
| 682 | $dirname = basename($info['path']); |
| 683 | |
| 684 | # For foreign 'Simple Backup', we need to keep going down until we find wp-content |
| 685 | if (empty($this->ud_foreign)) { |
| 686 | $move_from = $working_dir; |
| 687 | } else { |
| 688 | $move_from = $this->search_for_folder('wp-content', $working_dir); |
| 689 | if (!is_string($move_from)) return new WP_Error('not_found', __('The WordPress content folder (wp-content) was not found in this zip file.', 'updraftplus')); |
| 690 | } |
| 691 | |
| 692 | // In this special case, the backup contents are not in a folder, so it is not simply a case of moving the folder around, but rather looping over all that we find |
| 693 | |
| 694 | # On subsequent archives of a multi-archive set, don't move anything; but do on the first |
| 695 | $preserve_existing = (isset($this->been_restored['others'])) ? 3 : 1; |
| 696 | |
| 697 | $this->move_backup_in($move_from, trailingslashit($wp_filesystem_dir), $preserve_existing, array('plugins', 'themes', 'uploads', 'upgrade'), 'others'); |
| 698 | |
| 699 | $this->been_restored['others'] = true; |
| 700 | |
| 701 | } else { |
| 702 | |
| 703 | // Default action: used for plugins, themes and uploads (and wpcore, via a filter) |
| 704 | |
| 705 | // Multi-archive sets: we record what we've already begun on, and on subsequent runs, copy in instead of replacing |
| 706 | $movedin = apply_filters('updraftplus_restore_movein_'.$type, $working_dir, $this->abspath, $wp_filesystem_dir); |
| 707 | // A filter, to allow add-ons to perform the install of non-standard entities, or to indicate that it's not possible |
| 708 | if (false === $movedin) { |
| 709 | $this->skin->feedback('not_possible'); |
| 710 | } elseif (is_wp_error($movedin)) { |
| 711 | return $movedin; |
| 712 | } elseif (true !== $movedin) { |
| 713 | |
| 714 | # On the first time, create the -old directory in updraft_dir |
| 715 | # (Old style: On the first time, move the existing data to -old) |
| 716 | if (!isset($this->been_restored[$type])) { |
| 717 | |
| 718 | # First, try filesystem-level move |
| 719 | $old_dir = $updraft_dir.'/'.$type.'-old'; |
| 720 | if (is_dir($old_dir)) { |
| 721 | $updraftplus->log_e('%s: This directory already exists, and will be replaced', $old_dir); |
| 722 | $updraftplus->remove_local_directory($old_dir); |
| 723 | } |
| 724 | |
| 725 | $move_old_destination = 0; |
| 726 | |
| 727 | if (@mkdir($old_dir)) { |
| 728 | $updraftplus->log("Moving old data: filesystem method / updraft_dir is potentially possible"); |
| 729 | $move_old_destination = 1; |
| 730 | } |
| 731 | |
| 732 | # Try wp_filesystem instead |
| 733 | if ($wp_filesystem->exists($wp_filesystem_dir."-old")) { |
| 734 | // Is better to warn and delete the backup than abort mid-restore and leave inconsistent site |
| 735 | $updraftplus->log_e('%s: This directory already exists, and will be replaced', $wp_filesystem_dir."-old"); |
| 736 | # In theory, supply true as the 3rd parameter of true achieves this; in practice, not always so (leads to support requests) |
| 737 | $wp_filesystem->delete($wp_filesystem_dir."-old", true); |
| 738 | if ($wp_filesystem->exists($wp_filesystem_dir."-old")) { |
| 739 | $updraftplus->log("Failed to remove existing directory (".$wp_filesystem_dir."-old"); |
| 740 | $failed_to_remove = true; |
| 741 | #return new WP_Error('old_move_failed', $this->strings['old_move_failed']); |
| 742 | } |
| 743 | } |
| 744 | |
| 745 | if (empty($failed_to_remove) && @$wp_filesystem->mkdir($wp_filesystem_dir."-old")) { |
| 746 | $updraftplus->log("Moving old data: can potentially use wp_filesystem method / -old"); |
| 747 | $move_old_destination += 2; |
| 748 | } |
| 749 | |
| 750 | if (0 == $move_old_destination) { |
| 751 | $updraftplus->log_e("File permissions do not allow the old data to be moved and retained; instead, it will be deleted."); |
| 752 | } |
| 753 | |
| 754 | $this->skin->feedback('moving_old'); |
| 755 | |
| 756 | # First, try direct filesystem method into updraft_dir |
| 757 | if (1 == $move_old_destination % 2) { |
| 758 | # The final 'true' forces direct filesystem access |
| 759 | $move_old = @$this->move_backup_in($get_dir, $updraft_dir.'/'.$type.'-old/' , 3, array(), $type, false, true); |
| 760 | if (is_wp_error($move_old)) $updraftplus->log_wp_error($move_old); |
| 761 | } |
| 762 | |
| 763 | # Try wp_filesystem method into -old if that failed |
| 764 | if (2 >= $move_old_destination && (0 == $move_old_destination % 2 || (!empty($move_old) && is_wp_error($move_old)))) { |
| 765 | $move_old = @$this->move_backup_in($wp_filesystem_dir, $wp_filesystem_dir."-old/" , 3, array(), $type); |
| 766 | #if (is_wp_error($move_old)) return $move_old; |
| 767 | if (is_wp_error($move_old)) $updraftplus->log_wp_error($move_old); |
| 768 | // if ( !$wp_filesystem->move($wp_filesystem_dir, $wp_filesystem_dir."-old", false) ) { |
| 769 | // return new WP_Error('old_move_failed', $this->strings['old_move_failed']); |
| 770 | // } |
| 771 | } |
| 772 | |
| 773 | # Finally, when all else fails, nuke it |
| 774 | if (0 == $move_old_destination || (!empty($move_old) && is_wp_error($move_old))) { |
| 775 | $updraftplus->log("$type: $wp_filesystem_dir: deleting contents (as attempts to copy failed)"); |
| 776 | $del_files = $wp_filesystem->dirlist($wp_filesystem_dir, true, false); |
| 777 | if (empty($del_files)) $del_files = array(); |
| 778 | foreach ( $del_files as $file => $filestruc ) { |
| 779 | if (empty($file)) continue; |
| 780 | $wp_filesystem->delete($wp_filesystem_dir.'/'.$file, true); |
| 781 | } |
| 782 | } |
| 783 | |
| 784 | } |
| 785 | |
| 786 | # For foreign 'Simple Backup', we need to keep going down until we find wp-content |
| 787 | if (empty($this->ud_foreign)) { |
| 788 | $working_dir_use = $working_dir; |
| 789 | } else { |
| 790 | $working_dir_use = $this->search_for_folder('wp-content', $working_dir); |
| 791 | if (!is_string($working_dir_use)) return new WP_Error('not_found', __('The WordPress content folder (wp-content) was not found in this zip file.', 'updraftplus')); |
| 792 | } |
| 793 | |
| 794 | // The backup may not actually have /$type, since that is info from the present site |
| 795 | $move_from = $this->get_first_directory($working_dir_use, array(basename($info['path']), $type)); |
| 796 | if (false === $move_from) return new WP_Error('new_move_failed', $this->strings['new_move_failed']); |
| 797 | |
| 798 | $this->skin->feedback('moving_backup'); |
| 799 | |
| 800 | // Old-style |
| 801 | // if (!isset($this->been_restored[$type])) { |
| 802 | // if (!$wp_filesystem->move($move_from, $wp_filesystem_dir, true) ) { |
| 803 | // return new WP_Error('new_move_failed', $this->strings['new_move_failed']); |
| 804 | // } |
| 805 | // } else { |
| 806 | $move_in = $this->move_backup_in($move_from, trailingslashit($wp_filesystem_dir), 3, array(), $type); |
| 807 | if (is_wp_error($move_in)) return $move_in; |
| 808 | if (!$move_in) return new WP_Error('new_move_failed', $this->strings['new_move_failed']); |
| 809 | $wp_filesystem->rmdir($move_from); |
| 810 | // } |
| 811 | |
| 812 | } |
| 813 | |
| 814 | $this->been_restored[$type] = true; |
| 815 | |
| 816 | } |
| 817 | |
| 818 | $attempt_delete = true; |
| 819 | if (!empty($this->ud_foreign) && !$last_one) $attempt_delete = false; |
| 820 | |
| 821 | // Non-recursive, so the directory needs to be empty |
| 822 | if ($attempt_delete) $this->skin->feedback('cleaning_up'); |
| 823 | |
| 824 | if ($attempt_delete && !$wp_filesystem->delete($working_dir, !empty($this->ud_foreign))) { |
| 825 | |
| 826 | # TODO: Can remove this after 1-Jan-2015; or at least, make it so that it requires the version number to be present. |
| 827 | $fixed_it_now = false; |
| 828 | # Deal with a corner-case in version 1.8.5 |
| 829 | if ('uploads' == $type && (empty($this->created_by_version) || (version_compare($this->created_by_version, '1.8.5', '>=') && version_compare($this->created_by_version, '1.8.8', '<')))) { |
| 830 | $updraftplus->log("Clean-up failed with uploads: will attempt 1.8.5-1.8.7 fix (".$this->created_by_version.")"); |
| 831 | $move_in = @$this->move_backup_in(dirname($move_from), trailingslashit($wp_filesystem_dir), 3, array(), $type); |
| 832 | $updraftplus->log("Result: ".serialize($move_in)); |
| 833 | if ($wp_filesystem->delete($working_dir)) $fixed_it_now = true; |
| 834 | } |
| 835 | |
| 836 | if (!$fixed_it_now) { |
| 837 | $updraftplus->log_e('Error: %s', $this->strings['delete_failed'].' ('.$working_dir.')'); |
| 838 | # List contents |
| 839 | // No need to make this a restoration-aborting error condition - it's not |
| 840 | #return new WP_Error('delete_failed', $this->strings['delete_failed'].' ('.$working_dir.')'); |
| 841 | $dirlist = $wp_filesystem->dirlist($working_dir, true, true); |
| 842 | if (is_array($dirlist)) { |
| 843 | echo __('Files found:', 'updraftplus').'<br><ul style="list-style: disc inside;">'; |
| 844 | foreach ($dirlist as $name => $struc) { |
| 845 | echo "<li>".htmlspecialchars($name)."</li>"; |
| 846 | } |
| 847 | echo '</ul>'; |
| 848 | } else { |
| 849 | $updraftplus->log_e('Unable to enumerate files in that directory.'); |
| 850 | } |
| 851 | } |
| 852 | } |
| 853 | |
| 854 | # Permissions changes (at the top level - i.e. this does not reply if using recursion) are now *additive* - i.e. there's no danger of permissions being removed from what's on-disk |
| 855 | switch($type) { |
| 856 | case 'wpcore': |
| 857 | $this->chmod_if_needed($wp_filesystem_dir, FS_CHMOD_DIR, false, $wp_filesystem); |
| 858 | // In case we restored a .htaccess which is incorrect for the local setup |
| 859 | $this->flush_rewrite_rules(); |
| 860 | break; |
| 861 | case 'uploads': |
| 862 | $this->chmod_if_needed($wp_filesystem_dir, FS_CHMOD_DIR, false, $wp_filesystem); |
| 863 | break; |
| 864 | case 'db': |
| 865 | do_action('updraftplus_restored_db', array('expected_oldsiteurl' => $this->old_siteurl, 'expected_oldhome' => $this->old_home, 'expected_oldcontent' => $this->old_content), $import_table_prefix); |
| 866 | $this->flush_rewrite_rules(); |
| 867 | break; |
| 868 | default: |
| 869 | $this->chmod_if_needed($wp_filesystem_dir, FS_CHMOD_DIR, false, $wp_filesystem); |
| 870 | } |
| 871 | # db was already done |
| 872 | if ('db' != $type) do_action('updraftplus_restored_'.$type); |
| 873 | |
| 874 | return true; |
| 875 | |
| 876 | } |
| 877 | |
| 878 | private function search_for_folder($folder, $startat) { |
| 879 | # Exists in this folder? |
| 880 | if (is_dir($startat.'/'.$folder)) return trailingslashit($startat).$folder; |
| 881 | # Does not |
| 882 | if($handle = opendir($startat)) { |
| 883 | while (($file = readdir($handle)) !== false) { |
| 884 | if ($file != '.' && $file != '..' && is_dir($startat).'/'.$file) { |
| 885 | $ss = $this->search_for_folder($folder, trailingslashit($startat).$file); |
| 886 | if (is_string($ss)) return $ss; |
| 887 | } |
| 888 | } |
| 889 | closedir($handle); |
| 890 | } |
| 891 | return false; |
| 892 | } |
| 893 | |
| 894 | # Returns an octal string (but not an octal number) |
| 895 | function get_current_chmod($file, $wpfs = false) { |
| 896 | if (false == $wpfs) { |
| 897 | global $wp_filesystem; |
| 898 | $wpfs = $wp_filesystem; |
| 899 | } |
| 900 | # getchmod() is broken at least as recently as WP3.8 - see: https://core.trac.wordpress.org/ticket/26598 |
| 901 | return (is_a($wpfs, 'WP_Filesystem_Direct')) ? substr(sprintf("%06d", decoct(@fileperms($file))),3) : $wpfs->getchmod($file); |
| 902 | } |
| 903 | |
| 904 | # Returns a string in octal format |
| 905 | # $new_chmod should be an octal, i.e. what you'd pass to chmod() |
| 906 | function calculate_additive_chmod_oct($old_chmod, $new_chmod) { |
| 907 | # chmod() expects octal form, which means a preceding zero - see http://php.net/chmod |
| 908 | $old_chmod = sprintf("%04d", $old_chmod); |
| 909 | $new_chmod = sprintf("%04d", decoct($new_chmod)); |
| 910 | |
| 911 | for ($i=1; $i<=3; $i++) { |
| 912 | $oldbit = substr($old_chmod, $i, 1); |
| 913 | $newbit = substr($new_chmod, $i, 1); |
| 914 | for ($j=0; $j<=2; $j++) { |
| 915 | if (($oldbit & (1<<$j)) && !($newbit & (1<<$j))) { |
| 916 | $newbit = (string)($newbit | 1<<$j); |
| 917 | $new_chmod = sprintf("%04d", substr($new_chmod, 0, $i).$newbit.substr($new_chmod, $i+1)); |
| 918 | } |
| 919 | } |
| 920 | } |
| 921 | |
| 922 | return $new_chmod; |
| 923 | } |
| 924 | |
| 925 | # "If needed" means, "If the permissions are not already more permissive than this". i.e. This will not tighten permissions from what the user had before (we trust them) |
| 926 | # $chmod should be an octal - i.e. the same as you'd pass to chmod() |
| 927 | function chmod_if_needed($dir, $chmod, $recursive = false, $wpfs = false, $suppress = true) { |
| 928 | |
| 929 | # Do nothing on Windows |
| 930 | if (strtoupper(substr(php_uname('s'), 0, 3)) === 'WIN') return true; |
| 931 | |
| 932 | if (false == $wpfs) { |
| 933 | global $wp_filesystem; |
| 934 | $wpfs = $wp_filesystem; |
| 935 | } |
| 936 | |
| 937 | $old_chmod = $this->get_current_chmod($dir, $wpfs); |
| 938 | |
| 939 | # Sanity fcheck |
| 940 | if (strlen($old_chmod) < 3) return; |
| 941 | |
| 942 | $new_chmod = $this->calculate_additive_chmod_oct($old_chmod, $chmod); |
| 943 | |
| 944 | # Don't fix what isn't broken |
| 945 | if (!$recursive && $new_chmod == $old_chmod) return true; |
| 946 | |
| 947 | $new_chmod = octdec($new_chmod); |
| 948 | |
| 949 | if ($suppress) { |
| 950 | return @$wpfs->chmod($dir, $new_chmod, $recursive); |
| 951 | } else { |
| 952 | return $wpfs->chmod($dir, $new_chmod, $recursive); |
| 953 | } |
| 954 | } |
| 955 | |
| 956 | // $dirnames: an array of preferred names |
| 957 | private function get_first_directory($working_dir, $dirnames) { |
| 958 | global $wp_filesystem, $updraftplus; |
| 959 | $fdirnames = array_flip($dirnames); |
| 960 | $dirlist = $wp_filesystem->dirlist($working_dir, true, false); |
| 961 | if (is_array($dirlist)) { |
| 962 | $move_from = false; |
| 963 | foreach ($dirlist as $name => $struc) { |
| 964 | if (isset($struc['type']) && 'd' != $struc['type']) continue; |
| 965 | if (false === $move_from) { |
| 966 | if (isset($fdirnames[$name])) { |
| 967 | $move_from = $working_dir . "/".$name; |
| 968 | } elseif (preg_match('/^([^\.].*)$/', $name, $fmatch)) { |
| 969 | $first_entry = $working_dir."/".$fmatch[1]; |
| 970 | } |
| 971 | } |
| 972 | } |
| 973 | if ($move_from === false && isset($first_entry)) { |
| 974 | $updraftplus->log_e('Using directory from backup: %s', basename($first_entry)); |
| 975 | $move_from = $first_entry; |
| 976 | } |
| 977 | } else { |
| 978 | # That shouldn't happen. Fall back to default |
| 979 | $move_from = $working_dir."/".$dirnames[0]; |
| 980 | } |
| 981 | return $move_from; |
| 982 | } |
| 983 | |
| 984 | function pre_sql_actions($import_table_prefix) { |
| 985 | |
| 986 | $import_table_prefix = apply_filters('updraftplus_restore_set_table_prefix', $import_table_prefix, $this->ud_backup_is_multisite); |
| 987 | |
| 988 | if (!is_string($import_table_prefix)) { |
| 989 | if ($import_table_prefix === false) { |
| 990 | echo '<p>'.__('Please supply the requested information, and then continue.', 'updraftplus').'</p>'; |
| 991 | return false; |
| 992 | } else { |
| 993 | return new WP_Error('invalid_table_prefix', __('Error:', 'updraftplus').' '.serialize($import_table_prefix)); |
| 994 | } |
| 995 | } |
| 996 | |
| 997 | global $updraftplus; |
| 998 | echo $updraftplus->log_e('New table prefix: %s', $import_table_prefix); |
| 999 | |
| 1000 | return $import_table_prefix; |
| 1001 | |
| 1002 | } |
| 1003 | |
| 1004 | public function option_filter_permalink_structure($val) { |
| 1005 | global $updraftplus; |
| 1006 | return $updraftplus->option_filter_get('permalink_structure'); |
| 1007 | } |
| 1008 | |
| 1009 | public function option_filter_page_on_front($val) { |
| 1010 | global $updraftplus; |
| 1011 | return $updraftplus->option_filter_get('page_on_front'); |
| 1012 | } |
| 1013 | |
| 1014 | public function option_filter_rewrite_rules($val) { |
| 1015 | global $updraftplus; |
| 1016 | return $updraftplus->option_filter_get('rewrite_rules'); |
| 1017 | } |
| 1018 | |
| 1019 | // The pass-by-reference on $import_table_prefix is due to historical refactoring |
| 1020 | private function restore_backup_db($working_dir, $working_dir_localpath, &$import_table_prefix) { |
| 1021 | |
| 1022 | do_action('updraftplus_restore_db_pre'); |
| 1023 | |
| 1024 | # This is now a legacy option (at least on the front end), so we should not see it much |
| 1025 | $this->prior_upload_path = get_option('upload_path'); |
| 1026 | |
| 1027 | // There is a file backup.db(.gz) inside the working directory |
| 1028 | |
| 1029 | # The 'off' check is for badly configured setups - http://wordpress.org/support/topic/plugin-wp-super-cache-warning-php-safe-mode-enabled-but-safe-mode-is-off |
| 1030 | if (@ini_get('safe_mode') && 'off' != strtolower(@ini_get('safe_mode'))) { |
| 1031 | echo "<p>".__('Warning: PHP safe_mode is active on your server. Timeouts are much more likely. If these happen, then you will need to manually restore the file via phpMyAdmin or another method.', 'updraftplus')."</p><br/>"; |
| 1032 | } |
| 1033 | |
| 1034 | $db_basename = 'backup.db.gz'; |
| 1035 | if (!empty($this->ud_foreign)) { |
| 1036 | |
| 1037 | $plugins = apply_filters('updraftplus_accept_archivename', array()); |
| 1038 | |
| 1039 | if (empty($plugins[$this->ud_foreign])) return new WP_Error('unknown', sprintf(__('Backup created by unknown source (%s) - cannot be restored.', 'updraftplus'), $this->ud_foreign)); |
| 1040 | |
| 1041 | if (empty($plugins[$this->ud_foreign]['separatedb'])) { |
| 1042 | $db_basename = apply_filters('updraftplus_foreign_separatedbname', false, $this->ud_foreign, $this->ud_backup_info, $working_dir_localpath); |
| 1043 | } elseif (file_exists($working_dir_localpath.'/backup.db')) { |
| 1044 | $db_basename = 'backup.db'; |
| 1045 | } |
| 1046 | } |
| 1047 | |
| 1048 | // wp_filesystem has no gzopen method, so we switch to using the local filesystem (which is harmless, since we are performing read-only operations) |
| 1049 | if (false === $db_basename || !is_readable($working_dir_localpath.'/'.$db_basename)) return new WP_Error('dbopen_failed',__('Failed to find database file','updraftplus')." ($working_dir/".$db_basename.")"); |
| 1050 | |
| 1051 | global $wpdb, $updraftplus; |
| 1052 | |
| 1053 | $this->skin->feedback('restore_database'); |
| 1054 | |
| 1055 | $is_plain = (substr($db_basename, -3, 3) == '.db'); |
| 1056 | |
| 1057 | // Read-only access: don't need to go through WP_Filesystem |
| 1058 | if ($is_plain) { |
| 1059 | $dbhandle = fopen($working_dir_localpath.'/'.$db_basename, 'r'); |
| 1060 | } else { |
| 1061 | $dbhandle = gzopen($working_dir_localpath.'/'.$db_basename, 'r'); |
| 1062 | } |
| 1063 | if (!$dbhandle) return new WP_Error('dbopen_failed',__('Failed to open database file','updraftplus')); |
| 1064 | |
| 1065 | $this->line = 0; |
| 1066 | |
| 1067 | if (true == $this->use_wpdb) { |
| 1068 | $updraftplus->log_e('Database access: Direct MySQL access is not available, so we are falling back to wpdb (this will be considerably slower)'); |
| 1069 | } else { |
| 1070 | $updraftplus->log("Using direct MySQL access; value of use_mysqli is: ".($this->use_mysqli ? '1' : '0')); |
| 1071 | if ($this->use_mysqli) { |
| 1072 | @mysqli_query($this->mysql_dbh, 'SET SESSION query_cache_type = OFF;'); |
| 1073 | } else { |
| 1074 | @mysql_query('SET SESSION query_cache_type = OFF;', $this->mysql_dbh ); |
| 1075 | } |
| 1076 | } |
| 1077 | |
| 1078 | // Find the supported engines - in case the dump had something else (case seen: saved from MariaDB with engine Aria; imported into plain MySQL without) |
| 1079 | $supported_engines = $wpdb->get_results("SHOW ENGINES", OBJECT_K); |
| 1080 | |
| 1081 | $this->errors = 0; |
| 1082 | $this->statements_run = 0; |
| 1083 | $this->insert_statements_run = 0; |
| 1084 | $this->tables_created = 0; |
| 1085 | |
| 1086 | $sql_line = ""; |
| 1087 | $sql_type = -1; |
| 1088 | |
| 1089 | $this->start_time = microtime(true); |
| 1090 | |
| 1091 | $old_wpversion = ''; |
| 1092 | $this->old_siteurl = ''; |
| 1093 | $this->old_home = ''; |
| 1094 | $this->old_content = ''; |
| 1095 | $old_table_prefix = ''; |
| 1096 | $old_siteinfo = array(); |
| 1097 | $gathering_siteinfo = true; |
| 1098 | |
| 1099 | $this->create_forbidden = false; |
| 1100 | $this->drop_forbidden = false; |
| 1101 | |
| 1102 | $this->last_error = ''; |
| 1103 | $random_table_name = 'updraft_tmp_'.rand(0,9999999).md5(microtime(true)); |
| 1104 | |
| 1105 | # The only purpose in funnelling queries directly here is to be able to get the error number |
| 1106 | if ($this->use_wpdb) { |
| 1107 | $req = $wpdb->query("CREATE TABLE $random_table_name"); |
| 1108 | if (!$req) $this->last_error = $wpdb->last_error; |
| 1109 | $this->last_error_no = false; |
| 1110 | } else { |
| 1111 | if ($this->use_mysqli) { |
| 1112 | $req = mysqli_query($this->mysql_dbh, "CREATE TABLE $random_table_name"); |
| 1113 | } else { |
| 1114 | $req = mysql_unbuffered_query("CREATE TABLE $random_table_name", $this->mysql_dbh); |
| 1115 | } |
| 1116 | if (!$req) { |
| 1117 | $this->last_error = ($this->use_mysqli) ? mysqli_error($this->mysql_dbh) : mysql_error($this->mysql_dbh); |
| 1118 | $this->last_error_no = ($this->use_mysqli) ? mysqli_errno($this->mysql_dbh) : mysql_errno($this->mysql_dbh); |
| 1119 | } |
| 1120 | } |
| 1121 | |
| 1122 | if (!$req && ($this->use_wpdb || 1142 === $this->last_error_no)) { |
| 1123 | $this->create_forbidden = true; |
| 1124 | # If we can't create, then there's no point dropping |
| 1125 | $this->drop_forbidden = true; |
| 1126 | echo '<strong>'.__('Warning:', 'updraftplus').'</strong> '; |
| 1127 | $updraftplus->log_e('Your database user does not have permission to create tables. We will attempt to restore by simply emptying the tables; this should work as long as a) you are restoring from a WordPress version with the same database structure, and b) Your imported database does not contain any tables which are not already present on the importing site.', ' ('.$this->last_error.')'); |
| 1128 | } else { |
| 1129 | if ($this->use_wpdb) { |
| 1130 | $req = $wpdb->query("DROP TABLE $random_table_name"); |
| 1131 | if (!$req) $this->last_error = $wpdb->last_error; |
| 1132 | $this->last_error_no = false; |
| 1133 | } else { |
| 1134 | if ($this->use_mysqli) { |
| 1135 | $req = mysqli_query($this->mysql_dbh, "DROP TABLE $random_table_name"); |
| 1136 | } else { |
| 1137 | $req = mysql_unbuffered_query("DROP TABLE $random_table_name", $this->mysql_dbh); |
| 1138 | } |
| 1139 | if (!$req) { |
| 1140 | $this->last_error = ($this->use_mysqli) ? mysqli_error($this->mysql_dbh) : mysql_error($this->mysql_dbh); |
| 1141 | $this->last_error_no = ($this->use_mysqli) ? mysqli_errno($this->mysql_dbh) : mysql_errno($this->mysql_dbh); |
| 1142 | } |
| 1143 | } |
| 1144 | if (!$req && ($this->use_wpdb || $this->last_error_no === 1142)) { |
| 1145 | $this->drop_forbidden = true; |
| 1146 | echo '<strong>'.__('Warning:','updraftplus').'</strong> '; |
| 1147 | $updraftplus->log_e('Your database user does not have permission to drop tables. We will attempt to restore by simply emptying the tables; this should work as long as you are restoring from a WordPress version with the same database structure (%s)', ' ('.$this->last_error.')'); |
| 1148 | } |
| 1149 | } |
| 1150 | |
| 1151 | $restoring_table = ''; |
| 1152 | |
| 1153 | $this->max_allowed_packet = $updraftplus->get_max_packet_size(); |
| 1154 | |
| 1155 | while (($is_plain && !feof($dbhandle)) || (!$is_plain && !gzeof($dbhandle))) { |
| 1156 | // Up to 1Mb |
| 1157 | $buffer = ($is_plain) ? rtrim(fgets($dbhandle, 1048576)) : rtrim(gzgets($dbhandle, 1048576)); |
| 1158 | // Discard comments |
| 1159 | if (empty($buffer) || substr($buffer, 0, 1) == '#' || preg_match('/^--(\s|$)/', substr($buffer, 0, 3))) { |
| 1160 | if ('' == $this->old_siteurl && preg_match('/^\# Backup of: (http(.*))$/', $buffer, $matches)) { |
| 1161 | $this->old_siteurl = untrailingslashit($matches[1]); |
| 1162 | $updraftplus->log_e('<strong>Backup of:</strong> %s', htmlspecialchars($this->old_siteurl)); |
| 1163 | do_action('updraftplus_restore_db_record_old_siteurl', $this->old_siteurl); |
| 1164 | } elseif (false === $this->created_by_version && preg_match('/^\# Created by UpdraftPlus version ([\d\.]+)/', $buffer, $matches)) { |
| 1165 | $this->created_by_version = trim($matches[1]); |
| 1166 | echo '<strong>'.__('Backup created by:', 'updraftplus').'</strong> '.htmlspecialchars($this->created_by_version).'<br>'; |
| 1167 | $updraftplus->log('Backup created by: '.$this->created_by_version); |
| 1168 | } elseif ('' == $this->old_home && preg_match('/^\# Home URL: (http(.*))$/', $buffer, $matches)) { |
| 1169 | $this->old_home = untrailingslashit($matches[1]); |
| 1170 | if ($this->old_siteurl && $this->old_home != $this->old_siteurl) { |
| 1171 | echo '<strong>'.__('Site home:', 'updraftplus').'</strong> '.htmlspecialchars($this->old_home).'<br>'; |
| 1172 | $updraftplus->log('Site home: '.$this->old_home); |
| 1173 | } |
| 1174 | do_action('updraftplus_restore_db_record_old_home', $this->old_home); |
| 1175 | } elseif ('' == $this->old_content && preg_match('/^\# Content URL: (http(.*))$/', $buffer, $matches)) { |
| 1176 | $this->old_content = untrailingslashit($matches[1]); |
| 1177 | echo '<strong>'.__('Content URL:', 'updraftplus').'</strong> '.htmlspecialchars($this->old_content).'<br>'; |
| 1178 | $updraftplus->log('Content URL: '.$this->old_content); |
| 1179 | do_action('updraftplus_restore_db_record_old_content', $this->old_content); |
| 1180 | } elseif ('' == $old_table_prefix && (preg_match('/^\# Table prefix: (\S+)$/', $buffer, $matches) || preg_match('/^-- Table Prefix: (\S+)$/i', $buffer, $matches))) { |
| 1181 | # We also support backwpup style: |
| 1182 | # -- Table Prefix: wp_ |
| 1183 | $old_table_prefix = $matches[1]; |
| 1184 | echo '<strong>'.__('Old table prefix:', 'updraftplus').'</strong> '.htmlspecialchars($old_table_prefix).'<br>'; |
| 1185 | $updraftplus->log("Old table prefix: ".$old_table_prefix); |
| 1186 | } elseif ($gathering_siteinfo && preg_match('/^\# Site info: (\S+)$/', $buffer, $matches)) { |
| 1187 | if ('end' == $matches[1]) { |
| 1188 | $gathering_siteinfo = false; |
| 1189 | // Sanity checks |
| 1190 | if (isset($old_siteinfo['multisite']) && !$old_siteinfo['multisite'] && is_multisite()) { |
| 1191 | // Just need to check that you're crazy |
| 1192 | if (!defined('UPDRAFTPLUS_EXPERIMENTAL_IMPORTINTOMULTISITE') || UPDRAFTPLUS_EXPERIMENTAL_IMPORTINTOMULTISITE != true) { |
| 1193 | return new WP_Error('multisite_error', $this->strings['multisite_error']); |
| 1194 | } |
| 1195 | // Got the needed code? |
| 1196 | if (!class_exists('UpdraftPlusAddOn_MultiSite') || !class_exists('UpdraftPlus_Addons_Migrator')) { |
| 1197 | return new WP_Error('missing_addons', __('To import an ordinary WordPress site into a multisite installation requires both the multisite and migrator add-ons.', 'updraftplus')); |
| 1198 | } |
| 1199 | } |
| 1200 | } elseif (preg_match('/^([^=]+)=(.*)$/', $matches[1], $kvmatches)) { |
| 1201 | $key = $kvmatches[1]; |
| 1202 | $val = $kvmatches[2]; |
| 1203 | echo '<strong>'.__('Site information:','updraftplus').'</strong>'.' '.htmlspecialchars($key).' = '.htmlspecialchars($val).'<br>'; |
| 1204 | $updraftplus->log("Site information: ".$key."=".$val); |
| 1205 | $old_siteinfo[$key]=$val; |
| 1206 | if ('multisite' == $key) { |
| 1207 | if ($val) { $this->ud_backup_is_multisite=1; } else { $this->ud_backup_is_multisite = 0;} |
| 1208 | } |
| 1209 | } |
| 1210 | } |
| 1211 | continue; |
| 1212 | } |
| 1213 | |
| 1214 | // Detect INSERT commands early, so that we can split them if necessary |
| 1215 | if ($sql_line && preg_match('/^\s*(insert into \`?([^\`]*)\`?\s+(values|\())/i', $sql_line, $matches)) { |
| 1216 | $sql_type = 3; |
| 1217 | $insert_prefix = $matches[1]; |
| 1218 | } |
| 1219 | |
| 1220 | # Deal with case where adding this line will take us over the MySQL max_allowed_packet limit - must split, if we can (if it looks like consecutive rows) |
| 1221 | # ALlow a 100-byte margin for error (including searching/replacing table prefix) |
| 1222 | if (3 == $sql_type && $sql_line && strlen($sql_line.$buffer) > ($this->max_allowed_packet - 100) && preg_match('/,\s*$/', $sql_line) && preg_match('/^\s*\(/', $buffer)) { |
| 1223 | // Remove the final comma; replace with semi-colon |
| 1224 | $sql_line = substr(rtrim($sql_line), 0, strlen($sql_line)-1).';'; |
| 1225 | if ('' != $old_table_prefix && $import_table_prefix != $old_table_prefix) $sql_line = $updraftplus->str_replace_once($old_table_prefix, $import_table_prefix, $sql_line); |
| 1226 | # Run the SQL command; then set up for the next one. |
| 1227 | $this->line++; |
| 1228 | echo __("Split line to avoid exceeding maximum packet size", 'updraftplus')." (".strlen($sql_line)." + ".strlen($buffer)." : ".$this->max_allowed_packet.")<br>"; |
| 1229 | $updraftplus->log("Split line to avoid exceeding maximum packet size (".strlen($sql_line)." + ".strlen($buffer)." : ".$this->max_allowed_packet.")"); |
| 1230 | $do_exec = $this->sql_exec($sql_line, $sql_type, $import_table_prefix); |
| 1231 | if (is_wp_error($do_exec)) return $do_exec; |
| 1232 | # Reset, then carry on |
| 1233 | $sql_line = $insert_prefix." "; |
| 1234 | } |
| 1235 | |
| 1236 | $sql_line .= $buffer; |
| 1237 | # Do we have a complete line yet? We used to just test the final character for ';' here (up to 1.8.12), but that was too unsophisticated |
| 1238 | if ( |
| 1239 | (3 == $sql_type && !preg_match('/\)\s*;$/', substr($sql_line, -3, 3))) |
| 1240 | || (3 != $sql_type && ';' != substr($sql_line, -1, 1)) |
| 1241 | ) continue; |
| 1242 | |
| 1243 | $this->line++; |
| 1244 | |
| 1245 | # We now have a complete line - process it |
| 1246 | |
| 1247 | if (3 == $sql_type && $sql_line && strlen($sql_line) > $this->max_allowed_packet) { |
| 1248 | $this->log_oversized_packet($sql_line); |
| 1249 | # Reset |
| 1250 | $sql_line = ''; |
| 1251 | $sql_type = -1; |
| 1252 | # If this is the very first SQL line of the options table, we need to bail; it's essential |
| 1253 | if (0 == $this->insert_statements_run && $restoring_table && $restoring_table == $import_table_prefix.'options') { |
| 1254 | return new WP_Error('initial_db_error', sprintf(__('An error occurred on the first %s command - aborting run','updraftplus'), 'INSERT (options)')); |
| 1255 | } |
| 1256 | continue; |
| 1257 | } |
| 1258 | |
| 1259 | # The timed overhead of this is negligible |
| 1260 | if (preg_match('/^\s*drop table if exists \`?([^\`]*)\`?\s*;/i', $sql_line, $matches)) { |
| 1261 | |
| 1262 | $sql_type = 1; |
| 1263 | |
| 1264 | if (!isset($printed_new_table_prefix)) { |
| 1265 | $import_table_prefix = $this->pre_sql_actions($import_table_prefix); |
| 1266 | if (false===$import_table_prefix || is_wp_error($import_table_prefix)) return $import_table_prefix; |
| 1267 | $printed_new_table_prefix = true; |
| 1268 | } |
| 1269 | |
| 1270 | $this->table_name = $matches[1]; |
| 1271 | |
| 1272 | // Legacy, less reliable - in case it was not caught before |
| 1273 | if ('' == $old_table_prefix && preg_match('/^([a-z0-9]+)_.*$/i', $this->table_name, $tmatches)) { |
| 1274 | $old_table_prefix = $tmatches[1].'_'; |
| 1275 | echo '<strong>'.__('Old table prefix:', 'updraftplus').'</strong> '.htmlspecialchars($old_table_prefix).'<br>'; |
| 1276 | $updraftplus->log("Old table prefix: $old_table_prefix"); |
| 1277 | } |
| 1278 | |
| 1279 | $this->new_table_name = ($old_table_prefix) ? $updraftplus->str_replace_once($old_table_prefix, $import_table_prefix, $this->table_name) : $this->table_name; |
| 1280 | |
| 1281 | if ('' != $old_table_prefix && $import_table_prefix != $old_table_prefix) { |
| 1282 | $sql_line = $updraftplus->str_replace_once($old_table_prefix, $import_table_prefix, $sql_line); |
| 1283 | } |
| 1284 | } elseif (preg_match('/^\s*create table \`?([^\`\(]*)\`?\s*\(/i', $sql_line, $matches)) { |
| 1285 | |
| 1286 | $sql_type = 2; |
| 1287 | $this->insert_statements_run = 0; |
| 1288 | $this->table_name = $matches[1]; |
| 1289 | |
| 1290 | // MySQL 4.1 outputs TYPE=, but accepts ENGINE=; 5.1 onwards accept *only* ENGINE= |
| 1291 | $sql_line = $updraftplus->str_lreplace('TYPE=', 'ENGINE=', $sql_line); |
| 1292 | |
| 1293 | if (!isset($printed_new_table_prefix)) { |
| 1294 | $import_table_prefix = $this->pre_sql_actions($import_table_prefix); |
| 1295 | if (false===$import_table_prefix || is_wp_error($import_table_prefix)) return $import_table_prefix; |
| 1296 | $printed_new_table_prefix = true; |
| 1297 | } |
| 1298 | |
| 1299 | $this->new_table_name = ($old_table_prefix) ? $updraftplus->str_replace_once($old_table_prefix, $import_table_prefix, $this->table_name) : $this->table_name; |
| 1300 | |
| 1301 | // This CREATE TABLE command may be the de-facto mark for the end of processing a previous table (which is so if this is not the first table in the SQL dump) |
| 1302 | if ($restoring_table) { |
| 1303 | |
| 1304 | // After restoring the options table, we can set old_siteurl if on legacy (i.e. not already set) |
| 1305 | if ($restoring_table == $import_table_prefix.'options') { |
| 1306 | if ('' == $this->old_siteurl || '' == $this->old_home || '' == $this->old_content) { |
| 1307 | global $updraftplus_addons_migrator; |
| 1308 | if (isset($updraftplus_addons_migrator->new_blogid)) switch_to_blog($updraftplus_addons_migrator->new_blogid); |
| 1309 | |
| 1310 | if ('' == $this->old_siteurl) { |
| 1311 | $this->old_siteurl = untrailingslashit($wpdb->get_row("SELECT option_value FROM $wpdb->options WHERE option_name='siteurl'")->option_value); |
| 1312 | do_action('updraftplus_restore_db_record_old_siteurl', $this->old_siteurl); |
| 1313 | } |
| 1314 | if ('' == $this->old_home) { |
| 1315 | $this->old_home = untrailingslashit($wpdb->get_row("SELECT option_value FROM $wpdb->options WHERE option_name='home'")->option_value); |
| 1316 | do_action('updraftplus_restore_db_record_old_home', $this->old_home); |
| 1317 | } |
| 1318 | if ('' == $this->old_content) { |
| 1319 | $this->old_content = $this->old_siteurl.'/wp-content'; |
| 1320 | do_action('updraftplus_restore_db_record_old_content', $this->old_content); |
| 1321 | } |
| 1322 | if (isset($updraftplus_addons_migrator->new_blogid)) restore_current_blog(); |
| 1323 | } |
| 1324 | } |
| 1325 | |
| 1326 | $this->restored_table($restoring_table, $import_table_prefix, $old_table_prefix); |
| 1327 | |
| 1328 | } |
| 1329 | |
| 1330 | $engine = "(?)"; $engine_change_message = ''; |
| 1331 | if (preg_match('/ENGINE=([^\s;]+)/', $sql_line, $eng_match)) { |
| 1332 | $engine = $eng_match[1]; |
| 1333 | if (isset($supported_engines[$engine])) { |
| 1334 | #echo sprintf(__('Requested table engine (%s) is present.', 'updraftplus'), $engine); |
| 1335 | if ('myisam' == strtolower($engine)) { |
| 1336 | $sql_line = preg_replace('/PAGE_CHECKSUM=\d\s?/', '', $sql_line, 1); |
| 1337 | } |
| 1338 | } else { |
| 1339 | $engine_change_message = sprintf(__('Requested table engine (%s) is not present - changing to MyISAM.', 'updraftplus'), $engine)."<br>"; |
| 1340 | $sql_line = $updraftplus->str_lreplace("ENGINE=$eng_match", "ENGINE=MyISAM", $sql_line); |
| 1341 | // Remove (M)aria options |
| 1342 | if ('maria' == strtolower($engine) || 'aria' == strtolower($engine)) { |
| 1343 | $sql_line = preg_replace('/PAGE_CHECKSUM=\d\s?/', '', $sql_line, 1); |
| 1344 | $sql_line = preg_replace('/TRANSACTIONAL=\d\s?/', '', $sql_line, 1); |
| 1345 | } |
| 1346 | } |
| 1347 | } |
| 1348 | |
| 1349 | $this->table_name = $matches[1]; |
| 1350 | echo '<strong>'.sprintf(__('Restoring table (%s)','updraftplus'), $engine).":</strong> ".htmlspecialchars($this->table_name); |
| 1351 | $logline = "Restoring table ($engine): ".$this->table_name; |
| 1352 | if ('' != $old_table_prefix && $import_table_prefix != $old_table_prefix) { |
| 1353 | $new_table_name = $updraftplus->str_replace_once($old_table_prefix, $import_table_prefix, $this->table_name); |
| 1354 | echo ' - '.__('will restore as:', 'updraftplus').' '.htmlspecialchars($new_table_name); |
| 1355 | $logline .= " - will restore as: ".$new_table_name; |
| 1356 | $sql_line = $updraftplus->str_replace_once($old_table_prefix, $import_table_prefix, $sql_line); |
| 1357 | } else { |
| 1358 | $new_table_name = $this->table_name; |
| 1359 | } |
| 1360 | $updraftplus->log($logline); |
| 1361 | $restoring_table = $new_table_name; |
| 1362 | echo '<br>'; |
| 1363 | if ($engine_change_message) echo $engine_change_message; |
| 1364 | |
| 1365 | } elseif (preg_match('/^\s*(insert into \`?([^\`]*)\`?\s+(values|\())/i', $sql_line, $matches)) { |
| 1366 | $sql_type = 3; |
| 1367 | if ('' != $old_table_prefix && $import_table_prefix != $old_table_prefix) $sql_line = $updraftplus->str_replace_once($old_table_prefix, $import_table_prefix, $sql_line); |
| 1368 | } elseif (preg_match('/^\s*(\/\*\!40000 )?(alter|lock) tables? \`?([^\`\(]*)\`?\s+(write|disable|enable)/i', $sql_line, $matches)) { |
| 1369 | # Only binary mysqldump produces this pattern (LOCK TABLES `table` WRITE, ALTER TABLE `table` (DISABLE|ENABLE) KEYS) |
| 1370 | $sql_type = 4; |
| 1371 | if ('' != $old_table_prefix && $import_table_prefix != $old_table_prefix) $sql_line = $updraftplus->str_replace_once($old_table_prefix, $import_table_prefix, $sql_line); |
| 1372 | } elseif (preg_match('/^(un)?lock tables/i', $sql_line)) { |
| 1373 | # BackWPup produces these |
| 1374 | $sql_type = 5; |
| 1375 | } |
| 1376 | // if (5 !== $sql_type) { |
| 1377 | $do_exec = $this->sql_exec($sql_line, $sql_type); |
| 1378 | if (is_wp_error($do_exec)) return $do_exec; |
| 1379 | // } |
| 1380 | |
| 1381 | # Reset |
| 1382 | $sql_line = ''; |
| 1383 | $sql_type = -1; |
| 1384 | |
| 1385 | } |
| 1386 | |
| 1387 | if ($restoring_table) $this->restored_table($restoring_table, $import_table_prefix, $old_table_prefix); |
| 1388 | |
| 1389 | $time_taken = microtime(true) - $this->start_time; |
| 1390 | $updraftplus->log_e('Finished: lines processed: %d in %.2f seconds', $this->line, $time_taken); |
| 1391 | if ($is_plain) { |
| 1392 | fclose($dbhandle); |
| 1393 | } else { |
| 1394 | gzclose($dbhandle); |
| 1395 | } |
| 1396 | |
| 1397 | global $wp_filesystem; |
| 1398 | |
| 1399 | $wp_filesystem->delete($working_dir.'/'.$db_basename, false, 'f'); |
| 1400 | return true; |
| 1401 | |
| 1402 | } |
| 1403 | |
| 1404 | private function log_oversized_packet($sql_line) { |
| 1405 | global $updraftplus; |
| 1406 | $logit = substr($sql_line, 0, 100); |
| 1407 | $updraftplus->log(sprintf("An SQL line that is larger than the maximum packet size and cannot be split was found: %s", '('.strlen($sql_line).', '.$logit.' ...)')); |
| 1408 | echo '<strong>'.__('Warning:', 'updraftplus').'</strong> '.sprintf(__("An SQL line that is larger than the maximum packet size and cannot be split was found; this line will not be processed, but will be dropped: %s", 'updraftplus'), '('.strlen($sql_line).', '.$this->max_allowed_packet.', '.$logit.' ...)')."<br>"; |
| 1409 | } |
| 1410 | |
| 1411 | # UPDATE is sql_type=5 (not used in the function, but used in Migrator and so noted here for reference) |
| 1412 | # $import_table_prefix is only use in one place in this function, and otherwise need/should not be supplied |
| 1413 | public function sql_exec($sql_line, $sql_type, $import_table_prefix = '') { |
| 1414 | |
| 1415 | global $wpdb, $updraftplus; |
| 1416 | $ignore_errors = false; |
| 1417 | if (2 == $sql_type && $this->create_forbidden) { |
| 1418 | $updraftplus->log_e('Cannot create new tables, so skipping this command (%s)', htmlspecialchars($sql_line)); |
| 1419 | $req = true; |
| 1420 | } else { |
| 1421 | if (1 == $sql_type && $this->drop_forbidden) { |
| 1422 | $sql_line = "DELETE FROM ".$updraftplus->backquote($this->new_table_name); |
| 1423 | $updraftplus->log_e('Cannot drop tables, so deleting instead (%s)', $sql_line); |
| 1424 | $ignore_errors = true; |
| 1425 | } |
| 1426 | |
| 1427 | if (3 == $sql_type && $sql_line && strlen($sql_line) > $this->max_allowed_packet) { |
| 1428 | $this->log_oversized_packet($sql_line); |
| 1429 | # If this is the very first SQL line of the options table, we need to bail; it's essential |
| 1430 | $this->errors++; |
| 1431 | if (0 == $this->insert_statements_run && $this->new_table_name && $this->new_table_name == $import_table_prefix.'options') { |
| 1432 | return new WP_Error('initial_db_error', sprintf(__('An error occurred on the first %s command - aborting run','updraftplus'), 'INSERT (options)')); |
| 1433 | } |
| 1434 | return false; |
| 1435 | } |
| 1436 | |
| 1437 | if ($this->use_wpdb) { |
| 1438 | $req = $wpdb->query($sql_line); |
| 1439 | if (!$req) $this->last_error = $wpdb->last_error; |
| 1440 | } else { |
| 1441 | if ($this->use_mysqli) { |
| 1442 | $req = mysqli_query($this->mysql_dbh, $sql_line); |
| 1443 | if (!$req) $this->last_error = mysqli_error($this->mysql_dbh); |
| 1444 | } else { |
| 1445 | $req = mysql_unbuffered_query($sql_line, $this->mysql_dbh); |
| 1446 | if (!$req) $this->last_error = mysql_error($this->mysql_dbh); |
| 1447 | } |
| 1448 | } |
| 1449 | if (3 == $sql_type) $this->insert_statements_run++; |
| 1450 | $this->statements_run++; |
| 1451 | } |
| 1452 | |
| 1453 | if (!$req) { |
| 1454 | if (!$ignore_errors) $this->errors++; |
| 1455 | $print_err = (strlen($sql_line) > 100) ? substr($sql_line, 0, 100).' ...' : $sql_line; |
| 1456 | echo sprintf(_x('An error (%s) occurred:', 'The user is being told the number of times an error has happened, e.g. An error (27) occurred', 'updraftplus'), $this->errors)." - ".htmlspecialchars($this->last_error)." - ".__('the database query being run was:','updraftplus').' '.htmlspecialchars($print_err).'<br>'; |
| 1457 | $updraftplus->log("An error (".$this->errors.") occurred: ".$this->last_error." - SQL query was: ".substr($sql_line, 0, 65536)); |
| 1458 | // First command is expected to be DROP TABLE |
| 1459 | if (1 == $this->errors && 2 == $sql_type && 0 == $this->tables_created) { |
| 1460 | return new WP_Error('initial_db_error', sprintf(__('An error occurred on the first %s command - aborting run','updraftplus'), 'CREATE TABLE')); |
| 1461 | } |
| 1462 | if ($this->errors>49) { |
| 1463 | return new WP_Error('too_many_db_errors', __('Too many database errors have occurred - aborting','updraftplus')); |
| 1464 | } |
| 1465 | } elseif ($sql_type == 2) { |
| 1466 | $this->tables_created++; |
| 1467 | } |
| 1468 | if (($this->line)%50 == 0) { |
| 1469 | if (($this->line)%250 == 0 || $this->line<250) { |
| 1470 | $time_taken = microtime(true) - $this->start_time; |
| 1471 | $updraftplus->log_e('Database queries processed: %d in %.2f seconds',$this->line, $time_taken); |
| 1472 | } |
| 1473 | } |
| 1474 | return $req; |
| 1475 | } |
| 1476 | |
| 1477 | // function option_filter($which) { |
| 1478 | // if (strpos($which, 'pre_option') !== false) { echo "OPT_FILT: $which<br>\n"; } |
| 1479 | // return false; |
| 1480 | // } |
| 1481 | |
| 1482 | private function flush_rewrite_rules() { |
| 1483 | |
| 1484 | // We have to deal with the fact that the procedures used call get_option, which could be looking at the wrong table prefix, or have the wrong thing cached |
| 1485 | |
| 1486 | global $updraftplus_addons_migrator; |
| 1487 | if (!empty($updraftplus_addons_migrator->new_blogid)) switch_to_blog($updraftplus_addons_migrator->new_blogid); |
| 1488 | |
| 1489 | foreach (array('permalink_structure', 'rewrite_rules', 'page_on_front') as $opt) { |
| 1490 | add_filter('pre_option_'.$opt, array($this, 'option_filter_'.$opt)); |
| 1491 | } |
| 1492 | |
| 1493 | global $wp_rewrite; |
| 1494 | $wp_rewrite->init(); |
| 1495 | // Don't do this: it will cause rules created by plugins that weren't active at the start of the restore run to be lost |
| 1496 | # flush_rewrite_rules(true); |
| 1497 | |
| 1498 | if ( function_exists( 'save_mod_rewrite_rules' ) ) |
| 1499 | save_mod_rewrite_rules(); |
| 1500 | if ( function_exists( 'iis7_save_url_rewrite_rules' ) ) |
| 1501 | iis7_save_url_rewrite_rules(); |
| 1502 | |
| 1503 | foreach (array('permalink_structure', 'rewrite_rules', 'page_on_front') as $opt) { |
| 1504 | remove_filter('pre_option_'.$opt, array($this, 'option_filter_'.$opt)); |
| 1505 | } |
| 1506 | |
| 1507 | if (!empty($updraftplus_addons_migrator->new_blogid)) restore_current_blog(); |
| 1508 | |
| 1509 | } |
| 1510 | |
| 1511 | private function restored_table($table, $import_table_prefix, $old_table_prefix) { |
| 1512 | |
| 1513 | global $wpdb, $updraftplus; |
| 1514 | |
| 1515 | // WordPress has an option name predicated upon the table prefix. Yuk. |
| 1516 | // if ($table == $import_table_prefix.'options') { |
| 1517 | if (preg_match('/^([\d+]_)?options$/', substr($table, strlen($import_table_prefix)), $matches)) { |
| 1518 | if (($this->is_multisite && !empty($matches[1])) || !$this->is_multisite && $table == $import_table_prefix.'options') { |
| 1519 | |
| 1520 | if ($import_table_prefix != $old_table_prefix) { |
| 1521 | $updraftplus->log("Table prefix has changed: changing options table field(s) accordingly (".$matches[1]."options)"); |
| 1522 | echo sprintf(__('Table prefix has changed: changing %s table field(s) accordingly:', 'updraftplus'),'option').' '; |
| 1523 | if (false === $wpdb->query("UPDATE ${import_table_prefix}".$matches[1]."options SET option_name='${import_table_prefix}".$matches[1]."user_roles' WHERE option_name='${old_table_prefix}".$matches[1]."user_roles' LIMIT 1")) { |
| 1524 | echo __('Error','updraftplus'); |
| 1525 | $updraftplus->log("Error when changing options table fields"); |
| 1526 | } else { |
| 1527 | $updraftplus->log("Options table fields changed OK"); |
| 1528 | echo __('OK', 'updraftplus'); |
| 1529 | } |
| 1530 | echo '<br>'; |
| 1531 | |
| 1532 | // Now deal with the situation where the imported database sets a new over-ride upload_path that is absolute - which may not be wanted |
| 1533 | $new_upload_path = $wpdb->get_row($wpdb->prepare("SELECT option_value FROM ${import_table_prefix}".$matches[1]."options WHERE option_name = %s LIMIT 1", 'upload_path')); |
| 1534 | $new_upload_path = (is_object($new_upload_path)) ? $new_upload_path->option_value : ''; |
| 1535 | // The danger situation is absolute and points somewhere that is now perhaps not accessible at all |
| 1536 | if (!empty($new_upload_path) && $new_upload_path != $this->prior_upload_path && strpos($new_upload_path, '/') === 0) { |
| 1537 | if (!file_exists($new_upload_path)) { |
| 1538 | $updraftplus->log_e("Uploads path (%s) does not exist - resetting (%s)", $new_upload_path, $this->prior_upload_path); |
| 1539 | if (false === $wpdb->query("UPDATE ${import_table_prefix}".$matches[1]."options SET option_value='".esc_sql($this->prior_upload_path)."' WHERE option_name='upload_path' LIMIT 1")) { |
| 1540 | echo __('Error','updraftplus'); |
| 1541 | $updraftplus->log("Failed"); |
| 1542 | } |
| 1543 | #update_option('upload_path', $this->prior_upload_path); |
| 1544 | } |
| 1545 | } |
| 1546 | } |
| 1547 | |
| 1548 | # TODO: Do on all WPMU tables |
| 1549 | if ($table == $import_table_prefix.'options') { |
| 1550 | # Bad plugin that hard-codes path references - https://wordpress.org/plugins/custom-content-type-manager/ |
| 1551 | $cctm_data = $wpdb->get_row($wpdb->prepare("SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", 'cctm_data')); |
| 1552 | if (!empty($cctm_data->option_value)) { |
| 1553 | $cctm_data = maybe_unserialize($cctm_data->option_value); |
| 1554 | if (is_array($cctm_data) && !empty($cctm_data['cache']) && is_array($cctm_data['cache'])) { |
| 1555 | $cctm_data['cache'] = array(); |
| 1556 | $updraftplus->log_e("Custom content type manager plugin data detected: clearing option cache"); |
| 1557 | update_option('cctm_data', $cctm_data); |
| 1558 | } |
| 1559 | } |
| 1560 | # Another - http://www.elegantthemes.com/gallery/elegant-builder/ |
| 1561 | $elegant_data = $wpdb->get_row($wpdb->prepare("SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", 'et_images_temp_folder')); |
| 1562 | if (!empty($elegant_data->option_value)) { |
| 1563 | $dbase = basename($elegant_data->option_value); |
| 1564 | $wp_upload_dir = wp_upload_dir(); |
| 1565 | $edir = $wp_upload_dir['basedir']; |
| 1566 | if (!is_dir($edir.'/'.$dbase)) @mkdir($edir.'/'.$dbase); |
| 1567 | $updraftplus->log_e("Elegant themes theme builder plugin data detected: resetting temporary folder"); |
| 1568 | update_option('et_images_temp_folder', $edir.'/'.$dbase); |
| 1569 | } |
| 1570 | } |
| 1571 | } |
| 1572 | |
| 1573 | // } elseif (preg_match('/^([\d+]_)?usermeta/', substr($table, strlen($import_table_prefix)), $matches)) { |
| 1574 | } elseif ($table == $import_table_prefix.'usermeta') { |
| 1575 | |
| 1576 | # This table is not a per-site table, but per-install |
| 1577 | |
| 1578 | $updraftplus->log("Table prefix has changed: changing usermeta table field(s) accordingly"); |
| 1579 | echo sprintf(__('Table prefix has changed: changing %s table field(s) accordingly:', 'updraftplus'),'usermeta').' '; |
| 1580 | |
| 1581 | $um_sql = "SELECT umeta_id, meta_key |
| 1582 | FROM ${import_table_prefix}usermeta |
| 1583 | WHERE meta_key |
| 1584 | LIKE '".str_replace('_', '\_', $old_table_prefix)."%'"; |
| 1585 | |
| 1586 | $meta_keys = $wpdb->get_results($um_sql); |
| 1587 | |
| 1588 | $old_prefix_length = strlen($old_table_prefix); |
| 1589 | |
| 1590 | $errors_occurred = false; |
| 1591 | foreach ($meta_keys as $meta_key ) { |
| 1592 | //Create new meta key |
| 1593 | $new_meta_key = $import_table_prefix . substr($meta_key->meta_key, $old_prefix_length); |
| 1594 | |
| 1595 | $query = "UPDATE " . $import_table_prefix . "usermeta |
| 1596 | SET meta_key='".$new_meta_key."' |
| 1597 | WHERE umeta_id=".$meta_key->umeta_id; |
| 1598 | |
| 1599 | if (false === $wpdb->query($query)) $errors_occurred = true; |
| 1600 | } |
| 1601 | |
| 1602 | if ($errors_occurred) { |
| 1603 | $updraftplus->log("Error when changing usermeta table fields"); |
| 1604 | echo __('Error', 'updraftplus'); |
| 1605 | } else { |
| 1606 | $updraftplus->log("Usermeta table fields changed OK"); |
| 1607 | echo __('OK', 'updraftplus'); |
| 1608 | } |
| 1609 | echo "<br>"; |
| 1610 | |
| 1611 | } |
| 1612 | |
| 1613 | do_action('updraftplus_restored_db_table', $table, $import_table_prefix); |
| 1614 | |
| 1615 | // Re-generate permalinks. Do this last - i.e. make sure everything else is fixed up first. |
| 1616 | if ($table == $import_table_prefix.'options') $this->flush_rewrite_rules(); |
| 1617 | |
| 1618 | } |
| 1619 | |
| 1620 | } |
| 1621 | |
| 1622 | // The purpose of this is that, in a certain case, we want to forbid the "move" operation from doing a copy/delete if a direct move fails... because we have our own method for retrying (and don't want to risk copying a tonne of data if we can avoid it) |
| 1623 | if (!class_exists('WP_Filesystem_Direct')) { |
| 1624 | if (!class_exists('WP_Filesystem_Base')) require_once(ABSPATH.'wp-admin/includes/class-wp-filesystem-base.php'); |
| 1625 | require_once(ABSPATH.'wp-admin/includes/class-wp-filesystem-direct.php'); |
| 1626 | } |
| 1627 | class UpdraftPlus_WP_Filesystem_Direct extends WP_Filesystem_Direct { |
| 1628 | |
| 1629 | function move($source, $destination, $overwrite = false) { |
| 1630 | if ( ! $overwrite && $this->exists($destination) ) |
| 1631 | return false; |
| 1632 | |
| 1633 | // try using rename first. if that fails (for example, source is read only) try copy |
| 1634 | if ( @rename($source, $destination) ) |
| 1635 | return true; |
| 1636 | |
| 1637 | return false; |
| 1638 | } |
| 1639 | |
| 1640 | } |
| 1641 | |
| 1642 | if (!class_exists('WP_Upgrader_Skin')) require_once(ABSPATH.'wp-admin/includes/class-wp-upgrader.php'); |
| 1643 | class Updraft_Restorer_Skin extends WP_Upgrader_Skin { |
| 1644 | |
| 1645 | function header() {} |
| 1646 | function footer() {} |
| 1647 | function bulk_header() {} |
| 1648 | function bulk_footer() {} |
| 1649 | |
| 1650 | function error($error) { |
| 1651 | if (!$error) return; |
| 1652 | global $updraftplus; |
| 1653 | if (is_wp_error($error)) { |
| 1654 | $updraftplus->log_wp_error($error, true); |
| 1655 | } elseif (is_string($error)) { |
| 1656 | echo '<strong>'; |
| 1657 | $updraftplus->log_e($error); |
| 1658 | echo '</strong>'; |
| 1659 | } |
| 1660 | } |
| 1661 | |
| 1662 | function feedback($string) { |
| 1663 | |
| 1664 | if ( isset( $this->upgrader->strings[$string] ) ) |
| 1665 | $string = $this->upgrader->strings[$string]; |
| 1666 | |
| 1667 | if ( strpos($string, '%') !== false ) { |
| 1668 | $args = func_get_args(); |
| 1669 | $args = array_splice($args, 1); |
| 1670 | if ( $args ) { |
| 1671 | $args = array_map( 'strip_tags', $args ); |
| 1672 | $args = array_map( 'esc_html', $args ); |
| 1673 | $string = vsprintf($string, $args); |
| 1674 | } |
| 1675 | } |
| 1676 | if ( empty($string) ) return; |
| 1677 | |
| 1678 | global $updraftplus; |
| 1679 | $updraftplus->log_e($string); |
| 1680 | } |
| 1681 | } |
| 1682 | |
| 1683 | // Get a protected property |
| 1684 | class UpdraftPlus_WPDB extends wpdb { |
| 1685 | public function updraftplus_getdbh() { |
| 1686 | return $this->dbh; |
| 1687 | } |
| 1688 | public function updraftplus_use_mysqli() { |
| 1689 | return !empty($this->use_mysqli); |
| 1690 | } |
| 1691 | } |
| 1692 |