Version Description
Download this release
Release Info
Developer | willmot |
Plugin | BackUpWordPress |
Version | 1.5.1 |
Comparing to | |
See all releases |
Code changes from version 1.5 to 1.5.1
- admin.menus.php +6 -7
- assets/hmbkp.css +1 -1
- assets/hmbkp.js +5 -1
- functions/backup.functions.php +2 -1
- functions/core.functions.php +22 -50
- hm-backup/hm-backup.php +112 -59
- plugin.php +5 -1
- readme.txt +10 -3
admin.menus.php
CHANGED
@@ -49,13 +49,12 @@ function hmbkp_contextual_help() {
|
|
49 |
|
50 |
require_once( ABSPATH . 'wp-admin/includes/plugin-install.php' );
|
51 |
$plugin = plugins_api( 'plugin_information', array( 'slug' => 'backupwordpress' ) );
|
|
|
|
|
52 |
|
53 |
// Check if help is for the right version.
|
54 |
-
if ( ! empty( $plugin->version ) && version_compare( HMBKP_VERSION, $plugin->version, '
|
55 |
-
$
|
56 |
-
|
57 |
-
if ( ! empty( $plugin->sections['faq'] ) )
|
58 |
-
$contextual_help .= $plugin->sections['faq'];
|
59 |
|
60 |
ob_start();
|
61 |
require_once( HMBKP_PLUGIN_PATH . '/admin.constants.php' );
|
@@ -65,8 +64,8 @@ function hmbkp_contextual_help() {
|
|
65 |
if ( ! method_exists( get_current_screen(), 'add_help_tab' ) )
|
66 |
return;
|
67 |
|
68 |
-
get_current_screen()->add_help_tab( array( 'title' => 'FAQ', 'id' => 'hmbkp_faq', 'content' => $
|
69 |
-
get_current_screen()->add_help_tab( array( 'title' => 'Constants', 'id' => 'hmbkp_constants', 'content' => $constants ) );
|
70 |
|
71 |
get_current_screen()->set_help_sidebar(
|
72 |
'<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
|
49 |
|
50 |
require_once( ABSPATH . 'wp-admin/includes/plugin-install.php' );
|
51 |
$plugin = plugins_api( 'plugin_information', array( 'slug' => 'backupwordpress' ) );
|
52 |
+
|
53 |
+
$warning = '';
|
54 |
|
55 |
// Check if help is for the right version.
|
56 |
+
if ( ! empty( $plugin->version ) && version_compare( HMBKP_VERSION, $plugin->version, '=' ) )
|
57 |
+
$warning = sprintf( '<div id="message" class="updated inline"><p><strong>' . __( 'You are not using the latest stable version of BackUpWordPress', 'hmbkp' ) . '</strong>' . __( ' — The information below is for version %s. View the readme.txt file for help specific to version %s.', 'hmbkp' ) . '</p></div>', '<code>' . $plugin->version . '</code>', '<code>' . HMBKP_VERSION . '</code>' );
|
|
|
|
|
|
|
58 |
|
59 |
ob_start();
|
60 |
require_once( HMBKP_PLUGIN_PATH . '/admin.constants.php' );
|
64 |
if ( ! method_exists( get_current_screen(), 'add_help_tab' ) )
|
65 |
return;
|
66 |
|
67 |
+
get_current_screen()->add_help_tab( array( 'title' => 'FAQ', 'id' => 'hmbkp_faq', 'content' => $warning . $plugin->sections['faq'] ) );
|
68 |
+
get_current_screen()->add_help_tab( array( 'title' => 'Constants', 'id' => 'hmbkp_constants', 'content' => $warning . $constants ) );
|
69 |
|
70 |
get_current_screen()->set_help_sidebar(
|
71 |
'<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
|
assets/hmbkp.css
CHANGED
@@ -19,4 +19,4 @@ tfoot p { margin: 0; font-weight: normal; }
|
|
19 |
.completed th, .completed td { background-color: #FFFFE0; }
|
20 |
.hmbkp_active:before { content: "\00a0 \2713 "; font-size: 11px; }
|
21 |
.hmbkp_active, .hmbkp_active code, #hmbkp-constants .hmbkp_active + dd { background: #E5F7E8; }
|
22 |
-
|
19 |
.completed th, .completed td { background-color: #FFFFE0; }
|
20 |
.hmbkp_active:before { content: "\00a0 \2713 "; font-size: 11px; }
|
21 |
.hmbkp_active, .hmbkp_active code, #hmbkp-constants .hmbkp_active + dd { background: #E5F7E8; }
|
22 |
+
.contextual-help-tabs-wrap .updated { margin: 15px 0 0; }
|
assets/hmbkp.js
CHANGED
@@ -22,8 +22,12 @@ jQuery( document ).ready( function( $ ) {
|
|
22 |
}
|
23 |
);
|
24 |
|
25 |
-
$( '.hmbkp-settings-toggle' ).click( function() {
|
|
|
26 |
$( '#hmbkp-settings' ).toggle();
|
|
|
|
|
|
|
27 |
} );
|
28 |
|
29 |
if ( typeof( screenMeta ) != 'undefined' ) {
|
22 |
}
|
23 |
);
|
24 |
|
25 |
+
$( '.hmbkp-settings-toggle' ).click( function( e ) {
|
26 |
+
|
27 |
$( '#hmbkp-settings' ).toggle();
|
28 |
+
|
29 |
+
e.preventDefault();
|
30 |
+
|
31 |
} );
|
32 |
|
33 |
if ( typeof( screenMeta ) != 'undefined' ) {
|
functions/backup.functions.php
CHANGED
@@ -62,6 +62,7 @@ function hmbkp_delete_old_backups() {
|
|
62 |
/**
|
63 |
* Returns an array of backup files
|
64 |
*
|
|
|
65 |
* @return array $files
|
66 |
*/
|
67 |
function hmbkp_get_backups() {
|
@@ -73,7 +74,7 @@ function hmbkp_get_backups() {
|
|
73 |
if ( $handle = opendir( $hmbkp_path ) ) :
|
74 |
|
75 |
while ( false !== ( $file = readdir( $handle ) ) )
|
76 |
-
if (
|
77 |
$files[@filemtime( trailingslashit( $hmbkp_path ) . $file )] = trailingslashit( $hmbkp_path ) . $file;
|
78 |
|
79 |
closedir( $handle );
|
62 |
/**
|
63 |
* Returns an array of backup files
|
64 |
*
|
65 |
+
* @todo exclude the currently running backup
|
66 |
* @return array $files
|
67 |
*/
|
68 |
function hmbkp_get_backups() {
|
74 |
if ( $handle = opendir( $hmbkp_path ) ) :
|
75 |
|
76 |
while ( false !== ( $file = readdir( $handle ) ) )
|
77 |
+
if ( end( explode( '.', $file ) ) == 'zip' )
|
78 |
$files[@filemtime( trailingslashit( $hmbkp_path ) . $file )] = trailingslashit( $hmbkp_path ) . $file;
|
79 |
|
80 |
closedir( $handle );
|
functions/core.functions.php
CHANGED
@@ -29,10 +29,7 @@ function hmbkp_deactivate() {
|
|
29 |
'hmbkp_running',
|
30 |
'hmbkp_status',
|
31 |
'hmbkp_complete',
|
32 |
-
'hmbkp_email_error'
|
33 |
-
'hmbkp_email_address',
|
34 |
-
'hmbkp_schedule_frequency',
|
35 |
-
'hmbkp_excludes'
|
36 |
);
|
37 |
|
38 |
foreach ( $options as $option )
|
@@ -233,46 +230,6 @@ function hmbkp_send_file( $path ) {
|
|
233 |
return ( connection_status() == 0 ) and !connection_aborted();
|
234 |
}
|
235 |
|
236 |
-
/**
|
237 |
-
* Takes a directory and returns an array of files.
|
238 |
-
* Does traverse sub-directories
|
239 |
-
*
|
240 |
-
* @param string $dir
|
241 |
-
* @param array $files. (default: array())
|
242 |
-
* @return arrat $files
|
243 |
-
*/
|
244 |
-
function hmbkp_ls( $dir, $files = array() ) {
|
245 |
-
|
246 |
-
if ( ! is_readable( $dir ) )
|
247 |
-
return $files;
|
248 |
-
|
249 |
-
$d = opendir( $dir );
|
250 |
-
|
251 |
-
// Get excluded files & directories.
|
252 |
-
$excludes = hmbkp_exclude_string( 'pclzip' );
|
253 |
-
|
254 |
-
while ( $file = readdir( $d ) ) :
|
255 |
-
|
256 |
-
// Ignore current dir and containing dir and any unreadable files or directories
|
257 |
-
if ( $file == '.' || $file == '..' )
|
258 |
-
continue;
|
259 |
-
|
260 |
-
$file = hmbkp_conform_dir( trailingslashit( $dir ) . $file );
|
261 |
-
|
262 |
-
// Skip the backups dir and any excluded paths
|
263 |
-
if ( ! is_readable( $file ) || $file == hmbkp_path() || preg_match( '(' . $excludes . ')', str_replace( ABSPATH, '', $file ) ) )
|
264 |
-
continue;
|
265 |
-
|
266 |
-
$files[] = $file;
|
267 |
-
|
268 |
-
if ( is_dir( $file ) )
|
269 |
-
$files = hmbkp_ls( $file, $files );
|
270 |
-
|
271 |
-
endwhile;
|
272 |
-
|
273 |
-
return $files;
|
274 |
-
}
|
275 |
-
|
276 |
/**
|
277 |
* Recursively delete a directory including
|
278 |
* all the files and sub-directories.
|
@@ -343,7 +300,7 @@ function hmbkp_calculate() {
|
|
343 |
$filesize = 0;
|
344 |
|
345 |
// Don't include database if files only
|
346 |
-
if ( ! hmbkp_get_files_only() )
|
347 |
|
348 |
global $wpdb;
|
349 |
|
@@ -352,17 +309,32 @@ function hmbkp_calculate() {
|
|
352 |
foreach ( $res as $r )
|
353 |
$filesize += (float) $r['Data_length'];
|
354 |
|
355 |
-
|
356 |
|
357 |
-
if ( ! hmbkp_get_database_only() )
|
358 |
|
359 |
// Get rid of any cached filesizes
|
360 |
clearstatcache();
|
361 |
|
362 |
-
|
363 |
-
$filesize += (float) @filesize( $f );
|
364 |
|
365 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
366 |
|
367 |
// Cache in a transient for a week
|
368 |
set_transient( 'hmbkp_estimated_filesize', $filesize, 604800 );
|
29 |
'hmbkp_running',
|
30 |
'hmbkp_status',
|
31 |
'hmbkp_complete',
|
32 |
+
'hmbkp_email_error'
|
|
|
|
|
|
|
33 |
);
|
34 |
|
35 |
foreach ( $options as $option )
|
230 |
return ( connection_status() == 0 ) and !connection_aborted();
|
231 |
}
|
232 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
233 |
/**
|
234 |
* Recursively delete a directory including
|
235 |
* all the files and sub-directories.
|
300 |
$filesize = 0;
|
301 |
|
302 |
// Don't include database if files only
|
303 |
+
if ( ! hmbkp_get_files_only() ) {
|
304 |
|
305 |
global $wpdb;
|
306 |
|
309 |
foreach ( $res as $r )
|
310 |
$filesize += (float) $r['Data_length'];
|
311 |
|
312 |
+
}
|
313 |
|
314 |
+
if ( ! hmbkp_get_database_only() ) {
|
315 |
|
316 |
// Get rid of any cached filesizes
|
317 |
clearstatcache();
|
318 |
|
319 |
+
$files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( ABSPATH ), RecursiveIteratorIterator::SELF_FIRST );
|
|
|
320 |
|
321 |
+
$excludes = hmbkp_exclude_string( 'regex' );
|
322 |
+
|
323 |
+
foreach ( $files as $file ) {
|
324 |
+
|
325 |
+
// Skip bad files
|
326 |
+
if ( ! is_readable( $file ) || ! file_exists( $file ) || is_link( $file ) )
|
327 |
+
continue;
|
328 |
+
|
329 |
+
// Excludes
|
330 |
+
if ( $excludes && preg_match( '(' . $excludes . ')', str_replace( ABSPATH, '', $file ) ) )
|
331 |
+
continue;
|
332 |
+
|
333 |
+
$filesize += (float) @filesize( $file );
|
334 |
+
|
335 |
+
}
|
336 |
+
|
337 |
+
}
|
338 |
|
339 |
// Cache in a transient for a week
|
340 |
set_transient( 'hmbkp_estimated_filesize', $filesize, 604800 );
|
hm-backup/hm-backup.php
CHANGED
@@ -2,6 +2,8 @@
|
|
2 |
|
3 |
/**
|
4 |
* Runs the backup process
|
|
|
|
|
5 |
*/
|
6 |
class HM_Backup {
|
7 |
|
@@ -76,15 +78,15 @@ class HM_Backup {
|
|
76 |
* @access public
|
77 |
*/
|
78 |
public $root;
|
79 |
-
|
80 |
/**
|
81 |
* Holds the current db connection
|
82 |
-
*
|
83 |
* @var resource
|
84 |
* @access private
|
85 |
*/
|
86 |
private $db;
|
87 |
-
|
88 |
static $instance;
|
89 |
|
90 |
/**
|
@@ -115,18 +117,14 @@ class HM_Backup {
|
|
115 |
$this->files_only = false;
|
116 |
|
117 |
}
|
118 |
-
|
119 |
public static function get_instance() {
|
120 |
-
|
121 |
if ( empty( self::$instance ) )
|
122 |
self::$instance = new HM_Backup();
|
123 |
-
|
124 |
return self::$instance;
|
125 |
-
|
126 |
-
}
|
127 |
-
|
128 |
-
public function __destruct() {
|
129 |
-
unset( $GLOBALS['hm_backup'] );
|
130 |
}
|
131 |
|
132 |
/**
|
@@ -210,7 +208,7 @@ class HM_Backup {
|
|
210 |
|
211 |
// The database we're dumping
|
212 |
$cmd .= ' ' . escapeshellarg( DB_NAME );
|
213 |
-
|
214 |
// Send stdout to null
|
215 |
$cmd .= ' 2> /dev/null';
|
216 |
|
@@ -279,21 +277,16 @@ class HM_Backup {
|
|
279 |
do_action( 'hmbkp_archive_started' );
|
280 |
|
281 |
// Do we have the path to the zip command
|
282 |
-
if ( $this->zip_command_path )
|
|
|
283 |
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
|
288 |
-
|
289 |
-
if ( ! $this->files_only )
|
290 |
-
shell_exec( 'cd ' . escapeshellarg( $this->path ) . ' && ' . escapeshellarg( $this->zip_command_path ) . ' -uq ' . escapeshellarg( $this->archive_filepath() ) . ' ' . escapeshellarg( $this->database_dump_filename ) . ' 2> /dev/null' );
|
291 |
-
|
292 |
-
}
|
293 |
-
|
294 |
-
// If not or if the shell zip failed then use the PHP fallback
|
295 |
if ( ! file_exists( $this->archive_filepath() ) )
|
296 |
-
$this->
|
297 |
|
298 |
// Delete the database dump file
|
299 |
if ( file_exists( $this->database_dump_filepath() ) )
|
@@ -303,22 +296,91 @@ class HM_Backup {
|
|
303 |
|
304 |
}
|
305 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
306 |
/**
|
307 |
* Fallback for creating zip archives if zip command is
|
308 |
* unnavailable.
|
309 |
*
|
310 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
311 |
*
|
312 |
-
* @todo support zipArchive
|
313 |
* @access public
|
314 |
* @param string $path
|
315 |
*/
|
316 |
-
public function
|
317 |
-
|
318 |
global $_hmbkp_exclude_string;
|
319 |
-
|
320 |
-
$_hmbkp_exclude_string = $this->exclude_string( '
|
321 |
-
|
322 |
if ( ! defined( 'PCLZIP_TEMPORARY_DIR' ) )
|
323 |
define( 'PCLZIP_TEMPORARY_DIR', $this->path );
|
324 |
|
@@ -330,9 +392,10 @@ class HM_Backup {
|
|
330 |
if ( ! $this->database_only )
|
331 |
$archive->add( $this->root, PCLZIP_OPT_REMOVE_PATH, $this->root, PCLZIP_CB_PRE_ADD, 'hmbkp_pclzip_callback' );
|
332 |
|
|
|
333 |
if ( ! $this->files_only )
|
334 |
$archive->add( $this->database_dump_filepath(), PCLZIP_OPT_REMOVE_PATH, $this->path );
|
335 |
-
|
336 |
unset( $GLOBALS['_hmbkp_exclude_string'] );
|
337 |
|
338 |
}
|
@@ -370,7 +433,7 @@ class HM_Backup {
|
|
370 |
|
371 |
// Find the one which works
|
372 |
foreach ( $mysqldump_locations as $location )
|
373 |
-
if ( shell_exec( $location . '
|
374 |
return $location;
|
375 |
|
376 |
return '';
|
@@ -397,23 +460,13 @@ class HM_Backup {
|
|
397 |
|
398 |
// Find the one which works
|
399 |
foreach ( $zip_locations as $location )
|
400 |
-
if ( shell_exec( $location . '
|
401 |
return $location;
|
402 |
|
403 |
return '';
|
404 |
|
405 |
}
|
406 |
|
407 |
-
/**
|
408 |
-
* Get the array of exclude rules
|
409 |
-
*
|
410 |
-
* @access public
|
411 |
-
* @return array
|
412 |
-
*/
|
413 |
-
public function excludes() {
|
414 |
-
return array_filter( array_unique( array_map( 'trim', array_merge( array( trailingslashit( $this->path ) ), (array) $this->excludes ) ) ) );
|
415 |
-
}
|
416 |
-
|
417 |
/**
|
418 |
* Generate the exclude param string for the zip backup
|
419 |
*
|
@@ -435,16 +488,16 @@ class HM_Backup {
|
|
435 |
$wildcard = '*';
|
436 |
$separator = ' -x ';
|
437 |
|
438 |
-
// The
|
439 |
-
} elseif ( $context == '
|
440 |
-
$wildcard = '([
|
441 |
$separator = '|';
|
442 |
|
443 |
}
|
444 |
|
445 |
-
|
|
|
446 |
|
447 |
-
// Add wildcards to the directories
|
448 |
foreach( $excludes as $key => &$rule ) {
|
449 |
|
450 |
$file = $absolute = $fragment = false;
|
@@ -464,31 +517,32 @@ class HM_Backup {
|
|
464 |
// Strip $this->root and conform
|
465 |
$rule = str_replace( $this->conform_dir( $this->root ), '', untrailingslashit( $this->conform_dir( $rule ) ) );
|
466 |
|
|
|
467 |
if ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) )
|
468 |
$rule = substr( $rule, 1 );
|
469 |
|
470 |
// Escape string for regex
|
471 |
-
if ( $context == '
|
472 |
$rule = str_replace( '.', '\.', $rule );
|
473 |
|
474 |
// Convert any existing wildcards
|
475 |
if ( $wildcard != '*' && strpos( $rule, '*' ) !== false )
|
476 |
$rule = str_replace( '*', $wildcard, $rule );
|
477 |
|
478 |
-
// Wrap directory fragments in wildcards for zip
|
479 |
-
if ( $context == 'zip' && $fragment )
|
480 |
$rule = $wildcard . $rule . $wildcard;
|
481 |
|
482 |
// Add a wildcard to the end of absolute url for zips
|
483 |
if ( $context == 'zip' && $absolute )
|
484 |
$rule .= $wildcard;
|
485 |
|
486 |
-
// Add and end carrot to files for pclzip
|
487 |
-
if ( $file && $context == '
|
488 |
$rule .= '$';
|
489 |
|
490 |
// Add a start carrot to absolute urls for pclzip
|
491 |
-
if ( $absolute && $context == '
|
492 |
$rule = '^' . $rule;
|
493 |
|
494 |
}
|
@@ -496,7 +550,6 @@ class HM_Backup {
|
|
496 |
// Escape shell args for zip command
|
497 |
if ( $context == 'zip' )
|
498 |
$excludes = array_map( 'escapeshellarg', $excludes );
|
499 |
-
|
500 |
|
501 |
return implode( $separator, $excludes );
|
502 |
|
@@ -553,7 +606,7 @@ class HM_Backup {
|
|
553 |
|
554 |
// Remove the trailing slash
|
555 |
$dir = untrailingslashit( $dir );
|
556 |
-
|
557 |
// Carry on until completely normalized
|
558 |
if ( ! $recursive && self::conform_dir( $dir, true ) != $dir )
|
559 |
return self::conform_dir( $dir );
|
@@ -800,11 +853,11 @@ function hmbkp_pclzip_callback( $event, &$file ) {
|
|
800 |
global $_hmbkp_exclude_string;
|
801 |
|
802 |
// Don't try to add unreadable files.
|
803 |
-
if ( ! is_readable( $file['filename'] ) )
|
804 |
return false;
|
805 |
|
806 |
// Match everything else past the exclude list
|
807 |
-
elseif ( preg_match( '(' . $_hmbkp_exclude_string . ')', $file['stored_filename'] ) )
|
808 |
return false;
|
809 |
|
810 |
return true;
|
2 |
|
3 |
/**
|
4 |
* Runs the backup process
|
5 |
+
*
|
6 |
+
* @version 1.2
|
7 |
*/
|
8 |
class HM_Backup {
|
9 |
|
78 |
* @access public
|
79 |
*/
|
80 |
public $root;
|
81 |
+
|
82 |
/**
|
83 |
* Holds the current db connection
|
84 |
+
*
|
85 |
* @var resource
|
86 |
* @access private
|
87 |
*/
|
88 |
private $db;
|
89 |
+
|
90 |
static $instance;
|
91 |
|
92 |
/**
|
117 |
$this->files_only = false;
|
118 |
|
119 |
}
|
120 |
+
|
121 |
public static function get_instance() {
|
122 |
+
|
123 |
if ( empty( self::$instance ) )
|
124 |
self::$instance = new HM_Backup();
|
125 |
+
|
126 |
return self::$instance;
|
127 |
+
|
|
|
|
|
|
|
|
|
128 |
}
|
129 |
|
130 |
/**
|
208 |
|
209 |
// The database we're dumping
|
210 |
$cmd .= ' ' . escapeshellarg( DB_NAME );
|
211 |
+
|
212 |
// Send stdout to null
|
213 |
$cmd .= ' 2> /dev/null';
|
214 |
|
277 |
do_action( 'hmbkp_archive_started' );
|
278 |
|
279 |
// Do we have the path to the zip command
|
280 |
+
if ( $this->zip_command_path )
|
281 |
+
$this->zip();
|
282 |
|
283 |
+
// If not or if the shell zip failed then use ZipArchive
|
284 |
+
if ( ! file_exists( $this->archive_filepath() ) && class_exists( 'ZipArchive' ) && empty( $this->skip_zip_archive ) )
|
285 |
+
$this->zip_archive();
|
286 |
|
287 |
+
// If ZipArchive is unavailable or one of the above failed
|
|
|
|
|
|
|
|
|
|
|
|
|
288 |
if ( ! file_exists( $this->archive_filepath() ) )
|
289 |
+
$this->pcl_zip();
|
290 |
|
291 |
// Delete the database dump file
|
292 |
if ( file_exists( $this->database_dump_filepath() ) )
|
296 |
|
297 |
}
|
298 |
|
299 |
+
public function zip() {
|
300 |
+
|
301 |
+
// Zip up $this->root with excludes
|
302 |
+
if ( ! $this->database_only && $this->exclude_string( 'zip' ) )
|
303 |
+
shell_exec( 'cd ' . escapeshellarg( $this->root ) . ' && ' . escapeshellarg( $this->zip_command_path ) . ' -rq ' . escapeshellarg( $this->archive_filepath() ) . ' ./' . ' -x ' . $this->exclude_string( 'zip' ) . ' 2> /dev/null' );
|
304 |
+
|
305 |
+
// Zip up $this->root
|
306 |
+
elseif ( ! $this->database_only )
|
307 |
+
shell_exec( 'cd ' . escapeshellarg( $this->root ) . ' && ' . escapeshellarg( $this->zip_command_path ) . ' -rq ' . escapeshellarg( $this->archive_filepath() ) . ' ./' . ' 2> /dev/null' );
|
308 |
+
|
309 |
+
// Add the database dump to the archive
|
310 |
+
if ( ! $this->files_only )
|
311 |
+
shell_exec( 'cd ' . escapeshellarg( $this->path ) . ' && ' . escapeshellarg( $this->zip_command_path ) . ' -uq ' . escapeshellarg( $this->archive_filepath() ) . ' ' . escapeshellarg( $this->database_dump_filename ) . ' 2> /dev/null' );
|
312 |
+
|
313 |
+
}
|
314 |
+
|
315 |
/**
|
316 |
* Fallback for creating zip archives if zip command is
|
317 |
* unnavailable.
|
318 |
*
|
319 |
+
* @access public
|
320 |
+
* @param string $path
|
321 |
+
*/
|
322 |
+
public function zip_archive() {
|
323 |
+
|
324 |
+
$zip = new ZipArchive();
|
325 |
+
|
326 |
+
if ( ! class_exists( 'ZipArchive' ) || ! $zip->open( $this->archive_filepath(), ZIPARCHIVE::CREATE ) )
|
327 |
+
return;
|
328 |
+
|
329 |
+
if ( ! $this->database_only ) {
|
330 |
+
|
331 |
+
$files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $this->root ), RecursiveIteratorIterator::SELF_FIRST );
|
332 |
+
|
333 |
+
$files_added = 0;
|
334 |
+
|
335 |
+
$excludes = $this->exclude_string( 'regex' );
|
336 |
+
|
337 |
+
foreach ( $files as $file ) {
|
338 |
+
|
339 |
+
// Skip bad files
|
340 |
+
if ( ! is_readable( $file ) || ! file_exists( $file ) || is_link( $file ) )
|
341 |
+
continue;
|
342 |
+
|
343 |
+
// Excludes
|
344 |
+
if ( $excludes && preg_match( '(' . $excludes . ')', str_replace( $this->root, '', $this->conform_dir( $file ) ) ) )
|
345 |
+
continue;
|
346 |
+
|
347 |
+
if ( is_dir( $file ) )
|
348 |
+
$zip->addEmptyDir( str_replace( trailingslashit( $this->root ), '', trailingslashit( $file ) ) );
|
349 |
+
|
350 |
+
elseif ( is_file( $file ) )
|
351 |
+
$zip->addFile( $file, str_replace( trailingslashit( $this->root ), '', $file ) );
|
352 |
+
|
353 |
+
if ( ++$files_added % 500 === 0 )
|
354 |
+
if ( ! $zip->close() || ! $zip->open( $this->archive_filepath(), ZIPARCHIVE::CREATE ) )
|
355 |
+
return;
|
356 |
+
|
357 |
+
}
|
358 |
+
|
359 |
+
}
|
360 |
+
|
361 |
+
// Add the database
|
362 |
+
if ( ! $this->files_only )
|
363 |
+
$zip->addFile( $this->database_dump_filepath(), $this->database_dump_filename );
|
364 |
+
|
365 |
+
$zip->close();
|
366 |
+
|
367 |
+
}
|
368 |
+
|
369 |
+
/**
|
370 |
+
* Fallback for creating zip archives if zip command and ZipArchive are
|
371 |
+
* unnavailable.
|
372 |
+
*
|
373 |
+
* Uses the PclZip library that ships with WordPress
|
374 |
*
|
|
|
375 |
* @access public
|
376 |
* @param string $path
|
377 |
*/
|
378 |
+
public function pcl_zip() {
|
379 |
+
|
380 |
global $_hmbkp_exclude_string;
|
381 |
+
|
382 |
+
$_hmbkp_exclude_string = $this->exclude_string( 'regex' );
|
383 |
+
|
384 |
if ( ! defined( 'PCLZIP_TEMPORARY_DIR' ) )
|
385 |
define( 'PCLZIP_TEMPORARY_DIR', $this->path );
|
386 |
|
392 |
if ( ! $this->database_only )
|
393 |
$archive->add( $this->root, PCLZIP_OPT_REMOVE_PATH, $this->root, PCLZIP_CB_PRE_ADD, 'hmbkp_pclzip_callback' );
|
394 |
|
395 |
+
// Add the database
|
396 |
if ( ! $this->files_only )
|
397 |
$archive->add( $this->database_dump_filepath(), PCLZIP_OPT_REMOVE_PATH, $this->path );
|
398 |
+
|
399 |
unset( $GLOBALS['_hmbkp_exclude_string'] );
|
400 |
|
401 |
}
|
433 |
|
434 |
// Find the one which works
|
435 |
foreach ( $mysqldump_locations as $location )
|
436 |
+
if ( ! shell_exec( 'hash ' . $location . ' 2>&1' ) )
|
437 |
return $location;
|
438 |
|
439 |
return '';
|
460 |
|
461 |
// Find the one which works
|
462 |
foreach ( $zip_locations as $location )
|
463 |
+
if ( ! shell_exec( 'hash ' . $location . ' 2>&1' ) )
|
464 |
return $location;
|
465 |
|
466 |
return '';
|
467 |
|
468 |
}
|
469 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
470 |
/**
|
471 |
* Generate the exclude param string for the zip backup
|
472 |
*
|
488 |
$wildcard = '*';
|
489 |
$separator = ' -x ';
|
490 |
|
491 |
+
// The PclZip fallback library
|
492 |
+
} elseif ( $context == 'regex' ) {
|
493 |
+
$wildcard = '([\s\S]*?)';
|
494 |
$separator = '|';
|
495 |
|
496 |
}
|
497 |
|
498 |
+
// Sanitize the excludes
|
499 |
+
$excludes = array_filter( array_unique( array_map( 'trim', (array) $this->excludes ) ) );
|
500 |
|
|
|
501 |
foreach( $excludes as $key => &$rule ) {
|
502 |
|
503 |
$file = $absolute = $fragment = false;
|
517 |
// Strip $this->root and conform
|
518 |
$rule = str_replace( $this->conform_dir( $this->root ), '', untrailingslashit( $this->conform_dir( $rule ) ) );
|
519 |
|
520 |
+
// Strip the preceeding slash
|
521 |
if ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) )
|
522 |
$rule = substr( $rule, 1 );
|
523 |
|
524 |
// Escape string for regex
|
525 |
+
if ( $context == 'regex' )
|
526 |
$rule = str_replace( '.', '\.', $rule );
|
527 |
|
528 |
// Convert any existing wildcards
|
529 |
if ( $wildcard != '*' && strpos( $rule, '*' ) !== false )
|
530 |
$rule = str_replace( '*', $wildcard, $rule );
|
531 |
|
532 |
+
// Wrap directory fragments and files in wildcards for zip
|
533 |
+
if ( $context == 'zip' && ( $fragment || $file ) )
|
534 |
$rule = $wildcard . $rule . $wildcard;
|
535 |
|
536 |
// Add a wildcard to the end of absolute url for zips
|
537 |
if ( $context == 'zip' && $absolute )
|
538 |
$rule .= $wildcard;
|
539 |
|
540 |
+
// Add and end carrot to files for pclzip but only if it doesn't end in a wildcard
|
541 |
+
if ( $file && $context == 'regex' )
|
542 |
$rule .= '$';
|
543 |
|
544 |
// Add a start carrot to absolute urls for pclzip
|
545 |
+
if ( $absolute && $context == 'regex' )
|
546 |
$rule = '^' . $rule;
|
547 |
|
548 |
}
|
550 |
// Escape shell args for zip command
|
551 |
if ( $context == 'zip' )
|
552 |
$excludes = array_map( 'escapeshellarg', $excludes );
|
|
|
553 |
|
554 |
return implode( $separator, $excludes );
|
555 |
|
606 |
|
607 |
// Remove the trailing slash
|
608 |
$dir = untrailingslashit( $dir );
|
609 |
+
|
610 |
// Carry on until completely normalized
|
611 |
if ( ! $recursive && self::conform_dir( $dir, true ) != $dir )
|
612 |
return self::conform_dir( $dir );
|
853 |
global $_hmbkp_exclude_string;
|
854 |
|
855 |
// Don't try to add unreadable files.
|
856 |
+
if ( ! is_readable( $file['filename'] ) || ! file_exists( $file['filename'] ) || is_link( $file['filename'] ) )
|
857 |
return false;
|
858 |
|
859 |
// Match everything else past the exclude list
|
860 |
+
elseif ( $_hmbkp_exclude_string && preg_match( '(' . $_hmbkp_exclude_string . ')', $file['stored_filename'] ) )
|
861 |
return false;
|
862 |
|
863 |
return true;
|
plugin.php
CHANGED
@@ -5,7 +5,7 @@ Plugin Name: BackUpWordPress
|
|
5 |
Plugin URI: http://hmn.md/backupwordpress/
|
6 |
Description: Simple automated backups of your WordPress powered website. Once activated you'll find me under <strong>Tools → Backups</strong>.
|
7 |
Author: Human Made Limited
|
8 |
-
Version: 1.5
|
9 |
Author URI: http://hmn.md/
|
10 |
*/
|
11 |
|
@@ -108,6 +108,10 @@ function hmbkp_setup_hm_backup() {
|
|
108 |
$hm_backup->zip_command_path = HMBKP_ZIP_PATH;
|
109 |
|
110 |
$hm_backup->excludes = hmbkp_valid_custom_excludes();
|
|
|
|
|
|
|
|
|
111 |
|
112 |
}
|
113 |
add_action( 'init', 'hmbkp_setup_hm_backup' );
|
5 |
Plugin URI: http://hmn.md/backupwordpress/
|
6 |
Description: Simple automated backups of your WordPress powered website. Once activated you'll find me under <strong>Tools → Backups</strong>.
|
7 |
Author: Human Made Limited
|
8 |
+
Version: 1.5.1
|
9 |
Author URI: http://hmn.md/
|
10 |
*/
|
11 |
|
108 |
$hm_backup->zip_command_path = HMBKP_ZIP_PATH;
|
109 |
|
110 |
$hm_backup->excludes = hmbkp_valid_custom_excludes();
|
111 |
+
|
112 |
+
// If the backup path is inside ABSPATH then exclude it by default
|
113 |
+
if ( strpos( hmbkp_path(), ABSPATH ) === 0 )
|
114 |
+
$hm_backup->excludes[] = trailingslashit( str_replace( untrailingslashit( ABSPATH ), '', hmbkp_path() ) );
|
115 |
|
116 |
}
|
117 |
add_action( 'init', 'hmbkp_setup_hm_backup' );
|
readme.txt
CHANGED
@@ -2,8 +2,8 @@
|
|
2 |
Contributors: humanmade, joehoyle, mattheu, tcrsavage, willmot
|
3 |
Tags: back up, backup, backups, database, zip, db, files, archive, humanmade
|
4 |
Requires at least: 3.1
|
5 |
-
Tested up to: 3.
|
6 |
-
Stable tag: 1.5
|
7 |
|
8 |
Simple automated back ups of your WordPress powered website.
|
9 |
|
@@ -90,6 +90,14 @@ You can also tweet <a href="http://twitter.com/humanmadeltd">@humanmadeltd</a> o
|
|
90 |
|
91 |
== Changelog ==
|
92 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
#### 1.5
|
94 |
|
95 |
* Re-written core backup engine should be more robust especially in edge case scenarios.
|
@@ -101,7 +109,6 @@ You can also tweet <a href="http://twitter.com/humanmadeltd">@humanmadeltd</a> o
|
|
101 |
* 3.3 compatability.
|
102 |
* Set proper charset of MySQL backup, props valericus.
|
103 |
* Fix some inconsistencies between the estimated backup size and actual backup size when excluding files.
|
104 |
-
*
|
105 |
|
106 |
#### 1.4.1
|
107 |
|
2 |
Contributors: humanmade, joehoyle, mattheu, tcrsavage, willmot
|
3 |
Tags: back up, backup, backups, database, zip, db, files, archive, humanmade
|
4 |
Requires at least: 3.1
|
5 |
+
Tested up to: 3.3
|
6 |
+
Stable tag: 1.5.1
|
7 |
|
8 |
Simple automated back ups of your WordPress powered website.
|
9 |
|
90 |
|
91 |
== Changelog ==
|
92 |
|
93 |
+
#### 1.5.1
|
94 |
+
|
95 |
+
* Better detection of `zip` command.
|
96 |
+
* Don't delete user settings on update / deactivate.
|
97 |
+
* Use `ZipArchive` if `zip` is not available, still falls back to `PclZip` if neither `zip` nor `ZipArchive` are installed.
|
98 |
+
* Better exclude rule parsing, fixes lots of edge cases, excludes now pass all 52 unit tests.
|
99 |
+
* Improved the speed of the backup size calculation.
|
100 |
+
|
101 |
#### 1.5
|
102 |
|
103 |
* Re-written core backup engine should be more robust especially in edge case scenarios.
|
109 |
* 3.3 compatability.
|
110 |
* Set proper charset of MySQL backup, props valericus.
|
111 |
* Fix some inconsistencies between the estimated backup size and actual backup size when excluding files.
|
|
|
112 |
|
113 |
#### 1.4.1
|
114 |
|