WP Clone by WP Academy - Version 2.2

Version Description

  • 2015-11-16 =
  • Fixed: Missing backups that some users encountered after upgrading to 2.1.9
  • Added: An option to refresh the backup list.
  • Added: An option to remove the database entry and delete all the backup files.
  • Added: A section that shows the uncompressed database size and the uncompressed size and the number of files that will be archived during a full backup.
  • Added: Notes in the advanced settings section regarding the Maximum memory limit and the Script execution time fields.
  • Added: The report returned from the search and replace process into the restore successful page.
  • Changed: Moved the backup list location from the custom table to the wp_options table. (previous backups will be imported and the custom table will be removed on existing installations)
  • Changed: Moved the system information block from the advanced settings section into the "normal" dashboard page.
  • Changed: Only the tables with the wordpress table prefix will be altered during a restore.
  • Changed: Only the tables with the wordpress table prefix will be saved during a backup.
  • Changed: Backup deletion is now handled using AJAX.
Download this release

Release Info

Developer wpacademy
Plugin Icon 128x128 WP Clone by WP Academy
Version 2.2
Comparing to
See all releases

Code changes from version 2.1.9 to 2.2

Files changed (6) hide show
  1. lib/css/style.css +72 -22
  2. lib/functions.php +272 -139
  3. lib/js/backupmanager.js +110 -0
  4. lib/view.php +66 -44
  5. readme.txt +22 -6
  6. wpclone.php +96 -29
lib/css/style.css CHANGED
@@ -1,12 +1,16 @@
1
  #wrapper {
2
- padding: 10px 0;
3
  }
4
 
5
  #MainView {
6
- padding: 10px;
7
- width: 800px;
8
- float: left;
9
- border-radius: 5px;
 
 
 
 
10
  }
11
 
12
  #sidebar {
@@ -49,20 +53,54 @@
49
  }
50
 
51
  div.info {
52
- padding: 15px;
53
- margin: 30px 0;
54
- width: 600px;
55
- background: #fea;
56
- border-radius: 5px;
57
- -moz-box-shadow: 5px 5px 15px #aaa;
58
- -webkit-box-shadow: 5px 5px 15px #aaa;
59
- box-shadow: 5px 5px 15px #aaa;
60
  }
61
 
62
- div.try .restore-backup-options {
63
  display: block;
64
  }
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  .btn-primary.active, .btn-warning.active, .btn-danger.active, .btn-success.active, .btn-info.active, .btn-inverse.active {
67
  color: rgba(255, 255, 255, 0.75);
68
  }
@@ -77,11 +115,11 @@ div.try .restore-backup-options {
77
 
78
  input[type="submit"].btn-primary {
79
  background-color: #006DCC;
80
- background-image: -moz-linear-gradient(top, #0088CC, #0044CC);
81
  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088CC), to(#0044CC));
82
- background-image: -webkit-linear-gradient(top, #0088CC, #0044CC);
83
- background-image: -o-linear-gradient(top, #0088CC, #0044CC);
84
- background-image: linear-gradient(to bottom, #0088CC, #0044CC);
85
  background-repeat: repeat-x;
86
  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
87
  color: #FFFFFF;
@@ -94,13 +132,14 @@ input[type="submit"].btn-primary:hover, input[type="submit"].btn-primary:active,
94
  }
95
  .btn-primary:active, .btn-primary.active {
96
  }
 
97
  input[type="submit"].btn-warning {
98
  background-color: #FAA732;
99
  background-image: linear-gradient(to bottom, #FBB450, #F89406);
100
  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#FBB450), to(#F89406));
101
- background-image: -webkit-linear-gradient(top, #FBB450, #F89406);
102
- background-image: -o-linear-gradient(top, #FBB450, #F89406);
103
- background-image: linear-gradient(to bottom, #FBB450, #F89406);
104
  background-repeat: repeat-x;
105
  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
106
  color: #FFFFFF;
@@ -110,11 +149,22 @@ input[type="submit"].btn-warning:hover, input[type="submit"].btn-warning:active,
110
  background-color: #F89406;
111
  color: #EEEEEE;
112
  }
 
 
 
 
 
 
 
 
 
 
 
113
  .btn-warning:active, .btn-warning.active {
114
  }
115
 
116
  .wpclone_notice {
117
- width: 500px;
118
  padding: 5px;
119
  margin: 25px 0 0 0;
120
  border-radius: 5px;
1
  #wrapper {
2
+
3
  }
4
 
5
  #MainView {
6
+ margin: 13px;
7
+ padding: 10px;
8
+ max-width: 60%;
9
+ float: left;
10
+ border-radius: 5px;
11
+ -moz-box-shadow: 5px 5px 15px #aaa;
12
+ -webkit-box-shadow: 5px 5px 15px #aaa;
13
+ box-shadow: 5px 5px 15px #aaa;
14
  }
15
 
16
  #sidebar {
53
  }
54
 
55
  div.info {
56
+ padding: 15px;
57
+ margin: 30px 0;
58
+ max-width: 60%;
59
+ background: #e1e1ea;
60
+ border-radius: 5px;
61
+ -moz-box-shadow: 5px 5px 15px #aaa;
62
+ -webkit-box-shadow: 5px 5px 15px #aaa;
63
+ box-shadow: 5px 5px 15px #aaa;
64
  }
65
 
66
+ div.try {
67
  display: block;
68
  }
69
 
70
+ table.restore-backup-options {
71
+ padding: 0 5px;
72
+ border-collapse: collapse;
73
+ }
74
+
75
+ table.restore-backup-options td, table.restore-backup-options th {
76
+ border: 1px solid #ccc;
77
+ padding: 3px;
78
+ }
79
+
80
+ .error {
81
+ border: solid 1px #c00;
82
+ padding: 5px;
83
+ background-color: #FFEBE8;
84
+ text-align: center;
85
+ border-radius: 5px;
86
+ -moz-box-shadow: 5px 5px 15px #aaa;
87
+ -webkit-box-shadow: 5px 5px 15px #aaa;
88
+ box-shadow: 5px 5px 15px #aaa;
89
+ }
90
+
91
+ .deleted {
92
+ background: #00cc99;
93
+ text-align: center;
94
+ }
95
+
96
+ .delete-error {
97
+ text-align: center;
98
+ background: #fff0b3;
99
+ }
100
+
101
+ a.copy-button {
102
+ }
103
+
104
  .btn-primary.active, .btn-warning.active, .btn-danger.active, .btn-success.active, .btn-info.active, .btn-inverse.active {
105
  color: rgba(255, 255, 255, 0.75);
106
  }
115
 
116
  input[type="submit"].btn-primary {
117
  background-color: #006DCC;
118
+ background-image: -moz-linear-gradient(top, #0088CC, #0044CC);
119
  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088CC), to(#0044CC));
120
+ background-image: -webkit-linear-gradient(top, #0088CC, #0044CC);
121
+ background-image: -o-linear-gradient(top, #0088CC, #0044CC);
122
+ background-image: linear-gradient(to bottom, #0088CC, #0044CC);
123
  background-repeat: repeat-x;
124
  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
125
  color: #FFFFFF;
132
  }
133
  .btn-primary:active, .btn-primary.active {
134
  }
135
+
136
  input[type="submit"].btn-warning {
137
  background-color: #FAA732;
138
  background-image: linear-gradient(to bottom, #FBB450, #F89406);
139
  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#FBB450), to(#F89406));
140
+ background-image: -webkit-linear-gradient(top, #FBB450, #F89406);
141
+ background-image: -o-linear-gradient(top, #FBB450, #F89406);
142
+ background-image: linear-gradient(to bottom, #FBB450, #F89406);
143
  background-repeat: repeat-x;
144
  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
145
  color: #FFFFFF;
149
  background-color: #F89406;
150
  color: #EEEEEE;
151
  }
152
+
153
+ textarea {
154
+ width: 100%;
155
+ padding: 0px
156
+ }
157
+
158
+ input.Url {
159
+ width: 80%;
160
+ padding: 0px
161
+ }
162
+
163
  .btn-warning:active, .btn-warning.active {
164
  }
165
 
166
  .wpclone_notice {
167
+ max-width: 500px;
168
  padding: 5px;
169
  margin: 25px 0 0 0;
170
  border-radius: 5px;
lib/functions.php CHANGED
@@ -19,13 +19,11 @@ function convertUrlIntoPath($url) {
19
  function wpa_db_backup_wpdb($destination)
20
  {
21
  global $wpdb;
22
- $WPCLONE_DB_ICONV_IN = "UTF-8";
23
- $WPCLONE_DB_ICONV_OUT = "ISO-8859-1//TRANSLIT";
24
 
25
  $return = '';
26
 
27
  // Get all of the tables
28
- $tables = $wpdb->get_col('SHOW TABLES');
29
  // Cycle through each provided table
30
  foreach ($tables as $table) {
31
 
@@ -36,6 +34,7 @@ function wpa_db_backup_wpdb($destination)
36
 
37
  // Second part of the output � create table
38
  $row2 = $wpdb->get_row("SHOW CREATE TABLE {$table}", ARRAY_N);
 
39
  $return .= "\n\n" . $row2[1] . ";\n\n";
40
 
41
  // Third part of the output � insert values into new table
@@ -45,7 +44,6 @@ function wpa_db_backup_wpdb($destination)
45
  $query = "INSERT INTO {$table} VALUES(";
46
 
47
  for ($j = 0; $j < $numberOfFields; $j++) {
48
- $row[$j] = iconv($WPCLONE_DB_ICONV_IN, $WPCLONE_DB_ICONV_OUT, $row[$j]);
49
  $query .= (empty($row[$j])) ? '"", ' : '"' . mysql_real_escape_string($row[$j]) . '", ';
50
  }
51
 
@@ -73,81 +71,92 @@ function wpa_db_backup_wpdb($destination)
73
  */
74
  function wpa_db_backup_direct($destination,$tables = '*')
75
  {
76
-
77
- $link = mysql_connect( DB_HOST, DB_USER, DB_PASSWORD );
78
- if ( false === $link ) {
79
- wpa_backup_error('db', mysql_error() );
80
- }
81
- mysql_select_db( DB_NAME, $link );
82
- mysql_set_charset(DB_CHARSET, $link);
83
- //get all of the tables
84
- if($tables == '*')
85
- {
86
- $tables = array();
87
- $result = mysql_query('SHOW TABLES');
88
- if ( false === $result ) {
89
- wpa_backup_error('db', mysql_error() );
90
- }
91
- while($row = mysql_fetch_row($result))
92
- {
93
- $tables[] = $row[0];
94
- }
95
- }
96
- else
97
- {
98
- $tables = is_array($tables) ? $tables : explode(',',$tables);
99
- }
100
- $return = '';
101
- //cycle through
102
- foreach($tables as $table)
103
- {
104
-
105
- $result = mysql_query('SELECT * FROM '.$table);
106
- if ( false === $result ) {
107
- wpa_backup_error('db', mysql_error() );
108
- }
109
- $num_fields = mysql_num_fields($result);
110
-
111
- $return.= 'DROP TABLE '.$table.';';
112
- $row2 = mysql_fetch_row(mysql_query('SHOW CREATE TABLE '.$table));
113
- $return.= "\n\n".$row2[1].";\n\n";
114
-
115
- for ($i = 0; $i < $num_fields; $i++)
116
- {
117
- while($row = mysql_fetch_row($result))
118
- {
119
- $return.= 'INSERT INTO '.$table.' VALUES(';
120
- for($j=0; $j<$num_fields; $j++)
121
- {
122
- $row[$j] = mysql_real_escape_string( $row[$j] );
123
- if (isset($row[$j])) { $return.= '"'.$row[$j].'"' ; } else { $return.= '""'; }
124
- if ($j<($num_fields-1)) { $return.= ','; }
125
- }
126
- $return.= ");\n";
127
- }
128
- }
129
- $return.="\n\n\n";
130
-
131
- }
132
- mysql_close($link);
133
- //save file
134
- $handle = fopen($destination . '/database.sql','w+');
135
- fwrite($handle,$return);
136
- fclose($handle);
137
  }
138
 
139
  function wpa_insert_data($name, $size)
140
  {
141
- global $wpdb;
 
142
  global $current_user;
143
- $wpdb->insert($wpdb->prefix . "wpclone", array(
144
- 'backup_name' => $name,
145
- 'data_time' => current_time('mysql', get_option('gmt_offset')),
146
- 'creator' => $current_user->user_login,
147
- 'backup_size' => $size)
 
148
  );
149
 
150
- $wpdb->flush();
 
 
 
 
 
 
 
 
 
151
  }
152
 
153
  function CreateWPFullBackupZip($backupName, $zipmode, $use_wpdb = false )
@@ -157,13 +166,13 @@ function CreateWPFullBackupZip($backupName, $zipmode, $use_wpdb = false )
157
  $zipFileName = WPCLONE_DIR_BACKUP . $backupName . '.zip';
158
  $exclude = wpa_excluded_dirs();
159
  $dbonly = isset( $_POST['dbonly'] ) && 'true' == $_POST['dbonly'] ? true : false;
160
-
161
  if( false === mkdir( $folderToBeZipped ) )
162
  wpa_backup_error ( 'file', sprintf( __( 'Unable to create the temporary backup directory,please make sure that PHP has permission to write into the <code>%s</code> directory.' ), WPCLONE_DIR_BACKUP ) );
163
-
164
  if( false === $dbonly )
165
  wpa_copy_dir( untrailingslashit( WPCLONE_WP_CONTENT ), $destinationPath, $exclude);
166
-
167
  wpa_save_prefix($folderToBeZipped);
168
  /* error handler is called from within the db backup functions */
169
  if ( $use_wpdb ) {
@@ -171,7 +180,7 @@ function CreateWPFullBackupZip($backupName, $zipmode, $use_wpdb = false )
171
  } else {
172
  wpa_db_backup_direct( $folderToBeZipped );
173
  }
174
-
175
  /* error haldler is called from within the wpa_zip function */
176
  wpa_zip($zipFileName, $folderToBeZipped, $zipmode);
177
  $zipSize = filesize($zipFileName);
@@ -181,13 +190,36 @@ function CreateWPFullBackupZip($backupName, $zipmode, $use_wpdb = false )
181
 
182
  function DeleteWPBackupZip($nm)
183
  {
184
- global $wpdb;
185
- $wp_backup = "{$wpdb->prefix}wpclone";
186
- $deleteRow = $wpdb->get_row("SELECT * FROM {$wp_backup} WHERE id = '{$nm}'");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
 
188
- $wpdb->query("DELETE FROM {$wp_backup} WHERE id = '{$nm}' ");
189
- if (file_exists(WPCLONE_DIR_BACKUP . $deleteRow->backup_name)) unlink(WPCLONE_DIR_BACKUP . $deleteRow->backup_name) or die ('unable to delete backup file.');
190
- return $deleteRow;
191
  }
192
 
193
  function bytesToSize($bytes, $precision = 2)
@@ -230,23 +262,17 @@ function processConfigAndDatabaseFile($databaseFileInZip)
230
  if ( false === $dbFileContent ) {
231
  wpa_backup_error( 'dbrest', sprintf ( __( 'Cannot read <code>%s</code>' ), $databaseFileInZip ) , true );
232
  }
233
-
234
-
235
  $conn = mysql_connect( DB_HOST, DB_USER, DB_PASSWORD );
236
  /* and we cannot nuke the db if the connection failed now can we */
237
  if ( false === $conn ) {
238
  wpa_backup_error('dbrest', __( 'database connection failed' ), true );
239
  }
240
-
241
  mysql_select_db( DB_NAME, $conn);
242
  mysql_set_charset(DB_CHARSET, $conn);
243
- $query = mysql_query("SHOW TABLES", $conn);
244
- /* point of no return,if it fails after this you're royally boned ;) */
245
- while (($fetch = mysql_fetch_array($query))) {
246
- mysql_query("Drop table `{$fetch[0]}`");
247
- }
248
- flush();
249
-
250
  $res = explode(";\n", $dbFileContent);
251
  foreach ($res AS $query) {
252
  mysql_query($query, $conn);
@@ -256,9 +282,9 @@ function processConfigAndDatabaseFile($databaseFileInZip)
256
  $currentSiteUrl = site_url();
257
  $backupSiteUrl = untrailingslashit($backupSiteUrl);
258
  $currentSiteUrl = untrailingslashit($currentSiteUrl);
259
- wpa_safe_replace_wrapper ( $backupSiteUrl, $currentSiteUrl );
260
-
261
- return $currentSiteUrl;
262
  }
263
 
264
  /**
@@ -270,30 +296,32 @@ function wpa_safe_replace_wrapper ( $search, $replace ) {
270
  if ( !function_exists( 'icit_srdb_replacer' ) && !function_exists( 'recursive_unserialize_replace' ) ) {
271
  require_once 'icit_srdb_replacer.php';
272
  }
 
273
  $connection = @mysql_connect( DB_HOST, DB_USER, DB_PASSWORD );
274
- $all_tables = array( );
275
  @mysql_select_db( DB_NAME, $connection );
276
- $all_tables_mysql = @mysql_query( 'SHOW TABLES', $connection );
 
277
 
278
  if ( ! $all_tables_mysql ) {
279
  wpa_backup_error( 'dbrest', mysql_error(), true );
280
  } else {
281
- while ( $table = mysql_fetch_array( $all_tables_mysql ) ) {
282
- $all_tables[] = $table[ 0 ];
283
- }
284
  }
285
 
286
  $report = icit_srdb_replacer( $connection, $search, $replace, $all_tables );
287
  return $report;
288
- }
289
-
290
 
291
  function processRestoringBackup($url, $zipmode) {
292
  wpa_cleanup( true );
293
  if (!is_string($url) || '' == $url) {
294
  wpa_backup_error( 'restore', sprintf( __( 'The provided URL "<code>%s</code>" is either not valid or empty' ), $url ), true );
295
  }
296
-
297
  global $wp_filesystem;
298
  $temp_dir = trailingslashit( WPCLONE_WP_CONTENT ) . 'wpclone-temp';
299
  $temp_dir_err = $wp_filesystem->mkdir( $temp_dir );
@@ -309,13 +337,13 @@ function processRestoringBackup($url, $zipmode) {
309
  if ( ! $wp_filesystem->is_dir( $unzippedFolderPath ) ) {
310
  $unzippedFolderPath = wpCloneSafePathMode( trailingslashit( $temp_dir ) . $pathParts['filename'] );
311
  }
312
-
313
  /* if we're here then the file extraction worked,but let's make doubly sure */
314
  if( ! $wp_filesystem->is_dir( $unzippedFolderPath ) ) {
315
  wpa_backup_error( 'restore', sprintf( __( 'Cannot find <code>%s<code>' ), $unzippedFolderPath ), true );
316
  }
317
  /* check the table prefixes */
318
- $old_db_prefix = $unzippedFolderPath . '/prefix.txt';
319
  $prefix = wpa_check_prefix($old_db_prefix);
320
  if ($prefix) {
321
  wpa_replace_prefix( $prefix );
@@ -328,8 +356,8 @@ function processRestoringBackup($url, $zipmode) {
328
  $wp_filesystem->delete( $databaseFile );
329
 
330
  wpa_copy( $unzippedFolderPath . '/wp-content', WPCLONE_WP_CONTENT );
331
-
332
-
333
  $wp_filesystem->delete( $temp_dir, true );
334
  /* remove the zip file only if it was downloaded from an external location. */
335
  $wptmp = explode('.', $zipFilename);
@@ -337,11 +365,28 @@ function processRestoringBackup($url, $zipmode) {
337
  $wp_filesystem->delete( $zipFilename );
338
  }
339
 
340
- echo "<h1>Restore Successful!</h1>";
 
 
341
 
342
- echo "Visit your restored site [ <a href='{$currentSiteUrl}' target=blank>here</a> ]<br><br>";
343
 
344
- echo "<strong>You may need to re-save your permalink structure <a href='{$currentSiteUrl}/wp-admin/options-permalink.php' target=blank>Here</a></strong>";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
 
346
  } else {
347
 
@@ -383,7 +428,7 @@ function wpa_check_prefix($file) {
383
 
384
  /**
385
  * @since 2.0.6
386
- *
387
  * @param type $zipfile path to the zip file that needs to be extracted.
388
  * @param type $path the place to where the file needs to be extracted.
389
  * @return as false in the event of failure.
@@ -400,9 +445,9 @@ function wpa_unzip($zipfile, $path, $zipmode = false){
400
  require_once ( ABSPATH . 'wp-admin/includes/class-pclzip.php' );
401
  $z = new PclZip($zipfile);
402
  $files = $z->extract(PCLZIP_OPT_PATH, $path);
403
-
404
  if ( isset($previous_encoding) ) mb_internal_encoding($previous_encoding);
405
-
406
  if ( $files == 0 ) {
407
  wpa_backup_error( 'pclunzip', $z->errorInfo(true), true );
408
  }
@@ -418,7 +463,7 @@ function wpa_unzip($zipfile, $path, $zipmode = false){
418
  }
419
  /**
420
  * @since 2.0.6
421
- *
422
  * @param type $name name of the zip file.
423
  * @param type $file_list an array of files that needs to be archived.
424
  */
@@ -441,7 +486,7 @@ function wpa_zip($zip_name, $folder, $zipmode = false){
441
  }
442
  }
443
 
444
- function wpa_ziparc($zip, $dir, $base) {
445
  $new_folder = str_replace($base, '', $dir);
446
  $zip->addEmptyDir($new_folder);
447
  foreach( glob( $dir . '/*' ) as $file ){
@@ -467,20 +512,20 @@ function wpa_bump_limits(){
467
  * @since 2.0.6
468
  */
469
  function wpa_wpfs_init(){
470
- if (!empty($_REQUEST['del'])) {
471
- wpa_remove_backup();
472
  return true;
473
  }
474
  if (empty($_POST)) return false;
475
  check_admin_referer('wpclone-submit');
476
-
477
  wpa_bump_limits();
478
-
479
  if (isset($_POST['createBackup'])) {
480
  wpa_create_backup();
481
  return true;
482
  }
483
-
484
  $form_post = wp_nonce_url('admin.php?page=wp-clone', 'wpclone-submit');
485
  $extra_fields = array( 'restore_from_url', 'maxmem', 'maxexec', 'zipmode', 'restoreBackup', 'createBackup' );
486
  $type = '';
@@ -490,8 +535,8 @@ function wpa_wpfs_init(){
490
  if (!WP_Filesystem($creds)) {
491
  request_filesystem_credentials($form_post, $type, true, false, $extra_fields);
492
  return true;
493
- }
494
-
495
  $zipmode = isset($_POST['zipmode']) ? true : false;
496
  $url = isset($_POST['restoreBackup']) ? $_POST['restoreBackup'] : $_POST['restore_from_url'];
497
  processRestoringBackup($url, $zipmode);
@@ -532,12 +577,12 @@ function wpa_copy($source, $target) {
532
  function wpa_replace_prefix($newPrefix){
533
  $wpconfig = wpa_wpconfig_path();
534
  global $wp_filesystem;
535
-
536
  if ( ! $wp_filesystem->is_writable($wpconfig) ) {
537
  if( false === $wp_filesystem->chmod( $wpconfig ) )
538
  wpa_backup_error('wpconfig', sprintf( __( "<code>%s</code> is not writable and wpclone was unable to change the file permissions." ), $wpconfig ), true );
539
  }
540
-
541
  $fileContent = $wp_filesystem->get_contents($wpconfig);
542
  $pos = strpos($fileContent, '$table_prefix');
543
  $str = substr($fileContent, $pos, strpos($fileContent, PHP_EOL, $pos) - $pos);
@@ -584,13 +629,8 @@ EOF;
584
  function wpa_remove_backup(){
585
  check_admin_referer('wpclone-submit');
586
  $deleteRow = DeleteWPBackupZip($_REQUEST['del']);
587
- echo <<<EOT
588
- <h1>Deleted Successful!</h1> <br />
589
 
590
- {$deleteRow->backup_name} <br />
591
-
592
- File deleted from backup folder and database...
593
- EOT;
594
  }
595
  /**
596
  * @since 2.1.2
@@ -598,13 +638,13 @@ EOT;
598
  * @return the path to wp-config.php
599
  */
600
  function wpa_wpconfig_path () {
601
-
602
  if ( file_exists( ABSPATH . 'wp-config.php') ) {
603
-
604
  /** The config file resides in ABSPATH */
605
  return ABSPATH . 'wp-config.php';
606
 
607
- }
608
  elseif ( file_exists( dirname(ABSPATH) . '/wp-config.php' ) && ! file_exists( dirname(ABSPATH) . '/wp-settings.php' ) ) {
609
 
610
  /** The config file resides one level above ABSPATH but is not part of another install */
@@ -612,9 +652,9 @@ function wpa_wpconfig_path () {
612
 
613
  }
614
  else {
615
-
616
  return false;
617
-
618
  }
619
 
620
  }
@@ -641,9 +681,9 @@ function wpa_backup_name() {
641
  }
642
 
643
  function wpa_backup_error($error, $data, $restore = false) {
644
-
645
  $temp_dir = $restore ? trailingslashit( WPCLONE_WP_CONTENT ) . 'wpclone-temp' : trailingslashit( WPCLONE_DIR_BACKUP ) . 'wpclone_backup';
646
-
647
  if( !file_exists( $temp_dir ) ) {
648
  unset($temp_dir);
649
  }
@@ -688,7 +728,7 @@ function wpa_backup_error($error, $data, $restore = false) {
688
  default :
689
  $error = sprintf( __( 'during the %s process' ), $error );
690
  endswitch;
691
-
692
  echo '<div class="wpclone_notice updated">';
693
  printf( __( 'The plugin encountered an error %s,the following error message was returned:</br>' ), $error );
694
  echo '<div class="error">' . __( 'Error Message : ' ) . $data . '</div></br>';
@@ -772,7 +812,7 @@ function wpa_excluded_dirs() {
772
  foreach( explode( "\n", $_POST['exclude'] ) as $ex ) {
773
  $ex = trim( $ex );
774
  if( '' !== $ex ) {
775
- $ex = trim( $ex, "/\\" );
776
  $exclude[] = trailingslashit( WPCLONE_WP_CONTENT ) . str_replace( '\\', '/', $ex ) ;
777
  }
778
  }
@@ -780,4 +820,97 @@ function wpa_excluded_dirs() {
780
  return $exclude;
781
  }
782
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
783
  /* end of file */
19
  function wpa_db_backup_wpdb($destination)
20
  {
21
  global $wpdb;
 
 
22
 
23
  $return = '';
24
 
25
  // Get all of the tables
26
+ $tables = $wpdb->get_col('SHOW TABLES LIKE "' . $wpdb->prefix . '%"');
27
  // Cycle through each provided table
28
  foreach ($tables as $table) {
29
 
34
 
35
  // Second part of the output � create table
36
  $row2 = $wpdb->get_row("SHOW CREATE TABLE {$table}", ARRAY_N);
37
+ $return.= 'DROP TABLE IF EXISTS '.$table.';';
38
  $return .= "\n\n" . $row2[1] . ";\n\n";
39
 
40
  // Third part of the output � insert values into new table
44
  $query = "INSERT INTO {$table} VALUES(";
45
 
46
  for ($j = 0; $j < $numberOfFields; $j++) {
 
47
  $query .= (empty($row[$j])) ? '"", ' : '"' . mysql_real_escape_string($row[$j]) . '", ';
48
  }
49
 
71
  */
72
  function wpa_db_backup_direct($destination,$tables = '*')
73
  {
74
+
75
+ global $wpdb;
76
+ $link = mysql_connect( DB_HOST, DB_USER, DB_PASSWORD );
77
+ if ( false === $link ) {
78
+ wpa_backup_error('db', mysql_error() );
79
+ }
80
+ mysql_select_db( DB_NAME, $link );
81
+ mysql_set_charset(DB_CHARSET, $link);
82
+ //get all of the tables
83
+ if($tables == '*')
84
+ {
85
+ $tables = array();
86
+ $result = mysql_query('SHOW TABLES LIKE "' . $wpdb->prefix . '%"');
87
+ if ( false === $result ) {
88
+ wpa_backup_error('db', mysql_error() );
89
+ }
90
+ while($row = mysql_fetch_row($result))
91
+ {
92
+ $tables[] = $row[0];
93
+ }
94
+ }
95
+ else
96
+ {
97
+ $tables = is_array($tables) ? $tables : explode(',',$tables);
98
+ }
99
+ $return = '';
100
+ //cycle through
101
+ foreach($tables as $table)
102
+ {
103
+
104
+ $result = mysql_query('SELECT * FROM '.$table);
105
+ if ( false === $result ) {
106
+ wpa_backup_error('db', mysql_error() );
107
+ }
108
+ $num_fields = mysql_num_fields($result);
109
+
110
+ $return.= 'DROP TABLE IF EXISTS '.$table.';';
111
+ $row2 = mysql_fetch_row(mysql_query('SHOW CREATE TABLE '.$table));
112
+ $return.= "\n\n".$row2[1].";\n\n";
113
+
114
+ for ($i = 0; $i < $num_fields; $i++)
115
+ {
116
+ while($row = mysql_fetch_row($result))
117
+ {
118
+ $return.= 'INSERT INTO '.$table.' VALUES(';
119
+ for($j=0; $j<$num_fields; $j++)
120
+ {
121
+ $row[$j] = mysql_real_escape_string( $row[$j] );
122
+ if (isset($row[$j])) { $return.= '"'.$row[$j].'"' ; } else { $return.= '""'; }
123
+ if ($j<($num_fields-1)) { $return.= ','; }
124
+ }
125
+ $return.= ");\n";
126
+ }
127
+ }
128
+ $return.="\n\n\n";
129
+
130
+ }
131
+ //save file
132
+ $handle = fopen($destination . '/database.sql','w+');
133
+ fwrite($handle,$return);
134
+ fclose($handle);
135
  }
136
 
137
  function wpa_insert_data($name, $size)
138
  {
139
+ $backups = get_option( 'wpclone_backups' );
140
+ $time = current_time( 'timestamp', get_option('gmt_offset') );
141
  global $current_user;
142
+ $backup = array(
143
+ $time => array(
144
+ 'name' => $name,
145
+ 'creator' => $current_user->user_login,
146
+ 'size' => $size
147
+ )
148
  );
149
 
150
+ if( false === $backups ) {
151
+ add_option( 'wpclone_backups', $backup );
152
+ return;
153
+ }
154
+
155
+ $backups = $backups + $backup;
156
+ update_option( 'wpclone_backups', $backups );
157
+
158
+ return;
159
+
160
  }
161
 
162
  function CreateWPFullBackupZip($backupName, $zipmode, $use_wpdb = false )
166
  $zipFileName = WPCLONE_DIR_BACKUP . $backupName . '.zip';
167
  $exclude = wpa_excluded_dirs();
168
  $dbonly = isset( $_POST['dbonly'] ) && 'true' == $_POST['dbonly'] ? true : false;
169
+
170
  if( false === mkdir( $folderToBeZipped ) )
171
  wpa_backup_error ( 'file', sprintf( __( 'Unable to create the temporary backup directory,please make sure that PHP has permission to write into the <code>%s</code> directory.' ), WPCLONE_DIR_BACKUP ) );
172
+
173
  if( false === $dbonly )
174
  wpa_copy_dir( untrailingslashit( WPCLONE_WP_CONTENT ), $destinationPath, $exclude);
175
+
176
  wpa_save_prefix($folderToBeZipped);
177
  /* error handler is called from within the db backup functions */
178
  if ( $use_wpdb ) {
180
  } else {
181
  wpa_db_backup_direct( $folderToBeZipped );
182
  }
183
+
184
  /* error haldler is called from within the wpa_zip function */
185
  wpa_zip($zipFileName, $folderToBeZipped, $zipmode);
186
  $zipSize = filesize($zipFileName);
190
 
191
  function DeleteWPBackupZip($nm)
192
  {
193
+ $backups = get_option( 'wpclone_backups' );
194
+
195
+ if( empty( $backups ) || ! isset( $backups[$nm] ) ) {
196
+ return array(
197
+ 'status' => 'failed',
198
+ 'msg' => 'Something is not quite right here, please try again later.' );
199
+ }
200
+
201
+ if ( file_exists( WPCLONE_DIR_BACKUP . $backups[$nm]['name'] ) ) {
202
+
203
+ if( ! unlink( WPCLONE_DIR_BACKUP . $backups[$nm]['name'] ) ) {
204
+ return array(
205
+ 'status' => 'failed',
206
+ 'msg' => 'Unable to delete file' );
207
+ }
208
+
209
+ unset( $backups[$nm] );
210
+ update_option( 'wpclone_backups', $backups );
211
+ return array(
212
+ 'status' => 'deleted',
213
+ 'msg' => 'File deleted' );
214
+
215
+ } else {
216
+
217
+ return array(
218
+ 'status' => 'failed',
219
+ 'msg' => 'File not found. Refresh the backup list to remove missing backups.' );
220
+
221
+ }
222
 
 
 
 
223
  }
224
 
225
  function bytesToSize($bytes, $precision = 2)
262
  if ( false === $dbFileContent ) {
263
  wpa_backup_error( 'dbrest', sprintf ( __( 'Cannot read <code>%s</code>' ), $databaseFileInZip ) , true );
264
  }
265
+
266
+
267
  $conn = mysql_connect( DB_HOST, DB_USER, DB_PASSWORD );
268
  /* and we cannot nuke the db if the connection failed now can we */
269
  if ( false === $conn ) {
270
  wpa_backup_error('dbrest', __( 'database connection failed' ), true );
271
  }
272
+
273
  mysql_select_db( DB_NAME, $conn);
274
  mysql_set_charset(DB_CHARSET, $conn);
275
+
 
 
 
 
 
 
276
  $res = explode(";\n", $dbFileContent);
277
  foreach ($res AS $query) {
278
  mysql_query($query, $conn);
282
  $currentSiteUrl = site_url();
283
  $backupSiteUrl = untrailingslashit($backupSiteUrl);
284
  $currentSiteUrl = untrailingslashit($currentSiteUrl);
285
+ $report = wpa_safe_replace_wrapper ( $backupSiteUrl, $currentSiteUrl );
286
+
287
+ return array( 'url' => $currentSiteUrl, 'report' => $report );
288
  }
289
 
290
  /**
296
  if ( !function_exists( 'icit_srdb_replacer' ) && !function_exists( 'recursive_unserialize_replace' ) ) {
297
  require_once 'icit_srdb_replacer.php';
298
  }
299
+ global $wpdb;
300
  $connection = @mysql_connect( DB_HOST, DB_USER, DB_PASSWORD );
301
+ $all_tables = array();
302
  @mysql_select_db( DB_NAME, $connection );
303
+ mysql_set_charset( DB_CHARSET, $connection );
304
+ $all_tables_mysql = @mysql_query( 'SHOW TABLES LIKE "' . $wpdb->prefix . '%"', $connection );
305
 
306
  if ( ! $all_tables_mysql ) {
307
  wpa_backup_error( 'dbrest', mysql_error(), true );
308
  } else {
309
+ while ( $table = mysql_fetch_array( $all_tables_mysql ) ) {
310
+ $all_tables[] = $table[ 0 ];
311
+ }
312
  }
313
 
314
  $report = icit_srdb_replacer( $connection, $search, $replace, $all_tables );
315
  return $report;
316
+ }
317
+
318
 
319
  function processRestoringBackup($url, $zipmode) {
320
  wpa_cleanup( true );
321
  if (!is_string($url) || '' == $url) {
322
  wpa_backup_error( 'restore', sprintf( __( 'The provided URL "<code>%s</code>" is either not valid or empty' ), $url ), true );
323
  }
324
+
325
  global $wp_filesystem;
326
  $temp_dir = trailingslashit( WPCLONE_WP_CONTENT ) . 'wpclone-temp';
327
  $temp_dir_err = $wp_filesystem->mkdir( $temp_dir );
337
  if ( ! $wp_filesystem->is_dir( $unzippedFolderPath ) ) {
338
  $unzippedFolderPath = wpCloneSafePathMode( trailingslashit( $temp_dir ) . $pathParts['filename'] );
339
  }
340
+
341
  /* if we're here then the file extraction worked,but let's make doubly sure */
342
  if( ! $wp_filesystem->is_dir( $unzippedFolderPath ) ) {
343
  wpa_backup_error( 'restore', sprintf( __( 'Cannot find <code>%s<code>' ), $unzippedFolderPath ), true );
344
  }
345
  /* check the table prefixes */
346
+ $old_db_prefix = $unzippedFolderPath . '/prefix.txt';
347
  $prefix = wpa_check_prefix($old_db_prefix);
348
  if ($prefix) {
349
  wpa_replace_prefix( $prefix );
356
  $wp_filesystem->delete( $databaseFile );
357
 
358
  wpa_copy( $unzippedFolderPath . '/wp-content', WPCLONE_WP_CONTENT );
359
+
360
+
361
  $wp_filesystem->delete( $temp_dir, true );
362
  /* remove the zip file only if it was downloaded from an external location. */
363
  $wptmp = explode('.', $zipFilename);
365
  $wp_filesystem->delete( $zipFilename );
366
  }
367
 
368
+ echo "<div><h1>Restore Successful!</h1>";
369
+
370
+ echo "Visit your restored site [ <a href='{$currentSiteUrl['url']}' target=blank>here</a> ]<br><br>";
371
 
372
+ echo "<strong>You may need to re-save your permalink structure <a href='{$currentSiteUrl['url']}/wp-admin/options-permalink.php' target=blank>Here</a></strong>";
373
 
374
+ $report = $currentSiteUrl['report'];
375
+ /* copy pasta (more or less) from serialized search and replace script by interconnectit */
376
+ $time = array_sum( explode( ' ', $report[ 'end' ] ) ) - array_sum( explode( ' ', $report[ 'start' ] ) );
377
+ printf( '<div class="info"><p>Search and replace scanned <strong>%d</strong> tables with a total of <strong>%d</strong> rows, ' , $report['tables'], $report['rows'] );
378
+ printf( '<strong>%d</strong> cells were changed and <strong>%d</strong> db updates were performed. it took <strong>%f</strong> seconds.</p></div>', $report['change'], $report['updates'], $time );
379
+
380
+
381
+ if ( ! empty( $report['errors'] ) && is_array( $report['errors'] ) ) {
382
+ echo '<div class="error">';
383
+ echo '<h3>The following errors were encountered during the search and replace process.</h3>';
384
+ foreach( $report['errors'] as $error )
385
+ echo '<p>' . $error . '</p>';
386
+ echo '</div>';
387
+ }
388
+
389
+ echo '</div>';
390
 
391
  } else {
392
 
428
 
429
  /**
430
  * @since 2.0.6
431
+ *
432
  * @param type $zipfile path to the zip file that needs to be extracted.
433
  * @param type $path the place to where the file needs to be extracted.
434
  * @return as false in the event of failure.
445
  require_once ( ABSPATH . 'wp-admin/includes/class-pclzip.php' );
446
  $z = new PclZip($zipfile);
447
  $files = $z->extract(PCLZIP_OPT_PATH, $path);
448
+
449
  if ( isset($previous_encoding) ) mb_internal_encoding($previous_encoding);
450
+
451
  if ( $files == 0 ) {
452
  wpa_backup_error( 'pclunzip', $z->errorInfo(true), true );
453
  }
463
  }
464
  /**
465
  * @since 2.0.6
466
+ *
467
  * @param type $name name of the zip file.
468
  * @param type $file_list an array of files that needs to be archived.
469
  */
486
  }
487
  }
488
 
489
+ function wpa_ziparc($zip, $dir, $base) {
490
  $new_folder = str_replace($base, '', $dir);
491
  $zip->addEmptyDir($new_folder);
492
  foreach( glob( $dir . '/*' ) as $file ){
512
  * @since 2.0.6
513
  */
514
  function wpa_wpfs_init(){
515
+ if (!empty($_REQUEST['del'])) {
516
+ wpa_remove_backup();
517
  return true;
518
  }
519
  if (empty($_POST)) return false;
520
  check_admin_referer('wpclone-submit');
521
+
522
  wpa_bump_limits();
523
+
524
  if (isset($_POST['createBackup'])) {
525
  wpa_create_backup();
526
  return true;
527
  }
528
+
529
  $form_post = wp_nonce_url('admin.php?page=wp-clone', 'wpclone-submit');
530
  $extra_fields = array( 'restore_from_url', 'maxmem', 'maxexec', 'zipmode', 'restoreBackup', 'createBackup' );
531
  $type = '';
535
  if (!WP_Filesystem($creds)) {
536
  request_filesystem_credentials($form_post, $type, true, false, $extra_fields);
537
  return true;
538
+ }
539
+
540
  $zipmode = isset($_POST['zipmode']) ? true : false;
541
  $url = isset($_POST['restoreBackup']) ? $_POST['restoreBackup'] : $_POST['restore_from_url'];
542
  processRestoringBackup($url, $zipmode);
577
  function wpa_replace_prefix($newPrefix){
578
  $wpconfig = wpa_wpconfig_path();
579
  global $wp_filesystem;
580
+
581
  if ( ! $wp_filesystem->is_writable($wpconfig) ) {
582
  if( false === $wp_filesystem->chmod( $wpconfig ) )
583
  wpa_backup_error('wpconfig', sprintf( __( "<code>%s</code> is not writable and wpclone was unable to change the file permissions." ), $wpconfig ), true );
584
  }
585
+
586
  $fileContent = $wp_filesystem->get_contents($wpconfig);
587
  $pos = strpos($fileContent, '$table_prefix');
588
  $str = substr($fileContent, $pos, strpos($fileContent, PHP_EOL, $pos) - $pos);
629
  function wpa_remove_backup(){
630
  check_admin_referer('wpclone-submit');
631
  $deleteRow = DeleteWPBackupZip($_REQUEST['del']);
632
+ echo $deleteRow['msg'];
 
633
 
 
 
 
 
634
  }
635
  /**
636
  * @since 2.1.2
638
  * @return the path to wp-config.php
639
  */
640
  function wpa_wpconfig_path () {
641
+
642
  if ( file_exists( ABSPATH . 'wp-config.php') ) {
643
+
644
  /** The config file resides in ABSPATH */
645
  return ABSPATH . 'wp-config.php';
646
 
647
+ }
648
  elseif ( file_exists( dirname(ABSPATH) . '/wp-config.php' ) && ! file_exists( dirname(ABSPATH) . '/wp-settings.php' ) ) {
649
 
650
  /** The config file resides one level above ABSPATH but is not part of another install */
652
 
653
  }
654
  else {
655
+
656
  return false;
657
+
658
  }
659
 
660
  }
681
  }
682
 
683
  function wpa_backup_error($error, $data, $restore = false) {
684
+
685
  $temp_dir = $restore ? trailingslashit( WPCLONE_WP_CONTENT ) . 'wpclone-temp' : trailingslashit( WPCLONE_DIR_BACKUP ) . 'wpclone_backup';
686
+
687
  if( !file_exists( $temp_dir ) ) {
688
  unset($temp_dir);
689
  }
728
  default :
729
  $error = sprintf( __( 'during the %s process' ), $error );
730
  endswitch;
731
+
732
  echo '<div class="wpclone_notice updated">';
733
  printf( __( 'The plugin encountered an error %s,the following error message was returned:</br>' ), $error );
734
  echo '<div class="error">' . __( 'Error Message : ' ) . $data . '</div></br>';
812
  foreach( explode( "\n", $_POST['exclude'] ) as $ex ) {
813
  $ex = trim( $ex );
814
  if( '' !== $ex ) {
815
+ $ex = trim( $ex, "/\\" );
816
  $exclude[] = trailingslashit( WPCLONE_WP_CONTENT ) . str_replace( '\\', '/', $ex ) ;
817
  }
818
  }
820
  return $exclude;
821
  }
822
 
823
+ function wpa_wpc_dir_size( $path ) {
824
+
825
+ $i = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $path ) );
826
+ $size = 0;
827
+ $files = 0;
828
+
829
+ foreach( $i as $file => $info ) {
830
+
831
+ if( ! strpos( $file, 'wp-clone' ) ) {
832
+ $size += $info->getSize();
833
+ $files++;
834
+
835
+ }
836
+
837
+ }
838
+
839
+ return array( 'size' => size_format( $size ), 'files' => $files );
840
+
841
+ }
842
+
843
+ function wpa_wpc_db_size() {
844
+
845
+ global $wpdb;
846
+ $sql = 'SELECT sum(data_length + index_length) FROM information_schema.TABLES WHERE table_schema = "' . DB_NAME . '"';
847
+ $size = $wpdb->get_var( $sql );
848
+ return size_format( $size );
849
+
850
+ }
851
+
852
+ function wpa_wpc_scan_dir() {
853
+
854
+ $backups = get_option( 'wpclone_backups' );
855
+ $backup_list = array();
856
+ $files = array();
857
+ $old_backups = array();
858
+
859
+ foreach( glob( WPCLONE_DIR_BACKUP . '*.zip' ) as $file ){
860
+
861
+ $files[] = str_replace( WPCLONE_DIR_BACKUP, '', $file );
862
+
863
+ }
864
+
865
+ if( false === $backups ) {
866
+ $backups = array();
867
+ }
868
+
869
+ foreach( $backups as $key => $backup ) {
870
+
871
+ if( ! file_exists( WPCLONE_DIR_BACKUP . $backup['name'] ) ) {
872
+ unset( $backups[$key] );
873
+ continue;
874
+ }
875
+ $backup_list[] = $backup['name'];
876
+
877
+ }
878
+
879
+
880
+ $list = wpa_wpc_filter_list( $files, $backup_list );
881
+
882
+ if( ! empty( $list ) ) {
883
+
884
+ foreach( $list as $backup ) {
885
+
886
+ $time = strtotime( substr( str_replace( array( 'wpclone_backup_', '_', '-' ), array( '', ' ', ':' ), $backup ), 0, 21 ) ) + rand(1, 60);
887
+ $old_backups[$time] = array(
888
+ 'name' => $backup,
889
+ 'creator' => 'dirscan',
890
+ 'size' => @filesize( WPCLONE_DIR_BACKUP . $backup )
891
+ );
892
+
893
+ }
894
+
895
+ }
896
+
897
+ $backups = $backups + $old_backups;
898
+ ksort( $backups );
899
+ update_option( 'wpclone_backups', $backups );
900
+
901
+ }
902
+
903
+ /*
904
+ * @link http://stackoverflow.com/questions/2479963/how-does-array-diff-work/6700430#6700430
905
+ */
906
+ function wpa_wpc_filter_list( $a, $b ) {
907
+
908
+ $return = array();
909
+ foreach( $a as $v ) $return[$v] = '';
910
+ foreach( $b as $v ) unset( $return[$v] );
911
+ return array_keys( $return );
912
+
913
+ }
914
+
915
+
916
  /* end of file */
lib/js/backupmanager.js CHANGED
@@ -3,6 +3,10 @@ jQuery(function($) {
3
 
4
  initialize();
5
  bindActions();
 
 
 
 
6
 
7
  function initialize() {
8
  $("input[name$='backupChoice']").removeAttr('checked');
@@ -117,4 +121,110 @@ jQuery(function($) {
117
  $("input[name$='createBackup']").is(':checked') && !$("input[id$='customBackup']").is(':checked'));
118
  }
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  });
3
 
4
  initialize();
5
  bindActions();
6
+ getSize();
7
+ scanBackupDir();
8
+ uninstall();
9
+ deleteFile();
10
 
11
  function initialize() {
12
  $("input[name$='backupChoice']").removeAttr('checked');
121
  $("input[name$='createBackup']").is(':checked') && !$("input[id$='customBackup']").is(':checked'));
122
  }
123
 
124
+ function getSize() {
125
+
126
+ $.ajax({
127
+ url: ajaxurl,
128
+ type: 'get',
129
+ data: {
130
+ 'action': 'wpclone-ajax-size',
131
+ 'nonce': wpclone.nonce
132
+ },
133
+ success: function(data){
134
+ data = $.parseJSON(data);
135
+ $("span#filesize").html( "There are <code>" + data.files + "</code> files to backup, and their total size is <code>" + data.size + "</code>. Database size is <code>" + data.dbsize + "</code>." );
136
+ },
137
+ error: function(e){
138
+ $("span#filesize").html( "Unable to calculate size." );
139
+ }
140
+ });
141
+
142
+ }
143
+
144
+ function scanBackupDir() {
145
+
146
+ $("a#dirscan").click( function(e){
147
+
148
+ e.preventDefault();
149
+ $(this).html("<img src='" + wpclone.spinner + "'>");
150
+
151
+ $.ajax({
152
+ url: ajaxurl,
153
+ type: 'get',
154
+ data: {
155
+ 'action': 'wpclone-ajax-dir',
156
+ 'nonce': wpclone.nonce
157
+ },
158
+ success: function(data){
159
+ window.location.reload(true);
160
+ },
161
+ error: function(e){
162
+ }
163
+ });
164
+
165
+
166
+ });
167
+
168
+ }
169
+
170
+ function uninstall() {
171
+
172
+ $("a#uninstall").click( function(e){
173
+
174
+ e.preventDefault();
175
+ if( ! confirm('This will delete all your backups files, are you sure?') ) return;
176
+ $(this).html("<img src='" + wpclone.spinner + "'>");
177
+ $.ajax({
178
+ url: ajaxurl,
179
+ type: 'get',
180
+ data: {
181
+ 'action': 'wpclone-ajax-uninstall',
182
+ 'nonce': wpclone.nonce
183
+ },
184
+ success: function(data){
185
+ window.location.reload(true);
186
+ },
187
+ error: function(e){
188
+ }
189
+ });
190
+
191
+
192
+ });
193
+
194
+ }
195
+
196
+ function deleteFile() {
197
+
198
+ $("table.restore-backup-options a.delete").click( function(e){
199
+ e.preventDefault();
200
+ var row = $(this).closest("tr");
201
+ var cell = $(this).closest("td");
202
+ $(cell).html("<img src='" + wpclone.spinner + "'>");
203
+
204
+ $.ajax({
205
+ url: ajaxurl,
206
+ type: 'get',
207
+ data: {
208
+ 'action': 'wpclone-ajax-delete',
209
+ 'fileid': $(this).data("fileid"),
210
+ 'nonce': wpclone.nonce
211
+ },
212
+ success: function(data){
213
+ data = $.parseJSON( data );
214
+
215
+ if( 'deleted' == data.status ) {
216
+ $(row).html("<td colspan='5'><strong>" + data.msg + "</strong></td>");
217
+ $(row).addClass('deleted').hide(700);
218
+ } else {
219
+ $(row).html("<td colspan='5'>" + data.msg + "</td>").addClass('delete-error');
220
+ }
221
+ },
222
+ error: function(e){
223
+ }
224
+ });
225
+
226
+ });
227
+
228
+ }
229
+
230
  });
lib/view.php CHANGED
@@ -37,9 +37,9 @@
37
 
38
  <?php
39
  if (wpa_wpfs_init()) return;
40
- global $wpdb;
41
- $result = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}wpclone ORDER BY id DESC", ARRAY_A);
42
 
 
 
43
  ?>
44
  <div id="wrapper">
45
  <div id="MainView">
@@ -56,58 +56,69 @@ $result = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}wpclone ORDER BY id D
56
  would like to restore.</p>
57
 
58
  <p>&nbsp;</p>
59
-
60
  <form id="backupForm" name="backupForm" action="#" method="post">
61
- <?php
62
  if ( isset($_GET['mode']) && 'advanced' == $_GET['mode'] ) { ?>
63
  <div class="info">
64
  <table>
65
  <tr align="left"><th colspan=""><label for="zipmode">Alternate zip method</label></th><td colspan="2"><input type="checkbox" name="zipmode" value="alt" /></td></tr>
66
  <tr align="left"><th><label for="use_wpdb">Use wpdb to backup the database</label></th><td colspan="2"><input type="checkbox" name="use_wpdb" value="true" /></td></tr>
 
 
 
 
 
67
  <tr align="left"><th><label for="maxmem">Maximum memory limit</label></th><td colspan="2"><input type="text" name="maxmem" /></td></tr>
68
  <tr align="left"><th><label for="maxexec">Script execution time</label></th><td><input type="text" name="maxexec" /></td></tr>
69
  <tr><td colspan="4"><h3>Exclude directories from backup, and backup database only</h3></td></tr>
70
  <tr><td colspan="4"><p>Depending on your web host, WP Clone may not work for large sites.
71
- You may, however, exclude all of your 'wp-content' directory from the backup (use "Backup database only" option below), or exclude specific directories.
72
  You would then copy these files over to the new site via FTP before restoring the backup with WP Clone.</p></td></tr>
73
  <tr align="left"><th><label for="dbonly">Backup database only</label></th><td colspan="2"><input type="checkbox" name="dbonly" value="true" /></td></tr>
74
  <tr align="left"><th><label for="exclude">Excluded directories</label></th><td><textarea cols="70" rows="5" name="exclude" ></textarea></td></tr>
75
- <tr><th></th><td colspan="5"><p>Enter one per line, i.e. <code>uploads/backups</code>,use the forward slash <code>/</code> as the directory separator. Directories start at 'wp-content' level.</p></td></tr>
 
 
76
  </table>
77
  </div>
78
  <?php
79
  }
80
- ?>
81
  <strong>Create Backup</strong>
82
  <input id="createBackup" name="createBackup" type="radio" value="fullBackup" checked="checked"/><br/><br/>
83
 
84
- <?php if (count($result) > 0) : ?>
85
 
86
  <div class="try">
87
 
88
- <?php foreach ($result AS $row) :
 
 
 
 
89
 
90
- $filename = convertPathIntoUrl(WPCLONE_DIR_BACKUP . $row['backup_name']);
91
- $url = wp_nonce_url( get_bloginfo('wpurl') . '/wp-admin/options-general.php?page=wp-clone&del=' . $row['id'], 'wpclone-submit');
92
- ?>
93
- <div class="restore-backup-options">
94
- <strong>Restore backup </strong>
95
 
96
- <input class="restoreBackup" name="restoreBackup" type="radio"
97
- value="<?php echo $filename ?>" />&nbsp;
 
98
 
99
- <a href="<?php echo $filename ?>" class="zclip">
100
- (&nbsp;<?php echo bytesToSize($row['backup_size']);?>&nbsp;)&nbsp; <?php echo $row['backup_name'] ?>
101
- </a>&nbsp;|&nbsp;
102
 
103
- <input type="hidden" name="backup_name" value="<?php echo $filename ?>" />
 
 
 
104
 
105
- <a class="copy-button" href="#" data-clipboard-text="<?php echo $filename ?>" >Copy URL</a> &nbsp;|&nbsp;
106
- <a href="<?php echo $url; ?>">Delete</a>
107
- </div>
108
 
109
- <?php endforeach ?>
110
 
 
111
  </div>
112
 
113
  <?php endif ?>
@@ -137,6 +148,17 @@ $result = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}wpclone ORDER BY id D
137
  $link = admin_url( 'admin.php?page=wp-clone&mode=advanced' );
138
  echo "<p style='padding:5px;'><a href='{$link}' style='margin-top:10px'>Advanced Settings</a></p>";
139
  }
 
 
 
 
 
 
 
 
 
 
 
140
  ?>
141
  </div>
142
  <div id="sidebar">
@@ -149,10 +171,10 @@ $result = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}wpclone ORDER BY id D
149
  <li><a href="http://wpacademy.com/websites" target="_blank" title="WP Academy Websites">Websites</a></li>
150
  <li><a href="http://www.wpacademy.com/hosting" target="_blank" title="Managed WordPress Hosting">Managed WordPress Hosting</a></li>
151
  </ul>
152
-
153
  <ul>
154
  <h2>WP Academy News</h2>
155
- <h3>WPAcademy.com</h3>
156
  <?php wpa_fetch_feed ('http://members.wpacademy.com/category/news/feed', 3); ?>
157
  <h3>Twitter @WPAcademy</h3>
158
  <?php /* wpa_fetch_feed ('http://api.twitter.com/1/statuses/user_timeline.rss?screen_name=wpacademy', 5); */ ?>
@@ -160,45 +182,45 @@ $result = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}wpclone ORDER BY id D
160
  <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
161
 
162
  </ul>
163
-
164
  <ul>
165
  <h2>Help & Support</h2>
166
  <li><a href="http://members.wpacademy.com/wpclone-faq" target="_blank" title="WP Clone FAQ">Visit the WP Clone FAQ Page</a></li>
167
  <li><a href="http://wordpress.org/support/plugin/wp-clone-by-wp-academy" target="_blank" title="Support Forum">Support forum at WordPress.org</a></li>
168
  </ul>
169
-
170
  </div>
171
  </div> <!--wrapper-->
172
  <p style="clear: both;" ></p>
173
  <?php
174
- if ( isset($_GET['mode']) && 'advanced' == $_GET['mode'] ) {
 
175
  global $wpdb;
176
  echo '<div class="info">';
177
- echo '<h3>System Info:</h3>';
178
  echo 'Memory limit: ' . ini_get('memory_limit') . '</br>';
179
  echo 'Maximum execution time: ' . ini_get('max_execution_time') . ' seconds</br>';
180
  echo 'PHP version : ' . phpversion() . '</br>';
181
  echo 'MySQL version : ' . $wpdb->db_version() . '</br>';
182
  if (ini_get('safe_mode')) { echo '<span style="color:#f11">PHP is running in safemode!</span></br>'; }
183
- echo '<h4>Directory list:</h4>';
184
- echo 'Uploads path : <pre>' . WPCLONE_DIR_UPLOADS . '</pre></br>';
185
- echo 'Plugin path : <pre>' . WPCLONE_DIR_PLUGIN . '</pre></br>';
186
- echo 'Plugin URL : <pre>' . WPCLONE_URL_PLUGIN . '</pre></br>';
187
- echo 'Backup path : <pre>' . WPCLONE_DIR_BACKUP . '</pre></br>';
188
- echo 'wp-content path : <pre>' . WPCLONE_WP_CONTENT . '</pre></br>';
189
- echo 'Site Root : <pre>' . WPCLONE_ROOT . '</pre></br>';
190
- echo 'ABSPATH : <pre>' . ABSPATH . '</pre></br>';
191
- if (!is_writable(WPCLONE_DIR_BACKUP)) { echo '<span style="color:#f11">Cannot write to the backup directory!</span></br>'; }
192
- if (!is_writable(WPCLONE_WP_CONTENT)) { echo '<span style="color:#f11">Cannot write to the root directory!</span></br>'; }
193
- echo '</div>';
194
  }
195
-
196
  function wpa_fetch_feed ($feed, $limit) {
197
  include_once(ABSPATH . WPINC . '/feed.php');
198
  $rss = fetch_feed($feed);
199
  if (!is_wp_error( $rss ) ) :
200
  $maxitems = $rss->get_item_quantity($limit);
201
- $rss_items = $rss->get_items(0, $maxitems);
202
  endif;
203
  if ( isset($maxitems) && $maxitems == 0 ) echo '<li>No items.</li>';
204
  else
@@ -211,5 +233,5 @@ $result = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}wpclone ORDER BY id D
211
  </li>
212
  <?php endforeach;
213
  }
214
-
215
  /** it all ends here folks. */
37
 
38
  <?php
39
  if (wpa_wpfs_init()) return;
 
 
40
 
41
+ if( false === get_option( 'wpclone_backups' ) ) wpa_wpc_import_db();
42
+ $backups = get_option( 'wpclone_backups' );
43
  ?>
44
  <div id="wrapper">
45
  <div id="MainView">
56
  would like to restore.</p>
57
 
58
  <p>&nbsp;</p>
59
+
60
  <form id="backupForm" name="backupForm" action="#" method="post">
61
+ <?php
62
  if ( isset($_GET['mode']) && 'advanced' == $_GET['mode'] ) { ?>
63
  <div class="info">
64
  <table>
65
  <tr align="left"><th colspan=""><label for="zipmode">Alternate zip method</label></th><td colspan="2"><input type="checkbox" name="zipmode" value="alt" /></td></tr>
66
  <tr align="left"><th><label for="use_wpdb">Use wpdb to backup the database</label></th><td colspan="2"><input type="checkbox" name="use_wpdb" value="true" /></td></tr>
67
+ <tr><td colspan="4"><h3>Overriding the Maximum memory and Execution time</h3></td></tr>
68
+ <tr><td colspan="4"><p>You can use these two fields to override the maximum memory and execution time on most hosts.</br>
69
+ For example, if you want to increase the RAM to 1GB, enter <code>1024</code> into the Maximum memory limit field.</br>
70
+ And if you want to increase the execution time to 10 minutes, enter <code>600</code> into the Script execution time field.</br>
71
+ Default values will be used if you leave them blank. The default value for RAM is 512MB and the default value for execution time is 300 seconds (five minutes).</p></td></tr>
72
  <tr align="left"><th><label for="maxmem">Maximum memory limit</label></th><td colspan="2"><input type="text" name="maxmem" /></td></tr>
73
  <tr align="left"><th><label for="maxexec">Script execution time</label></th><td><input type="text" name="maxexec" /></td></tr>
74
  <tr><td colspan="4"><h3>Exclude directories from backup, and backup database only</h3></td></tr>
75
  <tr><td colspan="4"><p>Depending on your web host, WP Clone may not work for large sites.
76
+ You may, however, exclude all of your 'wp-content' directory from the backup (use "Backup database only" option below), or exclude specific directories.
77
  You would then copy these files over to the new site via FTP before restoring the backup with WP Clone.</p></td></tr>
78
  <tr align="left"><th><label for="dbonly">Backup database only</label></th><td colspan="2"><input type="checkbox" name="dbonly" value="true" /></td></tr>
79
  <tr align="left"><th><label for="exclude">Excluded directories</label></th><td><textarea cols="70" rows="5" name="exclude" ></textarea></td></tr>
80
+ <tr><th></th><td colspan="5"><p>Enter one per line, i.e. <code>uploads/backups</code>,use the forward slash <code>/</code> as the directory separator. Directories start at 'wp-content' level.</br>
81
+ </br>For example, BackWPup saves its backups into <code>/wp-content/uploads/backwpup-abc123-backups/</code> (the middle part, 'abc123' in this case, is random characters).
82
+ If you wanted to exclude that directory, you have to enter <code>uploads/backwpup-abc123-backups</code> into the above field.</p></td></tr>
83
  </table>
84
  </div>
85
  <?php
86
  }
87
+ ?>
88
  <strong>Create Backup</strong>
89
  <input id="createBackup" name="createBackup" type="radio" value="fullBackup" checked="checked"/><br/><br/>
90
 
91
+ <?php if( false !== $backups && ! empty( $backups ) ) : ?>
92
 
93
  <div class="try">
94
 
95
+ <table class="restore-backup-options">
96
+
97
+ <?php
98
+
99
+ foreach ($backups AS $key => $backup) :
100
 
101
+ $filename = convertPathIntoUrl(WPCLONE_DIR_BACKUP . $backup['name']);
102
+ $url = wp_nonce_url( get_bloginfo('wpurl') . '/wp-admin/admin.php?page=wp-clone&del=' . $key, 'wpclone-submit');
 
 
 
103
 
104
+ ?>
105
+ <tr>
106
+ <th>Restore backup</th>
107
 
108
+ <td><input class="restoreBackup" name="restoreBackup" type="radio" value="<?php echo $filename ?>" /></td>
 
 
109
 
110
+ <td>
111
+ <a href="<?php echo $filename ?>" class="zclip"> (<?php echo bytesToSize($backup['size']);?>)&nbsp;&nbsp;<?php echo $backup['name'] ?></a>
112
+ <input type="hidden" name="backup_name" value="<?php echo $filename ?>" />
113
+ </td>
114
 
115
+ <td><a class="copy-button" href="#" data-clipboard-text="<?php echo $filename ?>" >Copy URL</a></td>
116
+ <td><a href="<?php echo $url; ?>" class="delete" data-fileid="<?php echo $key; ?>">Delete</a></td>
117
+ </tr>
118
 
119
+ <?php endforeach ?>
120
 
121
+ </table>
122
  </div>
123
 
124
  <?php endif ?>
148
  $link = admin_url( 'admin.php?page=wp-clone&mode=advanced' );
149
  echo "<p style='padding:5px;'><a href='{$link}' style='margin-top:10px'>Advanced Settings</a></p>";
150
  }
151
+
152
+
153
+ echo "<p><a href='#' id='dirscan' class='button' style='margin-top:10px'>Scan and repopulate the backup list</a>"
154
+ . "</br>Use the above button to refresh your backup list. It will list <em>all</em> the zip files found in the backup directory, it will also remove references to files that no longer exist.</p>";
155
+
156
+ wpa_wpc_sysinfo();
157
+
158
+ echo "<p><a href='#' id='uninstall' class='button' style='margin-top:10px'>Delete backups and remove database entries</a>"
159
+ . "</br>WP Clone does not remove backups when you deactivate the plugin. Use the above button if you want to remove all the backups.</p>";
160
+
161
+
162
  ?>
163
  </div>
164
  <div id="sidebar">
171
  <li><a href="http://wpacademy.com/websites" target="_blank" title="WP Academy Websites">Websites</a></li>
172
  <li><a href="http://www.wpacademy.com/hosting" target="_blank" title="Managed WordPress Hosting">Managed WordPress Hosting</a></li>
173
  </ul>
174
+
175
  <ul>
176
  <h2>WP Academy News</h2>
177
+ <h3>WPAcademy.com</h3>
178
  <?php wpa_fetch_feed ('http://members.wpacademy.com/category/news/feed', 3); ?>
179
  <h3>Twitter @WPAcademy</h3>
180
  <?php /* wpa_fetch_feed ('http://api.twitter.com/1/statuses/user_timeline.rss?screen_name=wpacademy', 5); */ ?>
182
  <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
183
 
184
  </ul>
185
+
186
  <ul>
187
  <h2>Help & Support</h2>
188
  <li><a href="http://members.wpacademy.com/wpclone-faq" target="_blank" title="WP Clone FAQ">Visit the WP Clone FAQ Page</a></li>
189
  <li><a href="http://wordpress.org/support/plugin/wp-clone-by-wp-academy" target="_blank" title="Support Forum">Support forum at WordPress.org</a></li>
190
  </ul>
191
+
192
  </div>
193
  </div> <!--wrapper-->
194
  <p style="clear: both;" ></p>
195
  <?php
196
+
197
+ function wpa_wpc_sysinfo(){
198
  global $wpdb;
199
  echo '<div class="info">';
200
+ echo '<h3>System Info:</h3><p>';
201
  echo 'Memory limit: ' . ini_get('memory_limit') . '</br>';
202
  echo 'Maximum execution time: ' . ini_get('max_execution_time') . ' seconds</br>';
203
  echo 'PHP version : ' . phpversion() . '</br>';
204
  echo 'MySQL version : ' . $wpdb->db_version() . '</br>';
205
  if (ini_get('safe_mode')) { echo '<span style="color:#f11">PHP is running in safemode!</span></br>'; }
206
+ if ( ! file_exists( WPCLONE_DIR_BACKUP ) ) {
207
+ echo 'Backup path :<span style="color:#660000">Backup directory not found. '
208
+ . 'Unless there is a permissions or ownership issue, refreshing the backup list should create the directory.</span></br>';
209
+ } else {
210
+ echo 'Backup path : <code>' . WPCLONE_DIR_BACKUP . '</code></br>';
211
+ }
212
+ echo 'Files : <span id="filesize"><img src="' . esc_url( admin_url( 'images/spinner.gif' ) ) . '"></span></br>';
213
+ if ( file_exists( WPCLONE_DIR_BACKUP ) && !is_writable(WPCLONE_DIR_BACKUP)) { echo '<span style="color:#f11">Backup directory is not writable, please change its permissions.</span></br>'; }
214
+ if (!is_writable(WPCLONE_WP_CONTENT)) { echo '<span style="color:#f11">wp-content is not writable, please change its permissions before you perform a restore.</span></br>'; }
215
+ if (!is_writable(wpa_wpconfig_path())) { echo '<span style="color:#f11">wp-config.php is not writable, please change its permissions before you perform a restore.</span></br>'; }
216
+ echo '</p></div>';
217
  }
 
218
  function wpa_fetch_feed ($feed, $limit) {
219
  include_once(ABSPATH . WPINC . '/feed.php');
220
  $rss = fetch_feed($feed);
221
  if (!is_wp_error( $rss ) ) :
222
  $maxitems = $rss->get_item_quantity($limit);
223
+ $rss_items = $rss->get_items(0, $maxitems);
224
  endif;
225
  if ( isset($maxitems) && $maxitems == 0 ) echo '<li>No items.</li>';
226
  else
233
  </li>
234
  <?php endforeach;
235
  }
236
+
237
  /** it all ends here folks. */
readme.txt CHANGED
@@ -6,7 +6,7 @@ Author URI: http://wpacademy.com
6
  Plugin URI: http://wpacademy.com/software
7
  Requires at least: 3.0
8
  Tested up to: 4.3
9
- Stable tag: 2.1.9
10
  License: GPLv2 or later
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 
@@ -14,9 +14,9 @@ Move or copy a WordPress site to another server or to another domain name, move
14
 
15
  == Description ==
16
 
17
- WP Clone is the easiest, fastest and most secure way to move or copy a WordPress site to another domain or hosting server. You can also use it to move your site to/from local server hosting, to create copies of your site for development or testing purposes, to backup your site, and to install pre-configured versions of WordPress.
18
 
19
- WP Clone is a superior solution to even commercial WordPress cloning plugins for the following reasons:
20
 
21
  * Does not require FTP access to either the source or destination site &ndash; just install a new WordPress on the destination site, upload and activate WP Clone plugin, and follow the prompts
22
  * It does not backup or restore the WordPress system files (just the user content and database) &ndash; reducing upload time and improving security of your site
@@ -40,7 +40,7 @@ Feel free to leave a negative review and details of your failure on the support
40
  We have implemented exclude-directories on the backup, and also database-only backup! By transferring the contents of 'wp-content' directory with FTP from your old site to new site, you should now be able to migrate sites of any size.
41
 
42
  = Support and Disclaimer =
43
- No WordPress backup plugin will work reliably on all hosts. If you have any problems, try doing a "Database Only" backup (use "Advanced Options"), transfer the wp-content directory over with FTP, and then restore new site. You should also deactivate and delete any page caching plugins (i.e. W3 Total Cache) before backup.
44
  If you still have an issue, please post to the WordPress.org support forum where we support this plugin for free, and we'll respond on a "best-effort" basis. You can also try the Duplicator plugin http://wordpress.org/plugins/duplicator/ or All-in-One WP Migration https://wordpress.org/plugins/all-in-one-wp-migration/, both of which work pretty good, but are not as fast as WP Clone to migrate sites; or use the manual method described here http://members.wpacademy.com/ww3.htm?moving-wordpress.htm
45
 
46
  = Please donate to support plugin development & ongoing support =
@@ -51,7 +51,7 @@ Donation page.
51
  Additional documentation, including supported hosts, at the [WP Clone FAQ Page](http://members.wpacademy.com/wpclone-faq "WP Clone FAQ")
52
 
53
  = Other contributors =
54
- WP Clone uses functions from the "Safe Search and Replace on Database with Serialized Data" script first written by David Coveney of Interconnect IT Ltd (UK) http://www.davidcoveney.com or http://www.interconnectit.com and
55
  released under the WTFPL http://sam.zoy.org/wtfpl/. Partial script with full changelog is placed inside 'lib/files' directory.
56
 
57
 
@@ -66,13 +66,29 @@ released under the WTFPL http://sam.zoy.org/wtfpl/. Partial script with full cha
66
  Review FAQ's and Help Video at the [WP Clone FAQ Page](http://members.wpacademy.com/wpclone-faq "WP Clone FAQ")
67
 
68
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  = 2.1.9 - 2015-11-10 =
70
  * Disabled heartbeat on wpclone's admin page.
71
  * DB_CHARSET in wp-config.php is used during direct database transactions.
 
72
  = 2.1.8 - 2014-09-18 =
73
  * Updated: Readme description.
 
74
  = 2.1.7 - 2014-07-30 =
75
  * Changed: Admin page links.
 
76
  = 2.1.6 - 2013-07-07 =
77
  * Added: An option to exclude specific directories during backup.
78
  * Added: An option to only backup the database.
@@ -108,7 +124,7 @@ Review FAQ's and Help Video at the [WP Clone FAQ Page](http://members.wpacademy.
108
  = 2.0.6 - 2012-08-05 =
109
  * Added: WP Filesystem integration
110
  * Added: Alternate zip method for better compatibility with hosts that haven't enabled PHP's zip extension
111
-
112
  = 2.0.5 - 2012-06-25 =
113
  * Fixed: A secondary search and replace that was corrupting serialized entries
114
 
6
  Plugin URI: http://wpacademy.com/software
7
  Requires at least: 3.0
8
  Tested up to: 4.3
9
+ Stable tag: 2.2
10
  License: GPLv2 or later
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 
14
 
15
  == Description ==
16
 
17
+ WP Clone is the easiest, fastest and most secure way to move or copy a WordPress site to another domain or hosting server. You can also use it to move your site to/from local server hosting, to create copies of your site for development or testing purposes, to backup your site, and to install pre-configured versions of WordPress.
18
 
19
+ WP Clone is a superior solution to even commercial WordPress cloning plugins for the following reasons:
20
 
21
  * Does not require FTP access to either the source or destination site &ndash; just install a new WordPress on the destination site, upload and activate WP Clone plugin, and follow the prompts
22
  * It does not backup or restore the WordPress system files (just the user content and database) &ndash; reducing upload time and improving security of your site
40
  We have implemented exclude-directories on the backup, and also database-only backup! By transferring the contents of 'wp-content' directory with FTP from your old site to new site, you should now be able to migrate sites of any size.
41
 
42
  = Support and Disclaimer =
43
+ No WordPress backup plugin will work reliably on all hosts. If you have any problems, try doing a "Database Only" backup (use "Advanced Options"), transfer the wp-content directory over with FTP, and then restore new site. You should also deactivate and delete any page caching plugins (i.e. W3 Total Cache) before backup.
44
  If you still have an issue, please post to the WordPress.org support forum where we support this plugin for free, and we'll respond on a "best-effort" basis. You can also try the Duplicator plugin http://wordpress.org/plugins/duplicator/ or All-in-One WP Migration https://wordpress.org/plugins/all-in-one-wp-migration/, both of which work pretty good, but are not as fast as WP Clone to migrate sites; or use the manual method described here http://members.wpacademy.com/ww3.htm?moving-wordpress.htm
45
 
46
  = Please donate to support plugin development & ongoing support =
51
  Additional documentation, including supported hosts, at the [WP Clone FAQ Page](http://members.wpacademy.com/wpclone-faq "WP Clone FAQ")
52
 
53
  = Other contributors =
54
+ WP Clone uses functions from the "Safe Search and Replace on Database with Serialized Data" script first written by David Coveney of Interconnect IT Ltd (UK) http://www.davidcoveney.com or http://www.interconnectit.com and
55
  released under the WTFPL http://sam.zoy.org/wtfpl/. Partial script with full changelog is placed inside 'lib/files' directory.
56
 
57
 
66
  Review FAQ's and Help Video at the [WP Clone FAQ Page](http://members.wpacademy.com/wpclone-faq "WP Clone FAQ")
67
 
68
  == Changelog ==
69
+ = 2.2 - 2015-11-16 =
70
+ * Fixed: Missing backups that some users encountered after upgrading to 2.1.9
71
+ * Added: An option to refresh the backup list.
72
+ * Added: An option to remove the database entry and delete all the backup files.
73
+ * Added: A section that shows the uncompressed database size and the uncompressed size and the number of files that will be archived during a full backup.
74
+ * Added: Notes in the advanced settings section regarding the Maximum memory limit and the Script execution time fields.
75
+ * Added: The report returned from the search and replace process into the restore successful page.
76
+ * Changed: Moved the backup list location from the custom table to the wp_options table. (previous backups will be imported and the custom table will be removed on existing installations)
77
+ * Changed: Moved the system information block from the advanced settings section into the "normal" dashboard page.
78
+ * Changed: Only the tables with the wordpress table prefix will be altered during a restore.
79
+ * Changed: Only the tables with the wordpress table prefix will be saved during a backup.
80
+ * Changed: Backup deletion is now handled using AJAX.
81
+
82
  = 2.1.9 - 2015-11-10 =
83
  * Disabled heartbeat on wpclone's admin page.
84
  * DB_CHARSET in wp-config.php is used during direct database transactions.
85
+
86
  = 2.1.8 - 2014-09-18 =
87
  * Updated: Readme description.
88
+
89
  = 2.1.7 - 2014-07-30 =
90
  * Changed: Admin page links.
91
+
92
  = 2.1.6 - 2013-07-07 =
93
  * Added: An option to exclude specific directories during backup.
94
  * Added: An option to only backup the database.
124
  = 2.0.6 - 2012-08-05 =
125
  * Added: WP Filesystem integration
126
  * Added: Alternate zip method for better compatibility with hosts that haven't enabled PHP's zip extension
127
+
128
  = 2.0.5 - 2012-06-25 =
129
  * Fixed: A secondary search and replace that was corrupting serialized entries
130
 
wpclone.php CHANGED
@@ -4,7 +4,7 @@ Plugin name: WP Clone by WP Academy
4
  Plugin URI: http://wpacademy.com/software/
5
  Description: Move or copy a WordPress site to another server or to another domain name, move to/from local server hosting, and backup sites.
6
  Author: WP Academy
7
- Version: 2.1.9
8
  Author URI: http://wpacademy.com/
9
  */
10
 
@@ -28,6 +28,10 @@ define('WPCLONE_WP_CONTENT' , str_replace('\\', '/', WP_CONTENT_DIR));
28
  register_activation_hook((__FILE__), 'wpa_wpclone_activate');
29
  register_deactivation_hook(__FILE__ , 'wpa_wpclone_deactivate');
30
  add_action('admin_menu', 'wpclone_plugin_menu');
 
 
 
 
31
 
32
  function wpclone_plugin_menu() {
33
  add_menu_page (
@@ -39,6 +43,50 @@ function wpclone_plugin_menu() {
39
  );
40
  }
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  function wpclone_plugin_options() {
43
  include_once 'lib/view.php';
44
  }
@@ -47,29 +95,34 @@ function wpa_enqueue_scripts(){
47
  wp_register_script('jquery-zclip', plugin_dir_url(__FILE__) . '/lib/js/zeroclipboard.min.js', array('jquery'));
48
  wp_register_script('wpclone', plugin_dir_url(__FILE__) . '/lib/js/backupmanager.js', array('jquery'));
49
  wp_register_style('wpclone', plugin_dir_url(__FILE__) . '/lib/css/style.css');
 
50
  wp_enqueue_script('jquery-zclip');
51
  wp_enqueue_script('wpclone');
52
  wp_enqueue_style('wpclone');
53
- wp_deregister_script('heartbeat');
54
  }
55
  if( isset($_GET['page']) && 'wp-clone' == $_GET['page'] ) add_action('admin_enqueue_scripts', 'wpa_enqueue_scripts');
56
 
57
  function wpa_wpclone_activate() {
58
  wpa_create_directory();
59
- wpa_install_database();
60
  }
61
 
62
  function wpa_wpclone_deactivate() {
63
- //removing the table
 
 
 
 
 
 
 
 
 
64
  global $wpdb;
65
  $wp_backup = $wpdb->prefix . 'wpclone';
66
  $wpdb->query ("DROP TABLE IF EXISTS $wp_backup");
67
- $data = "<Files>\r\n\tOrder allow,deny\r\n\tDeny from all\r\n\tSatisfy all\r\n</Files>";
68
- $file = WPCLONE_DIR_BACKUP . '.htaccess';
69
- file_put_contents($file, $data);
70
  }
71
 
72
-
73
  function wpa_create_directory() {
74
  $indexFile = (WPCLONE_DIR_BACKUP.'index.html');
75
  $htacc = WPCLONE_DIR_BACKUP . '.htaccess';
@@ -83,31 +136,45 @@ function wpa_create_directory() {
83
  $handle = fopen($indexFile, "w");
84
  fclose($handle);
85
  }
 
 
 
86
  file_put_contents($htacc, $htacc_data);
87
  }
88
 
89
- function wpa_install_database() {
90
- global $wpdb , $wp_roles, $wp_version;
91
- require_once(WPCLONE_ROOT . 'wp-admin/upgrade-functions.php');
92
- // add charset & collate like wp core
93
- $charset_collate = '';
94
- if ( version_compare(mysql_get_server_info(), '4.1.0', '>=') ) {
95
- if ( ! empty($wpdb->charset) )
96
- $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
97
- if ( ! empty($wpdb->collate) )
98
- $charset_collate .= " COLLATE $wpdb->collate";
99
- }
100
- $wp_backup = $wpdb->prefix . 'wpclone';
101
- /* could be case senstive : http://dev.mysql.com/doc/refman/5.1/en/identifier-case-sensitivity.html */
102
- if( !$wpdb->get_var( "SHOW TABLES LIKE '{$wp_backup}'" ) ) {
103
- $sql = "CREATE TABLE {$wp_backup} (
104
- id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
105
- backup_name VARCHAR(250) NOT NULL,
106
- backup_size INT (11),
107
- data_time DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
108
- creator VARCHAR(60) NOT NULL) $charset_collate;";
109
- dbDelta($sql);
 
 
 
 
 
 
 
 
 
110
  }
 
 
111
  }
112
 
113
  function wpa_wpc_msnotice() {
4
  Plugin URI: http://wpacademy.com/software/
5
  Description: Move or copy a WordPress site to another server or to another domain name, move to/from local server hosting, and backup sites.
6
  Author: WP Academy
7
+ Version: 2.2
8
  Author URI: http://wpacademy.com/
9
  */
10
 
28
  register_activation_hook((__FILE__), 'wpa_wpclone_activate');
29
  register_deactivation_hook(__FILE__ , 'wpa_wpclone_deactivate');
30
  add_action('admin_menu', 'wpclone_plugin_menu');
31
+ add_action( 'wp_ajax_wpclone-ajax-size', 'wpa_wpc_ajax_size' );
32
+ add_action( 'wp_ajax_wpclone-ajax-dir', 'wpa_wpc_ajax_dir' );
33
+ add_action( 'wp_ajax_wpclone-ajax-delete', 'wpa_wpc_ajax_delete' );
34
+ add_action( 'wp_ajax_wpclone-ajax-uninstall', 'wpa_wpc_ajax_uninstall' );
35
 
36
  function wpclone_plugin_menu() {
37
  add_menu_page (
43
  );
44
  }
45
 
46
+ function wpa_wpc_ajax_size() {
47
+
48
+ check_ajax_referer( 'wpclone-ajax-submit', 'nonce' );
49
+ $size = wpa_wpc_dir_size( WP_CONTENT_DIR );
50
+ $size['dbsize'] = wpa_wpc_db_size();
51
+ echo json_encode( $size );
52
+ wp_die();
53
+
54
+ }
55
+
56
+ function wpa_wpc_ajax_dir() {
57
+
58
+ check_ajax_referer( 'wpclone-ajax-submit', 'nonce' );
59
+ if( ! file_exists( WPCLONE_DIR_BACKUP ) ) wpa_create_directory();
60
+ wpa_wpc_scan_dir();
61
+ wp_die();
62
+
63
+ }
64
+
65
+ function wpa_wpc_ajax_delete() {
66
+
67
+ check_ajax_referer( 'wpclone-ajax-submit', 'nonce' );
68
+
69
+ if( isset( $_REQUEST['fileid'] ) && ! empty( $_REQUEST['fileid'] ) ) {
70
+
71
+ echo json_encode( DeleteWPBackupZip( $_REQUEST['fileid'] ) );
72
+
73
+
74
+ }
75
+
76
+ wp_die();
77
+
78
+ }
79
+
80
+ function wpa_wpc_ajax_uninstall() {
81
+
82
+ check_ajax_referer( 'wpclone-ajax-submit', 'nonce' );
83
+ if( file_exists( WPCLONE_DIR_BACKUP ) ) wpa_delete_dir( WPCLONE_DIR_BACKUP );
84
+ delete_option( 'wpclone_backups' );
85
+ wpa_wpc_remove_table();
86
+ wp_die();
87
+
88
+ }
89
+
90
  function wpclone_plugin_options() {
91
  include_once 'lib/view.php';
92
  }
95
  wp_register_script('jquery-zclip', plugin_dir_url(__FILE__) . '/lib/js/zeroclipboard.min.js', array('jquery'));
96
  wp_register_script('wpclone', plugin_dir_url(__FILE__) . '/lib/js/backupmanager.js', array('jquery'));
97
  wp_register_style('wpclone', plugin_dir_url(__FILE__) . '/lib/css/style.css');
98
+ wp_localize_script('wpclone', 'wpclone', array( 'nonce' => wp_create_nonce( 'wpclone-ajax-submit' ), 'spinner' => esc_url( admin_url( 'images/spinner.gif' ) ) ) );
99
  wp_enqueue_script('jquery-zclip');
100
  wp_enqueue_script('wpclone');
101
  wp_enqueue_style('wpclone');
102
+ wp_deregister_script('heartbeat');
103
  }
104
  if( isset($_GET['page']) && 'wp-clone' == $_GET['page'] ) add_action('admin_enqueue_scripts', 'wpa_enqueue_scripts');
105
 
106
  function wpa_wpclone_activate() {
107
  wpa_create_directory();
 
108
  }
109
 
110
  function wpa_wpclone_deactivate() {
111
+
112
+ if( file_exists( WPCLONE_DIR_BACKUP ) ) {
113
+ $data = "<Files>\r\n\tOrder allow,deny\r\n\tDeny from all\r\n\tSatisfy all\r\n</Files>";
114
+ $file = WPCLONE_DIR_BACKUP . '.htaccess';
115
+ file_put_contents($file, $data);
116
+ }
117
+
118
+ }
119
+
120
+ function wpa_wpc_remove_table() {
121
  global $wpdb;
122
  $wp_backup = $wpdb->prefix . 'wpclone';
123
  $wpdb->query ("DROP TABLE IF EXISTS $wp_backup");
 
 
 
124
  }
125
 
 
126
  function wpa_create_directory() {
127
  $indexFile = (WPCLONE_DIR_BACKUP.'index.html');
128
  $htacc = WPCLONE_DIR_BACKUP . '.htaccess';
136
  $handle = fopen($indexFile, "w");
137
  fclose($handle);
138
  }
139
+ if( file_exists( $htacc ) ) {
140
+ @unlink ( $htacc );
141
+ }
142
  file_put_contents($htacc, $htacc_data);
143
  }
144
 
145
+ function wpa_wpc_import_db(){
146
+
147
+ global $wpdb;
148
+ $table_name = $wpdb->prefix . 'wpclone';
149
+
150
+ if( $wpdb->get_var( "SHOW TABLES LIKE '$table_name'") === $table_name ) {
151
+
152
+ $old_backups = array();
153
+ $result = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}wpclone ORDER BY id DESC", ARRAY_A);
154
+
155
+ foreach( $result as $row ) {
156
+
157
+ $time = strtotime( $row['data_time'] );
158
+ $old_backups[$time] = array(
159
+ 'name' => $row['backup_name'],
160
+ 'creator' => $row['creator'],
161
+ 'size' => $row['backup_size']
162
+
163
+ );
164
+
165
+ }
166
+
167
+ if( false !== get_option( 'wpclone_backups' ) ) {
168
+ $old_backups = get_option( 'wpclone_backups' ) + $old_backups;
169
+ }
170
+
171
+ update_option( 'wpclone_backups', $old_backups );
172
+
173
+ wpa_wpc_remove_table();
174
+
175
  }
176
+
177
+
178
  }
179
 
180
  function wpa_wpc_msnotice() {