The WP Remote WordPress Plugin - Version 2.2.2

Version Description

Download this release

Release Info

Developer joehoyle
Plugin Icon 128x128 The WP Remote WordPress Plugin
Version 2.2.2
Comparing to
See all releases

Code changes from version 2.2.1 to 2.2.2

Files changed (6) hide show
  1. hm-backup/hm-backup.php +647 -338
  2. plugin.php +1 -1
  3. readme.txt +1 -1
  4. wprp.api.php +6 -1
  5. wprp.backups.php +27 -14
  6. wprp.themes.php +35 -11
hm-backup/hm-backup.php CHANGED
@@ -3,7 +3,7 @@
3
  /**
4
  * Generic file and database backup class
5
  *
6
- * @version 1.5.1
7
  */
8
  class HM_Backup {
9
 
@@ -11,73 +11,65 @@ class HM_Backup {
11
  * The path where the backup file should be saved
12
  *
13
  * @string
14
- * @access public
15
- */
16
- public $path;
17
-
18
- /**
19
- * Whether the backup should be files only
20
- *
21
- * @bool
22
- * @access public
23
  */
24
- public $files_only;
25
 
26
  /**
27
- * Whether the backup should be database only
28
  *
29
- * @bool
30
- * @access public
31
  */
32
- public $database_only;
33
 
34
  /**
35
  * The filename of the backup file
36
  *
37
  * @string
38
- * @access public
39
  */
40
- public $archive_filename;
41
 
42
  /**
43
  * The filename of the database dump
44
  *
45
  * @string
46
- * @access public
47
  */
48
- public $database_dump_filename;
49
 
50
  /**
51
  * The path to the zip command
52
  *
53
  * @string
54
- * @access public
55
  */
56
- public $zip_command_path;
57
 
58
  /**
59
  * The path to the mysqldump command
60
  *
61
  * @string
62
- * @access public
63
  */
64
- public $mysqldump_command_path;
65
 
66
  /**
67
  * An array of exclude rules
68
  *
69
  * @array
70
- * @access public
71
  */
72
- public $excludes;
73
 
74
  /**
75
  * The path that should be backed up
76
  *
77
  * @var string
78
- * @access public
79
  */
80
- public $root;
81
 
82
  /**
83
  * Holds the current db connection
@@ -88,22 +80,31 @@ class HM_Backup {
88
  private $db;
89
 
90
  /**
91
- * Store the current backup instance
 
92
  *
93
- * @var object
94
- * @static
95
- * @access public
96
  */
97
- private static $instance;
98
 
99
  /**
100
  * An array of all the files in root
101
- * excluding excludes
102
  *
103
  * @var array
104
  * @access private
105
  */
106
- private $files;
 
 
 
 
 
 
 
 
 
107
 
108
  /**
109
  * Contains an array of errors
@@ -111,7 +112,7 @@ class HM_Backup {
111
  * @var mixed
112
  * @access private
113
  */
114
- private $errors;
115
 
116
  /**
117
  * Contains an array of warnings
@@ -119,7 +120,7 @@ class HM_Backup {
119
  * @var mixed
120
  * @access private
121
  */
122
- private $warnings;
123
 
124
  /**
125
  * The archive method used
@@ -127,7 +128,7 @@ class HM_Backup {
127
  * @var string
128
  * @access private
129
  */
130
- private $archive_method;
131
 
132
  /**
133
  * The mysqldump method used
@@ -135,107 +136,470 @@ class HM_Backup {
135
  * @var string
136
  * @access private
137
  */
138
- private $mysqldump_method;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
140
  /**
141
  * Sets up the default properties
142
  *
143
  * @access public
144
- * @return null
145
  */
146
  public function __construct() {
147
 
148
- // Raise the memory limit and max_execution_time time
149
  @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
150
  @set_time_limit( 0 );
151
 
152
- $this->errors = array();
153
-
154
  set_error_handler( array( &$this, 'error_handler' ) );
155
 
156
- // Defaults
157
- $this->root = $this->conform_dir( ABSPATH );
158
 
159
- $this->path = $this->conform_dir( WP_CONTENT_DIR . '/backups' );
 
 
 
 
 
 
 
 
160
 
161
- $this->database_dump_filename = 'database_' . DB_NAME . '.sql';
162
 
163
- $this->archive_filename = strtolower( sanitize_file_name( get_bloginfo( 'name' ) . '.backup.' . date( 'Y-m-d-H-i-s', time() + ( current_time( 'timestamp' ) - time() ) ) . '.zip' ) );
 
 
 
 
 
 
164
 
165
- $this->mysqldump_command_path = $this->guess_mysqldump_command_path();
166
- $this->zip_command_path = $this->guess_zip_command_path();
167
 
168
- $this->database_only = false;
169
- $this->files_only = false;
170
 
171
  }
172
 
173
  /**
174
- * Return the current instance
175
  *
176
  * @access public
177
- * @static
178
- * @return object
179
  */
180
- public static function get_instance() {
 
 
 
181
 
182
- if ( empty( self::$instance ) )
183
- self::$instance = new HM_Backup();
184
 
185
- return self::$instance;
186
 
187
  }
188
 
189
  /**
190
- * The full filepath to the archive file.
191
  *
192
  * @access public
193
  * @return string
194
  */
195
- public function archive_filepath() {
196
- return trailingslashit( $this->path() ) . $this->archive_filename();
 
 
197
  }
198
 
199
  /**
200
- * The full filepath to the archive file.
201
  *
202
  * @access public
203
  * @return string
204
  */
205
- public function archive_filename() {
206
- return strtolower( sanitize_file_name( remove_accents( $this->archive_filename ) ) );
 
 
 
 
 
207
  }
208
 
209
  /**
210
- * The full filepath to the database dump file.
211
  *
212
  * @access public
213
- * @return string
214
  */
215
- public function database_dump_filepath() {
216
- return trailingslashit( $this->path() ) . $this->database_dump_filename();
217
- }
 
 
 
 
 
 
218
 
219
- public function database_dump_filename() {
220
- return strtolower( sanitize_file_name( remove_accents( $this->database_dump_filename ) ) );
221
  }
222
 
223
- public function root() {
224
- return $this->conform_dir( $this->root );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
  }
226
 
227
- public function path() {
228
- return $this->conform_dir( $this->path );
 
 
 
 
 
 
 
 
 
 
 
 
229
  }
230
 
231
- public function archive_method() {
 
 
 
 
 
 
 
232
  return $this->archive_method;
233
  }
234
 
235
- public function mysqldump_method() {
 
 
 
 
 
 
 
236
  return $this->mysqldump_method;
237
  }
238
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  /**
240
  * Kick off a backup
241
  *
@@ -244,16 +608,16 @@ class HM_Backup {
244
  */
245
  public function backup() {
246
 
247
- do_action( 'hmbkp_backup_started', $this );
248
 
249
  // Backup database
250
- if ( ! $this->files_only )
251
- $this->mysqldump();
252
 
253
  // Zip everything up
254
  $this->archive();
255
 
256
- do_action( 'hmbkp_backup_complete', $this );
257
 
258
  }
259
 
@@ -264,62 +628,64 @@ class HM_Backup {
264
  * if not.
265
  *
266
  * @access public
267
- * @return null
268
  */
269
- public function mysqldump() {
270
 
271
- do_action( 'hmbkp_mysqldump_started' );
272
 
273
- $this->mysqldump_method = 'mysqldump';
 
274
 
275
- // Use mysqldump if we can
276
- if ( $this->mysqldump_command_path ) {
277
 
278
- $host = reset( explode( ':', DB_HOST ) );
279
- $port = strpos( DB_HOST, ':' ) ? end( explode( ':', DB_HOST ) ) : '';
280
 
281
- // Path to the mysqldump executable
282
- $cmd = escapeshellarg( $this->mysqldump_command_path );
283
 
284
- // No Create DB command
285
- $cmd .= ' --no-create-db';
286
 
287
- // Make sure binary data is exported properly
288
- $cmd .= ' --hex-blob';
289
 
290
- // Username
291
- $cmd .= ' -u ' . escapeshellarg( DB_USER );
292
 
293
- // Don't pass the password if it's blank
294
- if ( DB_PASSWORD )
295
- $cmd .= ' -p' . escapeshellarg( DB_PASSWORD );
296
 
297
- // Set the host
298
- $cmd .= ' -h ' . escapeshellarg( $host );
299
 
300
- // Set the port if it was set
301
- if ( ! empty( $port ) )
302
- $cmd .= ' -P ' . $port;
303
 
304
- // The file we're saving too
305
- $cmd .= ' -r ' . escapeshellarg( $this->database_dump_filepath() );
306
 
307
- // The database we're dumping
308
- $cmd .= ' ' . escapeshellarg( DB_NAME );
 
309
 
310
- // Pipe STDERR to STDOUT
311
- $cmd .= ' 2>&1';
312
 
313
- // Store any returned data in warning
314
- $this->warning( $this->mysqldump_method, shell_exec( $cmd ) );
 
315
 
316
- }
 
317
 
318
- // If not or if the shell mysqldump command failed, use the PHP fallback
319
- if ( ! file_exists( $this->database_dump_filepath() ) )
320
- $this->mysqldump_fallback();
 
 
321
 
322
- do_action( 'hmbkp_mysqldump_finished' );
 
 
 
323
 
324
  }
325
 
@@ -327,11 +693,10 @@ class HM_Backup {
327
  * PHP mysqldump fallback functions, exports the database to a .sql file
328
  *
329
  * @access public
330
- * @return null
331
  */
332
  public function mysqldump_fallback() {
333
 
334
- $this->errors_to_warnings( $this->mysqldump_method );
335
 
336
  $this->mysqldump_method = 'mysqldump_fallback';
337
 
@@ -369,18 +734,17 @@ class HM_Backup {
369
  * Zip up all the files.
370
  *
371
  * Attempts to use the shell zip command, if
372
- * thats not available then it fallsback to
373
  * PHP ZipArchive and finally PclZip.
374
  *
375
  * @access public
376
- * @return null
377
  */
378
  public function archive() {
379
 
380
- do_action( 'hmbkp_archive_started' );
381
 
382
  // Do we have the path to the zip command
383
- if ( $this->zip_command_path )
384
  $this->zip();
385
 
386
  // If not or if the shell zip failed then use ZipArchive
@@ -392,10 +756,10 @@ class HM_Backup {
392
  $this->pcl_zip();
393
 
394
  // Delete the database dump file
395
- if ( file_exists( $this->database_dump_filepath() ) )
396
- unlink( $this->database_dump_filepath() );
397
 
398
- do_action( 'hmbkp_archive_finished' );
399
 
400
  }
401
 
@@ -403,31 +767,30 @@ class HM_Backup {
403
  * Zip using the native zip command
404
  *
405
  * @access public
406
- * @return null
407
  */
408
  public function zip() {
409
 
410
  $this->archive_method = 'zip';
411
 
412
  // Zip up $this->root with excludes
413
- if ( ! $this->database_only && $this->exclude_string( 'zip' ) )
414
- $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->root() ) . ' && ' . escapeshellarg( $this->zip_command_path ) . ' -rq ' . escapeshellarg( $this->archive_filepath() ) . ' ./' . ' -x ' . $this->exclude_string( 'zip' ) . ' 2>&1' ) );
415
 
416
  // Zip up $this->root without excludes
417
- elseif ( ! $this->database_only )
418
- $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->root() ) . ' && ' . escapeshellarg( $this->zip_command_path ) . ' -rq ' . escapeshellarg( $this->archive_filepath() ) . ' ./' . ' 2>&1' ) );
419
 
420
  // Add the database dump to the archive
421
- if ( ! $this->files_only )
422
- $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->path() ) . ' && ' . escapeshellarg( $this->zip_command_path ) . ' -uq ' . escapeshellarg( $this->archive_filepath() ) . ' ' . escapeshellarg( $this->database_dump_filename() ) . ' 2>&1' ) );
423
 
424
- $this->check_archive();
425
 
426
  }
427
 
428
  /**
429
  * Fallback for creating zip archives if zip command is
430
- * unnavailable.
431
  *
432
  * @access public
433
  * @param string $path
@@ -439,23 +802,23 @@ class HM_Backup {
439
 
440
  $zip = new ZipArchive();
441
 
442
- if ( ! class_exists( 'ZipArchive' ) || ! $zip->open( $this->archive_filepath(), ZIPARCHIVE::CREATE ) )
443
  return;
444
 
445
- if ( ! $this->database_only ) {
446
 
447
  $files_added = 0;
448
 
449
- foreach ( $this->files() as $file ) {
450
 
451
- if ( is_dir( trailingslashit( $this->root() ) . $file ) )
452
- $zip->addEmptyDir( trailingslashit( $file ) );
453
 
454
- elseif ( is_file( trailingslashit( $this->root() ) . $file ) )
455
- $zip->addFile( trailingslashit( $this->root() ) . $file, $file );
456
 
457
  if ( ++$files_added % 500 === 0 )
458
- if ( ! $zip->close() || ! $zip->open( $this->archive_filepath(), ZIPARCHIVE::CREATE ) )
459
  return;
460
 
461
  }
@@ -463,8 +826,8 @@ class HM_Backup {
463
  }
464
 
465
  // Add the database
466
- if ( ! $this->files_only )
467
- $zip->addFile( $this->database_dump_filepath(), $this->database_dump_filename() );
468
 
469
  if ( $zip->status )
470
  $this->warning( $this->archive_method, $zip->status );
@@ -474,13 +837,13 @@ class HM_Backup {
474
 
475
  $zip->close();
476
 
477
- $this->check_archive();
478
 
479
  }
480
 
481
  /**
482
  * Fallback for creating zip archives if zip command and ZipArchive are
483
- * unnavailable.
484
  *
485
  * Uses the PclZip library that ships with WordPress
486
  *
@@ -498,21 +861,38 @@ class HM_Backup {
498
 
499
  $this->load_pclzip();
500
 
501
- $archive = new PclZip( $this->archive_filepath() );
502
 
503
  // Zip up everything
504
- if ( ! $this->database_only )
505
- if ( ! $archive->add( $this->root(), PCLZIP_OPT_REMOVE_PATH, $this->root(), PCLZIP_CB_PRE_ADD, 'hmbkp_pclzip_callback' ) )
506
  $this->warning( $this->archive_method, $archive->errorInfo( true ) );
507
 
508
  // Add the database
509
- if ( ! $this->files_only )
510
- if ( ! $archive->add( $this->database_dump_filepath(), PCLZIP_OPT_REMOVE_PATH, $this->path() ) )
511
  $this->warning( $this->archive_method, $archive->errorInfo( true ) );
512
 
513
  unset( $GLOBALS['_hmbkp_exclude_string'] );
514
 
515
- $this->check_archive();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
516
 
517
  }
518
 
@@ -522,30 +902,30 @@ class HM_Backup {
522
  * @access public
523
  * @return bool
524
  */
525
- public function check_archive() {
526
 
527
  // If we've already passed then no need to check again
528
  if ( ! empty( $this->archive_verified ) )
529
  return true;
530
 
531
- if ( ! file_exists( $this->archive_filepath() ) )
532
- $this->error( $this->archive_method(), __( 'The backup file was not created', 'hmbkp' ) );
533
 
534
  // Verify using the zip command if possible
535
- if ( $this->zip_command_path ) {
536
 
537
- $verify = shell_exec( escapeshellarg( $this->zip_command_path ) . ' -T ' . escapeshellarg( $this->archive_filepath() ) . ' 2> /dev/null' );
538
 
539
  if ( strpos( $verify, 'OK' ) === false )
540
- $this->error( $this->archive_method(), $verify );
541
 
542
  }
543
 
544
  // If there are errors delete the backup file.
545
- if ( $this->errors( $this->archive_method() ) && file_exists( $this->archive_filepath() ) )
546
- unlink( $this->archive_filepath() );
547
 
548
- if ( $this->errors( $this->archive_method() ) )
549
  return false;
550
 
551
  return $this->archive_verified = true;
@@ -554,12 +934,12 @@ class HM_Backup {
554
 
555
  /**
556
  * Generate the array of files to be backed up by looping through
557
- * root, ignored unreadable files and excludes
558
  *
559
  * @access public
560
  * @return array
561
  */
562
- public function files() {
563
 
564
  if ( ! empty( $this->files ) )
565
  return $this->files;
@@ -568,39 +948,42 @@ class HM_Backup {
568
 
569
  if ( defined( 'RecursiveDirectoryIterator::FOLLOW_SYMLINKS' ) ) {
570
 
571
- $filesystem = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $this->root(), RecursiveDirectoryIterator::FOLLOW_SYMLINKS ), RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD );
572
 
573
  $excludes = $this->exclude_string( 'regex' );
574
 
575
  foreach ( $filesystem as $file ) {
576
 
577
- if ( ! $file->isReadable() ) {
578
- $this->unreadable_files[] = $file->getPathName();
 
 
 
 
 
 
 
 
579
  continue;
580
- }
581
 
582
- $pathname = str_ireplace( trailingslashit( $this->root() ), '', $this->conform_dir( $file->getPathname() ) );
583
 
584
  // Excludes
585
- if ( $excludes && preg_match( '(' . $excludes . ')', $pathname ) )
586
  continue;
587
 
588
- // Don't include database dump as it's added separately
589
- if ( basename( $pathname ) == $this->database_dump_filename() )
590
- continue;
591
-
592
- $this->files[] = $pathname;
593
 
594
  }
595
 
596
  } else {
597
 
598
- $this->files = $this->files_fallback( $this->root() );
599
 
600
  }
601
 
602
  if ( ! empty( $this->unreadable_files ) )
603
- $this->warning( $this->archive_method(), __( 'The following files are unreadable and couldn\'t be backed up: ', 'hmbkp' ) . implode( ', ', $this->unreadable_files ) );
604
 
605
  return $this->files;
606
 
@@ -613,7 +996,7 @@ class HM_Backup {
613
  * Used if RecursiveDirectoryIterator::FOLLOW_SYMLINKS isn't available
614
  *
615
  * @access private
616
- * @param stromg $dir
617
  * @param array $files. (default: array())
618
  * @return array
619
  */
@@ -626,22 +1009,21 @@ class HM_Backup {
626
  while ( $file = readdir( $handle ) ) :
627
 
628
  // Ignore current dir and containing dir and any unreadable files or directories
629
- if ( $file == '.' || $file == '..' )
630
  continue;
631
 
632
  $filepath = $this->conform_dir( trailingslashit( $dir ) . $file );
633
- $file = str_ireplace( trailingslashit( $this->root() ), '', $filepath );
634
 
635
- if ( ! is_readable( $filepath ) ) {
636
- $this->unreadable_files[] = $filepath;
637
  continue;
638
- }
639
 
640
  // Skip the backups dir and any excluded paths
641
- if ( ( $excludes && preg_match( '(' . $excludes . ')', $file ) ) )
642
  continue;
643
 
644
- $files[] = $file;
645
 
646
  if ( is_dir( $filepath ) )
647
  $files = $this->files_fallback( $filepath, $files );
@@ -652,84 +1034,91 @@ class HM_Backup {
652
 
653
  }
654
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
655
  private function load_pclzip() {
656
 
657
  // Load PclZip
658
  if ( ! defined( 'PCLZIP_TEMPORARY_DIR' ) )
659
- define( 'PCLZIP_TEMPORARY_DIR', trailingslashit( $this->path() ) );
660
 
661
  require_once( ABSPATH . 'wp-admin/includes/class-pclzip.php' );
662
 
663
  }
664
 
665
  /**
666
- * Attempt to work out the path to mysqldump
 
 
667
  *
668
  * @access public
669
- * @return bool
670
  */
671
- public function guess_mysqldump_command_path() {
672
 
673
- if ( ! $this->shell_exec_available() )
674
- return '';
675
-
676
- // List of possible mysqldump locations
677
- $mysqldump_locations = array(
678
- '/usr/local/bin/mysqldump',
679
- '/usr/local/mysql/bin/mysqldump',
680
- '/usr/mysql/bin/mysqldump',
681
- '/usr/bin/mysqldump',
682
- '/opt/local/lib/mysql6/bin/mysqldump',
683
- '/opt/local/lib/mysql5/bin/mysqldump',
684
- '/opt/local/lib/mysql4/bin/mysqldump',
685
- '/xampp/mysql/bin/mysqldump',
686
- '/Program Files/xampp/mysql/bin/mysqldump',
687
- '/Program Files/MySQL/MySQL Server 6.0/bin/mysqldump',
688
- '/Program Files/MySQL/MySQL Server 5.5/bin/mysqldump',
689
- '/Program Files/MySQL/MySQL Server 5.4/bin/mysqldump',
690
- '/Program Files/MySQL/MySQL Server 5.1/bin/mysqldump',
691
- '/Program Files/MySQL/MySQL Server 5.0/bin/mysqldump',
692
- '/Program Files/MySQL/MySQL Server 4.1/bin/mysqldump'
693
- );
694
 
695
- if ( is_null( shell_exec( 'hash mysqldump 2>&1' ) ) )
696
- return 'mysqldump';
697
 
698
- // Find the one which works
699
- foreach ( $mysqldump_locations as $location )
700
- if ( @file_exists( $this->conform_dir( $location ) ) )
701
- return $location;
702
 
703
- return '';
704
 
705
  }
706
 
707
  /**
708
- * Attempt to work out the path to the zip command
709
  *
710
  * @access public
711
- * @return bool
 
712
  */
713
- public function guess_zip_command_path() {
714
-
715
- // Check shell_exec is available and hasn't been explicitly bypassed
716
- if ( ! $this->shell_exec_available() )
717
- return '';
718
-
719
- // List of possible zip locations
720
- $zip_locations = array(
721
- '/usr/bin/zip'
722
- );
723
 
724
- if ( is_null( shell_exec( 'hash zip 2>&1' ) ) )
725
- return 'zip';
726
 
727
- // Find the one which works
728
- foreach ( $zip_locations as $location )
729
- if ( @file_exists( $this->conform_dir( $location ) ) )
730
- return $location;
731
 
732
- return '';
733
 
734
  }
735
 
@@ -743,30 +1132,25 @@ class HM_Backup {
743
  * @param string $context. (default: 'zip')
744
  * @return string
745
  */
746
- public function exclude_string( $context = 'zip' ) {
747
 
748
  // Return a comma separated list by default
749
  $separator = ', ';
750
  $wildcard = '';
751
 
752
  // The zip command
753
- if ( $context == 'zip' ) {
754
  $wildcard = '*';
755
  $separator = ' -x ';
756
 
757
  // The PclZip fallback library
758
- } elseif ( $context == 'regex' ) {
759
  $wildcard = '([\s\S]*?)';
760
  $separator = '|';
761
 
762
  }
763
 
764
- // Sanitize the excludes
765
- $excludes = array_filter( array_unique( array_map( 'trim', (array) $this->excludes ) ) );
766
-
767
- // If path() is inside root(), exclude it
768
- if ( strpos( $this->path(), $this->root() ) !== false )
769
- $excludes[] = trailingslashit( $this->path() );
770
 
771
  foreach( $excludes as $key => &$rule ) {
772
 
@@ -785,115 +1169,46 @@ class HM_Backup {
785
  $fragment = true;
786
 
787
  // Strip $this->root and conform
788
- $rule = str_ireplace( $this->root(), '', untrailingslashit( $this->conform_dir( $rule ) ) );
789
 
790
  // Strip the preceeding slash
791
  if ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) )
792
  $rule = substr( $rule, 1 );
793
 
794
  // Escape string for regex
795
- if ( $context == 'regex' )
796
  $rule = str_replace( '.', '\.', $rule );
797
 
798
  // Convert any existing wildcards
799
- if ( $wildcard != '*' && strpos( $rule, '*' ) !== false )
800
  $rule = str_replace( '*', $wildcard, $rule );
801
 
802
  // Wrap directory fragments and files in wildcards for zip
803
- if ( $context == 'zip' && ( $fragment || $file ) )
804
  $rule = $wildcard . $rule . $wildcard;
805
 
806
  // Add a wildcard to the end of absolute url for zips
807
- if ( $context == 'zip' && $absolute )
808
  $rule .= $wildcard;
809
 
810
  // Add and end carrot to files for pclzip but only if it doesn't end in a wildcard
811
- if ( $file && $context == 'regex' )
812
  $rule .= '$';
813
 
814
  // Add a start carrot to absolute urls for pclzip
815
- if ( $absolute && $context == 'regex' )
816
  $rule = '^' . $rule;
817
 
818
  }
819
 
820
  // Escape shell args for zip command
821
- if ( $context == 'zip' )
822
  $excludes = array_map( 'escapeshellarg', array_unique( $excludes ) );
823
 
824
  return implode( $separator, $excludes );
825
 
826
  }
827
 
828
- /**
829
- * Check whether safe mode is active or not
830
- *
831
- * @access private
832
- * @return bool
833
- */
834
- public function is_safe_mode_active() {
835
-
836
- if ( $safe_mode = ini_get( 'safe_mode' ) && strtolower( $safe_mode ) != 'off' )
837
- return true;
838
-
839
- return false;
840
-
841
- }
842
-
843
- /**
844
- * Check whether shell_exec has been disabled.
845
- *
846
- * @access private
847
- * @return bool
848
- */
849
- private function shell_exec_available() {
850
-
851
- // Are we in Safe Mode
852
- if ( $this->is_safe_mode_active() )
853
- return false;
854
-
855
- // Is shell_exec disabled?
856
- if ( in_array( 'shell_exec', array_map( 'trim', explode( ',', ini_get( 'disable_functions' ) ) ) ) )
857
- return false;
858
-
859
- // Can we issue a simple command
860
- if ( ! @shell_exec( 'pwd' ) )
861
- return false;
862
-
863
- return true;
864
-
865
- }
866
-
867
- /**
868
- * Sanitize a directory path
869
- *
870
- * @access public
871
- * @param string $dir
872
- * @param bool $rel. (default: false)
873
- * @return string $dir
874
- */
875
- public function conform_dir( $dir, $recursive = false ) {
876
-
877
- // Assume empty dir is root
878
- if ( ! $dir )
879
- $dir = '/';
880
-
881
- // Replace single forward slash (looks like double slash because we have to escape it)
882
- $dir = str_replace( '\\', '/', $dir );
883
- $dir = str_replace( '//', '/', $dir );
884
-
885
- // Remove the trailing slash
886
- if ( $dir !== '/' )
887
- $dir = untrailingslashit( $dir );
888
-
889
- // Carry on until completely normalized
890
- if ( ! $recursive && $this->conform_dir( $dir, true ) != $dir )
891
- return $this->conform_dir( $dir );
892
-
893
- return (string) $dir;
894
-
895
- }
896
-
897
  /**
898
  * Add backquotes to tables and db-names inSQL queries. Taken from phpMyAdmin.
899
  *
@@ -902,7 +1217,7 @@ class HM_Backup {
902
  */
903
  private function sql_backquote( $a_name ) {
904
 
905
- if ( ! empty( $a_name ) && $a_name != '*' ) {
906
 
907
  if ( is_array( $a_name ) ) {
908
 
@@ -1001,7 +1316,7 @@ class HM_Backup {
1001
  $field_set[$j] = $this->sql_backquote( mysql_field_name( $result, $j ) );
1002
  $type = mysql_field_type( $result, $j );
1003
 
1004
- if ( $type == 'tinyint' || $type == 'smallint' || $type == 'mediumint' || $type == 'int' || $type == 'bigint' || $type == 'timestamp')
1005
  $field_num[$j] = true;
1006
 
1007
  else
@@ -1026,7 +1341,7 @@ class HM_Backup {
1026
  if ( ! isset($row[$j] ) ) {
1027
  $values[] = 'NULL';
1028
 
1029
- } elseif ( $row[$j] == '0' || $row[$j] != '' ) {
1030
 
1031
  // a number
1032
  if ( $field_num[$j] )
@@ -1045,7 +1360,7 @@ class HM_Backup {
1045
  $sql_file .= " \n" . $entries . implode( ', ', $values ) . ") ;";
1046
 
1047
  // write the rows in batches of 100
1048
- if ( $batch_write == 100 ) {
1049
  $batch_write = 0;
1050
  $this->write_sql( $sql_file );
1051
  $sql_file = '';
@@ -1099,7 +1414,7 @@ class HM_Backup {
1099
  */
1100
  private function write_sql( $sql ) {
1101
 
1102
- $sqlname = $this->database_dump_filepath();
1103
 
1104
  // Actually write the sql file
1105
  if ( is_writable( $sqlname ) || ! file_exists( $sqlname ) ) {
@@ -1122,9 +1437,8 @@ class HM_Backup {
1122
  * Get the errors
1123
  *
1124
  * @access public
1125
- * @return null
1126
  */
1127
- public function errors( $context = null ) {
1128
 
1129
  if ( ! empty( $context ) )
1130
  return isset( $this->errors[$context] ) ? $this->errors[$context] : array();
@@ -1140,7 +1454,6 @@ class HM_Backup {
1140
  * @access private
1141
  * @param string $context
1142
  * @param mixed $error
1143
- * @return null
1144
  */
1145
  private function error( $context, $error ) {
1146
 
@@ -1156,11 +1469,10 @@ class HM_Backup {
1156
  *
1157
  * @access private
1158
  * @param string $context. (default: null)
1159
- * @return null
1160
  */
1161
  private function errors_to_warnings( $context = null ) {
1162
 
1163
- $errors = empty( $context ) ? $this->errors() : array( $context => $this->errors( $context ) );
1164
 
1165
  if ( empty( $errors ) )
1166
  return;
@@ -1181,9 +1493,8 @@ class HM_Backup {
1181
  * Get the warnings
1182
  *
1183
  * @access public
1184
- * @return null
1185
  */
1186
- public function warnings( $context = null ) {
1187
 
1188
  if ( ! empty( $context ) )
1189
  return isset( $this->warnings[$context] ) ? $this->warnings[$context] : array();
@@ -1199,7 +1510,6 @@ class HM_Backup {
1199
  * @access private
1200
  * @param string $context
1201
  * @param mixed $warning
1202
- * @return null
1203
  */
1204
  private function warning( $context, $warning ) {
1205
 
@@ -1219,11 +1529,10 @@ class HM_Backup {
1219
  * @param string $message
1220
  * @param string $file
1221
  * @param string $line
1222
- * @return null
1223
  */
1224
  public function error_handler( $type ) {
1225
 
1226
- if ( ( defined( 'E_DEPRECATED' ) && $type == E_DEPRECATED ) || ( defined( 'E_STRICT' ) && $type == E_STRICT ) || error_reporting() === 0 )
1227
  return false;
1228
 
1229
  $args = func_get_args();
3
  /**
4
  * Generic file and database backup class
5
  *
6
+ * @version 2.0 Beta
7
  */
8
  class HM_Backup {
9
 
11
  * The path where the backup file should be saved
12
  *
13
  * @string
14
+ * @access private
 
 
 
 
 
 
 
 
15
  */
16
+ private $path = '';
17
 
18
  /**
19
+ * The backup type, must be either complete, file or database
20
  *
21
+ * @string
22
+ * @access private
23
  */
24
+ private $type = '';
25
 
26
  /**
27
  * The filename of the backup file
28
  *
29
  * @string
30
+ * @access private
31
  */
32
+ private $archive_filename = '';
33
 
34
  /**
35
  * The filename of the database dump
36
  *
37
  * @string
38
+ * @access private
39
  */
40
+ private $database_dump_filename = '';
41
 
42
  /**
43
  * The path to the zip command
44
  *
45
  * @string
46
+ * @access private
47
  */
48
+ private $zip_command_path;
49
 
50
  /**
51
  * The path to the mysqldump command
52
  *
53
  * @string
54
+ * @access private
55
  */
56
+ private $mysqldump_command_path;
57
 
58
  /**
59
  * An array of exclude rules
60
  *
61
  * @array
62
+ * @access private
63
  */
64
+ private $excludes = array();
65
 
66
  /**
67
  * The path that should be backed up
68
  *
69
  * @var string
70
+ * @access private
71
  */
72
+ private $root = '';
73
 
74
  /**
75
  * Holds the current db connection
80
  private $db;
81
 
82
  /**
83
+ * An array of all the files in root
84
+ * excluding excludes and unreadable files
85
  *
86
+ * @var array
87
+ * @access private
 
88
  */
89
+ private $files = array();
90
 
91
  /**
92
  * An array of all the files in root
93
+ * that match the exclude rules
94
  *
95
  * @var array
96
  * @access private
97
  */
98
+ private $excluded_files = array();
99
+
100
+ /**
101
+ * An array of all the files in root
102
+ * that are unreadable
103
+ *
104
+ * @var array
105
+ * @access private
106
+ */
107
+ private $unreadable_files = array();
108
 
109
  /**
110
  * Contains an array of errors
112
  * @var mixed
113
  * @access private
114
  */
115
+ private $errors = array();
116
 
117
  /**
118
  * Contains an array of warnings
120
  * @var mixed
121
  * @access private
122
  */
123
+ private $warnings = array();
124
 
125
  /**
126
  * The archive method used
128
  * @var string
129
  * @access private
130
  */
131
+ private $archive_method = '';
132
 
133
  /**
134
  * The mysqldump method used
136
  * @var string
137
  * @access private
138
  */
139
+ private $mysqldump_method = '';
140
+
141
+ /**
142
+ * Check whether safe mode is active or not
143
+ *
144
+ * @access public
145
+ * @static
146
+ * @return bool
147
+ */
148
+ public static function is_safe_mode_active() {
149
+
150
+ if ( ( $safe_mode = @ini_get( 'safe_mode' ) ) && strtolower( $safe_mode ) != 'off' )
151
+ return true;
152
+
153
+ return false;
154
+
155
+ }
156
+
157
+ /**
158
+ * Check whether shell_exec has been disabled.
159
+ *
160
+ * @access public
161
+ * @static
162
+ * @return bool
163
+ */
164
+ public static function is_shell_exec_available() {
165
+
166
+ // Are we in Safe Mode
167
+ if ( self::is_safe_mode_active() )
168
+ return false;
169
+
170
+ // Is shell_exec disabled?
171
+ if ( in_array( 'shell_exec', array_map( 'trim', explode( ',', @ini_get( 'disable_functions' ) ) ) ) )
172
+ return false;
173
+
174
+ // Can we issue a simple echo command?
175
+ if ( ! @shell_exec( 'echo backupwordpress' ) )
176
+ return false;
177
+
178
+ return true;
179
+
180
+ }
181
+
182
+
183
+ /**
184
+ * Attempt to work out the root directory of the site, that
185
+ * is, the path equivelant of home_url().
186
+ *
187
+ * @access public
188
+ * @static
189
+ * @return string $home_path
190
+ */
191
+ public static function get_home_path() {
192
+
193
+ $home = get_option( 'home' );
194
+ $siteurl = get_option( 'siteurl' );
195
+
196
+ $home_path = ABSPATH;
197
+
198
+ if ( ! empty( $home ) && $home !== $siteurl )
199
+ $home_path = trailingslashit( substr( ABSPATH, 0, strrpos( ABSPATH, str_replace( $home, '', $siteurl ) ) ) );
200
+
201
+ return self::conform_dir( $home_path );
202
+
203
+ }
204
+
205
+ /**
206
+ * Sanitize a directory path
207
+ *
208
+ * @access public
209
+ * @static
210
+ * @param string $dir
211
+ * @param bool $rel. (default: false)
212
+ * @return string $dir
213
+ */
214
+ public static function conform_dir( $dir, $recursive = false ) {
215
+
216
+ // Assume empty dir is root
217
+ if ( ! $dir )
218
+ $dir = '/';
219
+
220
+ // Replace single forward slash (looks like double slash because we have to escape it)
221
+ $dir = str_replace( '\\', '/', $dir );
222
+ $dir = str_replace( '//', '/', $dir );
223
+
224
+ // Remove the trailing slash
225
+ if ( $dir !== '/' )
226
+ $dir = untrailingslashit( $dir );
227
+
228
+ // Carry on until completely normalized
229
+ if ( ! $recursive && self::conform_dir( $dir, true ) != $dir )
230
+ return self::conform_dir( $dir );
231
+
232
+ return (string) $dir;
233
+
234
+ }
235
 
236
  /**
237
  * Sets up the default properties
238
  *
239
  * @access public
 
240
  */
241
  public function __construct() {
242
 
243
+ // Raise the memory limit and max_execution time
244
  @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
245
  @set_time_limit( 0 );
246
 
247
+ // Set a custom error handler so we can track errors
 
248
  set_error_handler( array( &$this, 'error_handler' ) );
249
 
250
+ }
 
251
 
252
+ /**
253
+ * Get the full filepath to the archive file
254
+ *
255
+ * @access public
256
+ * @return string
257
+ */
258
+ public function get_archive_filepath() {
259
+
260
+ return trailingslashit( $this->get_path() ) . $this->get_archive_filename();
261
 
262
+ }
263
 
264
+ /**
265
+ * Get the filename of the archive file
266
+ *
267
+ * @access public
268
+ * @return string
269
+ */
270
+ public function get_archive_filename() {
271
 
272
+ if ( empty( $this->archive_filename ) )
273
+ $this->set_archive_filename( strtolower( sanitize_file_name( implode( '-', array( get_bloginfo( 'name' ), 'backup', date( 'Y-m-d-H-i-s', current_time( 'timestamp' ) ) ) ) ) ) . '.zip' );
274
 
275
+ return $this->archive_filename;
 
276
 
277
  }
278
 
279
  /**
280
+ * Set the filename of the archive file
281
  *
282
  * @access public
283
+ * @param string $filename
 
284
  */
285
+ public function set_archive_filename( $filename ) {
286
+
287
+ if ( empty( $filename ) || ! is_string( $filename ) )
288
+ throw new Exception( 'archive filename must be a non empty string' );
289
 
290
+ if ( pathinfo( $filename, PATHINFO_EXTENSION ) !== 'zip' )
291
+ throw new Exception( 'invalid file extension for archive filename <code>' . $filename . '</code>' );
292
 
293
+ $this->archive_filename = strtolower( sanitize_file_name( remove_accents( $filename ) ) );
294
 
295
  }
296
 
297
  /**
298
+ * Get the full filepath to the database dump file.
299
  *
300
  * @access public
301
  * @return string
302
  */
303
+ public function get_database_dump_filepath() {
304
+
305
+ return trailingslashit( $this->get_path() ) . $this->get_database_dump_filename();
306
+
307
  }
308
 
309
  /**
310
+ * Get the filename of the database dump file
311
  *
312
  * @access public
313
  * @return string
314
  */
315
+ public function get_database_dump_filename() {
316
+
317
+ if ( empty( $this->database_dump_filename ) )
318
+ $this->set_database_dump_filename( strtolower( sanitize_file_name( remove_accents( 'database_' . DB_NAME . '.sql' ) ) ) );
319
+
320
+ return $this->database_dump_filename;
321
+
322
  }
323
 
324
  /**
325
+ * Set the filename of the database dump file
326
  *
327
  * @access public
328
+ * @param string $filename
329
  */
330
+ public function set_database_dump_filename( $filename ) {
331
+
332
+ if ( empty( $filename ) || ! is_string( $filename ) )
333
+ throw new Exception( 'database dump filename must be a non empty string' );
334
+
335
+ if ( pathinfo( $filename, PATHINFO_EXTENSION ) !== 'sql' )
336
+ throw new Exception( 'invalid file extension for database dump filename <code>' . $filename . '</code>' );
337
+
338
+ $this->database_dump_filename = strtolower( sanitize_file_name( remove_accents( $filename ) ) );
339
 
 
 
340
  }
341
 
342
+ /**
343
+ * Get the root directory to backup from
344
+ *
345
+ * Defaults to the root of the path equivalent of your home_url
346
+ *
347
+ * @access public
348
+ * @return string
349
+ */
350
+ public function get_root() {
351
+
352
+ if ( empty( $this->root ) )
353
+ $this->set_root( $this->conform_dir( self::get_home_path() ) );
354
+
355
+ return $this->root;
356
+
357
+ }
358
+
359
+ /**
360
+ * Set the root directory to backup from
361
+ *
362
+ * @access public
363
+ * @param string $path
364
+ * @return null
365
+ */
366
+ public function set_root( $path ) {
367
+
368
+ if ( empty( $path ) || ! is_string( $path ) || ! is_dir ( $path ) )
369
+ throw new Exception( 'Invalid root path <code>' . $path . '</code> must be a valid directory path' );
370
+
371
+ $this->root = $this->conform_dir( $path );
372
+
373
+ }
374
+
375
+ /**
376
+ * Get the directory backups are saved to
377
+ *
378
+ * @access public
379
+ * @return string
380
+ */
381
+ public function get_path() {
382
+
383
+ if ( empty( $this->path ) )
384
+ $this->set_path( $this->conform_dir( WP_CONTENT_DIR . '/backups' ) );
385
+
386
+ return $this->path;
387
+
388
  }
389
 
390
+ /**
391
+ * Set the directory backups are saved to
392
+ *
393
+ * @access public
394
+ * @param string $path
395
+ * @return null
396
+ */
397
+ public function set_path( $path ) {
398
+
399
+ if ( empty( $path ) || ! is_string( $path ) )
400
+ throw new Exception( 'Invalid backup path <code>' . $path . '</code> must be a non empty (string)' );
401
+
402
+ $this->path = $this->conform_dir( $path );
403
+
404
  }
405
 
406
+ /**
407
+ * Get the archive method that was used for the backup
408
+ *
409
+ * Will be either zip, ZipArchive or PclZip
410
+ *
411
+ * @access public
412
+ */
413
+ public function get_archive_method() {
414
  return $this->archive_method;
415
  }
416
 
417
+ /**
418
+ * Get the database dump method that was used for the backup
419
+ *
420
+ * Will be either mysqldump or mysqldump_fallback
421
+ *
422
+ * @access public
423
+ */
424
+ public function get_mysqldump_method() {
425
  return $this->mysqldump_method;
426
  }
427
 
428
+ /**
429
+ * Get the backup type
430
+ *
431
+ * Defaults to complete
432
+ *
433
+ * @access public
434
+ */
435
+ public function get_type() {
436
+
437
+ if ( empty( $this->type ) )
438
+ $this->set_type( 'complete' );
439
+
440
+ return $this->type;
441
+
442
+ }
443
+
444
+ /**
445
+ * Set the backup type
446
+ *
447
+ * $type must be one of complete, database or file
448
+ *
449
+ * @access public
450
+ * @param string $type
451
+ */
452
+ public function set_type( $type ) {
453
+
454
+ if ( ! is_string( $type ) || ! in_array( $type, array( 'file', 'database', 'complete' ) ) )
455
+ throw new Exception( 'Invalid backup type <code>' . $type . '</code> must be one of (string) file, database or complete' );
456
+
457
+ $this->type = $type;
458
+
459
+ }
460
+
461
+ /**
462
+ * Get the path to the mysqldump bin
463
+ *
464
+ * If not explicitly set will attempt to work
465
+ * it out by checking common locations
466
+ *
467
+ * @access public
468
+ * @return string
469
+ */
470
+ public function get_mysqldump_command_path() {
471
+
472
+ // Check shell_exec is available
473
+ if ( ! self::is_shell_exec_available() )
474
+ return '';
475
+
476
+ // Return now if it's already been set
477
+ if ( isset( $this->mysqldump_command_path ) )
478
+ return $this->mysqldump_command_path;
479
+
480
+ $this->mysqldump_command_path = '';
481
+
482
+ // Does mysqldump work
483
+ if ( is_null( shell_exec( 'hash mysqldump 2>&1' ) ) ) {
484
+
485
+ // If so store it for later
486
+ $this->set_mysqldump_command_path( 'mysqldump' );
487
+
488
+ // And return now
489
+ return $this->mysqldump_command_path;
490
+
491
+ }
492
+
493
+ // List of possible mysqldump locations
494
+ $mysqldump_locations = array(
495
+ '/usr/local/bin/mysqldump',
496
+ '/usr/local/mysql/bin/mysqldump',
497
+ '/usr/mysql/bin/mysqldump',
498
+ '/usr/bin/mysqldump',
499
+ '/opt/local/lib/mysql6/bin/mysqldump',
500
+ '/opt/local/lib/mysql5/bin/mysqldump',
501
+ '/opt/local/lib/mysql4/bin/mysqldump',
502
+ '/xampp/mysql/bin/mysqldump',
503
+ '/Program Files/xampp/mysql/bin/mysqldump',
504
+ '/Program Files/MySQL/MySQL Server 6.0/bin/mysqldump',
505
+ '/Program Files/MySQL/MySQL Server 5.5/bin/mysqldump',
506
+ '/Program Files/MySQL/MySQL Server 5.4/bin/mysqldump',
507
+ '/Program Files/MySQL/MySQL Server 5.1/bin/mysqldump',
508
+ '/Program Files/MySQL/MySQL Server 5.0/bin/mysqldump',
509
+ '/Program Files/MySQL/MySQL Server 4.1/bin/mysqldump'
510
+ );
511
+
512
+ // Find the one which works
513
+ foreach ( $mysqldump_locations as $location )
514
+ if ( is_executable( $this->conform_dir( $location ) ) )
515
+ $this->set_mysqldump_command_path( $location );
516
+
517
+ return $this->mysqldump_command_path;
518
+
519
+ }
520
+
521
+ /**
522
+ * Set the path to the mysqldump bin
523
+ *
524
+ * Setting the path to false will cause the database
525
+ * dump to use the php fallback
526
+ *
527
+ * @access public
528
+ * @param mixed $path
529
+ */
530
+ public function set_mysqldump_command_path( $path ) {
531
+
532
+ $this->mysqldump_command_path = $path;
533
+
534
+ }
535
+
536
+ /**
537
+ * Get the path to the zip bin
538
+ *
539
+ * If not explicitly set will attempt to work
540
+ * it out by checking common locations
541
+ *
542
+ * @access public
543
+ * @return string
544
+ */
545
+ public function get_zip_command_path() {
546
+
547
+ // Check shell_exec is available
548
+ if ( ! self::is_shell_exec_available() )
549
+ return '';
550
+
551
+ // Return now if it's already been set
552
+ if ( isset( $this->zip_command_path ) )
553
+ return $this->zip_command_path;
554
+
555
+ $this->zip_command_path = '';
556
+
557
+ // Does zip work
558
+ if ( is_null( shell_exec( 'hash zip 2>&1' ) ) ) {
559
+
560
+ // If so store it for later
561
+ $this->set_zip_command_path( 'zip' );
562
+
563
+ // And return now
564
+ return $this->zip_command_path;
565
+
566
+ }
567
+
568
+ // List of possible zip locations
569
+ $zip_locations = array(
570
+ '/usr/bin/zip'
571
+ );
572
+
573
+ // Find the one which works
574
+ foreach ( $zip_locations as $location )
575
+ if ( is_executable( $this->conform_dir( $location ) ) )
576
+ $this->set_zip_command_path( $location );
577
+
578
+ return $this->zip_command_path;
579
+
580
+ }
581
+
582
+ /**
583
+ * Set the path to the zip bin
584
+ *
585
+ * Setting the path to false will cause the database
586
+ * dump to use the php fallback
587
+ *
588
+ * @access public
589
+ * @param mixed $path
590
+ */
591
+ public function set_zip_command_path( $path ) {
592
+
593
+ $this->zip_command_path = $path;
594
+
595
+ }
596
+
597
+ protected function do_action( $action ) {
598
+
599
+ do_action( $action, $this );
600
+
601
+ }
602
+
603
  /**
604
  * Kick off a backup
605
  *
608
  */
609
  public function backup() {
610
 
611
+ $this->do_action( 'hmbkp_backup_started' );
612
 
613
  // Backup database
614
+ if ( $this->get_type() !== 'file' )
615
+ $this->dump_database();
616
 
617
  // Zip everything up
618
  $this->archive();
619
 
620
+ $this->do_action( 'hmbkp_backup_complete' );
621
 
622
  }
623
 
628
  * if not.
629
  *
630
  * @access public
 
631
  */
632
+ public function dump_database() {
633
 
634
+ $this->do_action( 'hmbkp_mysqldump_started' );
635
 
636
+ if ( $this->get_mysqldump_command_path() )
637
+ $this->mysqldump();
638
 
639
+ if ( empty( $this->mysqldump_verified ) )
640
+ $this->mysqldump_fallback();
641
 
642
+ $this->do_action( 'hmbkp_mysqldump_finished' );
 
643
 
644
+ }
 
645
 
646
+ public function mysqldump() {
 
647
 
648
+ $this->mysqldump_method = 'mysqldump';
 
649
 
650
+ $host = reset( explode( ':', DB_HOST ) );
651
+ $port = strpos( DB_HOST, ':' ) ? end( explode( ':', DB_HOST ) ) : '';
652
 
653
+ // Path to the mysqldump executable
654
+ $cmd = escapeshellarg( $this->get_mysqldump_command_path() );
 
655
 
656
+ // No Create DB command
657
+ $cmd .= ' --no-create-db';
658
 
659
+ // Make sure binary data is exported properly
660
+ $cmd .= ' --hex-blob';
 
661
 
662
+ // Username
663
+ $cmd .= ' -u ' . escapeshellarg( DB_USER );
664
 
665
+ // Don't pass the password if it's blank
666
+ if ( DB_PASSWORD )
667
+ $cmd .= ' -p' . escapeshellarg( DB_PASSWORD );
668
 
669
+ // Set the host
670
+ $cmd .= ' -h ' . escapeshellarg( $host );
671
 
672
+ // Set the port if it was set
673
+ if ( ! empty( $port ) )
674
+ $cmd .= ' -P ' . $port;
675
 
676
+ // The file we're saving too
677
+ $cmd .= ' -r ' . escapeshellarg( $this->get_database_dump_filepath() );
678
 
679
+ // The database we're dumping
680
+ $cmd .= ' ' . escapeshellarg( DB_NAME );
681
+
682
+ // Pipe STDERR to STDOUT
683
+ $cmd .= ' 2>&1';
684
 
685
+ // Store any returned data in warning
686
+ $this->warning( $this->get_mysqldump_method(), shell_exec( $cmd ) );
687
+
688
+ $this->verify_mysqldump();
689
 
690
  }
691
 
693
  * PHP mysqldump fallback functions, exports the database to a .sql file
694
  *
695
  * @access public
 
696
  */
697
  public function mysqldump_fallback() {
698
 
699
+ $this->errors_to_warnings( $this->get_mysqldump_method() );
700
 
701
  $this->mysqldump_method = 'mysqldump_fallback';
702
 
734
  * Zip up all the files.
735
  *
736
  * Attempts to use the shell zip command, if
737
+ * thats not available then it falls back to
738
  * PHP ZipArchive and finally PclZip.
739
  *
740
  * @access public
 
741
  */
742
  public function archive() {
743
 
744
+ $this->do_action( 'hmbkp_archive_started' );
745
 
746
  // Do we have the path to the zip command
747
+ if ( $this->get_zip_command_path() )
748
  $this->zip();
749
 
750
  // If not or if the shell zip failed then use ZipArchive
756
  $this->pcl_zip();
757
 
758
  // Delete the database dump file
759
+ if ( file_exists( $this->get_database_dump_filepath() ) )
760
+ unlink( $this->get_database_dump_filepath() );
761
 
762
+ $this->do_action( 'hmbkp_archive_finished' );
763
 
764
  }
765
 
767
  * Zip using the native zip command
768
  *
769
  * @access public
 
770
  */
771
  public function zip() {
772
 
773
  $this->archive_method = 'zip';
774
 
775
  // Zip up $this->root with excludes
776
+ if ( $this->get_type() !== 'database' && $this->exclude_string( 'zip' ) )
777
+ $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->get_root() ) . ' && ' . escapeshellarg( $this->get_zip_command_path() ) . ' -rq ' . escapeshellarg( $this->get_archive_filepath() ) . ' ./' . ' -x ' . $this->exclude_string( 'zip' ) . ' 2>&1' ) );
778
 
779
  // Zip up $this->root without excludes
780
+ elseif ( $this->get_type() !== 'database' )
781
+ $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->get_root() ) . ' && ' . escapeshellarg( $this->get_zip_command_path() ) . ' -rq ' . escapeshellarg( $this->get_archive_filepath() ) . ' ./' . ' 2>&1' ) );
782
 
783
  // Add the database dump to the archive
784
+ if ( $this->get_type() !== 'file' )
785
+ $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->get_path() ) . ' && ' . escapeshellarg( $this->get_zip_command_path() ) . ' -uq ' . escapeshellarg( $this->get_archive_filepath() ) . ' ' . escapeshellarg( $this->get_database_dump_filename() ) . ' 2>&1' ) );
786
 
787
+ $this->verify_archive();
788
 
789
  }
790
 
791
  /**
792
  * Fallback for creating zip archives if zip command is
793
+ * unavailable.
794
  *
795
  * @access public
796
  * @param string $path
802
 
803
  $zip = new ZipArchive();
804
 
805
+ if ( ! class_exists( 'ZipArchive' ) || ! $zip->open( $this->get_archive_filepath(), ZIPARCHIVE::CREATE ) )
806
  return;
807
 
808
+ if ( $this->get_type() !== 'database' ) {
809
 
810
  $files_added = 0;
811
 
812
+ foreach ( $this->get_files() as $file ) {
813
 
814
+ if ( $file->isDir() )
815
+ $zip->addEmptyDir( trailingslashit( str_ireplace( trailingslashit( $this->get_root() ), '', $this->conform_dir( $file->getPathname() ) ) ) );
816
 
817
+ elseif ( $file->isFile() )
818
+ $zip->addFile( $file->getPathname(), str_ireplace( trailingslashit( $this->get_root() ), '', $this->conform_dir( $file->getPathname() ) ) );
819
 
820
  if ( ++$files_added % 500 === 0 )
821
+ if ( ! $zip->close() || ! $zip->open( $this->get_archive_filepath(), ZIPARCHIVE::CREATE ) )
822
  return;
823
 
824
  }
826
  }
827
 
828
  // Add the database
829
+ if ( $this->get_type() !== 'file' )
830
+ $zip->addFile( $this->get_database_dump_filepath(), $this->get_database_dump_filename() );
831
 
832
  if ( $zip->status )
833
  $this->warning( $this->archive_method, $zip->status );
837
 
838
  $zip->close();
839
 
840
+ $this->verify_archive();
841
 
842
  }
843
 
844
  /**
845
  * Fallback for creating zip archives if zip command and ZipArchive are
846
+ * unavailable.
847
  *
848
  * Uses the PclZip library that ships with WordPress
849
  *
861
 
862
  $this->load_pclzip();
863
 
864
+ $archive = new PclZip( $this->get_archive_filepath() );
865
 
866
  // Zip up everything
867
+ if ( $this->get_type() !== 'database' )
868
+ if ( ! $archive->add( $this->get_root(), PCLZIP_OPT_REMOVE_PATH, $this->get_root(), PCLZIP_CB_PRE_ADD, 'hmbkp_pclzip_callback' ) )
869
  $this->warning( $this->archive_method, $archive->errorInfo( true ) );
870
 
871
  // Add the database
872
+ if ( $this->get_type() !== 'file' )
873
+ if ( ! $archive->add( $this->get_database_dump_filepath(), PCLZIP_OPT_REMOVE_PATH, $this->get_path() ) )
874
  $this->warning( $this->archive_method, $archive->errorInfo( true ) );
875
 
876
  unset( $GLOBALS['_hmbkp_exclude_string'] );
877
 
878
+ $this->verify_archive();
879
+
880
+ }
881
+
882
+ public function verify_mysqldump() {
883
+
884
+ // If we've already passed then no need to check again
885
+ if ( ! empty( $this->mysqldump_verified ) )
886
+ return true;
887
+
888
+ if ( ! file_exists( $this->get_database_dump_filepath() ) )
889
+ $this->error( $this->get_mysqldump_method(), __( 'The mysqldump file was not created', 'hmbkp' ) );
890
+
891
+ if ( $this->get_errors( $this->get_mysqldump_method() ) )
892
+ return false;
893
+
894
+ return $this->mysqldump_verified = true;
895
+
896
 
897
  }
898
 
902
  * @access public
903
  * @return bool
904
  */
905
+ public function verify_archive() {
906
 
907
  // If we've already passed then no need to check again
908
  if ( ! empty( $this->archive_verified ) )
909
  return true;
910
 
911
+ if ( ! file_exists( $this->get_archive_filepath() ) )
912
+ $this->error( $this->get_archive_method(), __( 'The backup file was not created', 'hmbkp' ) );
913
 
914
  // Verify using the zip command if possible
915
+ if ( $this->get_zip_command_path() && $this->get_archive_method() === 'zip' ) {
916
 
917
+ $verify = shell_exec( escapeshellarg( $this->get_zip_command_path() ) . ' -T ' . escapeshellarg( $this->get_archive_filepath() ) . ' 2> /dev/null' );
918
 
919
  if ( strpos( $verify, 'OK' ) === false )
920
+ $this->error( $this->get_archive_method(), $verify );
921
 
922
  }
923
 
924
  // If there are errors delete the backup file.
925
+ if ( $this->get_errors( $this->get_archive_method() ) && file_exists( $this->get_archive_filepath() ) )
926
+ unlink( $this->get_archive_filepath() );
927
 
928
+ if ( $this->get_errors( $this->get_archive_method() ) )
929
  return false;
930
 
931
  return $this->archive_verified = true;
934
 
935
  /**
936
  * Generate the array of files to be backed up by looping through
937
+ * root, ignore unreadable files and excludes
938
  *
939
  * @access public
940
  * @return array
941
  */
942
+ public function get_files() {
943
 
944
  if ( ! empty( $this->files ) )
945
  return $this->files;
948
 
949
  if ( defined( 'RecursiveDirectoryIterator::FOLLOW_SYMLINKS' ) ) {
950
 
951
+ $filesystem = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $this->get_root(), RecursiveDirectoryIterator::FOLLOW_SYMLINKS ), RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD );
952
 
953
  $excludes = $this->exclude_string( 'regex' );
954
 
955
  foreach ( $filesystem as $file ) {
956
 
957
+ /*
958
+ * Ignore current dir and containing dir
959
+ *
960
+ * Required because in PHP 5.2 these aren't skipped automatically by RecursiveDirectoryIterator, they are skipped in PHP > 5.3
961
+ */
962
+ if ( $file === '.' || $file === '..' )
963
+ continue;
964
+
965
+ // Track & skip unreadable files
966
+ if ( ! $file->isReadable() && $this->unreadable_files[] = $file )
967
  continue;
 
968
 
969
+ $pathname = str_ireplace( trailingslashit( $this->get_root() ), '', $this->conform_dir( $file->getPathname() ) );
970
 
971
  // Excludes
972
+ if ( $excludes && preg_match( '(' . $excludes . ')', $pathname ) && $this->excluded_files[] = $file )
973
  continue;
974
 
975
+ $this->files[] = $file;
 
 
 
 
976
 
977
  }
978
 
979
  } else {
980
 
981
+ $this->files = $this->files_fallback( $this->get_root() );
982
 
983
  }
984
 
985
  if ( ! empty( $this->unreadable_files ) )
986
+ $this->warning( $this->get_archive_method(), __( 'The following files are unreadable and couldn\'t be backed up: ', 'hmbkp' ) . implode( ', ', $this->unreadable_files ) );
987
 
988
  return $this->files;
989
 
996
  * Used if RecursiveDirectoryIterator::FOLLOW_SYMLINKS isn't available
997
  *
998
  * @access private
999
+ * @param string $dir
1000
  * @param array $files. (default: array())
1001
  * @return array
1002
  */
1009
  while ( $file = readdir( $handle ) ) :
1010
 
1011
  // Ignore current dir and containing dir and any unreadable files or directories
1012
+ if ( $file === '.' || $file === '..' )
1013
  continue;
1014
 
1015
  $filepath = $this->conform_dir( trailingslashit( $dir ) . $file );
1016
+ $file = str_ireplace( trailingslashit( $this->get_root() ), '', $filepath );
1017
 
1018
+ // Track & skip unreadable files
1019
+ if ( ! is_readable( $filepath ) && $this->unreadable_files[] = new SplFileInfo( $filepath ) )
1020
  continue;
 
1021
 
1022
  // Skip the backups dir and any excluded paths
1023
+ if ( ( $excludes && preg_match( '(' . $excludes . ')', $file ) ) && $this->excluded_files[] = new SplFileInfo( $filepath ) )
1024
  continue;
1025
 
1026
+ $files[] = new SplFileInfo( $filepath );
1027
 
1028
  if ( is_dir( $filepath ) )
1029
  $files = $this->files_fallback( $filepath, $files );
1034
 
1035
  }
1036
 
1037
+ /**
1038
+ * Returns an array of files that match the exclude rules.
1039
+ *
1040
+ * @access public
1041
+ * @return array
1042
+ */
1043
+ public function get_excluded_files() {
1044
+
1045
+ if ( empty( $this->files ) )
1046
+ $this->get_files();
1047
+
1048
+ if ( ! empty( $this->excluded_files ) )
1049
+ return $this->excluded_files;
1050
+
1051
+ return array();
1052
+
1053
+ }
1054
+
1055
+ /**
1056
+ * Returns an array of unreadable files.
1057
+ *
1058
+ * @access public
1059
+ * @return array
1060
+ */
1061
+ public function get_unreadable_files() {
1062
+
1063
+ if ( empty( $this->files ) )
1064
+ $this->get_files();
1065
+
1066
+ if ( ! empty( $this->unreadable_files ) )
1067
+ return $this->unreadable_files;
1068
+
1069
+ return array();
1070
+
1071
+ }
1072
+
1073
  private function load_pclzip() {
1074
 
1075
  // Load PclZip
1076
  if ( ! defined( 'PCLZIP_TEMPORARY_DIR' ) )
1077
+ define( 'PCLZIP_TEMPORARY_DIR', trailingslashit( $this->get_path() ) );
1078
 
1079
  require_once( ABSPATH . 'wp-admin/includes/class-pclzip.php' );
1080
 
1081
  }
1082
 
1083
  /**
1084
+ * Get an array of exclude rules
1085
+ *
1086
+ * The backup path is automatically excluded
1087
  *
1088
  * @access public
1089
+ * @return array
1090
  */
1091
+ public function get_excludes() {
1092
 
1093
+ $excludes = array();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1094
 
1095
+ if ( isset( $this->excludes ) )
1096
+ $excludes = $this->excludes;
1097
 
1098
+ // If path() is inside root(), exclude it
1099
+ if ( strpos( $this->get_path(), $this->get_root() ) !== false )
1100
+ $excludes[] = trailingslashit( $this->get_path() );
 
1101
 
1102
+ return array_unique( $excludes );
1103
 
1104
  }
1105
 
1106
  /**
1107
+ * Set the excludes, expects and array
1108
  *
1109
  * @access public
1110
+ * @param Array $excludes
1111
+ * @param Bool $append
1112
  */
1113
+ public function set_excludes( $excludes, $append = false ) {
 
 
 
 
 
 
 
 
 
1114
 
1115
+ if ( is_string( $excludes ) )
1116
+ $excludes = explode( ',', $excludes );
1117
 
1118
+ if ( $append )
1119
+ $excludes = array_merge( $this->excludes, $excludes );
 
 
1120
 
1121
+ $this->excludes = array_filter( array_unique( array_map( 'trim', $excludes ) ) );
1122
 
1123
  }
1124
 
1132
  * @param string $context. (default: 'zip')
1133
  * @return string
1134
  */
1135
+ private function exclude_string( $context = 'zip' ) {
1136
 
1137
  // Return a comma separated list by default
1138
  $separator = ', ';
1139
  $wildcard = '';
1140
 
1141
  // The zip command
1142
+ if ( $context === 'zip' ) {
1143
  $wildcard = '*';
1144
  $separator = ' -x ';
1145
 
1146
  // The PclZip fallback library
1147
+ } elseif ( $context === 'regex' ) {
1148
  $wildcard = '([\s\S]*?)';
1149
  $separator = '|';
1150
 
1151
  }
1152
 
1153
+ $excludes = $this->get_excludes();
 
 
 
 
 
1154
 
1155
  foreach( $excludes as $key => &$rule ) {
1156
 
1169
  $fragment = true;
1170
 
1171
  // Strip $this->root and conform
1172
+ $rule = str_ireplace( $this->get_root(), '', untrailingslashit( $this->conform_dir( $rule ) ) );
1173
 
1174
  // Strip the preceeding slash
1175
  if ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) )
1176
  $rule = substr( $rule, 1 );
1177
 
1178
  // Escape string for regex
1179
+ if ( $context === 'regex' )
1180
  $rule = str_replace( '.', '\.', $rule );
1181
 
1182
  // Convert any existing wildcards
1183
+ if ( $wildcard !== '*' && strpos( $rule, '*' ) !== false )
1184
  $rule = str_replace( '*', $wildcard, $rule );
1185
 
1186
  // Wrap directory fragments and files in wildcards for zip
1187
+ if ( $context === 'zip' && ( $fragment || $file ) )
1188
  $rule = $wildcard . $rule . $wildcard;
1189
 
1190
  // Add a wildcard to the end of absolute url for zips
1191
+ if ( $context === 'zip' && $absolute )
1192
  $rule .= $wildcard;
1193
 
1194
  // Add and end carrot to files for pclzip but only if it doesn't end in a wildcard
1195
+ if ( $file && $context === 'regex' )
1196
  $rule .= '$';
1197
 
1198
  // Add a start carrot to absolute urls for pclzip
1199
+ if ( $absolute && $context === 'regex' )
1200
  $rule = '^' . $rule;
1201
 
1202
  }
1203
 
1204
  // Escape shell args for zip command
1205
+ if ( $context === 'zip' )
1206
  $excludes = array_map( 'escapeshellarg', array_unique( $excludes ) );
1207
 
1208
  return implode( $separator, $excludes );
1209
 
1210
  }
1211
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1212
  /**
1213
  * Add backquotes to tables and db-names inSQL queries. Taken from phpMyAdmin.
1214
  *
1217
  */
1218
  private function sql_backquote( $a_name ) {
1219
 
1220
+ if ( ! empty( $a_name ) && $a_name !== '*' ) {
1221
 
1222
  if ( is_array( $a_name ) ) {
1223
 
1316
  $field_set[$j] = $this->sql_backquote( mysql_field_name( $result, $j ) );
1317
  $type = mysql_field_type( $result, $j );
1318
 
1319
+ if ( $type === 'tinyint' || $type === 'smallint' || $type === 'mediumint' || $type === 'int' || $type === 'bigint' || $type === 'timestamp')
1320
  $field_num[$j] = true;
1321
 
1322
  else
1341
  if ( ! isset($row[$j] ) ) {
1342
  $values[] = 'NULL';
1343
 
1344
+ } elseif ( $row[$j] === '0' || $row[$j] !== '' ) {
1345
 
1346
  // a number
1347
  if ( $field_num[$j] )
1360
  $sql_file .= " \n" . $entries . implode( ', ', $values ) . ") ;";
1361
 
1362
  // write the rows in batches of 100
1363
+ if ( $batch_write === 100 ) {
1364
  $batch_write = 0;
1365
  $this->write_sql( $sql_file );
1366
  $sql_file = '';
1414
  */
1415
  private function write_sql( $sql ) {
1416
 
1417
+ $sqlname = $this->get_database_dump_filepath();
1418
 
1419
  // Actually write the sql file
1420
  if ( is_writable( $sqlname ) || ! file_exists( $sqlname ) ) {
1437
  * Get the errors
1438
  *
1439
  * @access public
 
1440
  */
1441
+ public function get_errors( $context = null ) {
1442
 
1443
  if ( ! empty( $context ) )
1444
  return isset( $this->errors[$context] ) ? $this->errors[$context] : array();
1454
  * @access private
1455
  * @param string $context
1456
  * @param mixed $error
 
1457
  */
1458
  private function error( $context, $error ) {
1459
 
1469
  *
1470
  * @access private
1471
  * @param string $context. (default: null)
 
1472
  */
1473
  private function errors_to_warnings( $context = null ) {
1474
 
1475
+ $errors = empty( $context ) ? $this->get_errors() : array( $context => $this->get_errors( $context ) );
1476
 
1477
  if ( empty( $errors ) )
1478
  return;
1493
  * Get the warnings
1494
  *
1495
  * @access public
 
1496
  */
1497
+ public function get_warnings( $context = null ) {
1498
 
1499
  if ( ! empty( $context ) )
1500
  return isset( $this->warnings[$context] ) ? $this->warnings[$context] : array();
1510
  * @access private
1511
  * @param string $context
1512
  * @param mixed $warning
 
1513
  */
1514
  private function warning( $context, $warning ) {
1515
 
1529
  * @param string $message
1530
  * @param string $file
1531
  * @param string $line
 
1532
  */
1533
  public function error_handler( $type ) {
1534
 
1535
+ if ( ( defined( 'E_DEPRECATED' ) && $type === E_DEPRECATED ) || ( defined( 'E_STRICT' ) && $type === E_STRICT ) || error_reporting() === 0 )
1536
  return false;
1537
 
1538
  $args = func_get_args();
plugin.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  Plugin Name: WP Remote
5
  Description: Manage your WordPress site with <a href="https://wpremote.com/">WP Remote</a>. Deactivate to clear your API Key.
6
- Version: 2.2.1
7
  Author: Human Made Limited
8
  Author URI: http://hmn.md/
9
  */
3
  /*
4
  Plugin Name: WP Remote
5
  Description: Manage your WordPress site with <a href="https://wpremote.com/">WP Remote</a>. Deactivate to clear your API Key.
6
+ Version: 2.2.2
7
  Author: Human Made Limited
8
  Author URI: http://hmn.md/
9
  */
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: humanmade, joehoyle, mattheu, tcrsavage, willmot
3
  Tags: wpremote, remote administration, multiple wordpress
4
  Requires at least: 2.9
5
  Tested up to: 3.4.1
6
- Stable tag: 2.2.1
7
 
8
  WP Remote is a free web app that enables you to easily manage all of your WordPress powered sites from one place.
9
 
3
  Tags: wpremote, remote administration, multiple wordpress
4
  Requires at least: 2.9
5
  Tested up to: 3.4.1
6
+ Stable tag: 2.2.2
7
 
8
  WP Remote is a free web app that enables you to easily manage all of your WordPress powered sites from one place.
9
 
wprp.api.php CHANGED
@@ -87,7 +87,12 @@ foreach( $actions as $action => $value ) {
87
  // get site info
88
  case 'get_site_info' :
89
 
90
- $actions[$action] = array( 'site_url' => get_site_url(), 'home_url' => get_home_url(), 'admin_url' => get_admin_url(), );
 
 
 
 
 
91
 
92
  break;
93
 
87
  // get site info
88
  case 'get_site_info' :
89
 
90
+ $actions[$action] = array(
91
+ 'site_url' => get_site_url(),
92
+ 'home_url' => get_home_url(),
93
+ 'admin_url' => get_admin_url(),
94
+ 'backups' => _wprp_get_backups_info()
95
+ );
96
 
97
  break;
98
 
wprp.backups.php CHANGED
@@ -25,18 +25,18 @@ function _wprp_backups_api_call( $action ) {
25
  $upload_dir = wp_upload_dir();
26
 
27
  // Store the backup file in the uploads dir
28
- $backup->path = $upload_dir['basedir'] . '/_wpremote_backups';
29
 
30
- $running_file = $backup->path() . '/.backup_running';
31
- $index_php = $backup->path() . '/index.php';
32
 
33
  // Set a random backup filename
34
- $backup->archive_filename = md5( time() ) . '.zip';
35
 
36
  // delete the backups folder to cleanup old backups
37
- _wprp_backups_rmdirtree( $backup->path() );
38
 
39
- if ( ! @mkdir( $backup->path() ) )
40
  return new WP_Error( 'unable-to-create-backups-directory', 'Unable to write the .backup_running file - check your permissions on wp-content/uploads' );
41
 
42
 
@@ -55,7 +55,7 @@ function _wprp_backups_api_call( $action ) {
55
  if ( ! $handle = @fopen( $running_file, 'w' ) )
56
  return new WP_Error( 'unable-to-write-backup-running-file' );
57
 
58
- fwrite( $handle, $backup->archive_filename() );
59
 
60
  fclose( $handle );
61
 
@@ -66,28 +66,28 @@ function _wprp_backups_api_call( $action ) {
66
  if ( ! empty( $_REQUEST['backup_excludes'] ) ) {
67
 
68
  $excludes = array_map( 'urldecode', (array) $_REQUEST['backup_excludes'] );
69
- $backup->excludes = $excludes;
70
  }
71
 
72
  $backup->backup();
73
 
74
- unlink( $backup->path() . '/.backup_completed' );
75
- unlink( $backup->path() . '/.backup_running' );
76
 
77
  // Write the backup runing file for tracking...
78
- $completed_file = $backup->path() . '/.backup_completed';
79
 
80
  if ( ! $handle = @fopen( $completed_file, 'w' ) )
81
  return new WP_Error( 'unable-to-write-backup-completed-file' );
82
 
83
- if ( $backup->errors() || ( $backup->warnings() && ! file_exists( $backup->archive_filepath() ) ) ) {
84
 
85
- $errors = array_merge( $backup->errors(), $backup->warnings() );
86
  fwrite( $handle, json_encode( $errors ) );
87
 
88
  } else {
89
 
90
- fwrite( $handle, 'file:' . $backup->archive_filename() );
91
  }
92
 
93
  fclose( $handle );
@@ -153,4 +153,17 @@ function _wprp_backups_rmdirtree( $dir ) {
153
 
154
  return @rmdir( $dir );
155
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  }
25
  $upload_dir = wp_upload_dir();
26
 
27
  // Store the backup file in the uploads dir
28
+ $backup->set_path( $upload_dir['basedir'] . '/_wpremote_backups' );
29
 
30
+ $running_file = $backup->get_path() . '/.backup_running';
31
+ $index_php = $backup->get_path() . '/index.php';
32
 
33
  // Set a random backup filename
34
+ $backup->set_archive_filename( md5( time() ) . '.zip' );
35
 
36
  // delete the backups folder to cleanup old backups
37
+ _wprp_backups_rmdirtree( $backup->get_path() );
38
 
39
+ if ( ! @mkdir( $backup->get_path() ) )
40
  return new WP_Error( 'unable-to-create-backups-directory', 'Unable to write the .backup_running file - check your permissions on wp-content/uploads' );
41
 
42
 
55
  if ( ! $handle = @fopen( $running_file, 'w' ) )
56
  return new WP_Error( 'unable-to-write-backup-running-file' );
57
 
58
+ fwrite( $handle, $backup->get_archive_filename() );
59
 
60
  fclose( $handle );
61
 
66
  if ( ! empty( $_REQUEST['backup_excludes'] ) ) {
67
 
68
  $excludes = array_map( 'urldecode', (array) $_REQUEST['backup_excludes'] );
69
+ $backup->set_excludes( $excludes );
70
  }
71
 
72
  $backup->backup();
73
 
74
+ unlink( $backup->get_path() . '/.backup_completed' );
75
+ unlink( $backup->get_path() . '/.backup_running' );
76
 
77
  // Write the backup runing file for tracking...
78
+ $completed_file = $backup->get_path() . '/.backup_completed';
79
 
80
  if ( ! $handle = @fopen( $completed_file, 'w' ) )
81
  return new WP_Error( 'unable-to-write-backup-completed-file' );
82
 
83
+ if ( $backup->get_errors() || ( $backup->get_warnings() && ! file_exists( $backup->get_archive_filepath() ) ) ) {
84
 
85
+ $errors = array_merge( $backup->get_errors(), $backup->get_warnings() );
86
  fwrite( $handle, json_encode( $errors ) );
87
 
88
  } else {
89
 
90
+ fwrite( $handle, 'file:' . $backup->get_archive_filename() );
91
  }
92
 
93
  fclose( $handle );
153
 
154
  return @rmdir( $dir );
155
 
156
+ }
157
+
158
+ function _wprp_get_backups_info() {
159
+ if ( ! class_exists( 'hm_backup' ) )
160
+ return;
161
+
162
+ $hm_backup = new HM_Backup();
163
+ $info = array(
164
+ 'mysqldump_path' => $hm_backup->get_mysqldump_command_path(),
165
+ 'zip_path' => $hm_backup->get_zip_command_path()
166
+ );
167
+
168
+ return $info;
169
  }
wprp.themes.php CHANGED
@@ -31,25 +31,49 @@ function _wprp_get_themes() {
31
 
32
  foreach ( (array) $themes as $theme ) {
33
 
34
- $new_version = isset( $current->response[$theme['Template']] ) ? $current->response[$theme['Template']]['new_version'] : null;
 
35
 
36
- if ( $active == $theme['Name'] )
37
- $themes[$theme['Name']]['active'] = true;
38
 
39
- else
40
- $themes[$theme['Name']]['active'] = false;
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
- if ( $new_version ) {
43
 
44
- $themes[$theme['Name']]['latest_version'] = $new_version;
45
- $themes[$theme['Name']]['latest_package'] = $current->response[$theme['Template']]['package'];
46
 
47
- } else {
48
 
49
- $themes[$theme['Name']]['latest_version'] = $theme['Version'];
 
50
 
51
- }
 
52
 
 
 
 
 
 
 
 
 
 
 
 
53
  }
54
 
55
  return $themes;
31
 
32
  foreach ( (array) $themes as $theme ) {
33
 
34
+ // WordPress 3.4+
35
+ if ( is_object( $theme ) && is_a( $theme, 'WP_Theme' ) ) {
36
 
37
+ $new_version = isset( $current->response[$theme['Template']] ) ? $current->response[$theme['Template']]['new_version'] : null;
 
38
 
39
+ $theme_array = array(
40
+ 'Name' => $theme->get( 'Name' ),
41
+ 'Template' => $theme->get( 'Template' ),
42
+ 'active' => $active == $theme->get( 'Name' ),
43
+ 'Stylesheet' => $theme->get( 'Stylesheet' ),
44
+ 'Template' => $theme->get_template(),
45
+ 'Stylesheet'=> $theme->get_stylesheet(),
46
+ 'Screenshot'=> $theme->get_screenshot(),
47
+ 'AuthorURI'=> $theme->get( 'AuthorURI' ),
48
+ 'Author' => $theme->get( 'Author' ),
49
+ 'latest_version' => $new_version ? $new_version : $theme->get( 'Version' ),
50
+ 'Version' => $theme->get( 'Version' ),
51
+ 'ThemeURI' => $theme->get( 'ThemeURI' )
52
+ );
53
 
54
+ $themes[$theme['Name']] = $theme_array;
55
 
56
+ } else {
 
57
 
58
+ $new_version = isset( $current->response[$theme['Template']] ) ? $current->response[$theme['Template']]['new_version'] : null;
59
 
60
+ if ( $active == $theme['Name'] )
61
+ $themes[$theme['Name']]['active'] = true;
62
 
63
+ else
64
+ $themes[$theme['Name']]['active'] = false;
65
 
66
+ if ( $new_version ) {
67
+
68
+ $themes[$theme['Name']]['latest_version'] = $new_version;
69
+ $themes[$theme['Name']]['latest_package'] = $current->response[$theme['Template']]['package'];
70
+
71
+ } else {
72
+
73
+ $themes[$theme['Name']]['latest_version'] = $theme['Version'];
74
+
75
+ }
76
+ }
77
  }
78
 
79
  return $themes;