Version Description
= 3.4 =
This version introduces a major refactoring code responsible for the files and database backup. We made sure to write unit tests for the new code, and we have tested it on several user's sites. It fixes a lot of old bugs, and Windows users should see major improvments to reliablity.
= 3.3.4 =
- WordPress 4.4 compatibility.
= 3.3.1 =
- Fixes a bug that would prevent downloading backups since 3.3.0 - please update.
= 3.2.5 =
- Security fixes related to add_query_arg
= 3.2.1 =
- Important bug fixes. Please upgrade to this version to avoid incomplete or broken backups.
= 3.1.3 =
- Fixes backwards compatibility for add-ons and avoids a Fatal Error. Please upgrade straight to this version before upgrading your add-ons.
= 3.0.4 =
- Fixes a few minor bugs. Immediate update is recommended.
= 3.0.2 =
- Important: we have dropped support for PHP 5.2, you will not be able to activate BackUpWordPress on a server running PHP versions older than PHP 5.3.29
= 3.0.1 =
- This is a critical update. Fixes a bug in the core backup library. Please update immediately.
Download this release
Release Info
Developer | pauldewouters |
Plugin | BackUpWordPress |
Version | 3.4.0 |
Comparing to | |
See all releases |
Code changes from version 3.3.4 to 3.4.0
- admin/actions.php +101 -114
- admin/backups-table.php +8 -2
- admin/backups.php +10 -7
- admin/constants.php +9 -3
- admin/menu.php +12 -14
- admin/page.php +7 -1
- admin/schedule-form-excludes.php +72 -65
- admin/schedule-form.php +18 -11
- admin/schedule-sentence.php +25 -17
- admin/schedule-settings.php +10 -8
- assets/hmbkp.js +10 -46
- assets/hmbkp.min.css +1 -1
- assets/hmbkp.min.js +24 -1
- backupwordpress.php +1 -1
- classes/backup/class-backup-engine-database-imysqldump.php +82 -0
- classes/backup/class-backup-engine-database-mysqldump.php +215 -0
- classes/backup/class-backup-engine-database.php +218 -0
- classes/backup/class-backup-engine-file-zip-archive.php +55 -0
- classes/backup/class-backup-engine-file-zip.php +166 -0
- classes/backup/class-backup-engine-file.php +112 -0
- classes/backup/class-backup-engine.php +197 -0
- classes/backup/class-backup-status.php +120 -0
- classes/backup/class-backup-utilities.php +129 -0
- classes/backup/class-backup.php +200 -0
- classes/class-backup.php +0 -1663
- classes/class-backupwordpress-wp-cli-command.php +22 -32
- classes/class-email-service.php +3 -3
- classes/class-excludes.php +186 -0
- classes/class-path.php +109 -27
- classes/class-plugin.php +21 -6
- classes/class-requirement.php +18 -18
- classes/class-schedule.php +0 -1173
- classes/class-scheduled-backup.php +680 -0
- classes/class-service.php +1 -1
- classes/class-services.php +1 -1
- classes/class-site-size.php +231 -0
- classes/class-webhook-service.php +2 -2
- classes/class-wpremote-webhook-service.php +1 -1
- composer.json +25 -0
- composer.lock +120 -0
- functions/core.php +132 -46
- functions/interface.php +59 -100
- languages/backupwordpress.pot +194 -281
- readme.md +52 -0
- readme.txt +55 -1
- vendor/composer/installed.json +11 -8
- vendor/symfony/finder/Adapter/AbstractAdapter.php +4 -0
- vendor/symfony/finder/Adapter/AbstractFindAdapter.php +4 -0
- vendor/symfony/finder/Adapter/AdapterInterface.php +2 -0
- vendor/symfony/finder/Adapter/BsdFindAdapter.php +4 -0
- vendor/symfony/finder/Adapter/GnuFindAdapter.php +4 -0
- vendor/symfony/finder/Adapter/PhpAdapter.php +4 -0
- vendor/symfony/finder/CHANGELOG.md +5 -0
- vendor/symfony/finder/Exception/AdapterFailureException.php +4 -0
- vendor/symfony/finder/Exception/OperationNotPermitedException.php +4 -0
- vendor/symfony/finder/Exception/ShellCommandFailureException.php +4 -0
- vendor/symfony/finder/Expression/Expression.php +2 -0
- vendor/symfony/finder/Expression/Glob.php +2 -0
- vendor/symfony/finder/Expression/Regex.php +2 -0
- vendor/symfony/finder/Expression/ValueInterface.php +2 -0
- vendor/symfony/finder/Finder.php +125 -18
- vendor/symfony/finder/Iterator/FilePathsIterator.php +4 -0
- vendor/symfony/finder/Iterator/FilecontentFilterIterator.php +1 -19
- vendor/symfony/finder/Iterator/FilenameFilterIterator.php +3 -23
- vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php +51 -3
- vendor/symfony/finder/Iterator/PathFilterIterator.php +1 -19
- vendor/symfony/finder/Iterator/SortableIterator.php +3 -3
- vendor/symfony/finder/LICENSE +1 -1
- vendor/symfony/finder/Shell/Command.php +4 -0
- vendor/symfony/finder/Shell/Shell.php +4 -0
- vendor/symfony/finder/Symfony/Component/Finder/Adapter/AbstractAdapter.php +0 -236
- vendor/symfony/finder/Symfony/Component/Finder/Adapter/AbstractFindAdapter.php +0 -327
- vendor/symfony/finder/Symfony/Component/Finder/Adapter/AdapterInterface.php +0 -144
- vendor/symfony/finder/Symfony/Component/Finder/Adapter/BsdFindAdapter.php +0 -103
- vendor/symfony/finder/Symfony/Component/Finder/Adapter/GnuFindAdapter.php +0 -104
- vendor/symfony/finder/Symfony/Component/Finder/Adapter/PhpAdapter.php +0 -98
- vendor/symfony/finder/Symfony/Component/Finder/CHANGELOG.md +0 -34
- vendor/symfony/finder/Symfony/Component/Finder/Comparator/Comparator.php +0 -98
- vendor/symfony/finder/Symfony/Component/Finder/Comparator/DateComparator.php +0 -53
- vendor/symfony/finder/Symfony/Component/Finder/Comparator/NumberComparator.php +0 -81
- vendor/symfony/finder/Symfony/Component/Finder/Exception/AccessDeniedException.php +0 -19
- vendor/symfony/finder/Symfony/Component/Finder/Exception/AdapterFailureException.php +0 -46
- vendor/symfony/finder/Symfony/Component/Finder/Exception/ExceptionInterface.php +0 -23
- vendor/symfony/finder/Symfony/Component/Finder/Exception/OperationNotPermitedException.php +0 -19
- vendor/symfony/finder/Symfony/Component/Finder/Exception/ShellCommandFailureException.php +0 -45
- vendor/symfony/finder/Symfony/Component/Finder/Expression/Expression.php +0 -146
- vendor/symfony/finder/Symfony/Component/Finder/Expression/Glob.php +0 -157
- vendor/symfony/finder/Symfony/Component/Finder/Expression/Regex.php +0 -321
- vendor/symfony/finder/Symfony/Component/Finder/Expression/ValueInterface.php +0 -60
- vendor/symfony/finder/Symfony/Component/Finder/Finder.php +0 -840
- vendor/symfony/finder/Symfony/Component/Finder/Glob.php +0 -103
- vendor/symfony/finder/Symfony/Component/Finder/Iterator/CustomFilterIterator.php +0 -63
- vendor/symfony/finder/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.php +0 -60
- vendor/symfony/finder/Symfony/Component/Finder/Iterator/DepthRangeFilterIterator.php +0 -47
- vendor/symfony/finder/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php +0 -55
- vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilePathsIterator.php +0 -131
- vendor/symfony/finder/Symfony/Component/Finder/Iterator/FileTypeFilterIterator.php +0 -55
- vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilecontentFilterIterator.php +0 -76
- vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilenameFilterIterator.php +0 -67
- vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilterIterator.php +0 -49
- vendor/symfony/finder/Symfony/Component/Finder/Iterator/MultiplePcreFilterIterator.php +0 -66
- vendor/symfony/finder/Symfony/Component/Finder/Iterator/PathFilterIterator.php +0 -74
- vendor/symfony/finder/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php +0 -126
- vendor/symfony/finder/Symfony/Component/Finder/Iterator/SizeRangeFilterIterator.php +0 -59
- vendor/symfony/finder/Symfony/Component/Finder/Iterator/SortableIterator.php +0 -82
- vendor/symfony/finder/Symfony/Component/Finder/LICENSE +0 -19
- vendor/symfony/finder/Symfony/Component/Finder/README.md +0 -53
- vendor/symfony/finder/Symfony/Component/Finder/Shell/Command.php +0 -294
- vendor/symfony/finder/Symfony/Component/Finder/Shell/Shell.php +0 -97
- vendor/symfony/finder/Symfony/Component/Finder/SplFileInfo.php +0 -77
- vendor/symfony/finder/Symfony/Component/Finder/composer.json +0 -31
- vendor/symfony/finder/Symfony/Component/Finder/phpunit.xml.dist +0 -28
- vendor/symfony/finder/composer.json +5 -2
admin/actions.php
CHANGED
@@ -1,13 +1,15 @@
|
|
1 |
<?php
|
2 |
|
|
|
|
|
3 |
/**
|
4 |
* Delete the backup and then redirect back to the backups page
|
5 |
*/
|
6 |
-
function
|
7 |
|
8 |
check_admin_referer( 'hmbkp_delete_backup', 'hmbkp_delete_backup_nonce' );
|
9 |
|
10 |
-
$schedule = new
|
11 |
|
12 |
$deleted = $schedule->delete_backup( sanitize_text_field( base64_decode( $_GET['hmbkp_backup_archive'] ) ) );
|
13 |
|
@@ -15,54 +17,54 @@ function hmbkp_request_delete_backup() {
|
|
15 |
wp_die( $deleted->get_error_message() );
|
16 |
}
|
17 |
|
18 |
-
wp_safe_redirect(
|
19 |
|
20 |
die;
|
21 |
|
22 |
}
|
23 |
-
add_action( 'admin_post_hmbkp_request_delete_backup', '
|
24 |
|
25 |
/**
|
26 |
* Enable support and then redirect back to the backups page
|
27 |
*/
|
28 |
-
function
|
29 |
|
30 |
check_admin_referer( 'hmbkp_enable_support', 'hmbkp_enable_support_nonce' );
|
31 |
|
32 |
update_option( 'hmbkp_enable_support', true );
|
33 |
|
34 |
-
wp_safe_redirect(
|
35 |
|
36 |
die;
|
37 |
|
38 |
}
|
39 |
-
add_action( 'admin_post_hmbkp_request_enable_support', '
|
40 |
|
41 |
/**
|
42 |
* Delete a schedule and all it's backups and then redirect back to the backups page
|
43 |
*/
|
44 |
-
function
|
45 |
|
46 |
check_admin_referer( 'hmbkp_delete_schedule', 'hmbkp_delete_schedule_nonce' );
|
47 |
|
48 |
-
$schedule = new
|
49 |
$schedule->cancel( true );
|
50 |
|
51 |
-
wp_safe_redirect(
|
52 |
|
53 |
die;
|
54 |
|
55 |
}
|
56 |
-
add_action( 'admin_post_hmbkp_request_delete_schedule', '
|
57 |
|
58 |
/**
|
59 |
* Perform a manual backup
|
60 |
*
|
61 |
* Handles ajax requests as well as standard GET requests
|
62 |
*/
|
63 |
-
function
|
64 |
|
65 |
-
if ( empty( $
|
66 |
die;
|
67 |
}
|
68 |
|
@@ -72,41 +74,29 @@ function hmbkp_request_do_backup() {
|
|
72 |
check_admin_referer( 'hmbkp_run_schedule', 'hmbkp_run_schedule_nonce' );
|
73 |
}
|
74 |
|
75 |
-
|
76 |
|
77 |
// Fixes an issue on servers which only allow a single session per client
|
78 |
session_write_close();
|
79 |
|
80 |
-
$schedule_id = sanitize_text_field( urldecode( $
|
81 |
-
$task = new \HM\Backdrop\Task( '
|
82 |
$task->schedule();
|
83 |
|
84 |
die;
|
85 |
|
86 |
}
|
87 |
-
add_action( 'wp_ajax_hmbkp_run_schedule', '
|
88 |
-
|
89 |
-
function hmbkp_run_schedule_async( $schedule_id ) {
|
90 |
-
|
91 |
-
$schedule = new HM\BackUpWordPress\Scheduled_Backup( $schedule_id );
|
92 |
|
|
|
|
|
93 |
$schedule->run();
|
94 |
-
|
95 |
-
$errors = array_merge( $schedule->backup->get_errors(), $schedule->backup->get_warnings() );
|
96 |
-
|
97 |
-
$notices = array();
|
98 |
-
|
99 |
-
foreach ( $errors as $key => $error ) {
|
100 |
-
$notices[] = implode( ', ', $error );
|
101 |
-
}
|
102 |
-
|
103 |
-
\HM\BackUpWordPress\Notices::get_instance()->set_notices( 'backup_errors', $notices );
|
104 |
}
|
105 |
|
106 |
/**
|
107 |
* Send the download file to the browser and then redirect back to the backups page
|
108 |
*/
|
109 |
-
function
|
110 |
|
111 |
check_admin_referer( 'hmbkp_download_backup', 'hmbkp_download_backup_nonce' );
|
112 |
|
@@ -114,13 +104,13 @@ function hmbkp_request_download_backup() {
|
|
114 |
return;
|
115 |
}
|
116 |
|
117 |
-
$url = str_replace( wp_normalize_path(
|
118 |
|
119 |
global $is_apache;
|
120 |
|
121 |
if ( $is_apache ) {
|
122 |
|
123 |
-
|
124 |
|
125 |
$url = add_query_arg( 'key', HMBKP_SECURE_KEY, $url );
|
126 |
|
@@ -131,59 +121,58 @@ function hmbkp_request_download_backup() {
|
|
131 |
die;
|
132 |
|
133 |
}
|
134 |
-
add_action( 'admin_post_hmbkp_request_download_backup', '
|
135 |
|
136 |
/**
|
137 |
* Cancels a running backup then redirect back to the backups page
|
138 |
*/
|
139 |
-
function
|
140 |
|
141 |
check_admin_referer( 'hmbkp_request_cancel_backup', 'hmbkp-request_cancel_backup_nonce' );
|
142 |
|
143 |
-
$schedule = new
|
|
|
144 |
|
145 |
// Delete the running backup
|
146 |
-
if ( $
|
147 |
-
unlink( trailingslashit(
|
148 |
}
|
149 |
|
150 |
-
if (
|
151 |
-
unlink( $
|
152 |
}
|
153 |
|
154 |
-
|
155 |
|
156 |
-
wp_safe_redirect(
|
157 |
|
158 |
die;
|
159 |
|
160 |
}
|
161 |
-
add_action( 'admin_post_hmbkp_request_cancel_backup', '
|
162 |
|
163 |
/**
|
164 |
* Dismiss an error and then redirect back to the backups page
|
165 |
*/
|
166 |
-
function
|
167 |
|
168 |
-
|
169 |
|
170 |
-
|
171 |
-
|
172 |
-
HM\BackUpWordPress\Notices::get_instance()->clear_all_notices();
|
173 |
|
174 |
wp_safe_redirect( wp_get_referer(), 303 );
|
175 |
|
176 |
die;
|
177 |
|
178 |
}
|
179 |
-
add_action( '
|
180 |
|
181 |
/**
|
182 |
* Catch the schedule service settings form submission
|
183 |
*
|
184 |
* Validate and either return errors or update the schedule
|
185 |
*/
|
186 |
-
function
|
187 |
|
188 |
check_admin_referer( 'hmbkp-edit-schedule-services', 'hmbkp-edit-schedule-services-nonce' );
|
189 |
|
@@ -191,12 +180,12 @@ function hmbkp_edit_schedule_services_submit() {
|
|
191 |
wp_die( __( 'The schedule ID was not provided. Aborting.', 'backupwordpress' ) );
|
192 |
}
|
193 |
|
194 |
-
$schedule = new
|
195 |
|
196 |
$errors = array();
|
197 |
|
198 |
// Save the service options
|
199 |
-
foreach (
|
200 |
$errors = array_merge( $errors, $service->save() );
|
201 |
}
|
202 |
|
@@ -204,22 +193,28 @@ function hmbkp_edit_schedule_services_submit() {
|
|
204 |
|
205 |
if ( $errors ) {
|
206 |
foreach ( $errors as $error ) {
|
207 |
-
|
208 |
}
|
209 |
}
|
210 |
|
211 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
212 |
die;
|
213 |
|
214 |
}
|
215 |
-
add_action( 'admin_post_hmbkp_edit_schedule_services_submit', '
|
216 |
|
217 |
/**
|
218 |
* Catch the schedule settings form submission
|
219 |
*
|
220 |
* Validate and either return errors or update the schedule
|
221 |
*/
|
222 |
-
function
|
223 |
|
224 |
check_admin_referer( 'hmbkp-edit-schedule', 'hmbkp-edit-schedule-nonce' );
|
225 |
|
@@ -227,7 +222,7 @@ function hmbkp_edit_schedule_submit() {
|
|
227 |
die;
|
228 |
}
|
229 |
|
230 |
-
$schedule = new
|
231 |
|
232 |
$errors = array();
|
233 |
|
@@ -259,7 +254,7 @@ function hmbkp_edit_schedule_submit() {
|
|
259 |
$errors['hmbkp_schedule_recurrence']['hmbkp_type'] = __( 'Schedule cannot be empty', 'backupwordpress' );
|
260 |
}
|
261 |
|
262 |
-
elseif ( ! in_array( $schedule_recurrence_type, array_keys(
|
263 |
$errors['hmbkp_schedule_recurrence']['hmbkp_type'] = __( 'Invalid schedule', 'backupwordpress' );
|
264 |
}
|
265 |
|
@@ -363,14 +358,14 @@ function hmbkp_edit_schedule_submit() {
|
|
363 |
}
|
364 |
|
365 |
// Save the service options
|
366 |
-
foreach (
|
367 |
$errors = array_merge( $errors, $service->save() );
|
368 |
}
|
369 |
|
370 |
if ( ! empty( $settings['recurrence'] ) && ! empty( $settings['start_time'] ) ) {
|
371 |
|
372 |
// Calculate the start time depending on the recurrence
|
373 |
-
$start_time =
|
374 |
|
375 |
if ( $start_time ) {
|
376 |
$schedule->set_schedule_start_time( $start_time );
|
@@ -399,7 +394,7 @@ function hmbkp_edit_schedule_submit() {
|
|
399 |
if ( $errors ) {
|
400 |
|
401 |
foreach ( $errors as $error ) {
|
402 |
-
|
403 |
}
|
404 |
|
405 |
}
|
@@ -414,7 +409,7 @@ function hmbkp_edit_schedule_submit() {
|
|
414 |
die;
|
415 |
|
416 |
}
|
417 |
-
add_action( 'admin_post_hmbkp_edit_schedule_submit', '
|
418 |
|
419 |
/**
|
420 |
* Add an exclude rule
|
@@ -422,7 +417,7 @@ add_action( 'admin_post_hmbkp_edit_schedule_submit', 'hmbkp_edit_schedule_submit
|
|
422 |
* @access public
|
423 |
* @return void
|
424 |
*/
|
425 |
-
function
|
426 |
|
427 |
check_admin_referer( 'hmbkp-add-exclude-rule', 'hmbkp-add-exclude-rule-nonce' );
|
428 |
|
@@ -430,7 +425,7 @@ function hmbkp_add_exclude_rule() {
|
|
430 |
return;
|
431 |
}
|
432 |
|
433 |
-
$schedule = new
|
434 |
|
435 |
$exclude_rule = sanitize_text_field( $_GET['hmbkp_exclude_pathname'] );
|
436 |
|
@@ -443,7 +438,7 @@ function hmbkp_add_exclude_rule() {
|
|
443 |
die;
|
444 |
|
445 |
}
|
446 |
-
add_action( 'admin_post_hmbkp_add_exclude_rule', '
|
447 |
|
448 |
/**
|
449 |
* Delete an exclude rule
|
@@ -451,7 +446,7 @@ add_action( 'admin_post_hmbkp_add_exclude_rule', 'hmbkp_add_exclude_rule' );
|
|
451 |
* @access public
|
452 |
* @return void
|
453 |
*/
|
454 |
-
function
|
455 |
|
456 |
check_admin_referer( 'hmbkp_remove_exclude_rule', 'hmbkp-remove_exclude_rule_nonce' );
|
457 |
|
@@ -459,11 +454,12 @@ function hmbkp_remove_exclude_rule() {
|
|
459 |
die;
|
460 |
}
|
461 |
|
462 |
-
$schedule = new
|
463 |
|
464 |
$excludes = $schedule->get_excludes();
|
|
|
465 |
|
466 |
-
$schedule->set_excludes( array_diff( $excludes, (array)
|
467 |
|
468 |
$schedule->save();
|
469 |
|
@@ -472,13 +468,13 @@ function hmbkp_remove_exclude_rule() {
|
|
472 |
die;
|
473 |
|
474 |
}
|
475 |
-
add_action( 'admin_post_hmbkp_remove_exclude_rule', '
|
476 |
|
477 |
/**
|
478 |
*
|
479 |
* @param null
|
480 |
*/
|
481 |
-
function
|
482 |
|
483 |
if ( ! isset( $_GET['hmbkp_recalculate_directory_filesize'] ) || ! check_admin_referer( 'hmbkp-recalculate_directory_filesize' ) ) {
|
484 |
return;
|
@@ -487,7 +483,7 @@ function hmbkp_recalculate_directory_filesize() {
|
|
487 |
// Delete the cached directory size
|
488 |
delete_transient( 'hmbkp_directory_filesizes' );
|
489 |
|
490 |
-
$url = add_query_arg( array( 'action' => 'hmbkp_edit_schedule', 'hmbkp_panel' => 'hmbkp_edit_schedule_excludes' ),
|
491 |
|
492 |
if ( isset( $_GET['hmbkp_directory_browse'] ) ) {
|
493 |
$url = add_query_arg( 'hmbkp_directory_browse', sanitize_text_field( $_GET['hmbkp_directory_browse'] ), $url );
|
@@ -497,54 +493,42 @@ function hmbkp_recalculate_directory_filesize() {
|
|
497 |
die;
|
498 |
|
499 |
}
|
500 |
-
add_action( 'load-' . HMBKP_ADMIN_PAGE, '
|
501 |
-
|
502 |
-
function hmbkp_calculate_site_size() {
|
503 |
-
|
504 |
-
if ( isset( $_GET['hmbkp_schedule_id'] ) ) {
|
505 |
-
|
506 |
-
$current_schedule = new HM\BackUpWordPress\Scheduled_Backup( sanitize_text_field( $_GET['hmbkp_schedule_id'] ) );
|
507 |
|
508 |
-
|
509 |
-
|
510 |
-
// Refresh the schedules from the database to make sure we have the latest changes
|
511 |
-
HM\BackUpWordPress\Schedules::get_instance()->refresh_schedules();
|
512 |
|
513 |
-
|
514 |
-
|
515 |
-
$current_schedule = reset( $schedules );
|
516 |
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
$root = new SplFileInfo( $current_schedule->backup->get_root() );
|
521 |
-
$current_schedule->filesize( $root );
|
522 |
}
|
523 |
|
524 |
}
|
525 |
-
add_action( 'load-' . HMBKP_ADMIN_PAGE, '
|
526 |
|
527 |
/**
|
528 |
* Receive the heartbeat and return backup status
|
529 |
*/
|
530 |
-
function
|
531 |
|
532 |
$response['heartbeat_interval'] = 'fast';
|
533 |
|
534 |
if ( ! empty( $data['hmbkp_schedule_id'] ) ) {
|
535 |
|
536 |
-
$schedule = new
|
|
|
537 |
|
538 |
if ( ! empty( $data['hmbkp_is_in_progress'] ) ) {
|
539 |
|
540 |
-
if ( ! $
|
541 |
$response['hmbkp_schedule_status'] = 0;
|
542 |
|
543 |
// Slow the heartbeat back down
|
544 |
$response['heartbeat_interval'] = 'slow';
|
545 |
|
546 |
} else {
|
547 |
-
$response['hmbkp_schedule_status'] =
|
548 |
}
|
549 |
|
550 |
}
|
@@ -552,9 +536,11 @@ function hmbkp_heartbeat_received( $response, $data ) {
|
|
552 |
if ( ! empty( $data['hmbkp_client_request'] ) ) {
|
553 |
|
554 |
// Pass the site size to be displayed when it's ready.
|
555 |
-
if (
|
|
|
|
|
556 |
|
557 |
-
$response['hmbkp_site_size'] = $
|
558 |
|
559 |
ob_start();
|
560 |
require( HMBKP_PLUGIN_PATH . 'admin/schedule-form-excludes.php' );
|
@@ -566,13 +552,14 @@ function hmbkp_heartbeat_received( $response, $data ) {
|
|
566 |
}
|
567 |
|
568 |
}
|
|
|
569 |
return $response;
|
570 |
|
571 |
}
|
572 |
-
add_filter( 'heartbeat_received', '
|
573 |
|
574 |
// TODO needs work
|
575 |
-
function
|
576 |
|
577 |
check_ajax_referer( 'hmbkp_nonce', 'nonce' );
|
578 |
|
@@ -582,15 +569,15 @@ function hmbkp_display_error_and_offer_to_email_it() {
|
|
582 |
|
583 |
$errors = explode( "\n", wp_strip_all_tags( stripslashes( $_POST['hmbkp_error'] ) ) );
|
584 |
|
585 |
-
|
586 |
|
587 |
wp_send_json_success( wp_get_referer() );
|
588 |
|
589 |
}
|
590 |
-
add_action( 'wp_ajax_hmbkp_backup_error', '
|
591 |
|
592 |
// TODO needs work
|
593 |
-
function
|
594 |
|
595 |
check_ajax_referer( 'hmbkp_nonce', 'nonce' );
|
596 |
|
@@ -605,14 +592,14 @@ function hmbkp_send_error_via_email() {
|
|
605 |
die;
|
606 |
|
607 |
}
|
608 |
-
add_action( 'wp_ajax_hmbkp_email_error', '
|
609 |
|
610 |
/**
|
611 |
* Load the enable support modal contents
|
612 |
*
|
613 |
* @return void
|
614 |
*/
|
615 |
-
function
|
616 |
|
617 |
check_ajax_referer( 'hmbkp_nonce', '_wpnonce' );
|
618 |
|
@@ -621,12 +608,12 @@ function hmbkp_load_enable_support() {
|
|
621 |
die;
|
622 |
|
623 |
}
|
624 |
-
add_action( 'wp_ajax_load_enable_support', '
|
625 |
|
626 |
/**
|
627 |
* Display the running status via ajax
|
628 |
*/
|
629 |
-
function
|
630 |
|
631 |
check_ajax_referer( 'hmbkp_nonce', 'nonce' );
|
632 |
|
@@ -634,7 +621,7 @@ function hmbkp_ajax_is_backup_in_progress() {
|
|
634 |
die;
|
635 |
}
|
636 |
|
637 |
-
$schedule = new
|
638 |
|
639 |
if ( ! $schedule->get_status() ) {
|
640 |
echo 0;
|
@@ -645,12 +632,12 @@ function hmbkp_ajax_is_backup_in_progress() {
|
|
645 |
die;
|
646 |
|
647 |
}
|
648 |
-
add_action( 'wp_ajax_hmbkp_is_in_progress', '
|
649 |
|
650 |
/**
|
651 |
* Display the calculated size via ajax
|
652 |
*/
|
653 |
-
function
|
654 |
|
655 |
check_ajax_referer( 'hmbkp_nonce', 'nonce' );
|
656 |
|
@@ -658,7 +645,7 @@ function hmbkp_ajax_calculate_backup_size() {
|
|
658 |
die;
|
659 |
}
|
660 |
|
661 |
-
$schedule = new
|
662 |
|
663 |
$recalculate_filesize = true;
|
664 |
|
@@ -667,12 +654,12 @@ function hmbkp_ajax_calculate_backup_size() {
|
|
667 |
die;
|
668 |
|
669 |
}
|
670 |
-
add_action( 'wp_ajax_hmbkp_calculate', '
|
671 |
|
672 |
/**
|
673 |
* Test the cron response and if it's not 200 show a warning message
|
674 |
*/
|
675 |
-
function
|
676 |
|
677 |
check_ajax_referer( 'hmbkp_nonce', 'nonce' );
|
678 |
|
@@ -727,4 +714,4 @@ function hmbkp_ajax_cron_test() {
|
|
727 |
die;
|
728 |
|
729 |
}
|
730 |
-
add_action( 'wp_ajax_hmbkp_cron_test', '
|
1 |
<?php
|
2 |
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
/**
|
6 |
* Delete the backup and then redirect back to the backups page
|
7 |
*/
|
8 |
+
function request_delete_backup() {
|
9 |
|
10 |
check_admin_referer( 'hmbkp_delete_backup', 'hmbkp_delete_backup_nonce' );
|
11 |
|
12 |
+
$schedule = new Scheduled_Backup( sanitize_text_field( urldecode( $_GET['hmbkp_schedule_id'] ) ) );
|
13 |
|
14 |
$deleted = $schedule->delete_backup( sanitize_text_field( base64_decode( $_GET['hmbkp_backup_archive'] ) ) );
|
15 |
|
17 |
wp_die( $deleted->get_error_message() );
|
18 |
}
|
19 |
|
20 |
+
wp_safe_redirect( get_settings_url(), 303 );
|
21 |
|
22 |
die;
|
23 |
|
24 |
}
|
25 |
+
add_action( 'admin_post_hmbkp_request_delete_backup', 'HM\BackUpWordPress\request_delete_backup' );
|
26 |
|
27 |
/**
|
28 |
* Enable support and then redirect back to the backups page
|
29 |
*/
|
30 |
+
function request_enable_support() {
|
31 |
|
32 |
check_admin_referer( 'hmbkp_enable_support', 'hmbkp_enable_support_nonce' );
|
33 |
|
34 |
update_option( 'hmbkp_enable_support', true );
|
35 |
|
36 |
+
wp_safe_redirect( get_settings_url(), 303 );
|
37 |
|
38 |
die;
|
39 |
|
40 |
}
|
41 |
+
add_action( 'admin_post_hmbkp_request_enable_support', 'HM\BackUpWordPress\request_enable_support' );
|
42 |
|
43 |
/**
|
44 |
* Delete a schedule and all it's backups and then redirect back to the backups page
|
45 |
*/
|
46 |
+
function request_delete_schedule() {
|
47 |
|
48 |
check_admin_referer( 'hmbkp_delete_schedule', 'hmbkp_delete_schedule_nonce' );
|
49 |
|
50 |
+
$schedule = new Scheduled_Backup( sanitize_text_field( urldecode( $_GET['hmbkp_schedule_id'] ) ) );
|
51 |
$schedule->cancel( true );
|
52 |
|
53 |
+
wp_safe_redirect( get_settings_url(), 303 );
|
54 |
|
55 |
die;
|
56 |
|
57 |
}
|
58 |
+
add_action( 'admin_post_hmbkp_request_delete_schedule', 'HM\BackUpWordPress\request_delete_schedule' );
|
59 |
|
60 |
/**
|
61 |
* Perform a manual backup
|
62 |
*
|
63 |
* Handles ajax requests as well as standard GET requests
|
64 |
*/
|
65 |
+
function request_do_backup() {
|
66 |
|
67 |
+
if ( empty( $_REQUEST['hmbkp_schedule_id'] ) ) {
|
68 |
die;
|
69 |
}
|
70 |
|
74 |
check_admin_referer( 'hmbkp_run_schedule', 'hmbkp_run_schedule_nonce' );
|
75 |
}
|
76 |
|
77 |
+
Path::get_instance()->cleanup();
|
78 |
|
79 |
// Fixes an issue on servers which only allow a single session per client
|
80 |
session_write_close();
|
81 |
|
82 |
+
$schedule_id = sanitize_text_field( urldecode( $_REQUEST['hmbkp_schedule_id'] ) );
|
83 |
+
$task = new \HM\Backdrop\Task( '\HM\BackUpWordPress\run_schedule_async', $schedule_id );
|
84 |
$task->schedule();
|
85 |
|
86 |
die;
|
87 |
|
88 |
}
|
89 |
+
add_action( 'wp_ajax_hmbkp_run_schedule', 'HM\BackUpWordPress\request_do_backup' );
|
|
|
|
|
|
|
|
|
90 |
|
91 |
+
function run_schedule_async( $schedule_id ) {
|
92 |
+
$schedule = new Scheduled_Backup( $schedule_id );
|
93 |
$schedule->run();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
}
|
95 |
|
96 |
/**
|
97 |
* Send the download file to the browser and then redirect back to the backups page
|
98 |
*/
|
99 |
+
function request_download_backup() {
|
100 |
|
101 |
check_admin_referer( 'hmbkp_download_backup', 'hmbkp_download_backup_nonce' );
|
102 |
|
104 |
return;
|
105 |
}
|
106 |
|
107 |
+
$url = str_replace( wp_normalize_path( Path::get_home_path() ), home_url( '/' ), trailingslashit( dirname( sanitize_text_field( base64_decode( $_GET['hmbkp_backup_archive'] ) ) ) ) ) . urlencode( pathinfo( sanitize_text_field( base64_decode( $_GET['hmbkp_backup_archive'] ) ), PATHINFO_BASENAME ) );
|
108 |
|
109 |
global $is_apache;
|
110 |
|
111 |
if ( $is_apache ) {
|
112 |
|
113 |
+
Path::get_instance()->protect_path( 'reset' );
|
114 |
|
115 |
$url = add_query_arg( 'key', HMBKP_SECURE_KEY, $url );
|
116 |
|
121 |
die;
|
122 |
|
123 |
}
|
124 |
+
add_action( 'admin_post_hmbkp_request_download_backup', 'HM\BackUpWordPress\request_download_backup' );
|
125 |
|
126 |
/**
|
127 |
* Cancels a running backup then redirect back to the backups page
|
128 |
*/
|
129 |
+
function request_cancel_backup() {
|
130 |
|
131 |
check_admin_referer( 'hmbkp_request_cancel_backup', 'hmbkp-request_cancel_backup_nonce' );
|
132 |
|
133 |
+
$schedule = new Scheduled_Backup( sanitize_text_field( urldecode( $_GET['hmbkp_schedule_id'] ) ) );
|
134 |
+
$status = $schedule->get_status();
|
135 |
|
136 |
// Delete the running backup
|
137 |
+
if ( $status->get_backup_filename() && file_exists( trailingslashit( Path::get_path() ) . $status->get_backup_filename() ) ) {
|
138 |
+
unlink( trailingslashit( Path::get_path() ) . $status->get_backup_filename() );
|
139 |
}
|
140 |
|
141 |
+
if ( file_exists( $status->get_status_filepath() ) ) {
|
142 |
+
unlink( $status->get_status_filepath() );
|
143 |
}
|
144 |
|
145 |
+
Path::get_instance()->cleanup();
|
146 |
|
147 |
+
wp_safe_redirect( get_settings_url(), 303 );
|
148 |
|
149 |
die;
|
150 |
|
151 |
}
|
152 |
+
add_action( 'admin_post_hmbkp_request_cancel_backup', 'HM\BackUpWordPress\request_cancel_backup' );
|
153 |
|
154 |
/**
|
155 |
* Dismiss an error and then redirect back to the backups page
|
156 |
*/
|
157 |
+
function dismiss_error() {
|
158 |
|
159 |
+
Path::get_instance()->cleanup();
|
160 |
|
161 |
+
Notices::get_instance()->clear_all_notices();
|
|
|
|
|
162 |
|
163 |
wp_safe_redirect( wp_get_referer(), 303 );
|
164 |
|
165 |
die;
|
166 |
|
167 |
}
|
168 |
+
add_action( 'wp_ajax_hmbkp_dismiss_error', 'HM\BackUpWordPress\dismiss_error' );
|
169 |
|
170 |
/**
|
171 |
* Catch the schedule service settings form submission
|
172 |
*
|
173 |
* Validate and either return errors or update the schedule
|
174 |
*/
|
175 |
+
function edit_schedule_services_submit() {
|
176 |
|
177 |
check_admin_referer( 'hmbkp-edit-schedule-services', 'hmbkp-edit-schedule-services-nonce' );
|
178 |
|
180 |
wp_die( __( 'The schedule ID was not provided. Aborting.', 'backupwordpress' ) );
|
181 |
}
|
182 |
|
183 |
+
$schedule = new Scheduled_Backup( sanitize_text_field( $_POST['hmbkp_schedule_id'] ) );
|
184 |
|
185 |
$errors = array();
|
186 |
|
187 |
// Save the service options
|
188 |
+
foreach ( Services::get_services( $schedule ) as $service ) {
|
189 |
$errors = array_merge( $errors, $service->save() );
|
190 |
}
|
191 |
|
193 |
|
194 |
if ( $errors ) {
|
195 |
foreach ( $errors as $error ) {
|
196 |
+
add_settings_error( $error );
|
197 |
}
|
198 |
}
|
199 |
|
200 |
+
$redirect = remove_query_arg( array( 'hmbkp_panel', 'action' ), wp_get_referer() );
|
201 |
+
|
202 |
+
if ( $errors ) {
|
203 |
+
$redirect = wp_get_referer();
|
204 |
+
}
|
205 |
+
|
206 |
+
wp_safe_redirect( $redirect, '303' );
|
207 |
die;
|
208 |
|
209 |
}
|
210 |
+
add_action( 'admin_post_hmbkp_edit_schedule_services_submit', 'HM\BackUpWordPress\edit_schedule_services_submit' );
|
211 |
|
212 |
/**
|
213 |
* Catch the schedule settings form submission
|
214 |
*
|
215 |
* Validate and either return errors or update the schedule
|
216 |
*/
|
217 |
+
function edit_schedule_submit() {
|
218 |
|
219 |
check_admin_referer( 'hmbkp-edit-schedule', 'hmbkp-edit-schedule-nonce' );
|
220 |
|
222 |
die;
|
223 |
}
|
224 |
|
225 |
+
$schedule = new Scheduled_Backup( sanitize_text_field( $_POST['hmbkp_schedule_id'] ) );
|
226 |
|
227 |
$errors = array();
|
228 |
|
254 |
$errors['hmbkp_schedule_recurrence']['hmbkp_type'] = __( 'Schedule cannot be empty', 'backupwordpress' );
|
255 |
}
|
256 |
|
257 |
+
elseif ( ! in_array( $schedule_recurrence_type, array_keys( cron_schedules() ) ) && 'manually' !== $schedule_recurrence_type ) {
|
258 |
$errors['hmbkp_schedule_recurrence']['hmbkp_type'] = __( 'Invalid schedule', 'backupwordpress' );
|
259 |
}
|
260 |
|
358 |
}
|
359 |
|
360 |
// Save the service options
|
361 |
+
foreach ( Services::get_services( $schedule ) as $service ) {
|
362 |
$errors = array_merge( $errors, $service->save() );
|
363 |
}
|
364 |
|
365 |
if ( ! empty( $settings['recurrence'] ) && ! empty( $settings['start_time'] ) ) {
|
366 |
|
367 |
// Calculate the start time depending on the recurrence
|
368 |
+
$start_time = determine_start_time( $settings['recurrence'], $settings['start_time'] );
|
369 |
|
370 |
if ( $start_time ) {
|
371 |
$schedule->set_schedule_start_time( $start_time );
|
394 |
if ( $errors ) {
|
395 |
|
396 |
foreach ( $errors as $error ) {
|
397 |
+
add_settings_error( $error );
|
398 |
}
|
399 |
|
400 |
}
|
409 |
die;
|
410 |
|
411 |
}
|
412 |
+
add_action( 'admin_post_hmbkp_edit_schedule_submit', 'HM\BackUpWordPress\edit_schedule_submit' );
|
413 |
|
414 |
/**
|
415 |
* Add an exclude rule
|
417 |
* @access public
|
418 |
* @return void
|
419 |
*/
|
420 |
+
function add_exclude_rule() {
|
421 |
|
422 |
check_admin_referer( 'hmbkp-add-exclude-rule', 'hmbkp-add-exclude-rule-nonce' );
|
423 |
|
425 |
return;
|
426 |
}
|
427 |
|
428 |
+
$schedule = new Scheduled_Backup( sanitize_text_field( $_GET['hmbkp_schedule_id'] ) );
|
429 |
|
430 |
$exclude_rule = sanitize_text_field( $_GET['hmbkp_exclude_pathname'] );
|
431 |
|
438 |
die;
|
439 |
|
440 |
}
|
441 |
+
add_action( 'admin_post_hmbkp_add_exclude_rule', 'HM\BackUpWordPress\add_exclude_rule' );
|
442 |
|
443 |
/**
|
444 |
* Delete an exclude rule
|
446 |
* @access public
|
447 |
* @return void
|
448 |
*/
|
449 |
+
function remove_exclude_rule() {
|
450 |
|
451 |
check_admin_referer( 'hmbkp_remove_exclude_rule', 'hmbkp-remove_exclude_rule_nonce' );
|
452 |
|
454 |
die;
|
455 |
}
|
456 |
|
457 |
+
$schedule = new Scheduled_Backup( sanitize_text_field( $_GET['hmbkp_schedule_id'] ) );
|
458 |
|
459 |
$excludes = $schedule->get_excludes();
|
460 |
+
$exclude_rule_to_remove = stripslashes( sanitize_text_field( $_GET['hmbkp_remove_exclude'] ) );
|
461 |
|
462 |
+
$schedule->set_excludes( array_diff( $excludes->get_user_excludes(), (array) $exclude_rule_to_remove ) );
|
463 |
|
464 |
$schedule->save();
|
465 |
|
468 |
die;
|
469 |
|
470 |
}
|
471 |
+
add_action( 'admin_post_hmbkp_remove_exclude_rule', 'HM\BackUpWordPress\remove_exclude_rule' );
|
472 |
|
473 |
/**
|
474 |
*
|
475 |
* @param null
|
476 |
*/
|
477 |
+
function recalculate_directory_filesize() {
|
478 |
|
479 |
if ( ! isset( $_GET['hmbkp_recalculate_directory_filesize'] ) || ! check_admin_referer( 'hmbkp-recalculate_directory_filesize' ) ) {
|
480 |
return;
|
483 |
// Delete the cached directory size
|
484 |
delete_transient( 'hmbkp_directory_filesizes' );
|
485 |
|
486 |
+
$url = add_query_arg( array( 'action' => 'hmbkp_edit_schedule', 'hmbkp_panel' => 'hmbkp_edit_schedule_excludes' ), get_settings_url() );
|
487 |
|
488 |
if ( isset( $_GET['hmbkp_directory_browse'] ) ) {
|
489 |
$url = add_query_arg( 'hmbkp_directory_browse', sanitize_text_field( $_GET['hmbkp_directory_browse'] ), $url );
|
493 |
die;
|
494 |
|
495 |
}
|
496 |
+
add_action( 'load-' . HMBKP_ADMIN_PAGE, 'HM\BackUpWordPress\recalculate_directory_filesize' );
|
|
|
|
|
|
|
|
|
|
|
|
|
497 |
|
498 |
+
function calculate_site_size() {
|
|
|
|
|
|
|
499 |
|
500 |
+
$site_size = new Site_Size;
|
|
|
|
|
501 |
|
502 |
+
if ( ! $site_size::is_site_size_cached() ) {
|
503 |
+
$root = new \SplFileInfo( Path::get_root() );
|
504 |
+
$site_size->filesize( $root );
|
|
|
|
|
505 |
}
|
506 |
|
507 |
}
|
508 |
+
add_action( 'load-' . HMBKP_ADMIN_PAGE, 'HM\BackUpWordPress\calculate_site_size' );
|
509 |
|
510 |
/**
|
511 |
* Receive the heartbeat and return backup status
|
512 |
*/
|
513 |
+
function heartbeat_received( $response, $data ) {
|
514 |
|
515 |
$response['heartbeat_interval'] = 'fast';
|
516 |
|
517 |
if ( ! empty( $data['hmbkp_schedule_id'] ) ) {
|
518 |
|
519 |
+
$schedule = new Scheduled_Backup( sanitize_text_field( urldecode( $data['hmbkp_schedule_id'] ) ) );
|
520 |
+
$status = new Backup_Status( $schedule->get_id() );
|
521 |
|
522 |
if ( ! empty( $data['hmbkp_is_in_progress'] ) ) {
|
523 |
|
524 |
+
if ( ! $status->get_status() ) {
|
525 |
$response['hmbkp_schedule_status'] = 0;
|
526 |
|
527 |
// Slow the heartbeat back down
|
528 |
$response['heartbeat_interval'] = 'slow';
|
529 |
|
530 |
} else {
|
531 |
+
$response['hmbkp_schedule_status'] = schedule_status( $schedule, false );
|
532 |
}
|
533 |
|
534 |
}
|
536 |
if ( ! empty( $data['hmbkp_client_request'] ) ) {
|
537 |
|
538 |
// Pass the site size to be displayed when it's ready.
|
539 |
+
if ( Site_Size::is_site_size_cached() ) {
|
540 |
+
|
541 |
+
$site_size = new Site_Size( $schedule->get_type(), $schedule->get_excludes() );
|
542 |
|
543 |
+
$response['hmbkp_site_size'] = $site_size->get_formatted_site_size();
|
544 |
|
545 |
ob_start();
|
546 |
require( HMBKP_PLUGIN_PATH . 'admin/schedule-form-excludes.php' );
|
552 |
}
|
553 |
|
554 |
}
|
555 |
+
|
556 |
return $response;
|
557 |
|
558 |
}
|
559 |
+
add_filter( 'heartbeat_received', 'HM\BackUpWordPress\heartbeat_received', 10, 2 );
|
560 |
|
561 |
// TODO needs work
|
562 |
+
function display_error_and_offer_to_email_it() {
|
563 |
|
564 |
check_ajax_referer( 'hmbkp_nonce', 'nonce' );
|
565 |
|
569 |
|
570 |
$errors = explode( "\n", wp_strip_all_tags( stripslashes( $_POST['hmbkp_error'] ) ) );
|
571 |
|
572 |
+
Notices::get_instance()->set_notices( 'backup_errors', $errors );
|
573 |
|
574 |
wp_send_json_success( wp_get_referer() );
|
575 |
|
576 |
}
|
577 |
+
add_action( 'wp_ajax_hmbkp_backup_error', 'HM\BackUpWordPress\display_error_and_offer_to_email_it' );
|
578 |
|
579 |
// TODO needs work
|
580 |
+
function send_error_via_email() {
|
581 |
|
582 |
check_ajax_referer( 'hmbkp_nonce', 'nonce' );
|
583 |
|
592 |
die;
|
593 |
|
594 |
}
|
595 |
+
add_action( 'wp_ajax_hmbkp_email_error', 'HM\BackUpWordPress\send_error_via_email' );
|
596 |
|
597 |
/**
|
598 |
* Load the enable support modal contents
|
599 |
*
|
600 |
* @return void
|
601 |
*/
|
602 |
+
function load_enable_support() {
|
603 |
|
604 |
check_ajax_referer( 'hmbkp_nonce', '_wpnonce' );
|
605 |
|
608 |
die;
|
609 |
|
610 |
}
|
611 |
+
add_action( 'wp_ajax_load_enable_support', 'HM\BackUpWordPress\load_enable_support' );
|
612 |
|
613 |
/**
|
614 |
* Display the running status via ajax
|
615 |
*/
|
616 |
+
function ajax_is_backup_in_progress() {
|
617 |
|
618 |
check_ajax_referer( 'hmbkp_nonce', 'nonce' );
|
619 |
|
621 |
die;
|
622 |
}
|
623 |
|
624 |
+
$schedule = new Scheduled_Backup( sanitize_text_field( urldecode( $_POST['hmbkp_schedule_id'] ) ) );
|
625 |
|
626 |
if ( ! $schedule->get_status() ) {
|
627 |
echo 0;
|
632 |
die;
|
633 |
|
634 |
}
|
635 |
+
add_action( 'wp_ajax_hmbkp_is_in_progress', 'HM\BackUpWordPress\ajax_is_backup_in_progress' );
|
636 |
|
637 |
/**
|
638 |
* Display the calculated size via ajax
|
639 |
*/
|
640 |
+
function ajax_calculate_backup_size() {
|
641 |
|
642 |
check_ajax_referer( 'hmbkp_nonce', 'nonce' );
|
643 |
|
645 |
die;
|
646 |
}
|
647 |
|
648 |
+
$schedule = new Scheduled_Backup( sanitize_text_field( urldecode( $_POST['hmbkp_schedule_id'] ) ) );
|
649 |
|
650 |
$recalculate_filesize = true;
|
651 |
|
654 |
die;
|
655 |
|
656 |
}
|
657 |
+
add_action( 'wp_ajax_hmbkp_calculate', 'HM\BackUpWordPress\ajax_calculate_backup_size' );
|
658 |
|
659 |
/**
|
660 |
* Test the cron response and if it's not 200 show a warning message
|
661 |
*/
|
662 |
+
function ajax_cron_test() {
|
663 |
|
664 |
check_ajax_referer( 'hmbkp_nonce', 'nonce' );
|
665 |
|
714 |
die;
|
715 |
|
716 |
}
|
717 |
+
add_action( 'wp_ajax_hmbkp_cron_test', 'HM\BackUpWordPress\ajax_cron_test' );
|
admin/backups-table.php
CHANGED
@@ -1,10 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<table class="widefat">
|
2 |
|
3 |
<thead>
|
4 |
|
5 |
<tr>
|
6 |
|
7 |
-
<th scope="col"><?php
|
8 |
<th scope="col"><?php _e( 'Size', 'backupwordpress' ); ?></th>
|
9 |
<th scope="col"><?php _e( 'Type', 'backupwordpress' ); ?></th>
|
10 |
<th scope="col"><?php _e( 'Actions', 'backupwordpress' ); ?></th>
|
@@ -25,7 +31,7 @@
|
|
25 |
continue;
|
26 |
}
|
27 |
|
28 |
-
|
29 |
|
30 |
}
|
31 |
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
?>
|
6 |
+
|
7 |
<table class="widefat">
|
8 |
|
9 |
<thead>
|
10 |
|
11 |
<tr>
|
12 |
|
13 |
+
<th scope="col"><?php backups_number( $schedule ); ?></th>
|
14 |
<th scope="col"><?php _e( 'Size', 'backupwordpress' ); ?></th>
|
15 |
<th scope="col"><?php _e( 'Type', 'backupwordpress' ); ?></th>
|
16 |
<th scope="col"><?php _e( 'Actions', 'backupwordpress' ); ?></th>
|
31 |
continue;
|
32 |
}
|
33 |
|
34 |
+
get_backup_row( $file, $schedule );
|
35 |
|
36 |
}
|
37 |
|
admin/backups.php
CHANGED
@@ -1,25 +1,28 @@
|
|
1 |
<?php
|
2 |
|
|
|
|
|
3 |
// Refresh the schedules from the database to make sure we have the latest changes
|
4 |
-
|
5 |
|
6 |
-
$schedules =
|
7 |
|
8 |
if ( ! empty( $_GET['hmbkp_schedule_id'] ) ) {
|
9 |
-
$current_schedule = new
|
10 |
} else {
|
11 |
$current_schedule = reset( $schedules );
|
12 |
} ?>
|
13 |
|
14 |
<h2 class="nav-tab-wrapper">
|
15 |
|
16 |
-
<?php foreach ( $schedules as $schedule ) :
|
|
|
17 |
|
18 |
-
<a class="nav-tab<?php if ( $
|
19 |
|
20 |
<?php endforeach; ?>
|
21 |
|
22 |
-
<a class="nav-tab<?php if ( !
|
23 |
|
24 |
</h2>
|
25 |
|
@@ -34,4 +37,4 @@ if ( ! $schedule = $current_schedule ) {
|
|
34 |
|
35 |
<?php require( HMBKP_PLUGIN_PATH . 'admin/backups-table.php' ); ?>
|
36 |
|
37 |
-
</div>
|
1 |
<?php
|
2 |
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
// Refresh the schedules from the database to make sure we have the latest changes
|
6 |
+
Schedules::get_instance()->refresh_schedules();
|
7 |
|
8 |
+
$schedules = Schedules::get_instance()->get_schedules();
|
9 |
|
10 |
if ( ! empty( $_GET['hmbkp_schedule_id'] ) ) {
|
11 |
+
$current_schedule = new Scheduled_Backup( sanitize_text_field( $_GET['hmbkp_schedule_id'] ) );
|
12 |
} else {
|
13 |
$current_schedule = reset( $schedules );
|
14 |
} ?>
|
15 |
|
16 |
<h2 class="nav-tab-wrapper">
|
17 |
|
18 |
+
<?php foreach ( $schedules as $schedule ) :
|
19 |
+
$status = new Backup_Status( $schedule->get_id() ); ?>
|
20 |
|
21 |
+
<a class="nav-tab<?php if ( $status->get_status() ) { ?> hmbkp-running<?php } ?><?php if ( $schedule->get_id() === $current_schedule->get_id() ) { ?> nav-tab-active<?php } ?>" <?php if ( $status->get_status() ) { ?>title="<?php echo esc_attr( strip_tags( $status->get_status() ) ); ?>"<?php } ?> href="<?php echo esc_url( add_query_arg( 'hmbkp_schedule_id', $schedule->get_id(), HMBKP_ADMIN_URL ) ); ?> "><?php echo esc_html( translated_schedule_title( $schedule->get_slug(), $schedule->get_name() ) ); ?> <span class="count">(<?php echo esc_html( count( $schedule->get_backups() ) ); ?>)</span></a>
|
22 |
|
23 |
<?php endforeach; ?>
|
24 |
|
25 |
+
<a class="nav-tab<?php if ( ! Schedules::get_instance()->get_schedule( $current_schedule->get_id() ) ) { ?> nav-tab-active<?php } ?>" href="<?php echo esc_url( add_query_arg( array( 'hmbkp_add_schedule' => '1', 'action' => 'hmbkp_edit_schedule', 'hmbkp_schedule_id' => time(), 'hmbkp_panel' => 'hmbkp_edit_schedule_settings' ), HMBKP_ADMIN_URL ) ); ?>"> + <?php _e( 'add schedule', 'backupwordpress' ); ?></a>
|
26 |
|
27 |
</h2>
|
28 |
|
37 |
|
38 |
<?php require( HMBKP_PLUGIN_PATH . 'admin/backups-table.php' ); ?>
|
39 |
|
40 |
+
</div>
|
admin/constants.php
CHANGED
@@ -1,3 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<div id="hmbkp-constants">
|
2 |
|
3 |
<p><?php printf( __( 'You can %1$s any of the following %2$s in your %3$s to control advanced settings. %4$s. Defined %5$s will be highlighted.', 'backupwordpress' ), '<code>define</code>', '<code>' . __( 'Constants', 'backupwordpress' ) . '</code>', '<code>wp-config.php</code>', '<a href="http://codex.wordpress.org/Editing_wp-config.php">' . __( 'The Codex can help', 'backupwordpress' ) . '</a>', '<code>' . __( 'Constants', 'backupwordpress' ) . '</code>' ); ?></p>
|
@@ -14,7 +20,7 @@
|
|
14 |
<p><?php printf( __( 'You\'ve set it to: %s', 'backupwordpress' ), '<code>' . esc_html( HMBKP_PATH ) . '</code>' ); ?></p>
|
15 |
<?php } ?>
|
16 |
|
17 |
-
<p><?php printf( __( 'The path to the folder you would like to store your backup files in, defaults to %s.', 'backupwordpress' ), '<code>' . esc_html(
|
18 |
|
19 |
</td>
|
20 |
|
@@ -94,7 +100,7 @@
|
|
94 |
<p><?php printf( __( 'You\'ve set it to: %s', 'backupwordpress' ), '<code>' . esc_html( HMBKP_ROOT ) . '</code>' ); ?></p>
|
95 |
<?php } ?>
|
96 |
|
97 |
-
<p><?php printf( __( 'The root directory that is backed up. Defaults to %s.', 'backupwordpress' ), '<code>' .
|
98 |
|
99 |
</td>
|
100 |
|
@@ -116,7 +122,7 @@
|
|
116 |
|
117 |
</tr>
|
118 |
|
119 |
-
<?php foreach (
|
120 |
echo wp_kses_post( call_user_func( array( $service, 'constant' ) ) );
|
121 |
} ?>
|
122 |
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
?>
|
6 |
+
|
7 |
<div id="hmbkp-constants">
|
8 |
|
9 |
<p><?php printf( __( 'You can %1$s any of the following %2$s in your %3$s to control advanced settings. %4$s. Defined %5$s will be highlighted.', 'backupwordpress' ), '<code>define</code>', '<code>' . __( 'Constants', 'backupwordpress' ) . '</code>', '<code>wp-config.php</code>', '<a href="http://codex.wordpress.org/Editing_wp-config.php">' . __( 'The Codex can help', 'backupwordpress' ) . '</a>', '<code>' . __( 'Constants', 'backupwordpress' ) . '</code>' ); ?></p>
|
20 |
<p><?php printf( __( 'You\'ve set it to: %s', 'backupwordpress' ), '<code>' . esc_html( HMBKP_PATH ) . '</code>' ); ?></p>
|
21 |
<?php } ?>
|
22 |
|
23 |
+
<p><?php printf( __( 'The path to the folder you would like to store your backup files in, defaults to %s.', 'backupwordpress' ), '<code>' . esc_html( Path::get_path() ) . '</code>' ); ?> <?php _e( 'e.g.', 'backupwordpress' ); ?> <code>define( 'HMBKP_PATH', '/home/willmot/backups' );</code></p>
|
24 |
|
25 |
</td>
|
26 |
|
100 |
<p><?php printf( __( 'You\'ve set it to: %s', 'backupwordpress' ), '<code>' . esc_html( HMBKP_ROOT ) . '</code>' ); ?></p>
|
101 |
<?php } ?>
|
102 |
|
103 |
+
<p><?php printf( __( 'The root directory that is backed up. Defaults to %s.', 'backupwordpress' ), '<code>' . Path::get_home_path() . '</code>' ); ?> <?php _e( 'e.g.', 'backupwordpress' ); ?> <code>define( 'HMBKP_ROOT', ABSPATH . 'wp/' );</code></p>
|
104 |
|
105 |
</td>
|
106 |
|
122 |
|
123 |
</tr>
|
124 |
|
125 |
+
<?php foreach ( Services::get_services() as $file => $service ) {
|
126 |
echo wp_kses_post( call_user_func( array( $service, 'constant' ) ) );
|
127 |
} ?>
|
128 |
|
admin/menu.php
CHANGED
@@ -1,26 +1,24 @@
|
|
1 |
<?php
|
2 |
|
|
|
|
|
3 |
/**
|
4 |
* Add the backups menu item
|
5 |
* to the tools menu
|
6 |
*
|
7 |
* @return null
|
8 |
*/
|
9 |
-
function
|
10 |
|
11 |
if ( is_multisite() ) {
|
12 |
-
|
13 |
-
add_submenu_page( 'settings.php', __( 'Manage Backups', 'backupwordpress' ), __( 'Backups', 'backupwordpress' ), ( defined( 'HMBKP_CAPABILITY' ) && HMBKP_CAPABILITY ) ? HMBKP_CAPABILITY : 'manage_options', HMBKP_PLUGIN_SLUG, 'hmbkp_manage_backups' );
|
14 |
-
|
15 |
} else {
|
16 |
-
|
17 |
-
add_management_page( __( 'Manage Backups', 'backupwordpress' ), __( 'Backups', 'backupwordpress' ), ( defined( 'HMBKP_CAPABILITY' ) && HMBKP_CAPABILITY ) ? HMBKP_CAPABILITY : 'manage_options', HMBKP_PLUGIN_SLUG, 'hmbkp_manage_backups' );
|
18 |
-
|
19 |
}
|
20 |
}
|
21 |
|
22 |
-
add_action( 'network_admin_menu', '
|
23 |
-
add_action( 'admin_menu', '
|
24 |
|
25 |
/**
|
26 |
* Load the backups admin page
|
@@ -28,7 +26,7 @@ add_action( 'admin_menu', 'hmbkp_admin_menu' );
|
|
28 |
*
|
29 |
* @return null
|
30 |
*/
|
31 |
-
function
|
32 |
require_once( HMBKP_PLUGIN_PATH . 'admin/page.php' );
|
33 |
}
|
34 |
|
@@ -40,7 +38,7 @@ function hmbkp_manage_backups() {
|
|
40 |
*
|
41 |
* @return array $links
|
42 |
*/
|
43 |
-
function
|
44 |
|
45 |
if ( false !== strpos( $file, HMBKP_PLUGIN_SLUG ) ) {
|
46 |
array_push( $links, '<a href="' . esc_url( HMBKP_ADMIN_URL ) . '">' . __( 'Backups', 'backupwordpress' ) . '</a>' );
|
@@ -50,7 +48,7 @@ function hmbkp_plugin_action_link( $links, $file ) {
|
|
50 |
|
51 |
}
|
52 |
|
53 |
-
add_filter( 'plugin_action_links', '
|
54 |
|
55 |
/**
|
56 |
* Add Contextual Help to Backups tools page.
|
@@ -59,7 +57,7 @@ add_filter( 'plugin_action_links', 'hmbkp_plugin_action_link', 10, 2 );
|
|
59 |
*
|
60 |
* @return null
|
61 |
*/
|
62 |
-
function
|
63 |
|
64 |
// Pre WordPress 3.3 compat
|
65 |
if ( ! method_exists( get_current_screen(), 'add_help_tab' ) ) {
|
@@ -104,4 +102,4 @@ function hmbkp_contextual_help() {
|
|
104 |
|
105 |
}
|
106 |
|
107 |
-
add_action( 'load-' . HMBKP_ADMIN_PAGE, '
|
1 |
<?php
|
2 |
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
/**
|
6 |
* Add the backups menu item
|
7 |
* to the tools menu
|
8 |
*
|
9 |
* @return null
|
10 |
*/
|
11 |
+
function admin_menu() {
|
12 |
|
13 |
if ( is_multisite() ) {
|
14 |
+
add_submenu_page( 'settings.php', __( 'Manage Backups', 'backupwordpress' ), __( 'Backups', 'backupwordpress' ), ( defined( 'HMBKP_CAPABILITY' ) && HMBKP_CAPABILITY ) ? HMBKP_CAPABILITY : 'manage_options', HMBKP_PLUGIN_SLUG, 'HM\BackUpWordPress\manage_backups' );
|
|
|
|
|
15 |
} else {
|
16 |
+
add_management_page( __( 'Manage Backups', 'backupwordpress' ), __( 'Backups', 'backupwordpress' ), ( defined( 'HMBKP_CAPABILITY' ) && HMBKP_CAPABILITY ) ? HMBKP_CAPABILITY : 'manage_options', HMBKP_PLUGIN_SLUG, 'HM\BackUpWordPress\manage_backups' );
|
|
|
|
|
17 |
}
|
18 |
}
|
19 |
|
20 |
+
add_action( 'network_admin_menu', 'HM\BackUpWordPress\admin_menu' );
|
21 |
+
add_action( 'admin_menu', 'HM\BackUpWordPress\admin_menu' );
|
22 |
|
23 |
/**
|
24 |
* Load the backups admin page
|
26 |
*
|
27 |
* @return null
|
28 |
*/
|
29 |
+
function manage_backups() {
|
30 |
require_once( HMBKP_PLUGIN_PATH . 'admin/page.php' );
|
31 |
}
|
32 |
|
38 |
*
|
39 |
* @return array $links
|
40 |
*/
|
41 |
+
function plugin_action_link( $links, $file ) {
|
42 |
|
43 |
if ( false !== strpos( $file, HMBKP_PLUGIN_SLUG ) ) {
|
44 |
array_push( $links, '<a href="' . esc_url( HMBKP_ADMIN_URL ) . '">' . __( 'Backups', 'backupwordpress' ) . '</a>' );
|
48 |
|
49 |
}
|
50 |
|
51 |
+
add_filter( 'plugin_action_links', 'HM\BackUpWordPress\plugin_action_link', 10, 2 );
|
52 |
|
53 |
/**
|
54 |
* Add Contextual Help to Backups tools page.
|
57 |
*
|
58 |
* @return null
|
59 |
*/
|
60 |
+
function contextual_help() {
|
61 |
|
62 |
// Pre WordPress 3.3 compat
|
63 |
if ( ! method_exists( get_current_screen(), 'add_help_tab' ) ) {
|
102 |
|
103 |
}
|
104 |
|
105 |
+
add_action( 'load-' . HMBKP_ADMIN_PAGE, 'HM\BackUpWordPress\contextual_help' );
|
admin/page.php
CHANGED
@@ -1,3 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<div class="wrap">
|
2 |
|
3 |
<h1>
|
@@ -12,7 +18,7 @@
|
|
12 |
|
13 |
</h1>
|
14 |
|
15 |
-
<?php if (
|
16 |
|
17 |
<?php include_once( HMBKP_PLUGIN_PATH . 'admin/backups.php' ); ?>
|
18 |
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
?>
|
6 |
+
|
7 |
<div class="wrap">
|
8 |
|
9 |
<h1>
|
18 |
|
19 |
</h1>
|
20 |
|
21 |
+
<?php if ( is_backup_possible() ) : ?>
|
22 |
|
23 |
<?php include_once( HMBKP_PLUGIN_PATH . 'admin/backups.php' ); ?>
|
24 |
|
admin/schedule-form-excludes.php
CHANGED
@@ -1,71 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<div class="hmbkp-exclude-settings">
|
2 |
|
3 |
-
|
|
|
|
|
4 |
|
5 |
-
|
6 |
-
<?php _e( 'Currently Excluded', 'backupwordpress' ); ?>
|
7 |
-
</h3>
|
8 |
|
9 |
-
|
10 |
|
11 |
-
<
|
12 |
|
13 |
-
|
14 |
|
15 |
-
|
16 |
|
17 |
-
|
18 |
|
19 |
-
<
|
20 |
|
21 |
-
|
22 |
|
23 |
-
|
24 |
|
25 |
-
|
26 |
|
27 |
-
|
28 |
|
29 |
-
|
30 |
|
31 |
-
|
32 |
|
33 |
-
|
34 |
|
35 |
-
<
|
36 |
-
<code><?php echo esc_html( str_ireplace( $schedule->backup->get_root(), '', $exclude ) ); ?></code>
|
37 |
-
</td>
|
38 |
|
39 |
-
|
40 |
|
41 |
-
|
42 |
|
43 |
-
|
44 |
|
45 |
-
<?php
|
46 |
|
47 |
-
|
48 |
|
49 |
-
<?php
|
50 |
|
51 |
-
|
52 |
-
'hmbkp_remove_exclude' => $exclude,
|
53 |
-
'hmbkp_schedule_id' => $schedule->get_id()
|
54 |
-
) ); ?>" class="delete-action"><?php _e( 'Stop excluding', 'backupwordpress' ); ?></a>
|
55 |
|
56 |
-
<?php
|
|
|
|
|
|
|
57 |
|
58 |
-
|
59 |
|
60 |
-
</
|
61 |
|
62 |
-
|
63 |
|
64 |
-
|
65 |
|
66 |
-
</
|
67 |
|
68 |
-
|
69 |
|
70 |
<h3 id="directory-listing"><?php _e( 'Your Site', 'backupwordpress' ); ?></h3>
|
71 |
|
@@ -74,23 +79,25 @@
|
|
74 |
<?php
|
75 |
|
76 |
// The directory to display
|
77 |
-
$directory =
|
78 |
|
79 |
if ( isset( $_GET['hmbkp_directory_browse'] ) ) {
|
80 |
|
81 |
$untrusted_directory = urldecode( $_GET['hmbkp_directory_browse'] );
|
82 |
|
83 |
// Only allow real sub directories of the site root to be browsed
|
84 |
-
if ( false !== strpos( $untrusted_directory,
|
85 |
$directory = $untrusted_directory;
|
86 |
}
|
87 |
|
88 |
}
|
89 |
|
90 |
-
$exclude_string =
|
|
|
|
|
91 |
|
92 |
// Kick off a recursive filesize scan
|
93 |
-
$files =
|
94 |
|
95 |
<table class="widefat">
|
96 |
|
@@ -113,12 +120,12 @@
|
|
113 |
|
114 |
<th scope="col">
|
115 |
|
116 |
-
<?php if (
|
117 |
|
118 |
-
<a href="<?php echo esc_url( remove_query_arg( 'hmbkp_directory_browse' ) ); ?>"><?php echo esc_html(
|
119 |
<code>/</code>
|
120 |
|
121 |
-
<?php $parents = array_filter( explode( '/', str_replace( trailingslashit(
|
122 |
|
123 |
foreach ( $parents as $directory_basename ) { ?>
|
124 |
|
@@ -131,7 +138,7 @@
|
|
131 |
|
132 |
<?php } else { ?>
|
133 |
|
134 |
-
<?php echo esc_html(
|
135 |
|
136 |
<?php } ?>
|
137 |
|
@@ -139,15 +146,15 @@
|
|
139 |
|
140 |
<td class="column-filesize">
|
141 |
|
142 |
-
<?php if (
|
143 |
|
144 |
-
<span class="spinner"></span>
|
145 |
|
146 |
<?php } else {
|
147 |
|
148 |
-
$root = new SplFileInfo(
|
149 |
|
150 |
-
$size = $
|
151 |
|
152 |
if ( false !== $size ) {
|
153 |
|
@@ -162,7 +169,7 @@
|
|
162 |
<?php echo esc_html( $size ); ?>
|
163 |
|
164 |
<a class="dashicons dashicons-update"
|
165 |
-
href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'hmbkp_recalculate_directory_filesize', urlencode(
|
166 |
|
167 |
</code>
|
168 |
|
@@ -172,16 +179,16 @@
|
|
172 |
<?php } ?>
|
173 |
|
174 |
<td>
|
175 |
-
<?php echo esc_html( substr( sprintf( '%o', fileperms(
|
176 |
</td>
|
177 |
|
178 |
<td>
|
179 |
|
180 |
-
<?php if ( is_link(
|
181 |
|
182 |
_e( 'Symlink', 'backupwordpress' );
|
183 |
|
184 |
-
} elseif ( is_dir(
|
185 |
|
186 |
_e( 'Folder', 'backupwordpress' );
|
187 |
|
@@ -204,7 +211,7 @@
|
|
204 |
$is_excluded = $is_unreadable = false;
|
205 |
|
206 |
// Check if the file is excluded
|
207 |
-
if ( $exclude_string && preg_match( '(' . $exclude_string . ')', str_ireplace( trailingslashit(
|
208 |
$is_excluded = true;
|
209 |
}
|
210 |
|
@@ -238,17 +245,17 @@
|
|
238 |
<?php if ( $is_unreadable ) { ?>
|
239 |
|
240 |
<code class="strikethrough"
|
241 |
-
title="<?php echo esc_attr( $file->getRealPath() ); ?>"><?php echo esc_html( $file->getBasename() ); ?></code>
|
242 |
|
243 |
<?php } elseif ( $file->isFile() ) { ?>
|
244 |
|
245 |
<code
|
246 |
-
title="<?php echo esc_attr( $file->getRealPath() ); ?>"><?php echo esc_html( $file->getBasename() ); ?></code>
|
247 |
|
248 |
<?php } elseif ( $file->isDir() ) { ?>
|
249 |
|
250 |
-
<code title="<?php echo esc_attr( $file->getRealPath() ); ?>"><a
|
251 |
-
href="<?php echo esc_url( add_query_arg( 'hmbkp_directory_browse', urlencode( $file->getPathname() ) ) ); ?>"><?php echo esc_html( $file->getBasename() ); ?></a></code>
|
252 |
|
253 |
<?php } ?>
|
254 |
|
@@ -256,13 +263,13 @@
|
|
256 |
|
257 |
<td class="column-format column-filesize">
|
258 |
|
259 |
-
<?php if ( $file->isDir() &&
|
260 |
|
261 |
-
<span class="spinner"></span>
|
262 |
|
263 |
<?php } else {
|
264 |
|
265 |
-
$size = $
|
266 |
|
267 |
if ( false !== $size ) {
|
268 |
|
@@ -280,7 +287,7 @@
|
|
280 |
|
281 |
<a title="<?php _e( 'Recalculate the size of this directory', 'backupwordpress' ); ?>"
|
282 |
class="dashicons dashicons-update"
|
283 |
-
href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'hmbkp_recalculate_directory_filesize', urlencode( $file->getPathname() ) ), 'hmbkp-recalculate_directory_filesize' ) ); ?>"><span><?php _e( 'Refresh', 'backupwordpress' ); ?></span></a>
|
284 |
|
285 |
<?php } ?>
|
286 |
|
@@ -304,7 +311,7 @@
|
|
304 |
<?php if ( $file->isLink() ) { ?>
|
305 |
|
306 |
<span
|
307 |
-
title="<?php echo esc_attr( $file->
|
308 |
|
309 |
<?php } elseif ( $file->isDir() ) {
|
310 |
|
@@ -335,7 +342,7 @@
|
|
335 |
|
336 |
// Excluded directories need to be trailingslashed
|
337 |
if ( $file->isDir() ) {
|
338 |
-
$exclude_path = trailingslashit( $file->getPathname() );
|
339 |
} ?>
|
340 |
|
341 |
<a href="<?php echo esc_url( wp_nonce_url( add_query_arg( array(
|
@@ -367,7 +374,7 @@
|
|
367 |
|
368 |
|
369 |
<p class="submit">
|
370 |
-
<a href="<?php echo esc_url(
|
371 |
class="button-primary"><?php _e( 'Done', 'backupwordpress' ); ?></a>
|
372 |
</p>
|
373 |
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
$excludes = $schedule->get_excludes();
|
6 |
+
$user_excludes = $excludes->get_user_excludes(); ?>
|
7 |
+
|
8 |
<div class="hmbkp-exclude-settings">
|
9 |
|
10 |
+
<h3>
|
11 |
+
<?php _e( 'Currently Excluded', 'backupwordpress' ); ?>
|
12 |
+
</h3>
|
13 |
|
14 |
+
<p><?php _e( 'We automatically detect and ignore common <abbr title="Version Control Systems">VCS</abbr> folders and other backup plugin folders.', 'backupwordpress' ); ?></p>
|
|
|
|
|
15 |
|
16 |
+
<table class="widefat">
|
17 |
|
18 |
+
<tbody>
|
19 |
|
20 |
+
<?php foreach ( $user_excludes as $key => $exclude ) :
|
21 |
|
22 |
+
$exclude_path = new \SplFileInfo( trailingslashit( Path::get_root() ) . ltrim( str_ireplace( Path::get_root(), '', $exclude ), '/' ) ); ?>
|
23 |
|
24 |
+
<tr>
|
25 |
|
26 |
+
<th scope="row">
|
27 |
|
28 |
+
<?php if ( $exclude_path->isFile() ) { ?>
|
29 |
|
30 |
+
<div class="dashicons dashicons-media-default"></div>
|
31 |
|
32 |
+
<?php } elseif ( $exclude_path->isDir() ) { ?>
|
33 |
|
34 |
+
<div class="dashicons dashicons-portfolio"></div>
|
35 |
|
36 |
+
<?php } ?>
|
37 |
|
38 |
+
</th>
|
39 |
|
40 |
+
<td>
|
41 |
|
42 |
+
<code><?php echo esc_html( str_ireplace( Path::get_root(), '', $exclude ) ); ?></code>
|
|
|
|
|
43 |
|
44 |
+
</td>
|
45 |
|
46 |
+
<td>
|
47 |
|
48 |
+
<?php if ( ( in_array( $exclude, $excludes->get_default_excludes() ) ) || ( Path::get_path() === trailingslashit( Path::get_root() ) . untrailingslashit( $exclude ) ) ) : ?>
|
49 |
|
50 |
+
<?php _e( 'Default rule', 'backupwordpress' ); ?>
|
51 |
|
52 |
+
<?php elseif ( defined( 'HMBKP_EXCLUDE' ) && false !== strpos( HMBKP_EXCLUDE, $exclude ) ) : ?>
|
53 |
|
54 |
+
<?php _e( 'Defined in wp-config.php', 'backupwordpress' ); ?>
|
55 |
|
56 |
+
<?php else : ?>
|
|
|
|
|
|
|
57 |
|
58 |
+
<a href="<?php echo admin_action_url( 'remove_exclude_rule', array(
|
59 |
+
'hmbkp_remove_exclude' => $exclude,
|
60 |
+
'hmbkp_schedule_id' => $schedule->get_id()
|
61 |
+
) ); ?>" class="delete-action"><?php _e( 'Stop excluding', 'backupwordpress' ); ?></a>
|
62 |
|
63 |
+
<?php endif; ?>
|
64 |
|
65 |
+
</td>
|
66 |
|
67 |
+
</tr>
|
68 |
|
69 |
+
<?php endforeach; ?>
|
70 |
|
71 |
+
</tbody>
|
72 |
|
73 |
+
</table>
|
74 |
|
75 |
<h3 id="directory-listing"><?php _e( 'Your Site', 'backupwordpress' ); ?></h3>
|
76 |
|
79 |
<?php
|
80 |
|
81 |
// The directory to display
|
82 |
+
$directory = Path::get_root();
|
83 |
|
84 |
if ( isset( $_GET['hmbkp_directory_browse'] ) ) {
|
85 |
|
86 |
$untrusted_directory = urldecode( $_GET['hmbkp_directory_browse'] );
|
87 |
|
88 |
// Only allow real sub directories of the site root to be browsed
|
89 |
+
if ( false !== strpos( $untrusted_directory, Path::get_root() ) && is_dir( $untrusted_directory ) ) {
|
90 |
$directory = $untrusted_directory;
|
91 |
}
|
92 |
|
93 |
}
|
94 |
|
95 |
+
$exclude_string = implode( '|', $excludes->get_excludes_for_regex() );
|
96 |
+
|
97 |
+
$site_size = new Site_Size;
|
98 |
|
99 |
// Kick off a recursive filesize scan
|
100 |
+
$files = list_directory_by_total_filesize( $directory ); ?>
|
101 |
|
102 |
<table class="widefat">
|
103 |
|
120 |
|
121 |
<th scope="col">
|
122 |
|
123 |
+
<?php if ( Path::get_root() !== $directory ) { ?>
|
124 |
|
125 |
+
<a href="<?php echo esc_url( remove_query_arg( 'hmbkp_directory_browse' ) ); ?>"><?php echo esc_html( Path::get_root() ); ?></a>
|
126 |
<code>/</code>
|
127 |
|
128 |
+
<?php $parents = array_filter( explode( '/', str_replace( trailingslashit( Path::get_root() ), '', trailingslashit( dirname( $directory ) ) ) ) );
|
129 |
|
130 |
foreach ( $parents as $directory_basename ) { ?>
|
131 |
|
138 |
|
139 |
<?php } else { ?>
|
140 |
|
141 |
+
<?php echo esc_html( Path::get_root() ); ?>
|
142 |
|
143 |
<?php } ?>
|
144 |
|
146 |
|
147 |
<td class="column-filesize">
|
148 |
|
149 |
+
<?php if ( Site_Size::is_site_size_being_calculated() ) { ?>
|
150 |
|
151 |
+
<span class="spinner is-active"></span>
|
152 |
|
153 |
<?php } else {
|
154 |
|
155 |
+
$root = new \SplFileInfo( Path::get_root() );
|
156 |
|
157 |
+
$size = $site_size->filesize( $root );
|
158 |
|
159 |
if ( false !== $size ) {
|
160 |
|
169 |
<?php echo esc_html( $size ); ?>
|
170 |
|
171 |
<a class="dashicons dashicons-update"
|
172 |
+
href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'hmbkp_recalculate_directory_filesize', urlencode( Path::get_root() ) ), 'hmbkp-recalculate_directory_filesize' ) ); ?>"><span><?php _e( 'Refresh', 'backupwordpress' ); ?></span></a>
|
173 |
|
174 |
</code>
|
175 |
|
179 |
<?php } ?>
|
180 |
|
181 |
<td>
|
182 |
+
<?php echo esc_html( substr( sprintf( '%o', fileperms( Path::get_root() ) ), - 4 ) ); ?>
|
183 |
</td>
|
184 |
|
185 |
<td>
|
186 |
|
187 |
+
<?php if ( is_link( Path::get_root() ) ) {
|
188 |
|
189 |
_e( 'Symlink', 'backupwordpress' );
|
190 |
|
191 |
+
} elseif ( is_dir( Path::get_root() ) ) {
|
192 |
|
193 |
_e( 'Folder', 'backupwordpress' );
|
194 |
|
211 |
$is_excluded = $is_unreadable = false;
|
212 |
|
213 |
// Check if the file is excluded
|
214 |
+
if ( $exclude_string && preg_match( '(' . $exclude_string . ')', str_ireplace( trailingslashit( Path::get_root() ), '', wp_normalize_path( $file->getPathname() ) ) ) ) {
|
215 |
$is_excluded = true;
|
216 |
}
|
217 |
|
245 |
<?php if ( $is_unreadable ) { ?>
|
246 |
|
247 |
<code class="strikethrough"
|
248 |
+
title="<?php echo esc_attr( wp_normalize_path( $file->getRealPath() ) ); ?>"><?php echo esc_html( $file->getBasename() ); ?></code>
|
249 |
|
250 |
<?php } elseif ( $file->isFile() ) { ?>
|
251 |
|
252 |
<code
|
253 |
+
title="<?php echo esc_attr( wp_normalize_path( $file->getRealPath() ) ); ?>"><?php echo esc_html( $file->getBasename() ); ?></code>
|
254 |
|
255 |
<?php } elseif ( $file->isDir() ) { ?>
|
256 |
|
257 |
+
<code title="<?php echo esc_attr( wp_normalize_path( $file->getRealPath() ) ); ?>"><a
|
258 |
+
href="<?php echo esc_url( add_query_arg( 'hmbkp_directory_browse', urlencode( wp_normalize_path( $file->getPathname() ) ) ) ); ?>"><?php echo esc_html( $file->getBasename() ); ?></a></code>
|
259 |
|
260 |
<?php } ?>
|
261 |
|
263 |
|
264 |
<td class="column-format column-filesize">
|
265 |
|
266 |
+
<?php if ( $file->isDir() && Site_Size::is_site_size_being_calculated() ) { ?>
|
267 |
|
268 |
+
<span class="spinner is-active"></span>
|
269 |
|
270 |
<?php } else {
|
271 |
|
272 |
+
$size = $site_size->filesize( $file );
|
273 |
|
274 |
if ( false !== $size ) {
|
275 |
|
287 |
|
288 |
<a title="<?php _e( 'Recalculate the size of this directory', 'backupwordpress' ); ?>"
|
289 |
class="dashicons dashicons-update"
|
290 |
+
href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'hmbkp_recalculate_directory_filesize', urlencode( wp_normalize_path( $file->getPathname() ) ) ), 'hmbkp-recalculate_directory_filesize' ) ); ?>"><span><?php _e( 'Refresh', 'backupwordpress' ); ?></span></a>
|
291 |
|
292 |
<?php } ?>
|
293 |
|
311 |
<?php if ( $file->isLink() ) { ?>
|
312 |
|
313 |
<span
|
314 |
+
title="<?php echo esc_attr( wp_normalize_path( $file->getRealPath() ) ); ?>"><?php _e( 'Symlink', 'backupwordpress' ); ?></span>
|
315 |
|
316 |
<?php } elseif ( $file->isDir() ) {
|
317 |
|
342 |
|
343 |
// Excluded directories need to be trailingslashed
|
344 |
if ( $file->isDir() ) {
|
345 |
+
$exclude_path = trailingslashit( wp_normalize_path( $file->getPathname() ) );
|
346 |
} ?>
|
347 |
|
348 |
<a href="<?php echo esc_url( wp_nonce_url( add_query_arg( array(
|
374 |
|
375 |
|
376 |
<p class="submit">
|
377 |
+
<a href="<?php echo esc_url( get_settings_url() ) ?>"
|
378 |
class="button-primary"><?php _e( 'Done', 'backupwordpress' ); ?></a>
|
379 |
</p>
|
380 |
|
admin/schedule-form.php
CHANGED
@@ -1,6 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<h3><?php esc_html_e( 'Settings', 'backupwordpress' ); ?></h3>
|
2 |
|
3 |
-
<?php $hmbkp_form_errors =
|
4 |
|
5 |
<?php if ( ! empty( $hmbkp_form_errors ) ) { ?>
|
6 |
|
@@ -15,7 +21,7 @@
|
|
15 |
<?php }
|
16 |
|
17 |
// We can clear them now we've displayed them
|
18 |
-
|
19 |
|
20 |
?>
|
21 |
|
@@ -64,7 +70,7 @@ hmbkp_clear_settings_errors();
|
|
64 |
|
65 |
<option value="manually"><?php _e( 'Manual Only', 'backupwordpress' ); ?></option>
|
66 |
|
67 |
-
<?php foreach (
|
68 |
|
69 |
<option <?php selected( $schedule->get_reoccurrence(), $cron_schedule ); ?> value="<?php echo esc_attr( $cron_schedule ); ?>">
|
70 |
|
@@ -149,7 +155,7 @@ hmbkp_clear_settings_errors();
|
|
149 |
<?php _e( 'Minutes', 'backupwordpress' ); ?></label>
|
150 |
|
151 |
</span>
|
152 |
-
|
153 |
<p class="description">
|
154 |
<?php esc_html_e( '24-hour format.', 'backupwordpress' ); ?>
|
155 |
<span class="twice-js <?php if ( $schedule->get_reoccurrence() !== 'fortnightly' ) { ?> hidden<?php } ?>"><?php _e( 'The second backup will run 12 hours after the first.', 'backupwordpress' ); ?><span>
|
@@ -173,8 +179,12 @@ hmbkp_clear_settings_errors();
|
|
173 |
|
174 |
<?php printf( __( 'Past this limit older backups will be deleted automatically.', 'backupwordpress' ) ); ?>
|
175 |
|
176 |
-
<?php
|
177 |
-
|
|
|
|
|
|
|
|
|
178 |
} ?>
|
179 |
|
180 |
</p>
|
@@ -183,7 +193,7 @@ hmbkp_clear_settings_errors();
|
|
183 |
|
184 |
</tr>
|
185 |
|
186 |
-
<?php foreach (
|
187 |
$service->field();
|
188 |
} ?>
|
189 |
|
@@ -191,9 +201,6 @@ hmbkp_clear_settings_errors();
|
|
191 |
|
192 |
</table>
|
193 |
|
194 |
-
|
195 |
-
<button type="submit" class="button-primary"><?php _e( 'Done', 'backupwordpress' ); ?></button>
|
196 |
-
</p>
|
197 |
-
|
198 |
|
199 |
</form>
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
?>
|
6 |
+
|
7 |
<h3><?php esc_html_e( 'Settings', 'backupwordpress' ); ?></h3>
|
8 |
|
9 |
+
<?php $hmbkp_form_errors = get_settings_errors(); ?>
|
10 |
|
11 |
<?php if ( ! empty( $hmbkp_form_errors ) ) { ?>
|
12 |
|
21 |
<?php }
|
22 |
|
23 |
// We can clear them now we've displayed them
|
24 |
+
clear_settings_errors();
|
25 |
|
26 |
?>
|
27 |
|
70 |
|
71 |
<option value="manually"><?php _e( 'Manual Only', 'backupwordpress' ); ?></option>
|
72 |
|
73 |
+
<?php foreach ( get_cron_schedules() as $cron_schedule => $cron_details ) : ?>
|
74 |
|
75 |
<option <?php selected( $schedule->get_reoccurrence(), $cron_schedule ); ?> value="<?php echo esc_attr( $cron_schedule ); ?>">
|
76 |
|
155 |
<?php _e( 'Minutes', 'backupwordpress' ); ?></label>
|
156 |
|
157 |
</span>
|
158 |
+
|
159 |
<p class="description">
|
160 |
<?php esc_html_e( '24-hour format.', 'backupwordpress' ); ?>
|
161 |
<span class="twice-js <?php if ( $schedule->get_reoccurrence() !== 'fortnightly' ) { ?> hidden<?php } ?>"><?php _e( 'The second backup will run 12 hours after the first.', 'backupwordpress' ); ?><span>
|
179 |
|
180 |
<?php printf( __( 'Past this limit older backups will be deleted automatically.', 'backupwordpress' ) ); ?>
|
181 |
|
182 |
+
<?php
|
183 |
+
|
184 |
+
$site_size = new Site_Size;
|
185 |
+
|
186 |
+
if ( Site_Size::is_site_size_cached() ) {
|
187 |
+
printf( __( 'This schedule will store a maximum of %s of backups.', 'backupwordpress' ), '<code>' . esc_html( size_format( $site_size->get_site_size( $schedule->get_type(), $schedule->get_excludes() ) * $schedule->get_max_backups() ) ) . '</code>' );
|
188 |
} ?>
|
189 |
|
190 |
</p>
|
193 |
|
194 |
</tr>
|
195 |
|
196 |
+
<?php foreach ( Services::get_services( $schedule ) as $service ) {
|
197 |
$service->field();
|
198 |
} ?>
|
199 |
|
201 |
|
202 |
</table>
|
203 |
|
204 |
+
<?php submit_button( __( 'Done', 'backupwordpress' ) ); ?>
|
|
|
|
|
|
|
205 |
|
206 |
</form>
|
admin/schedule-sentence.php
CHANGED
@@ -1,15 +1,21 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
|
|
|
|
|
4 |
|
5 |
// Backup Type
|
6 |
-
$type = strtolower(
|
7 |
|
8 |
// Backup Time
|
9 |
$day = date_i18n( 'l', $schedule->get_next_occurrence( false ) );
|
10 |
|
|
|
11 |
$next_backup = 'title="' . esc_attr( sprintf( __( 'The next backup will be on %1$s at %2$s %3$s', 'backupwordpress' ), date_i18n( get_option( 'date_format' ), $schedule->get_next_occurrence( false ) ), date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence( false ) ), date_i18n( 'T', $schedule->get_next_occurrence( false ) ) ) ) . '"';
|
12 |
|
|
|
|
|
|
|
13 |
// Backup Re-occurrence
|
14 |
switch ( $schedule->get_reoccurrence() ) :
|
15 |
|
@@ -67,8 +73,8 @@ switch ( $schedule->get_reoccurrence() ) :
|
|
67 |
|
68 |
endswitch;
|
69 |
|
70 |
-
$server = '<span title="' . esc_attr(
|
71 |
-
$server = '<code>' . esc_attr( str_replace(
|
72 |
|
73 |
// Backup to keep
|
74 |
switch ( $schedule->get_max_backups() ) :
|
@@ -81,7 +87,7 @@ switch ( $schedule->get_max_backups() ) :
|
|
81 |
|
82 |
case 0 :
|
83 |
|
84 |
-
$backup_to_keep = sprintf( __( 'don\'t store any backups in on this server', 'backupwordpress' ),
|
85 |
|
86 |
break;
|
87 |
|
@@ -93,7 +99,7 @@ endswitch;
|
|
93 |
|
94 |
$email_msg = $services = '';
|
95 |
|
96 |
-
foreach (
|
97 |
|
98 |
if ( is_wp_error( $service ) ) {
|
99 |
$email_msg = $service->get_error_message();
|
@@ -113,22 +119,22 @@ if ( ! empty( $services ) && count( $services ) > 1 ) {
|
|
113 |
|
114 |
} ?>
|
115 |
|
116 |
-
<div class="hmbkp-schedule-sentence<?php if ( $
|
117 |
|
118 |
<?php $sentence = sprintf( _x( 'Backup my %1$s %2$s %3$s, %4$s.', '1: Backup Type 2: Total size of backup 3: Schedule 4: Number of backups to store', 'backupwordpress' ), '<span>' . esc_html( $type ) . '</span>', $filesize, $reoccurrence, $backup_to_keep );
|
119 |
|
120 |
if ( $email_msg ) {
|
121 |
-
$sentence .=
|
122 |
}
|
123 |
|
124 |
-
if ( $services ) {
|
125 |
-
$sentence .= sprintf( __( 'Send a copy of each backup to %s.', 'backupwordpress' ), implode( ', ', array_filter( $services ) ) );
|
126 |
}
|
127 |
|
128 |
echo $sentence; ?>
|
129 |
|
130 |
-
<?php if (
|
131 |
-
|
132 |
} ?>
|
133 |
|
134 |
<?php require( HMBKP_PLUGIN_PATH . 'admin/schedule-settings.php' ); ?>
|
@@ -145,19 +151,21 @@ if ( ! empty( $services ) && count( $services ) > 1 ) {
|
|
145 |
*
|
146 |
* @return string
|
147 |
*/
|
148 |
-
function
|
149 |
|
150 |
if ( isset( $_GET['hmbkp_add_schedule'] ) ) {
|
151 |
-
|
152 |
return '';
|
|
|
|
|
|
|
153 |
|
154 |
-
|
155 |
|
156 |
-
return sprintf( '(<code title="' . __( 'Backups will be compressed and should be smaller than this.', 'backupwordpress' ) . '">%s</code>)', esc_attr( $
|
157 |
|
158 |
} else {
|
159 |
|
160 |
-
return sprintf( '(<code class="calculating" title="' . __( 'this shouldn\'t take long…', 'backupwordpress' ) . '">' . __( 'calculating the size of your
|
161 |
|
162 |
}
|
163 |
|
1 |
<?php
|
2 |
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
$filesize = get_site_size_text( $schedule );
|
6 |
|
7 |
// Backup Type
|
8 |
+
$type = strtolower( human_get_type( $schedule->get_type() ) );
|
9 |
|
10 |
// Backup Time
|
11 |
$day = date_i18n( 'l', $schedule->get_next_occurrence( false ) );
|
12 |
|
13 |
+
// Next Backup
|
14 |
$next_backup = 'title="' . esc_attr( sprintf( __( 'The next backup will be on %1$s at %2$s %3$s', 'backupwordpress' ), date_i18n( get_option( 'date_format' ), $schedule->get_next_occurrence( false ) ), date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence( false ) ), date_i18n( 'T', $schedule->get_next_occurrence( false ) ) ) ) . '"';
|
15 |
|
16 |
+
// Backup status
|
17 |
+
$status = new Backup_Status( $schedule->get_id() );
|
18 |
+
|
19 |
// Backup Re-occurrence
|
20 |
switch ( $schedule->get_reoccurrence() ) :
|
21 |
|
73 |
|
74 |
endswitch;
|
75 |
|
76 |
+
$server = '<span title="' . esc_attr( Path::get_path() ) . '">' . __( 'this server', 'backupwordpress' ) . '</span>';
|
77 |
+
$server = '<code>' . esc_attr( str_replace( Path::get_home_path(), '', Path::get_path() ) ) . '</code>';
|
78 |
|
79 |
// Backup to keep
|
80 |
switch ( $schedule->get_max_backups() ) :
|
87 |
|
88 |
case 0 :
|
89 |
|
90 |
+
$backup_to_keep = sprintf( __( 'don\'t store any backups in on this server', 'backupwordpress' ), Path::get_path() );
|
91 |
|
92 |
break;
|
93 |
|
99 |
|
100 |
$email_msg = $services = '';
|
101 |
|
102 |
+
foreach ( Services::get_services( $schedule ) as $file => $service ) {
|
103 |
|
104 |
if ( is_wp_error( $service ) ) {
|
105 |
$email_msg = $service->get_error_message();
|
119 |
|
120 |
} ?>
|
121 |
|
122 |
+
<div class="hmbkp-schedule-sentence<?php if ( $status->get_status() ) { ?> hmbkp-running<?php } ?>">
|
123 |
|
124 |
<?php $sentence = sprintf( _x( 'Backup my %1$s %2$s %3$s, %4$s.', '1: Backup Type 2: Total size of backup 3: Schedule 4: Number of backups to store', 'backupwordpress' ), '<span>' . esc_html( $type ) . '</span>', $filesize, $reoccurrence, $backup_to_keep );
|
125 |
|
126 |
if ( $email_msg ) {
|
127 |
+
$sentence .= ' ' . $email_msg;
|
128 |
}
|
129 |
|
130 |
+
if ( array_filter( $services ) ) {
|
131 |
+
$sentence .= ' ' . sprintf( __( 'Send a copy of each backup to %s.', 'backupwordpress' ), implode( ', ', array_filter( $services ) ) );
|
132 |
}
|
133 |
|
134 |
echo $sentence; ?>
|
135 |
|
136 |
+
<?php if ( Schedules::get_instance()->get_schedule( $schedule->get_id() ) ) {
|
137 |
+
schedule_status( $schedule );
|
138 |
} ?>
|
139 |
|
140 |
<?php require( HMBKP_PLUGIN_PATH . 'admin/schedule-settings.php' ); ?>
|
151 |
*
|
152 |
* @return string
|
153 |
*/
|
154 |
+
function get_site_size_text( Scheduled_Backup $schedule ) {
|
155 |
|
156 |
if ( isset( $_GET['hmbkp_add_schedule'] ) ) {
|
|
|
157 |
return '';
|
158 |
+
}
|
159 |
+
|
160 |
+
$site_size = new Site_Size( $schedule->get_type(), $schedule->get_excludes() );
|
161 |
|
162 |
+
if ( ( 'database' === $schedule->get_type() ) || $site_size->is_site_size_cached() ) {
|
163 |
|
164 |
+
return sprintf( '(<code title="' . __( 'Backups will be compressed and should be smaller than this.', 'backupwordpress' ) . '">%s</code>)', esc_attr( $site_size->get_formatted_site_size() ) );
|
165 |
|
166 |
} else {
|
167 |
|
168 |
+
return sprintf( '(<code class="calculating" title="' . __( 'this shouldn\'t take long…', 'backupwordpress' ) . '">' . __( 'calculating the size of your site…', 'backupwordpress' ) . '</code>)' );
|
169 |
|
170 |
}
|
171 |
|
admin/schedule-settings.php
CHANGED
@@ -1,26 +1,28 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
|
|
|
|
|
4 |
|
5 |
<div class="hmbkp-schedule-actions row-actions">
|
6 |
|
7 |
<a class="hmbkp-run" href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'hmbkp_run_schedule', 'hmbkp_schedule_id' => $schedule->get_id() ), admin_url( 'admin-ajax.php' ) ), 'hmbkp_run_schedule', 'hmbkp_run_schedule_nonce' ) ); ?>"><?php _e( 'Run now', 'backupwordpress' ); ?></a> |
|
8 |
|
9 |
-
<a href="<?php echo esc_url( add_query_arg( array( 'action' => 'hmbkp_edit_schedule', 'hmbkp_panel' => 'hmbkp_edit_schedule_settings', 'hmbkp_schedule_id' => $schedule->get_id() ),
|
10 |
|
11 |
<?php
|
12 |
|
13 |
// Only show excludes if we are backing up files
|
14 |
if ( 'database' !== $schedule->get_type() ) : ?>
|
15 |
-
<a href="<?php echo esc_url( add_query_arg( array( 'action' => 'hmbkp_edit_schedule', 'hmbkp_panel' => 'hmbkp_edit_schedule_excludes', 'hmbkp_schedule_id' => $schedule->get_id() ),
|
16 |
<?php endif; ?>
|
17 |
|
18 |
-
<?php foreach (
|
19 |
|
20 |
if ( ! $service->has_form() )
|
21 |
continue; ?>
|
22 |
|
23 |
-
<a href="<?php echo esc_url( add_query_arg( array( 'action' => 'hmbkp_edit_schedule', 'hmbkp_panel' => 'hmbkp_edit_schedule_settings_' . $service->get_slug() , 'hmbkp_schedule_id' => $schedule->get_id() ),
|
24 |
|
25 |
<?php endforeach; ?>
|
26 |
|
@@ -45,7 +47,7 @@ if ( HM\BackUpWordPress\Schedules::get_instance()->get_schedule( $schedule->get_
|
|
45 |
} ?>
|
46 |
|
47 |
<?php // Show the service form if we are viewing one
|
48 |
-
foreach (
|
49 |
|
50 |
<?php if ( $_GET['action'] === 'hmbkp_edit_schedule' && $_GET['hmbkp_panel'] === 'hmbkp_edit_schedule_settings_' . $service->get_slug() ) { ?>
|
51 |
|
@@ -53,7 +55,7 @@ if ( HM\BackUpWordPress\Schedules::get_instance()->get_schedule( $schedule->get_
|
|
53 |
|
54 |
<?php
|
55 |
|
56 |
-
$hmbkp_form_errors =
|
57 |
|
58 |
if ( ! empty( $hmbkp_form_errors ) ) :
|
59 |
|
@@ -72,7 +74,7 @@ if ( HM\BackUpWordPress\Schedules::get_instance()->get_schedule( $schedule->get_
|
|
72 |
endif;
|
73 |
|
74 |
// We can clear them now we've displayed them
|
75 |
-
|
76 |
|
77 |
?>
|
78 |
|
1 |
<?php
|
2 |
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
if ( Schedules::get_instance()->get_schedule( $schedule->get_id() ) ) { ?>
|
6 |
|
7 |
<div class="hmbkp-schedule-actions row-actions">
|
8 |
|
9 |
<a class="hmbkp-run" href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'hmbkp_run_schedule', 'hmbkp_schedule_id' => $schedule->get_id() ), admin_url( 'admin-ajax.php' ) ), 'hmbkp_run_schedule', 'hmbkp_run_schedule_nonce' ) ); ?>"><?php _e( 'Run now', 'backupwordpress' ); ?></a> |
|
10 |
|
11 |
+
<a href="<?php echo esc_url( add_query_arg( array( 'action' => 'hmbkp_edit_schedule', 'hmbkp_panel' => 'hmbkp_edit_schedule_settings', 'hmbkp_schedule_id' => $schedule->get_id() ), get_settings_url() ), 'hmbkp-edit-schedule' ); ?>"><?php _e( 'Settings', 'backupwordpress' ); ?></a> |
|
12 |
|
13 |
<?php
|
14 |
|
15 |
// Only show excludes if we are backing up files
|
16 |
if ( 'database' !== $schedule->get_type() ) : ?>
|
17 |
+
<a href="<?php echo esc_url( add_query_arg( array( 'action' => 'hmbkp_edit_schedule', 'hmbkp_panel' => 'hmbkp_edit_schedule_excludes', 'hmbkp_schedule_id' => $schedule->get_id() ), get_settings_url() ) ); ?>"><?php _e( 'Excludes', 'backupwordpress' ); ?></a> |
|
18 |
<?php endif; ?>
|
19 |
|
20 |
+
<?php foreach ( Services::get_services( $schedule ) as $service ) :
|
21 |
|
22 |
if ( ! $service->has_form() )
|
23 |
continue; ?>
|
24 |
|
25 |
+
<a href="<?php echo esc_url( add_query_arg( array( 'action' => 'hmbkp_edit_schedule', 'hmbkp_panel' => 'hmbkp_edit_schedule_settings_' . $service->get_slug() , 'hmbkp_schedule_id' => $schedule->get_id() ), get_settings_url() ) ); ?>"><?php echo esc_html( $service->name ); ?></a> |
|
26 |
|
27 |
<?php endforeach; ?>
|
28 |
|
47 |
} ?>
|
48 |
|
49 |
<?php // Show the service form if we are viewing one
|
50 |
+
foreach ( Services::get_services( $schedule ) as $service ) : ?>
|
51 |
|
52 |
<?php if ( $_GET['action'] === 'hmbkp_edit_schedule' && $_GET['hmbkp_panel'] === 'hmbkp_edit_schedule_settings_' . $service->get_slug() ) { ?>
|
53 |
|
55 |
|
56 |
<?php
|
57 |
|
58 |
+
$hmbkp_form_errors = get_settings_errors();
|
59 |
|
60 |
if ( ! empty( $hmbkp_form_errors ) ) :
|
61 |
|
74 |
endif;
|
75 |
|
76 |
// We can clear them now we've displayed them
|
77 |
+
clear_settings_errors();
|
78 |
|
79 |
?>
|
80 |
|
assets/hmbkp.js
CHANGED
@@ -98,7 +98,7 @@ jQuery( document ).ready( function ( $ ) {
|
|
98 |
$( '.hmbkp-status' ).replaceWith( data.hmbkp_schedule_status );
|
99 |
}
|
100 |
|
101 |
-
if ( (data.hmbkp_site_size !== undefined ) && ( $( 'code.calculating' ).length ) ) {
|
102 |
$( 'code.calculating' ).text( data.hmbkp_site_size );
|
103 |
var excludes = $( '.hmbkp-exclude-settings' );
|
104 |
if ( excludes.length ) {
|
@@ -116,6 +116,15 @@ jQuery( document ).ready( function ( $ ) {
|
|
116 |
|
117 |
} );
|
118 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
} );
|
120 |
|
121 |
function hmbkpToggleScheduleFields( recurrence ) {
|
@@ -168,48 +177,3 @@ function hmbkpToggleScheduleFields( recurrence ) {
|
|
168 |
}
|
169 |
|
170 |
}
|
171 |
-
|
172 |
-
function hmbkpCatchResponseAndOfferToEmail( data ) {
|
173 |
-
|
174 |
-
// Backup Succeeded
|
175 |
-
if ( ! data || data === 0 ) {
|
176 |
-
location.reload( true );
|
177 |
-
}
|
178 |
-
|
179 |
-
// The backup failed, show the error and offer to have it emailed back
|
180 |
-
else {
|
181 |
-
|
182 |
-
jQuery( '.hmbkp-schedule-sentence.hmbkp-running' ).removeClass( 'hmbkp-running' ).addClass( 'hmbkp-error' );
|
183 |
-
|
184 |
-
jQuery.post(
|
185 |
-
ajaxurl,
|
186 |
-
{'nonce': hmbkp.nonce, 'action': 'hmbkp_backup_error', 'hmbkp_error': data},
|
187 |
-
function ( data ) {
|
188 |
-
|
189 |
-
if ( ! data || data === 0 ) {
|
190 |
-
return;
|
191 |
-
} else {
|
192 |
-
location.reload( true );
|
193 |
-
}
|
194 |
-
}
|
195 |
-
);
|
196 |
-
|
197 |
-
}
|
198 |
-
|
199 |
-
jQuery( document ).one( 'click', '.hmbkp_send_error_via_email', function ( e ) {
|
200 |
-
|
201 |
-
e.preventDefault();
|
202 |
-
|
203 |
-
jQuery( this ).addClass( 'hmbkp-ajax-loading' ).attr( 'disabled', 'disabled' );
|
204 |
-
|
205 |
-
jQuery.post(
|
206 |
-
ajaxurl,
|
207 |
-
{'nonce': hmbkp.nonce, 'action': 'hmbkp_email_error', 'hmbkp_error': data},
|
208 |
-
function () {
|
209 |
-
//jQuery.colorbox.close();
|
210 |
-
}
|
211 |
-
);
|
212 |
-
|
213 |
-
} );
|
214 |
-
|
215 |
-
}
|
98 |
$( '.hmbkp-status' ).replaceWith( data.hmbkp_schedule_status );
|
99 |
}
|
100 |
|
101 |
+
if ( ( data.hmbkp_site_size !== undefined ) && ( $( 'code.calculating' ).length ) ) {
|
102 |
$( 'code.calculating' ).text( data.hmbkp_site_size );
|
103 |
var excludes = $( '.hmbkp-exclude-settings' );
|
104 |
if ( excludes.length ) {
|
116 |
|
117 |
} );
|
118 |
|
119 |
+
$( document ).on( 'click', '#hmbkp-warning-backup .notice-dismiss', function(){
|
120 |
+
$.post(
|
121 |
+
ajaxurl,
|
122 |
+
{
|
123 |
+
'action': 'hmbkp_dismiss_error'
|
124 |
+
}
|
125 |
+
);
|
126 |
+
} )
|
127 |
+
|
128 |
} );
|
129 |
|
130 |
function hmbkpToggleScheduleFields( recurrence ) {
|
177 |
}
|
178 |
|
179 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assets/hmbkp.min.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
.hmbkp_active td:first-child>code:before{content:"\00a0 \2713 ";font-size:11px}.hmbkp_active{background:#E5F7E8}div#hmbkp-warning,h2.nav-tab-wrapper+div[id^=hmbkp]{margin:20px 0 15px}h2+div[id^=hmbkp] input{max-width:100%}.nav-tab.hmbkp-running:not(.nav-tab-active):before{width:20px;height:20px;margin:0 10px -4px 0;content:"";background:
|
1 |
+
.hmbkp-schedule-actions a,.hmbkp-schedule-settings .column-format code{white-space:nowrap}.hmbkp_active td:first-child>code:before{content:"\00a0 \2713 ";font-size:11px}.hmbkp_active{background:#E5F7E8}div#hmbkp-warning,h2.nav-tab-wrapper+div[id^=hmbkp]{margin:20px 0 15px}h2+div[id^=hmbkp] input{max-width:100%}.nav-tab.hmbkp-running:not(.nav-tab-active):before{width:20px;height:20px;margin:0 10px -4px 0;content:"";background:url(spinner-2x.gif) no-repeat;background-size:20px;display:inline-block}.hmbkp-upsell{margin-top:40px;padding-top:16px;border-top:1px solid #ccc}.hmbkp-upsell a{color:#57792b}.hmbkp-upsell a:hover{color:#98c063}.hmbkp-upsell-sep{color:#bbb}.hmbkp-upsell ul{overflow:hidden}.hmbkp-upsell li{float:left;margin:0 20px 20px 0}.hmbkp-upsell img{display:block;margin:0 auto;max-width:120px;min-height:60px}.hmbkp-upsell ul a{display:block;margin-bottom:0;width:120px}.hmbkp-upsell .howto{font-weight:400;display:inline}.hmbkp-upsell .hmbkp_hide{float:right}.hmbkp-schedule-sentence{font-size:16px;font-weight:lighter;margin:20px 0;background-color:#FBFBFB;padding:20px;border:1px solid #e5e5e5;box-shadow:0 1px 1px rgba(0,0,0,.04)}.hmbkp-schedule-sentence::before{content:"\2714";margin-right:10px;width:16px;height:60px;display:block;float:left}.hmbkp-schedule-sentence.hmbkp-error:before{content:"\2718"}.hmbkp-schedule-sentence.hmbkp-running:before{width:20px;height:80px;margin:-1px 10px 0 0;content:"";background:url(spinner-2x.gif) no-repeat;background-size:20px;display:inline-block}.hmbkp-schedule-sentence .hmbkp-status{display:none;font-size:12px;color:#666;margin:2px 0 0 30px}.hmbkp-schedule-sentence.hmbkp-running .hmbkp-status{display:block}.hmbkp-schedule-sentence.hmbkp-running .hmbkp-schedule-actions{display:none}.hmbkp-schedule-sentence :not(a)[title]{border-bottom:1px dotted #CCC;cursor:help}.hmbkp-schedule-sentence .hmbkp-status[title]{border-bottom:none}.hmbkp-schedule-sentence .submit{padding:0}.hmbkp-schedule-sentence .hmbkp-schedule-actions{visibility:visible;font-size:12px;font-weight:400;margin:0 0 0 26px}.hmbkp-schedule-sentence .row-actions{position:static}.hmbkp-schedule-settings{border-top:1px solid #e5e5e5;margin:20px -20px -20px;background-color:#f5f5f5;padding:0 20px 20px}.hmbkp-exclude-settings thead tr:last-child,table.widefat tbody tr:nth-child(odd){background-color:#f9f9f9}.hmbkp-ajax-loading,button.hmbkp-ajax-loading{padding-left:20px;position:relative}.hmbkp-ajax-loading::after{content:"";width:16px;height:16px;background-image:url(spinner-2x.gif);background-size:16px 16px;background-repeat:no-repeat;background-position:0 0;position:absolute;right:-30px;top:5px}.delete-action{color:#a00;-webkit-transition:all .3s ease;transition:all .3s ease}.delete-action:hover .delete-action:focus{color:red;-webkit-transition:all .3s ease;transition:all .3s ease}.strikethrough{text-decoration:line-through}.hmbkp-exclude-settings td:first-child,.hmbkp-exclude-settings th:first-child{width:20px;padding-right:0}.hmbkp-exclude-settings table .button-secondary{line-height:18px;height:20px}thead td{border-bottom:1px solid #e1e1e1}.hmbkp-exclude-settings table .spinner{display:block;float:left;margin:0}.column-filesize code{position:relative}.column-filesize .dashicons-update{display:none;overflow:hidden;position:absolute;width:100%;left:0;text-align:center;background-color:rgba(255,255,255,.8)}.column-filesize .dashicons-update span{display:none}.column-filesize:hover .dashicons-update{display:inline-block}.hmbkp-exclude-settings td span.reason{color:#CCC}.server-info{overflow:auto;max-height:50%;outline:#000 solid 1px}.server-info pre{max-height:100px;overflow-x:hidden}.page-title-action span.dashicons-admin-users{position:relative;display:inline-block;vertical-align:middle;top:-2px}pre{background-color:#eee;padding:10px;white-space:pre;max-height:320px;overflow:auto;word-wrap:normal!important}@media screen and (max-width:768px){.wrap h2{padding:10px 0 0}.hmbkp-schedule-sentence::before{height:80px}h2 .nav-tab{display:block;padding:10px;margin:0}#intercom-info,.hmbkp-exclude-settings tr>:first-child,.hmbkp-schedule-settings thead tr:nth-child(2),.hmbkp-schedule-settings tr :nth-child(4),.hmbkp-schedule-settings tr :nth-child(5){display:none}.hmbkp-schedule-sentence{margin:10px 0;padding:10px}.hmbkp-exclude-settings table{margin:0 -10px;border-left:none;border-right:none;width:calc(100% + 20px)}.hmbkp-schedule-settings{padding:0 10px 10px;margin-left:-10px;margin-right:-10px;margin-bottom:-10px}table.widefat tbody tr:nth-child(even){background-color:#fff}table.widefat tbody tr:nth-child(odd){background-color:#f9f9f9}}
|
assets/hmbkp.min.js
CHANGED
@@ -1 +1,24 @@
|
|
1 |
-
function hmbkpToggleScheduleFields(a){a="undefined"!=typeof a?a:"manually";var b=jQuery(".recurring-setting"),c=jQuery("#schedule-start"),d=jQuery(".twice-js");switch(a){case"manually":b.hide();break;case"hourly":b.hide();break;case"daily":b.hide(),c.show(),d.hide();break;case"twicedaily":b.hide(),c.show(),d.show();break;case"weekly"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
function hmbkpToggleScheduleFields(a){a="undefined"!=typeof a?a:"manually";var b=jQuery(".recurring-setting"),c=jQuery("#schedule-start"),d=jQuery(".twice-js");switch(a){case"manually":b.hide();break;case"hourly":b.hide();break;case"daily":b.hide(),c.show(),d.hide();break;case"twicedaily":b.hide(),c.show(),d.show();break;case"weekly":// fall through
|
2 |
+
case"fortnightly":b.hide(),jQuery("#start-day").show(),c.show(),d.hide();break;case"monthly":b.hide(),c.show(),jQuery("#start-date").show(),d.hide()}}jQuery(document).ready(function(a){"use strict";var b=a("select#hmbkp_schedule_recurrence_type");
|
3 |
+
// Don't ever cache ajax requests
|
4 |
+
a.ajaxSetup({cache:!1}),b.length&&(hmbkpToggleScheduleFields(b.val()),a(document).on("change","select#hmbkp_schedule_recurrence_type",function(){hmbkpToggleScheduleFields(a(this).val())})),
|
5 |
+
// Show delete confirm message for delete schedule
|
6 |
+
a(document).on("click",".hmbkp-schedule-actions .delete-action",function(a){confirm(hmbkp.delete_schedule)||a.preventDefault()}),
|
7 |
+
// Show delete confirm message for delete backup
|
8 |
+
a(document).on("click",".hmbkp_manage_backups_row .delete-action",function(a){confirm(hmbkp.delete_backup)||a.preventDefault()}),
|
9 |
+
// Show delete confirm message for remove exclude rule
|
10 |
+
a(document).on("click",".hmbkp-edit-schedule-excludes-form .delete-action",function(a){confirm(hmbkp.remove_exclude_rule)||a.preventDefault()}),
|
11 |
+
// Test the cron response using ajax
|
12 |
+
a.post(ajaxurl,{nonce:hmbkp.nonce,action:"hmbkp_cron_test"},function(b){"1"!==b&&a(".wrap > h2").after(b)}),
|
13 |
+
// Run a backup
|
14 |
+
a(document).on("click",".hmbkp-run",function(b){wp.heartbeat.interval("fast"),a(this).closest(".hmbkp-schedule-sentence").addClass("hmbkp-running"),a(".hmbkp-error").removeClass("hmbkp-error");var c=a("[data-hmbkp-schedule-id]").attr("data-hmbkp-schedule-id");a.post(ajaxurl,{hmbkp_run_schedule_nonce:hmbkp.hmbkp_run_schedule_nonce,action:"hmbkp_run_schedule",hmbkp_schedule_id:c}),b.preventDefault()}),
|
15 |
+
// Send the schedule id with the heartbeat
|
16 |
+
a(document).on("heartbeat-send",function(b,c){c.hmbkp_schedule_id=a("[data-hmbkp-schedule-id]").attr("data-hmbkp-schedule-id"),a(".hmbkp-schedule-sentence.hmbkp-running").length?c.hmbkp_is_in_progress=!0:c.hmbkp_client_request="site_size"}),
|
17 |
+
// Update schedule status on heartbeat tick
|
18 |
+
a(document).on("heartbeat-tick",function(b,c){if(
|
19 |
+
// If the schedule has finished then reload the page
|
20 |
+
0!==c.hmbkp_schedule_status||a(".hmbkp-error").length||location.reload(!0),
|
21 |
+
// If the schedule is still running then update the schedule status
|
22 |
+
0!==c.hmbkp_schedule_status&&void 0!==c.hmbkp_schedule_status&&a(".hmbkp-status").replaceWith(c.hmbkp_schedule_status),void 0!==c.hmbkp_site_size&&a("code.calculating").length){a("code.calculating").text(c.hmbkp_site_size);var d=a(".hmbkp-exclude-settings");d.length&&d.replaceWith(c.hmbkp_dir_sizes)}}),
|
23 |
+
// Closing ThickBox Modal Window
|
24 |
+
a(document).on("click",".hmbkp-thickbox-close",function(a){a.preventDefault(),window.parent.tb_remove()}),a(document).on("click","#hmbkp-warning-backup .notice-dismiss",function(){a.post(ajaxurl,{action:"hmbkp_dismiss_error"})})});
|
backupwordpress.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
Plugin Name: BackUpWordPress
|
4 |
Plugin URI: http://bwp.hmn.md/
|
5 |
Description: Simple automated backups of your WordPress powered website. Once activated you'll find me under <strong>Tools → Backups</strong>. On multisite, you'll find me under the Network Settings menu.
|
6 |
-
Version: 3.
|
7 |
Author: Human Made Limited
|
8 |
Author URI: http://hmn.md/
|
9 |
License: GPL-2+
|
3 |
Plugin Name: BackUpWordPress
|
4 |
Plugin URI: http://bwp.hmn.md/
|
5 |
Description: Simple automated backups of your WordPress powered website. Once activated you'll find me under <strong>Tools → Backups</strong>. On multisite, you'll find me under the Network Settings menu.
|
6 |
+
Version: 3.4.0
|
7 |
Author: Human Made Limited
|
8 |
Author URI: http://hmn.md/
|
9 |
License: GPL-2+
|
classes/backup/class-backup-engine-database-imysqldump.php
ADDED
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
use Ifsnop\Mysqldump as IMysqldump;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Perform a database backup using the mysqldump-php library
|
9 |
+
*
|
10 |
+
* @see https://github.com/ifsnop/mysqldump-php
|
11 |
+
*/
|
12 |
+
class IMysqldump_Database_Backup_Engine extends Database_Backup_Engine {
|
13 |
+
|
14 |
+
public function __construct() {
|
15 |
+
parent::__construct();
|
16 |
+
}
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Perform the database backupwordpress
|
20 |
+
*
|
21 |
+
* @return bool True if the backup completed successfully, else false.
|
22 |
+
*/
|
23 |
+
public function backup() {
|
24 |
+
|
25 |
+
try {
|
26 |
+
|
27 |
+
$dump = new IMysqldump\Mysqldump( $this->get_dsn(), $this->get_user(), $this->get_password(), $this->get_dump_settings() );
|
28 |
+
$dump->start( $this->get_backup_filepath() );
|
29 |
+
|
30 |
+
} catch ( \Exception $e ) {
|
31 |
+
$this->error( __CLASS__, $e->getMessage() );
|
32 |
+
}
|
33 |
+
|
34 |
+
return $this->verify_backup();
|
35 |
+
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Get the settings for the database bump.
|
40 |
+
*
|
41 |
+
* @return array The array of database dump settings.
|
42 |
+
*/
|
43 |
+
public function get_dump_settings() {
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Allow additional settings to be added.
|
47 |
+
*
|
48 |
+
* @param string[] $settings The array of settings.
|
49 |
+
* @todo can these be standardised across all database backup engines
|
50 |
+
*/
|
51 |
+
return apply_filters( 'hmbkp_imysqldump_command', array(
|
52 |
+
'default-character-set' => $this->get_charset(),
|
53 |
+
'hex-blob' => true,
|
54 |
+
'single-transaction' => defined( 'HMBKP_MYSQLDUMP_SINGLE_TRANSACTION' ) && HMBKP_MYSQLDUMP_SINGLE_TRANSACTION
|
55 |
+
) );
|
56 |
+
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Correctly calculates the DSN string for the various mysql
|
61 |
+
* connection variations including simplt hostname, non-standard ports
|
62 |
+
* and socket connections.
|
63 |
+
*
|
64 |
+
* @return string The DSN connection string
|
65 |
+
*/
|
66 |
+
public function get_dsn() {
|
67 |
+
|
68 |
+
$dsn = 'mysql:host=' . $this->get_host() . ';dbname=' . $this->get_name();
|
69 |
+
|
70 |
+
if ( $this->get_host() && $this->get_port() ) {
|
71 |
+
$dsn = 'mysql:host=' . $this->get_host() . ';port=' . $this->get_port() . ';dbname=' . $this->get_name();
|
72 |
+
}
|
73 |
+
|
74 |
+
elseif ( $this->get_socket() ) {
|
75 |
+
$dsn = 'mysql:unix_socket=' . $this->get_socket() . ';dbname=' . $this->get_name();
|
76 |
+
}
|
77 |
+
|
78 |
+
return $dsn;
|
79 |
+
|
80 |
+
}
|
81 |
+
|
82 |
+
}
|
classes/backup/class-backup-engine-database-mysqldump.php
ADDED
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Perform a database backup using the mysqldump cli command
|
7 |
+
*/
|
8 |
+
class Mysqldump_Database_Backup_Engine extends Database_Backup_Engine {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* The path to the mysqldump executable
|
12 |
+
*
|
13 |
+
* @var string
|
14 |
+
*/
|
15 |
+
private $mysqldump_executable_path = '';
|
16 |
+
|
17 |
+
public function __construct() {
|
18 |
+
parent::__construct();
|
19 |
+
}
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Calculate the path to the mysqldump executable.
|
23 |
+
*
|
24 |
+
* The executable path can be overridden using either the `HMBKP_MYSQLDUMP_PATH`
|
25 |
+
* Constant or the `hmbkp_mysqldump_executable_path` filter.
|
26 |
+
*
|
27 |
+
* If neither of those are set then we fallback to checking a number of
|
28 |
+
* common locations.
|
29 |
+
*
|
30 |
+
* @return string|false The path to the executable or false.
|
31 |
+
*/
|
32 |
+
public function get_mysqldump_executable_path() {
|
33 |
+
|
34 |
+
// Return now if it's set in a Constant
|
35 |
+
if ( defined( 'HMBKP_MYSQLDUMP_PATH' ) && HMBKP_MYSQLDUMP_PATH ) {
|
36 |
+
$this->mysqldump_executable_path = HMBKP_MYSQLDUMP_PATH;
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Allow the executable path to be set via a filter
|
41 |
+
*
|
42 |
+
* @param string The path to the mysqldump executable
|
43 |
+
*/
|
44 |
+
$this->mysqldump_executable_path = apply_filters( 'hmbkp_mysqldump_executable_path', '' );
|
45 |
+
|
46 |
+
if ( ! $this->mysqldump_executable_path ) {
|
47 |
+
|
48 |
+
// List of possible mysqldump locations
|
49 |
+
$paths = array(
|
50 |
+
'mysqldump',
|
51 |
+
'/usr/local/bin/mysqldump',
|
52 |
+
'/usr/local/mysql/bin/mysqldump',
|
53 |
+
'/usr/mysql/bin/mysqldump',
|
54 |
+
'/usr/bin/mysqldump',
|
55 |
+
'/opt/local/lib/mysql6/bin/mysqldump',
|
56 |
+
'/opt/local/lib/mysql5/bin/mysqldump',
|
57 |
+
'/opt/local/lib/mysql4/bin/mysqldump',
|
58 |
+
'/xampp/mysql/bin/mysqldump',
|
59 |
+
'/Program Files/xampp/mysql/bin/mysqldump',
|
60 |
+
'/Program Files/MySQL/MySQL Server 6.0/bin/mysqldump',
|
61 |
+
'/Program Files/MySQL/MySQL Server 5.7/bin/mysqldump',
|
62 |
+
'/Program Files/MySQL/MySQL Server 5.6/bin/mysqldump',
|
63 |
+
'/Program Files/MySQL/MySQL Server 5.5/bin/mysqldump',
|
64 |
+
'/Program Files/MySQL/MySQL Server 5.4/bin/mysqldump',
|
65 |
+
'/Program Files/MySQL/MySQL Server 5.1/bin/mysqldump',
|
66 |
+
'/Program Files/MySQL/MySQL Server 5.0/bin/mysqldump',
|
67 |
+
'/Program Files/MySQL/MySQL Server 4.1/bin/mysqldump',
|
68 |
+
'/opt/local/bin/mysqldump'
|
69 |
+
);
|
70 |
+
|
71 |
+
$this->mysqldump_executable_path = Backup_Utilities::get_executable_path( $paths );
|
72 |
+
|
73 |
+
}
|
74 |
+
|
75 |
+
return $this->mysqldump_executable_path;
|
76 |
+
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Check whether it's possible to connect to the database with the
|
81 |
+
* credentials we have.
|
82 |
+
*
|
83 |
+
* @return bool Whether the database connection was successful.
|
84 |
+
*/
|
85 |
+
public function check_user_can_connect_to_database_via_cli() {
|
86 |
+
|
87 |
+
if ( ! $this->get_mysqldump_executable_path() ) {
|
88 |
+
return false;
|
89 |
+
}
|
90 |
+
|
91 |
+
$args = $this->get_mysql_connection_args();
|
92 |
+
|
93 |
+
$args[] = escapeshellarg( $this->get_name() );
|
94 |
+
|
95 |
+
// Quit immediately as we're only interesting in testing the connection
|
96 |
+
$args[] = '--execute="quit"';
|
97 |
+
|
98 |
+
// Pipe STDERR to STDOUT
|
99 |
+
$args[] = ' 2>&1';
|
100 |
+
|
101 |
+
$output = $return_status = '';
|
102 |
+
$args = implode( ' ', $args );
|
103 |
+
exec( 'mysql ' . $args, $output, $return_status );
|
104 |
+
|
105 |
+
$output = $this->ignore_mysql_password_warning( $output );
|
106 |
+
|
107 |
+
// If there were errors connecting then track them
|
108 |
+
if ( $output ) {
|
109 |
+
if ( $return_status === 0 ) {
|
110 |
+
$this->warning( __CLASS__, implode( ', ', $output ) );
|
111 |
+
} else {
|
112 |
+
$this->error( __CLASS__, implode( ', ', $output ) );
|
113 |
+
return false;
|
114 |
+
}
|
115 |
+
}
|
116 |
+
|
117 |
+
return true;
|
118 |
+
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Perform the database backup.
|
123 |
+
*
|
124 |
+
* @return bool Whether the backup completed successfully or not.
|
125 |
+
*/
|
126 |
+
public function backup() {
|
127 |
+
|
128 |
+
if ( ! $this->check_user_can_connect_to_database_via_cli() || ! $this->get_mysqldump_executable_path() ) {
|
129 |
+
return false;
|
130 |
+
}
|
131 |
+
|
132 |
+
$output = $return_status = '';
|
133 |
+
|
134 |
+
// Grab the database connections args
|
135 |
+
$args = $this->get_mysql_connection_args();
|
136 |
+
|
137 |
+
// We don't want to create a new DB
|
138 |
+
$args[] = '--no-create-db';
|
139 |
+
|
140 |
+
// Allow lock-tables to be overridden
|
141 |
+
if ( defined( 'HMBKP_MYSQLDUMP_SINGLE_TRANSACTION' ) && HMBKP_MYSQLDUMP_SINGLE_TRANSACTION ) {
|
142 |
+
$args[] = '--single-transaction';
|
143 |
+
}
|
144 |
+
|
145 |
+
// Make sure binary data is exported properly
|
146 |
+
$args[] = '--hex-blob';
|
147 |
+
|
148 |
+
// The file we're saving too
|
149 |
+
$args[] = '-r ' . escapeshellarg( $this->get_backup_filepath() );
|
150 |
+
|
151 |
+
// The database we're dumping
|
152 |
+
$args[] = escapeshellarg( $this->get_name() );
|
153 |
+
|
154 |
+
// Pipe STDERR to STDOUT
|
155 |
+
$args[] = '2>&1';
|
156 |
+
|
157 |
+
exec( escapeshellcmd( $this->get_mysqldump_executable_path() ) . ' ' . implode( ' ', $args ), $output, $return_status );
|
158 |
+
|
159 |
+
$output = $this->ignore_mysql_password_warning( $output );
|
160 |
+
|
161 |
+
// Track any errors
|
162 |
+
if ( $output ) {
|
163 |
+
if ( $return_status === 0 ) {
|
164 |
+
$this->warning( __CLASS__, implode( ', ', $output ) );
|
165 |
+
} else {
|
166 |
+
$this->error( __CLASS__, implode( ', ', $output ) );
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
return $this->verify_backup();
|
171 |
+
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Get the connection args for the mysqldump command
|
176 |
+
*
|
177 |
+
* @return array The array of connection args
|
178 |
+
*/
|
179 |
+
public function get_mysql_connection_args() {
|
180 |
+
|
181 |
+
$args = array();
|
182 |
+
|
183 |
+
$args[] = '-u ' . escapeshellarg( $this->get_user() );
|
184 |
+
|
185 |
+
if ( $this->get_password() ) {
|
186 |
+
$args[] = '-p' . escapeshellarg( $this->get_password() );
|
187 |
+
}
|
188 |
+
|
189 |
+
$args[] = '-h ' . escapeshellarg( $this->get_host() );
|
190 |
+
|
191 |
+
if ( $this->get_port() ) {
|
192 |
+
$args[] = '-P ' . escapeshellarg( $this->get_port() );
|
193 |
+
}
|
194 |
+
|
195 |
+
if ( $this->get_socket() ) {
|
196 |
+
$args[] = '--protocol=socket -S ' . escapeshellarg( $this->get_socket() );
|
197 |
+
}
|
198 |
+
|
199 |
+
return $args;
|
200 |
+
|
201 |
+
}
|
202 |
+
|
203 |
+
private function ignore_mysql_password_warning( $output ) {
|
204 |
+
|
205 |
+
$key = array_search( 'Warning: Using a password on the command line interface can be insecure.', $output );
|
206 |
+
|
207 |
+
if ( $key !== false ) {
|
208 |
+
unset( $output[ $key ] );
|
209 |
+
}
|
210 |
+
|
211 |
+
return $output;
|
212 |
+
|
213 |
+
}
|
214 |
+
|
215 |
+
}
|
classes/backup/class-backup-engine-database.php
ADDED
@@ -0,0 +1,218 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* The Database Backup Engine type
|
7 |
+
*
|
8 |
+
* All Database Backup Engine implementations should extend this class
|
9 |
+
*/
|
10 |
+
abstract class Database_Backup_Engine extends Backup_Engine {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* The filename for the resulting Backup
|
14 |
+
*
|
15 |
+
* @var string
|
16 |
+
*/
|
17 |
+
public $backup_filename = '';
|
18 |
+
|
19 |
+
/**
|
20 |
+
* The database host string, typically the value of
|
21 |
+
* the `DB_HOST` Constant.
|
22 |
+
*
|
23 |
+
* @var string
|
24 |
+
*/
|
25 |
+
private $host = '';
|
26 |
+
|
27 |
+
/**
|
28 |
+
* The database socket, if it's using a socket connection
|
29 |
+
*
|
30 |
+
* @var string
|
31 |
+
*/
|
32 |
+
private $socket = '';
|
33 |
+
|
34 |
+
/**
|
35 |
+
* The database port, if a custom one is set
|
36 |
+
*
|
37 |
+
* @var integer
|
38 |
+
*/
|
39 |
+
private $port = 0;
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Individual Database Backup Engine implementations must include
|
43 |
+
* a backup method at a minimum.
|
44 |
+
*
|
45 |
+
* @return [type] [description]
|
46 |
+
*/
|
47 |
+
abstract public function backup();
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Setup some general database backup settings
|
51 |
+
*
|
52 |
+
* Child classes must call `parent::__construct` in their own constructor.
|
53 |
+
*/
|
54 |
+
public function __construct() {
|
55 |
+
|
56 |
+
parent::__construct();
|
57 |
+
|
58 |
+
$this->parse_db_host_constant();
|
59 |
+
|
60 |
+
// Set a default backup filename
|
61 |
+
$this->set_backup_filename( 'database-' . $this->get_name() . '.sql' );
|
62 |
+
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Get the database charset setting.
|
67 |
+
*
|
68 |
+
* @return [string The database charset.
|
69 |
+
*/
|
70 |
+
public function get_charset() {
|
71 |
+
global $wpdb;
|
72 |
+
return $wpdb->charset;
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Get the database collate setting.
|
77 |
+
*
|
78 |
+
* @return string The database collage setting.
|
79 |
+
*/
|
80 |
+
public function get_collate() {
|
81 |
+
global $wpdb;
|
82 |
+
return $wpdb->collate;
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Get the database name.
|
87 |
+
*
|
88 |
+
* @return string The database name.
|
89 |
+
*/
|
90 |
+
public function get_name() {
|
91 |
+
global $wpdb;
|
92 |
+
return $wpdb->dbname;
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Get the database user.
|
97 |
+
*
|
98 |
+
* @return string The database user.
|
99 |
+
*/
|
100 |
+
public function get_user() {
|
101 |
+
global $wpdb;
|
102 |
+
return $wpdb->dbuser;
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Get the database password.
|
107 |
+
*
|
108 |
+
* @return string The database password.
|
109 |
+
*/
|
110 |
+
public function get_password() {
|
111 |
+
global $wpdb;
|
112 |
+
return $wpdb->dbpassword;
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* Get the database hostname.
|
117 |
+
*
|
118 |
+
* @return string The database hostname.
|
119 |
+
*/
|
120 |
+
public function get_host() {
|
121 |
+
return $this->host;
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Get the database port.
|
126 |
+
*
|
127 |
+
* @return int The database port.
|
128 |
+
*/
|
129 |
+
public function get_port() {
|
130 |
+
return $this->port;
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Get the database socket.
|
135 |
+
*
|
136 |
+
* @return string The database socket.
|
137 |
+
*/
|
138 |
+
public function get_socket() {
|
139 |
+
return $this->socket;
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Parse the `DB_HOST` constant.
|
144 |
+
*
|
145 |
+
* The `DB_HOST` constant potentially contains the hostname, port or socket.
|
146 |
+
* We need to parse it to figure out the type of mysql connection to make.
|
147 |
+
*
|
148 |
+
* @param string $constant The Constant to parse. If the string isn't a
|
149 |
+
* defined Constant then it will be parsed directly.
|
150 |
+
*/
|
151 |
+
public function parse_db_host_constant( $constant = 'DB_HOST' ) {
|
152 |
+
|
153 |
+
// If we've been passed a Constant then grab it's contents
|
154 |
+
if ( defined( $constant ) ) {
|
155 |
+
$constant = constant( $constant );
|
156 |
+
}
|
157 |
+
|
158 |
+
// If we weren't passed a Constant then just parse the string directly.
|
159 |
+
$this->host = (string) $constant;
|
160 |
+
|
161 |
+
// Grab the part after :, it could either be a port or a socket
|
162 |
+
$port_or_socket = strstr( $constant, ':' );
|
163 |
+
|
164 |
+
if ( $port_or_socket ) {
|
165 |
+
|
166 |
+
// The host is the bit up to the :
|
167 |
+
$this->host = substr( $constant, 0, strpos( $constant, ':' ) );
|
168 |
+
|
169 |
+
// Strip the :
|
170 |
+
$port_or_socket = substr( $port_or_socket, 1 );
|
171 |
+
|
172 |
+
if ( 0 !== strpos( $port_or_socket, '/' ) ) {
|
173 |
+
|
174 |
+
$this->port = intval( $port_or_socket );
|
175 |
+
$maybe_socket = strstr( $port_or_socket, ':' );
|
176 |
+
|
177 |
+
if ( ! empty( $maybe_socket ) ) {
|
178 |
+
$this->socket = substr( $maybe_socket, 1 );
|
179 |
+
}
|
180 |
+
|
181 |
+
} else {
|
182 |
+
$this->socket = $port_or_socket;
|
183 |
+
}
|
184 |
+
|
185 |
+
}
|
186 |
+
|
187 |
+
}
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Verify that the database backup was successful.
|
191 |
+
*
|
192 |
+
* It's important this function is performant as it's called after every
|
193 |
+
* backup.
|
194 |
+
*
|
195 |
+
* @return bool Whether the backup completed successfully
|
196 |
+
*/
|
197 |
+
public function verify_backup() {
|
198 |
+
|
199 |
+
// If there are errors delete the database dump file
|
200 |
+
if ( $this->get_errors( __CLASS__ ) && file_exists( $this->get_backup_filepath() ) ) {
|
201 |
+
unlink( $this->get_backup_filepath() );
|
202 |
+
}
|
203 |
+
|
204 |
+
// If we have an empty file delete it
|
205 |
+
if ( @filesize( $this->get_backup_filepath() ) === 0 ) {
|
206 |
+
unlink( $this->get_backup_filepath() );
|
207 |
+
}
|
208 |
+
|
209 |
+
// If the database backup doesn't exist then the backup must have failed
|
210 |
+
if ( ! file_exists( $this->get_backup_filepath() ) ) {
|
211 |
+
return false;
|
212 |
+
}
|
213 |
+
|
214 |
+
return true;
|
215 |
+
|
216 |
+
}
|
217 |
+
|
218 |
+
}
|
classes/backup/class-backup-engine-file-zip-archive.php
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Perform a file backup using the native PHP ZipArchive extension
|
7 |
+
*/
|
8 |
+
class Zip_Archive_File_Backup_Engine extends File_Backup_Engine {
|
9 |
+
|
10 |
+
public function __construct() {
|
11 |
+
parent::__construct();
|
12 |
+
}
|
13 |
+
|
14 |
+
public function backup() {
|
15 |
+
|
16 |
+
if ( ! class_exists( 'ZipArchive' ) ) {
|
17 |
+
return false;
|
18 |
+
}
|
19 |
+
|
20 |
+
$zip = new \ZipArchive();
|
21 |
+
|
22 |
+
// Attempt to create the zip file.
|
23 |
+
if ( $zip->open( $this->get_backup_filepath(), \ZIPARCHIVE::CREATE ) ) {
|
24 |
+
|
25 |
+
foreach ( $this->get_files() as $file ) {
|
26 |
+
|
27 |
+
// Create an empty directory for each directory in the filesystem
|
28 |
+
if ( $file->isDir() ) {
|
29 |
+
$zip->addEmptyDir( $file->getRelativePathname() );
|
30 |
+
}
|
31 |
+
|
32 |
+
// Archive the file with a relative path
|
33 |
+
elseif ( $file->isFile() ) {
|
34 |
+
$zip->addFile( $file->getPathname(), $file->getRelativePathname() );
|
35 |
+
}
|
36 |
+
}
|
37 |
+
|
38 |
+
// Track any internal warnings
|
39 |
+
if ( $zip->status ) {
|
40 |
+
$this->warning( __CLASS__, $zip->status );
|
41 |
+
}
|
42 |
+
|
43 |
+
if ( $zip->statusSys ) {
|
44 |
+
$this->warning( __CLASS__, $zip->statusSys );
|
45 |
+
}
|
46 |
+
|
47 |
+
$zip->close();
|
48 |
+
|
49 |
+
}
|
50 |
+
|
51 |
+
return $this->verify_backup();
|
52 |
+
|
53 |
+
}
|
54 |
+
|
55 |
+
}
|
classes/backup/class-backup-engine-file-zip.php
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Perform a file backup using the zip cli command
|
7 |
+
*/
|
8 |
+
class Zip_File_Backup_Engine extends File_Backup_Engine {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* The path to the zip executable
|
12 |
+
*
|
13 |
+
* @var string
|
14 |
+
*/
|
15 |
+
private $zip_executable_path = '';
|
16 |
+
|
17 |
+
public function __construct() {
|
18 |
+
parent::__construct();
|
19 |
+
}
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Calculate the path to the zip executable.
|
23 |
+
*
|
24 |
+
* The executable path can be overridden using either the `HMBKP_ZIP_PATH`
|
25 |
+
* Constant or the `hmbkp_zip_executable_path` filter.
|
26 |
+
*
|
27 |
+
* If neither of those are set then we fallback to checking a number of
|
28 |
+
* common locations.
|
29 |
+
*
|
30 |
+
* @return string|false The path to the executable or false.
|
31 |
+
*/
|
32 |
+
public function get_zip_executable_path() {
|
33 |
+
|
34 |
+
if ( defined( 'HMBKP_ZIP_PATH' ) ) {
|
35 |
+
return HMBKP_ZIP_PATH;
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Allow the executable path to be set via a filter
|
40 |
+
*
|
41 |
+
* @param string The path to the zip executable
|
42 |
+
*/
|
43 |
+
$this->zip_executable_path = apply_filters( 'hmbkp_zip_executable_path', '' );
|
44 |
+
|
45 |
+
if ( ! $this->zip_executable_path ) {
|
46 |
+
|
47 |
+
// List of possible zip locations
|
48 |
+
$paths = array(
|
49 |
+
'zip',
|
50 |
+
'/usr/bin/zip',
|
51 |
+
'/opt/local/bin/zip'
|
52 |
+
);
|
53 |
+
|
54 |
+
$this->zip_executable_path = Backup_Utilities::get_executable_path( $paths );
|
55 |
+
|
56 |
+
}
|
57 |
+
|
58 |
+
return $this->zip_executable_path;
|
59 |
+
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Perform the file backup.
|
64 |
+
*
|
65 |
+
* @return bool Whether the backup completed successfully or not.
|
66 |
+
*/
|
67 |
+
public function backup() {
|
68 |
+
|
69 |
+
if ( ! Backup_Utilities::is_exec_available() || ! $this->get_zip_executable_path() ) {
|
70 |
+
return false;
|
71 |
+
}
|
72 |
+
|
73 |
+
// cd to the site root
|
74 |
+
$command[] = 'cd ' . escapeshellarg( Path::get_root() );
|
75 |
+
|
76 |
+
// Run the zip command with the recursive and quiet flags
|
77 |
+
$command[] = '&& ' . escapeshellcmd( $this->get_zip_executable_path() ) . ' -rq';
|
78 |
+
|
79 |
+
// Save the zip file to the correct path
|
80 |
+
$command[] = escapeshellarg( $this->get_backup_filepath() ) . ' ./';
|
81 |
+
|
82 |
+
// Pass exclude rules in if we have them
|
83 |
+
if ( $this->get_exclude_string() ) {
|
84 |
+
$command[] = '-x ' . $this->get_exclude_string();
|
85 |
+
}
|
86 |
+
|
87 |
+
// Push all output to STDERR
|
88 |
+
$command[] = '2>&1';
|
89 |
+
|
90 |
+
$command = implode( ' ', $command );
|
91 |
+
$output = $return_status = 0;
|
92 |
+
|
93 |
+
exec( $command, $output, $return_status );
|
94 |
+
|
95 |
+
// Track any errors
|
96 |
+
if ( $output ) {
|
97 |
+
if ( $return_status === 0 ) {
|
98 |
+
$this->warning( __CLASS__, implode( ', ', $output ) );
|
99 |
+
} else {
|
100 |
+
$this->error( __CLASS__, implode( ', ', $output ) );
|
101 |
+
}
|
102 |
+
}
|
103 |
+
|
104 |
+
return $this->verify_backup();
|
105 |
+
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* Convert the exclude rules to a format zip accepts
|
110 |
+
*
|
111 |
+
* @return string The exclude string ready to pass to `zip -x`
|
112 |
+
*/
|
113 |
+
public function get_exclude_string() {
|
114 |
+
|
115 |
+
if ( ! $this->excludes ) {
|
116 |
+
return '';
|
117 |
+
}
|
118 |
+
|
119 |
+
$excludes = $this->excludes->get_excludes();
|
120 |
+
|
121 |
+
foreach ( $excludes as $key => &$rule ) {
|
122 |
+
|
123 |
+
$file = $absolute = $fragment = false;
|
124 |
+
|
125 |
+
// Files don't end with /
|
126 |
+
if ( ! in_array( substr( $rule, - 1 ), array( '\\', '/' ) ) ) {
|
127 |
+
$file = true;
|
128 |
+
}
|
129 |
+
|
130 |
+
// If rule starts with a / then treat as absolute path
|
131 |
+
elseif ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) ) {
|
132 |
+
$absolute = true;
|
133 |
+
}
|
134 |
+
|
135 |
+
// Otherwise treat as dir fragment
|
136 |
+
else {
|
137 |
+
$fragment = true;
|
138 |
+
}
|
139 |
+
|
140 |
+
$rule = str_ireplace( Path::get_root(), '', untrailingslashit( wp_normalize_path( $rule ) ) );
|
141 |
+
|
142 |
+
// Strip the preceeding slash
|
143 |
+
if ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) ) {
|
144 |
+
$rule = substr( $rule, 1 );
|
145 |
+
}
|
146 |
+
|
147 |
+
// Wrap directory fragments and files in wildcards for zip
|
148 |
+
if ( $fragment || $file ) {
|
149 |
+
$rule = '*' . $rule . '*';
|
150 |
+
}
|
151 |
+
|
152 |
+
// Add a wildcard to the end of absolute url for zips
|
153 |
+
if ( $absolute ) {
|
154 |
+
$rule .= '*';
|
155 |
+
}
|
156 |
+
|
157 |
+
}
|
158 |
+
|
159 |
+
// Escape shell args for zip command
|
160 |
+
$excludes = array_map( 'escapeshellarg', array_unique( $excludes ) );
|
161 |
+
|
162 |
+
return implode( ' -x ', $excludes );
|
163 |
+
|
164 |
+
}
|
165 |
+
|
166 |
+
}
|
classes/backup/class-backup-engine-file.php
ADDED
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
use Symfony\Component\Finder\Finder as Finder;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* The File Backup Engine type
|
9 |
+
*
|
10 |
+
* All File Backup Engine implementations should extend this class
|
11 |
+
*/
|
12 |
+
abstract class File_Backup_Engine extends Backup_Engine {
|
13 |
+
|
14 |
+
/**
|
15 |
+
* The array of excludes rules
|
16 |
+
*
|
17 |
+
* @var array
|
18 |
+
*/
|
19 |
+
protected $excludes;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Set the default backup filename.
|
23 |
+
*/
|
24 |
+
public function __construct() {
|
25 |
+
|
26 |
+
parent::__construct();
|
27 |
+
|
28 |
+
$this->set_backup_filename( implode( '-', array(
|
29 |
+
str_ireplace( array( 'http://', 'https://', 'www' ), '', home_url() ),
|
30 |
+
'backup',
|
31 |
+
current_time( 'Y-m-d-H-i-s' )
|
32 |
+
) ) . '.zip' );
|
33 |
+
|
34 |
+
$this->excludes = new Excludes;
|
35 |
+
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Set the excludes rules for the backup.
|
40 |
+
*
|
41 |
+
* @param array $excludes The exclude rules.
|
42 |
+
*/
|
43 |
+
public function set_excludes( Excludes $excludes ) {
|
44 |
+
$this->excludes = $excludes;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Returns a Finder instance for the files that will be included in the
|
49 |
+
* backup.
|
50 |
+
*
|
51 |
+
* By default we ignore unreadable files and directories as well as, common
|
52 |
+
* version control folders / files, "Dot" files and anything matching the
|
53 |
+
* exclude rules.
|
54 |
+
*
|
55 |
+
* @uses Finder
|
56 |
+
* @return Finder The Finder iterator of all files to be included
|
57 |
+
*/
|
58 |
+
public function get_files() {
|
59 |
+
|
60 |
+
$finder = new Finder();
|
61 |
+
|
62 |
+
$finder->followLinks( true );
|
63 |
+
$finder->ignoreDotFiles( false );
|
64 |
+
$finder->ignoreVCS( true );
|
65 |
+
$finder->ignoreUnreadableDirs( true );
|
66 |
+
|
67 |
+
// Skip unreadable files too
|
68 |
+
$finder->filter(
|
69 |
+
function ( \SplFileInfo $file ) {
|
70 |
+
if ( ! $file->isReadable() ) {
|
71 |
+
return false;
|
72 |
+
}
|
73 |
+
}
|
74 |
+
);
|
75 |
+
|
76 |
+
// Finder expects exclude rules to be in a regex format
|
77 |
+
$exclude_rules = $this->excludes->get_excludes_for_regex();
|
78 |
+
|
79 |
+
// Skips folders/files that match default exclude patterns
|
80 |
+
foreach ( $exclude_rules as $exclude ) {
|
81 |
+
$finder->notPath( $exclude );
|
82 |
+
}
|
83 |
+
|
84 |
+
return $finder->in( Path::get_root() );
|
85 |
+
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Verify that the file backup completed successfully.
|
90 |
+
*
|
91 |
+
* This should be called from backup method of any final file backup engine
|
92 |
+
* implementations.
|
93 |
+
*
|
94 |
+
* @return bool Whether the backup completed successfully.
|
95 |
+
*/
|
96 |
+
public function verify_backup() {
|
97 |
+
|
98 |
+
// If there are errors delete the backup file.
|
99 |
+
if ( $this->get_errors( __CLASS__ ) && file_exists( $this->get_backup_filepath() ) ) {
|
100 |
+
unlink( $this->get_backup_filepath() );
|
101 |
+
}
|
102 |
+
|
103 |
+
// If the backup doesn't exist then we must have failed.
|
104 |
+
if ( ! file_exists( $this->get_backup_filepath() ) ) {
|
105 |
+
return false;
|
106 |
+
}
|
107 |
+
|
108 |
+
return true;
|
109 |
+
|
110 |
+
}
|
111 |
+
|
112 |
+
}
|
classes/backup/class-backup-engine.php
ADDED
@@ -0,0 +1,197 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* The base Backup Engine
|
7 |
+
*
|
8 |
+
* Base Backup Engine types should extend this class and call parent::__construct in
|
9 |
+
* there constructor.
|
10 |
+
*
|
11 |
+
* Defines base functionality shared across all types of backups
|
12 |
+
*/
|
13 |
+
abstract class Backup_Engine {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* An array of backup errors.
|
17 |
+
*
|
18 |
+
* @var array
|
19 |
+
*/
|
20 |
+
private $errors = array();
|
21 |
+
|
22 |
+
/**
|
23 |
+
* An array of backup warnings.
|
24 |
+
*
|
25 |
+
* @var array
|
26 |
+
*/
|
27 |
+
private $warnings = array();
|
28 |
+
|
29 |
+
public function __construct() {
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Raise the `memory_limit` and `max_execution time`
|
33 |
+
*
|
34 |
+
* Respects the WP_MAX_MEMORY_LIMIT Constant and the `admin_memory_limit`
|
35 |
+
* filter.
|
36 |
+
*/
|
37 |
+
@ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
|
38 |
+
@set_time_limit( 0 );
|
39 |
+
|
40 |
+
// Set a custom error handler so we can track errors
|
41 |
+
set_error_handler( array( $this, 'error_handler' ) );
|
42 |
+
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Backup Engine Types should always implement the `verify_backup` method.
|
47 |
+
*
|
48 |
+
* @return bool Whether the backup completed successfully or not.
|
49 |
+
*/
|
50 |
+
abstract public function verify_backup();
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Get the full filepath to the backup file.
|
54 |
+
*
|
55 |
+
* @return string The backup filepath.
|
56 |
+
*/
|
57 |
+
public function get_backup_filepath() {
|
58 |
+
return trailingslashit( Path::get_path() ) . $this->get_backup_filename();
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Get the filename of the backup.
|
63 |
+
*
|
64 |
+
* @return string The backup filename.
|
65 |
+
*/
|
66 |
+
public function get_backup_filename() {
|
67 |
+
return $this->backup_filename;
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Set the filename of the backup.
|
72 |
+
*
|
73 |
+
* @param string $filename The backup filename.
|
74 |
+
*/
|
75 |
+
public function set_backup_filename( $filename ) {
|
76 |
+
$this->backup_filename = strtolower( sanitize_file_name( remove_accents( $filename ) ) );
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Get the array of errors encountered during the backup process.
|
81 |
+
*
|
82 |
+
* @param string $context The context for the error, usually the Backup
|
83 |
+
* Engine that encountered the error.
|
84 |
+
*
|
85 |
+
* @return array The array of errors.
|
86 |
+
*/
|
87 |
+
public function get_errors( $context = null ) {
|
88 |
+
|
89 |
+
// Only return a specific contexts errors.
|
90 |
+
if ( ! empty( $context ) ) {
|
91 |
+
return isset( $this->errors[ $context ] ) ? $this->errors[ $context ] : array();
|
92 |
+
}
|
93 |
+
|
94 |
+
return $this->errors;
|
95 |
+
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Add an error to the errors array.
|
100 |
+
*
|
101 |
+
* An error is always treat as fatal and should only be used for unrecoverable
|
102 |
+
* issues with the backup process.
|
103 |
+
*
|
104 |
+
* @param string $context The context for the error.
|
105 |
+
* @param string $error The error that was encountered.
|
106 |
+
*/
|
107 |
+
public function error( $context, $error ) {
|
108 |
+
|
109 |
+
if ( empty( $context ) || empty( $error ) ) {
|
110 |
+
return;
|
111 |
+
}
|
112 |
+
|
113 |
+
// Ensure we don't store duplicate errors by md5'ing the error as the key
|
114 |
+
$this->errors[ $context ][ $_key = md5( implode( ':', (array) $error ) ) ] = $error;
|
115 |
+
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Get the array of warnings encountered during the backup process.
|
120 |
+
*
|
121 |
+
* @param string $context The context for the warning, usually the Backup
|
122 |
+
* Engine that encountered the warning.
|
123 |
+
*
|
124 |
+
* @return array The array of warnings.
|
125 |
+
*/
|
126 |
+
public function get_warnings( $context = null ) {
|
127 |
+
|
128 |
+
// Only return a specific contexts errors.
|
129 |
+
if ( ! empty( $context ) ) {
|
130 |
+
return isset( $this->warnings[ $context ] ) ? $this->warnings[ $context ] : array();
|
131 |
+
}
|
132 |
+
|
133 |
+
return $this->warnings;
|
134 |
+
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* Add an warning to the errors warnings.
|
139 |
+
*
|
140 |
+
* A warning is always treat as non-fatal and should only be used for recoverable
|
141 |
+
* issues with the backup process.
|
142 |
+
*
|
143 |
+
* @param string $context The context for the warning.
|
144 |
+
* @param string $error The warning that was encountered.
|
145 |
+
*/
|
146 |
+
public function warning( $context, $warning ) {
|
147 |
+
|
148 |
+
if ( empty( $context ) || empty( $warning ) ) {
|
149 |
+
return;
|
150 |
+
}
|
151 |
+
|
152 |
+
// Ensure we don't store duplicate warnings by md5'ing the error as the key
|
153 |
+
$this->warnings[ $context ][ $_key = md5( implode( ':', (array) $warning ) ) ] = $warning;
|
154 |
+
|
155 |
+
}
|
156 |
+
|
157 |
+
/**
|
158 |
+
* Hooked into `set_error_handler` to catch any PHP errors that happen during
|
159 |
+
* the backup process.
|
160 |
+
*
|
161 |
+
* PHP errors are always treat as warnings rather than errors.
|
162 |
+
*
|
163 |
+
* @param int $type The level of error raised
|
164 |
+
*
|
165 |
+
* @return false Return false to pass the error back to PHP so it can
|
166 |
+
* be handled natively.
|
167 |
+
*/
|
168 |
+
public function error_handler( $type ) {
|
169 |
+
|
170 |
+
// Skip strict & deprecated warnings
|
171 |
+
if ( ( defined( 'E_DEPRECATED' ) && $type === E_DEPRECATED ) || ( defined( 'E_STRICT' ) && $type === E_STRICT ) || error_reporting() === 0 ) {
|
172 |
+
return false;
|
173 |
+
}
|
174 |
+
|
175 |
+
/**
|
176 |
+
* Get the details of the error.
|
177 |
+
*
|
178 |
+
* These are:
|
179 |
+
*
|
180 |
+
* @param int $errorno The error level expressed as an integer/
|
181 |
+
* @param string $errstr The error message.
|
182 |
+
* @param string $errfile The file that the error raised in.
|
183 |
+
* @param string $errorline The line number the error was raised on.
|
184 |
+
*/
|
185 |
+
$args = func_get_args();
|
186 |
+
|
187 |
+
// Strip the error level
|
188 |
+
array_shift( $args );
|
189 |
+
|
190 |
+
// Fire a warning for the PHP error passing the message, file and line number.
|
191 |
+
$this->warning( 'php', implode( ', ', array_splice( $args, 0, 3 ) ) );
|
192 |
+
|
193 |
+
return false;
|
194 |
+
|
195 |
+
}
|
196 |
+
|
197 |
+
}
|
classes/backup/class-backup-status.php
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Manages status and progress of a backup
|
7 |
+
*/
|
8 |
+
class Backup_Status {
|
9 |
+
|
10 |
+
private $filename = '';
|
11 |
+
|
12 |
+
public function __construct( $id ) {
|
13 |
+
$this->id = $id;
|
14 |
+
}
|
15 |
+
|
16 |
+
public function start( $backup_filename, $status_message ) {
|
17 |
+
$this->filename = $backup_filename;
|
18 |
+
$this->set_status( $status_message );
|
19 |
+
}
|
20 |
+
|
21 |
+
public function get_backup_filename() {
|
22 |
+
|
23 |
+
if ( $this->is_started() ) {
|
24 |
+
$status = json_decode( file_get_contents( $this->get_status_filepath() ) );
|
25 |
+
|
26 |
+
if ( ! empty( $status->filename ) ) {
|
27 |
+
$this->filename = $status->filename;
|
28 |
+
}
|
29 |
+
}
|
30 |
+
|
31 |
+
return $this->filename;
|
32 |
+
}
|
33 |
+
|
34 |
+
public function is_started() {
|
35 |
+
return (bool) file_exists( $this->get_status_filepath() );
|
36 |
+
}
|
37 |
+
|
38 |
+
public function finish() {
|
39 |
+
// Delete the backup running file
|
40 |
+
if ( file_exists( $this->get_status_filepath() ) ) {
|
41 |
+
unlink( $this->get_status_filepath() );
|
42 |
+
}
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Get the status of the running backup.
|
47 |
+
*
|
48 |
+
* @return string
|
49 |
+
*/
|
50 |
+
public function get_status() {
|
51 |
+
|
52 |
+
if ( ! file_exists( $this->get_status_filepath() ) ) {
|
53 |
+
return '';
|
54 |
+
}
|
55 |
+
|
56 |
+
$status = json_decode( file_get_contents( $this->get_status_filepath() ) );
|
57 |
+
|
58 |
+
if ( ! empty( $status->status ) ) {
|
59 |
+
return $status->status;
|
60 |
+
}
|
61 |
+
|
62 |
+
return '';
|
63 |
+
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Set the status of the running backup
|
68 |
+
*
|
69 |
+
* @param string $message
|
70 |
+
*
|
71 |
+
* @return null
|
72 |
+
*/
|
73 |
+
public function set_status( $message ) {
|
74 |
+
|
75 |
+
// If start hasn't been called yet then we wont' have a backup filename
|
76 |
+
if ( ! $this->filename ) {
|
77 |
+
return '';
|
78 |
+
}
|
79 |
+
|
80 |
+
$status = json_encode( (object) array(
|
81 |
+
'filename' => $this->filename,
|
82 |
+
'started' => $this->get_start_time(),
|
83 |
+
'status' => $message,
|
84 |
+
) );
|
85 |
+
|
86 |
+
file_put_contents( $this->get_status_filepath(), $status );
|
87 |
+
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Get the time that the current running backup was started
|
92 |
+
*
|
93 |
+
* @return int $timestamp
|
94 |
+
*/
|
95 |
+
public function get_start_time() {
|
96 |
+
|
97 |
+
if ( ! file_exists( $this->get_status_filepath() ) ) {
|
98 |
+
return 0;
|
99 |
+
}
|
100 |
+
|
101 |
+
$status = json_decode( file_get_contents( $this->get_status_filepath() ) );
|
102 |
+
|
103 |
+
if ( ! empty( $status->started ) && (int) (string) $status->started === $status->started ) {
|
104 |
+
return $status->started;
|
105 |
+
}
|
106 |
+
|
107 |
+
return time();
|
108 |
+
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Get the path to the backup running file that stores the running backup status
|
113 |
+
*
|
114 |
+
* @return string
|
115 |
+
*/
|
116 |
+
public function get_status_filepath() {
|
117 |
+
return Path::get_path() . '/.backup-' . $this->id . '-running';
|
118 |
+
}
|
119 |
+
|
120 |
+
}
|
classes/backup/class-backup-utilities.php
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* A set of Backup Utility functions
|
7 |
+
*/
|
8 |
+
class Backup_Utilities {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Checks whether Safe Mode is currently on
|
12 |
+
*
|
13 |
+
* @param string $ini_get_callback By default we use `ini_get` to check for
|
14 |
+
* the Safe Mode setting but this can be
|
15 |
+
* overridden for testing purposes.
|
16 |
+
*
|
17 |
+
* @return boolean Whether Safe Mode is on or off.
|
18 |
+
*/
|
19 |
+
public static function is_safe_mode_on( $ini_get_callback = 'ini_get' ) {
|
20 |
+
|
21 |
+
$safe_mode = @call_user_func( $ini_get_callback, 'safe_mode' );
|
22 |
+
|
23 |
+
if ( $safe_mode && strtolower( $safe_mode ) !== 'off' ) {
|
24 |
+
return true;
|
25 |
+
}
|
26 |
+
|
27 |
+
return false;
|
28 |
+
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Check whether it's possible to use `exec`.
|
33 |
+
*
|
34 |
+
* @return boolean [description]
|
35 |
+
*/
|
36 |
+
public static function is_exec_available() {
|
37 |
+
|
38 |
+
// You can't use exec if Safe Mode is on.
|
39 |
+
if ( self::is_safe_mode_on() ) {
|
40 |
+
return false;
|
41 |
+
}
|
42 |
+
|
43 |
+
// Check if exec is specifically disabled
|
44 |
+
if ( self::is_function_disabled( 'exec' ) ) {
|
45 |
+
return false;
|
46 |
+
}
|
47 |
+
|
48 |
+
// Some servers seem to disable escapeshellcmd / escapeshellarg separately to exec, in
|
49 |
+
// that instance we don't want to use exec as it's insecure
|
50 |
+
if ( self::is_function_disabled( 'escapeshellcmd' ) || self::is_function_disabled( 'escapeshellarg' ) ) {
|
51 |
+
return false;
|
52 |
+
}
|
53 |
+
|
54 |
+
// Can we issue a simple echo command?
|
55 |
+
exec( 'echo backupwordpress', $output, $return );
|
56 |
+
|
57 |
+
if ( $return !== 0 ) {
|
58 |
+
return false;
|
59 |
+
}
|
60 |
+
|
61 |
+
return true;
|
62 |
+
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Check whether a PHP function has been disabled.
|
67 |
+
*
|
68 |
+
* @param string $function The function you want to test for.
|
69 |
+
* @param string $ini_get_callback By default we check with ini_get, but
|
70 |
+
* it's possible to overridde this for
|
71 |
+
* testing purposes.
|
72 |
+
*
|
73 |
+
* @return boolean Whether the function is disabled or not.
|
74 |
+
*/
|
75 |
+
public static function is_function_disabled( $function, $ini_get_callback = 'ini_get' ) {
|
76 |
+
|
77 |
+
// Suhosin stores it's disabled functions in `suhosin.executor.func.blacklist`
|
78 |
+
$suhosin_blacklist = array_map( 'trim', explode( ',', @call_user_func( $ini_get_callback, 'suhosin.executor.func.blacklist' ) ) );
|
79 |
+
|
80 |
+
// PHP supports disabling functions by adding them to `disable_functions` in php.ini.
|
81 |
+
$disabled_functions = array_map( 'trim', explode( ',', @call_user_func( $ini_get_callback, 'disable_functions' ) ) );
|
82 |
+
|
83 |
+
if ( in_array( $function, array_merge( $suhosin_blacklist, $disabled_functions ) ) ) {
|
84 |
+
return true;
|
85 |
+
}
|
86 |
+
|
87 |
+
return false;
|
88 |
+
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Attempt to work out path to a cli executable.
|
93 |
+
*
|
94 |
+
* @param array $paths An array of paths to check against.
|
95 |
+
*
|
96 |
+
* @return string|false The path to the executable.
|
97 |
+
*/
|
98 |
+
public static function get_executable_path( $paths ) {
|
99 |
+
|
100 |
+
if ( ! self::is_exec_available() ) {
|
101 |
+
return false;
|
102 |
+
}
|
103 |
+
|
104 |
+
$paths = array_map( 'wp_normalize_path', $paths );
|
105 |
+
|
106 |
+
foreach ( $paths as $path ) {
|
107 |
+
|
108 |
+
$output = $result = 0;
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Attempt to call `--version` on each path, the one which works
|
112 |
+
* must be the correct path.
|
113 |
+
*
|
114 |
+
* We pipe STDERR to /dev/null so we don't leak errors.
|
115 |
+
*/
|
116 |
+
exec( escapeshellarg( $path ) . ' --version ' . ignore_stderr(), $output, $result );
|
117 |
+
|
118 |
+
// If the command executed successfully then this must be the correct path
|
119 |
+
if ( $result === 0 ) {
|
120 |
+
return $path;
|
121 |
+
}
|
122 |
+
|
123 |
+
}
|
124 |
+
|
125 |
+
return false;
|
126 |
+
|
127 |
+
}
|
128 |
+
|
129 |
+
}
|
classes/backup/class-backup.php
ADDED
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
class Backup {
|
6 |
+
|
7 |
+
private $excludes;
|
8 |
+
public $warnings = array();
|
9 |
+
public $errors = array();
|
10 |
+
private $backup_filename;
|
11 |
+
private $database_dump_filename;
|
12 |
+
private $backup_filepath = '';
|
13 |
+
private $database_dump_filepath = '';
|
14 |
+
private $status = null;
|
15 |
+
private $type = 'complete';
|
16 |
+
|
17 |
+
public function __construct( $backup_filename, $database_dump_filename = null ) {
|
18 |
+
$this->backup_filename = $backup_filename;
|
19 |
+
$this->database_dump_filename = $database_dump_filename;
|
20 |
+
}
|
21 |
+
|
22 |
+
public function set_type( $type ) {
|
23 |
+
$this->type = $type;
|
24 |
+
}
|
25 |
+
|
26 |
+
public function set_backup_filename( $filename ) {
|
27 |
+
$this->backup_filename = $filename;
|
28 |
+
}
|
29 |
+
|
30 |
+
public function set_status( Backup_Status $status ) {
|
31 |
+
$this->status = $status;
|
32 |
+
}
|
33 |
+
|
34 |
+
public function set_excludes( Excludes $excludes ) {
|
35 |
+
$this->excludes = $excludes;
|
36 |
+
}
|
37 |
+
|
38 |
+
public function run() {
|
39 |
+
|
40 |
+
if ( $this->type !== 'file' ) {
|
41 |
+
$this->backup_database();
|
42 |
+
}
|
43 |
+
|
44 |
+
if ( $this->type !== 'database' ) {
|
45 |
+
$this->backup_files();
|
46 |
+
}
|
47 |
+
|
48 |
+
}
|
49 |
+
|
50 |
+
public function backup_database() {
|
51 |
+
|
52 |
+
if ( $this->status ) {
|
53 |
+
$this->status->set_status( __( 'Backing up database...', 'backupwordpress' ) );
|
54 |
+
}
|
55 |
+
|
56 |
+
$database_backup_engines = apply_filters( 'hmbkp_database_backup_engines', array(
|
57 |
+
new Mysqldump_Database_Backup_Engine,
|
58 |
+
new IMysqldump_Database_Backup_Engine
|
59 |
+
) );
|
60 |
+
|
61 |
+
// Set the file backup engine settings
|
62 |
+
if ( $this->database_dump_filename ) {
|
63 |
+
foreach( $database_backup_engines as &$backup_engine ) {
|
64 |
+
$backup_engine->set_backup_filename( $this->database_dump_filename );
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
// Dump the database
|
69 |
+
$database_dump = $this->perform_backup( $database_backup_engines );
|
70 |
+
|
71 |
+
if ( is_a( $database_dump, __NAMESPACE__ . '\\Backup_Engine' ) ) {
|
72 |
+
$this->database_dump_filepath = $database_dump->get_backup_filepath();
|
73 |
+
}
|
74 |
+
|
75 |
+
// Fire up the file backup engines
|
76 |
+
$file_backup_engines = apply_filters( 'hmbkp_file_backup_engines', array(
|
77 |
+
new Zip_File_Backup_Engine,
|
78 |
+
new Zip_Archive_File_Backup_Engine
|
79 |
+
) );
|
80 |
+
|
81 |
+
// Set the file backup engine settings
|
82 |
+
foreach( $file_backup_engines as &$backup_engine ) {
|
83 |
+
$backup_engine->set_backup_filename( $this->backup_filename );
|
84 |
+
$backup_engine->set_excludes( new Excludes( array( '*.zip', 'index.html', '.htaccess', '.*-running' ) ) );
|
85 |
+
}
|
86 |
+
|
87 |
+
// Zip up the database dump
|
88 |
+
$root = Path::get_root();
|
89 |
+
Path::get_instance()->set_root( Path::get_path() );
|
90 |
+
$file_backup = $this->perform_backup( $file_backup_engines );
|
91 |
+
Path::get_instance()->set_root( $root );
|
92 |
+
|
93 |
+
if ( is_a( $file_backup, __NAMESPACE__ . '\\Backup_Engine' ) ) {
|
94 |
+
$this->backup_filepath = $file_backup->get_backup_filepath();
|
95 |
+
}
|
96 |
+
|
97 |
+
// Delete the Database Backup now that we've zipped it up
|
98 |
+
if ( file_exists( $this->database_dump_filepath ) ) {
|
99 |
+
unlink( $this->database_dump_filepath );
|
100 |
+
}
|
101 |
+
|
102 |
+
}
|
103 |
+
|
104 |
+
public function backup_files() {
|
105 |
+
|
106 |
+
if ( $this->status ) {
|
107 |
+
$this->status->set_status( __( 'Backing up files...', 'backupwordpress' ) );
|
108 |
+
}
|
109 |
+
|
110 |
+
// Fire up the file backup engines
|
111 |
+
$backup_engines = apply_filters( 'hmbkp_file_backup_engines', array(
|
112 |
+
new Zip_File_Backup_Engine,
|
113 |
+
new Zip_Archive_File_Backup_Engine
|
114 |
+
) );
|
115 |
+
|
116 |
+
// Set the file backup engine settings
|
117 |
+
foreach( $backup_engines as &$backup_engine ) {
|
118 |
+
$backup_engine->set_backup_filename( $this->backup_filename );
|
119 |
+
if ( $this->excludes ) {
|
120 |
+
$backup_engine->set_excludes( $this->excludes );
|
121 |
+
}
|
122 |
+
}
|
123 |
+
|
124 |
+
$file_backup = $this->perform_backup( $backup_engines );
|
125 |
+
|
126 |
+
if ( is_a( $file_backup, __NAMESPACE__ . '\\Backup_Engine' ) ) {
|
127 |
+
$this->backup_filepath = $file_backup->get_backup_filepath();
|
128 |
+
}
|
129 |
+
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Perform the backup by iterating through each Backup_Engine in turn until
|
134 |
+
* we find one which works. If a backup filename or any excludes have been
|
135 |
+
* set then those are passed to each Backup_Engine.
|
136 |
+
*/
|
137 |
+
public function perform_backup( Array $backup_engines ) {
|
138 |
+
|
139 |
+
foreach ( $backup_engines as $backup_engine ) {
|
140 |
+
|
141 |
+
if ( $backup_engine->backup() ) {
|
142 |
+
$this->warnings = array_merge( $this->warnings, $backup_engine->get_warnings() );
|
143 |
+
return $backup_engine;
|
144 |
+
}
|
145 |
+
$this->warnings = array_merge( $this->warnings, $backup_engine->get_warnings() );
|
146 |
+
$this->errors = array_merge( $this->errors, $backup_engine->get_errors() );
|
147 |
+
}
|
148 |
+
|
149 |
+
return false;
|
150 |
+
|
151 |
+
}
|
152 |
+
|
153 |
+
public function get_warnings() {
|
154 |
+
return $this->warnings;
|
155 |
+
}
|
156 |
+
|
157 |
+
public function get_errors() {
|
158 |
+
return $this->errors;
|
159 |
+
}
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Add an warning to the errors warnings.
|
163 |
+
*
|
164 |
+
* A warning is always treat as non-fatal and should only be used for recoverable
|
165 |
+
* issues with the backup process.
|
166 |
+
*
|
167 |
+
* @param string $context The context for the warning.
|
168 |
+
* @param string $error The warning that was encountered.
|
169 |
+
*/
|
170 |
+
public function warning( $context, $warning ) {
|
171 |
+
|
172 |
+
if ( empty( $context ) || empty( $warning ) ) {
|
173 |
+
return;
|
174 |
+
}
|
175 |
+
|
176 |
+
// Ensure we don't store duplicate warnings by md5'ing the error as the key
|
177 |
+
$this->warnings[ $context ][ $_key = md5( implode( ':', (array) $warning ) ) ] = $warning;
|
178 |
+
|
179 |
+
}
|
180 |
+
|
181 |
+
public function get_database_backup_filepath() {
|
182 |
+
return $this->database_dump_filepath;
|
183 |
+
}
|
184 |
+
|
185 |
+
public function get_backup_filepath() {
|
186 |
+
return $this->backup_filepath;
|
187 |
+
}
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Back compat with old method name
|
191 |
+
*
|
192 |
+
* @see Backup::get_backup_filepath()
|
193 |
+
* @deprecated 3.4 Use Backup::get_backup_filepath()
|
194 |
+
*/
|
195 |
+
public function get_archive_filepath() {
|
196 |
+
_deprecated_function( __FUNCTION__, '3.4', 'get_backup_filepath()' );
|
197 |
+
return $this->get_backup_filepath();
|
198 |
+
}
|
199 |
+
|
200 |
+
}
|
classes/class-backup.php
DELETED
@@ -1,1663 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace HM\BackUpWordPress;
|
4 |
-
use Symfony\Component\Finder\Finder;
|
5 |
-
use Ifsnop\Mysqldump as IMysqldump;
|
6 |
-
|
7 |
-
/**
|
8 |
-
* Generic file and database backup class
|
9 |
-
*
|
10 |
-
* @version 2.3
|
11 |
-
*/
|
12 |
-
class Backup {
|
13 |
-
|
14 |
-
/**
|
15 |
-
* The backup type, must be either complete, file or database
|
16 |
-
*
|
17 |
-
* @string
|
18 |
-
*/
|
19 |
-
private $type = '';
|
20 |
-
|
21 |
-
/**
|
22 |
-
* The filename of the backup file
|
23 |
-
*
|
24 |
-
* @string
|
25 |
-
*/
|
26 |
-
private $archive_filename = '';
|
27 |
-
|
28 |
-
/**
|
29 |
-
* The filename of the database dump
|
30 |
-
*
|
31 |
-
* @string
|
32 |
-
*/
|
33 |
-
private $database_dump_filename = '';
|
34 |
-
|
35 |
-
/**
|
36 |
-
* The path to the zip command
|
37 |
-
*
|
38 |
-
* @string
|
39 |
-
*/
|
40 |
-
private $zip_command_path;
|
41 |
-
|
42 |
-
/**
|
43 |
-
* The path to the mysqldump command
|
44 |
-
*
|
45 |
-
* @string
|
46 |
-
*/
|
47 |
-
private $mysqldump_command_path;
|
48 |
-
|
49 |
-
/**
|
50 |
-
* The filename of the existing backup file
|
51 |
-
*
|
52 |
-
* @string
|
53 |
-
*/
|
54 |
-
private $existing_archive_filepath = '';
|
55 |
-
|
56 |
-
/**
|
57 |
-
* An array of exclude rules
|
58 |
-
*
|
59 |
-
* @array
|
60 |
-
*/
|
61 |
-
private $excludes = array();
|
62 |
-
|
63 |
-
/**
|
64 |
-
* The path that should be backed up
|
65 |
-
*
|
66 |
-
* @var string
|
67 |
-
*/
|
68 |
-
private $root = '';
|
69 |
-
|
70 |
-
/**
|
71 |
-
* An array of all the files in root
|
72 |
-
* excluding excludes and unreadable files
|
73 |
-
*
|
74 |
-
* @var array
|
75 |
-
*/
|
76 |
-
private $files = array();
|
77 |
-
|
78 |
-
/**
|
79 |
-
* An array of all the files in root
|
80 |
-
* that are unreadable
|
81 |
-
*
|
82 |
-
* @var array
|
83 |
-
*/
|
84 |
-
private $unreadable_files = array();
|
85 |
-
|
86 |
-
/**
|
87 |
-
* An array of all the files in root
|
88 |
-
* that will be included in the backup
|
89 |
-
*
|
90 |
-
* @var array
|
91 |
-
*/
|
92 |
-
protected $included_files = array();
|
93 |
-
|
94 |
-
/**
|
95 |
-
* An array of all the files in root
|
96 |
-
* that match the exclude rules
|
97 |
-
*
|
98 |
-
* @var array
|
99 |
-
*/
|
100 |
-
private $excluded_files = array();
|
101 |
-
|
102 |
-
/**
|
103 |
-
* Contains an array of errors
|
104 |
-
*
|
105 |
-
* @var mixed
|
106 |
-
*/
|
107 |
-
private $errors = array();
|
108 |
-
|
109 |
-
/**
|
110 |
-
* Contains an array of warnings
|
111 |
-
*
|
112 |
-
* @var mixed
|
113 |
-
*/
|
114 |
-
private $warnings = array();
|
115 |
-
|
116 |
-
/**
|
117 |
-
* The archive method used
|
118 |
-
*
|
119 |
-
* @var string
|
120 |
-
*/
|
121 |
-
private $archive_method = '';
|
122 |
-
|
123 |
-
/**
|
124 |
-
* The mysqldump method used
|
125 |
-
*
|
126 |
-
* @var string
|
127 |
-
*/
|
128 |
-
private $mysqldump_method = '';
|
129 |
-
|
130 |
-
/**
|
131 |
-
* @var bool
|
132 |
-
*/
|
133 |
-
protected $mysqldump_verified = false;
|
134 |
-
|
135 |
-
/**
|
136 |
-
* @var bool
|
137 |
-
*/
|
138 |
-
protected $archive_verified = false;
|
139 |
-
|
140 |
-
/**
|
141 |
-
* @var string
|
142 |
-
*/
|
143 |
-
protected $action_callback = '';
|
144 |
-
|
145 |
-
/**
|
146 |
-
* List of patterns we want to exclude by default.
|
147 |
-
* @var array
|
148 |
-
*/
|
149 |
-
protected $default_excludes = array(
|
150 |
-
'.git/',
|
151 |
-
'.svn/',
|
152 |
-
'.DS_Store',
|
153 |
-
'.idea/',
|
154 |
-
'backwpup-*',
|
155 |
-
'updraft',
|
156 |
-
'wp-snapshots',
|
157 |
-
'backupbuddy_backups',
|
158 |
-
'pb_backupbuddy',
|
159 |
-
'backup-db',
|
160 |
-
'Envato-backups',
|
161 |
-
'managewp',
|
162 |
-
'backupwordpress-*-backups',
|
163 |
-
);
|
164 |
-
|
165 |
-
/**
|
166 |
-
* Returns a filterable array of excluded directories and files.
|
167 |
-
*
|
168 |
-
* @return mixed|void
|
169 |
-
*/
|
170 |
-
public function default_excludes() {
|
171 |
-
return apply_filters( 'hmbkp_default_excludes', $this->default_excludes );
|
172 |
-
}
|
173 |
-
|
174 |
-
/**
|
175 |
-
* Check whether safe mode is active or not
|
176 |
-
*
|
177 |
-
* @param string $ini_get_callback
|
178 |
-
*
|
179 |
-
* @return bool
|
180 |
-
*/
|
181 |
-
public static function is_safe_mode_active( $ini_get_callback = 'ini_get' ) {
|
182 |
-
|
183 |
-
$safe_mode = @call_user_func( $ini_get_callback, 'safe_mode' );
|
184 |
-
|
185 |
-
if ( $safe_mode && strtolower( $safe_mode ) != 'off' ) {
|
186 |
-
return true;
|
187 |
-
}
|
188 |
-
|
189 |
-
return false;
|
190 |
-
|
191 |
-
}
|
192 |
-
|
193 |
-
/**
|
194 |
-
* Check whether shell_exec has been disabled.
|
195 |
-
*
|
196 |
-
* @return bool
|
197 |
-
*/
|
198 |
-
public static function is_shell_exec_available() {
|
199 |
-
|
200 |
-
// Are we in Safe Mode
|
201 |
-
if ( self::is_safe_mode_active() ) {
|
202 |
-
return false;
|
203 |
-
}
|
204 |
-
|
205 |
-
// Is shell_exec or escapeshellcmd or escapeshellarg disabled?
|
206 |
-
if ( self::is_function_disabled( 'suhosin.executor.func.blacklist' ) ) {
|
207 |
-
return false;
|
208 |
-
}
|
209 |
-
|
210 |
-
// Functions can also be disabled via suhosin
|
211 |
-
if ( self::is_function_disabled( 'disable_functions' ) ) {
|
212 |
-
return false;
|
213 |
-
}
|
214 |
-
|
215 |
-
// Can we issue a simple echo command?
|
216 |
-
if ( ! @shell_exec( 'echo backupwordpress' ) ) {
|
217 |
-
return false;
|
218 |
-
}
|
219 |
-
|
220 |
-
return true;
|
221 |
-
|
222 |
-
}
|
223 |
-
|
224 |
-
protected static function is_function_disabled( $ini_setting ) {
|
225 |
-
|
226 |
-
if ( array_intersect( array(
|
227 |
-
'shell_exec',
|
228 |
-
'escapeshellarg',
|
229 |
-
'escapeshellcmd'
|
230 |
-
), array_map( 'trim', explode( ',', @ini_get( $ini_setting ) ) ) ) ) {
|
231 |
-
return false;
|
232 |
-
}
|
233 |
-
|
234 |
-
}
|
235 |
-
|
236 |
-
|
237 |
-
/**
|
238 |
-
* Attempt to work out the root directory of the site, that
|
239 |
-
* is, the path equivelant of home_url().
|
240 |
-
*
|
241 |
-
* @return string $home_path
|
242 |
-
*/
|
243 |
-
public static function get_home_path() {
|
244 |
-
|
245 |
-
if ( defined( 'HMBKP_ROOT' ) && HMBKP_ROOT ) {
|
246 |
-
return wp_normalize_path( HMBKP_ROOT );
|
247 |
-
}
|
248 |
-
|
249 |
-
$home_url = home_url();
|
250 |
-
$site_url = site_url();
|
251 |
-
|
252 |
-
$home_path = ABSPATH;
|
253 |
-
|
254 |
-
// If site_url contains home_url and they differ then assume WordPress is installed in a sub directory
|
255 |
-
if ( $home_url !== $site_url && strpos( $site_url, $home_url ) === 0 ) {
|
256 |
-
$home_path = trailingslashit( substr( wp_normalize_path( ABSPATH ), 0, strrpos( wp_normalize_path( ABSPATH ), str_replace( $home_url, '', $site_url ) ) ) );
|
257 |
-
}
|
258 |
-
|
259 |
-
return wp_normalize_path( $home_path );
|
260 |
-
|
261 |
-
}
|
262 |
-
|
263 |
-
/**
|
264 |
-
* Sets up the default properties
|
265 |
-
*/
|
266 |
-
public function __construct() {
|
267 |
-
|
268 |
-
// Raise the memory limit and max_execution time
|
269 |
-
@ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
|
270 |
-
@set_time_limit( 0 );
|
271 |
-
|
272 |
-
// Set a custom error handler so we can track errors
|
273 |
-
set_error_handler( array( $this, 'error_handler' ) );
|
274 |
-
|
275 |
-
// Some properties can be overridden with defines
|
276 |
-
if ( defined( 'HMBKP_EXCLUDE' ) && HMBKP_EXCLUDE ) {
|
277 |
-
$this->set_excludes( HMBKP_EXCLUDE, true );
|
278 |
-
}
|
279 |
-
|
280 |
-
if ( defined( 'HMBKP_MYSQLDUMP_PATH' ) ) {
|
281 |
-
$this->set_mysqldump_command_path( HMBKP_MYSQLDUMP_PATH );
|
282 |
-
}
|
283 |
-
|
284 |
-
if ( defined( 'HMBKP_ZIP_PATH' ) ) {
|
285 |
-
$this->set_zip_command_path( HMBKP_ZIP_PATH );
|
286 |
-
}
|
287 |
-
|
288 |
-
}
|
289 |
-
|
290 |
-
/**
|
291 |
-
* Simple class wrapper for Path::get_path()
|
292 |
-
*
|
293 |
-
* @return string
|
294 |
-
*/
|
295 |
-
private function get_path() {
|
296 |
-
return Path::get_instance()->get_path();
|
297 |
-
}
|
298 |
-
|
299 |
-
/**
|
300 |
-
* Get the full filepath to the archive file
|
301 |
-
*
|
302 |
-
* @return string
|
303 |
-
*/
|
304 |
-
public function get_archive_filepath() {
|
305 |
-
return trailingslashit( $this->get_path() ) . $this->get_archive_filename();
|
306 |
-
}
|
307 |
-
|
308 |
-
/**
|
309 |
-
* Get the filename of the archive file
|
310 |
-
*
|
311 |
-
* @return string
|
312 |
-
*/
|
313 |
-
public function get_archive_filename() {
|
314 |
-
|
315 |
-
if ( empty( $this->archive_filename ) ) {
|
316 |
-
$this->set_archive_filename( implode( '-', array(
|
317 |
-
sanitize_title( str_ireplace( array(
|
318 |
-
'http://',
|
319 |
-
'https://',
|
320 |
-
'www'
|
321 |
-
), '', home_url() ) ),
|
322 |
-
'backup',
|
323 |
-
current_time( 'Y-m-d-H-i-s' )
|
324 |
-
) ) . '.zip' );
|
325 |
-
}
|
326 |
-
|
327 |
-
return $this->archive_filename;
|
328 |
-
|
329 |
-
}
|
330 |
-
|
331 |
-
/**
|
332 |
-
* Set the filename of the archive file
|
333 |
-
*
|
334 |
-
* @param string $filename
|
335 |
-
*
|
336 |
-
* @return \WP_Error|null
|
337 |
-
*/
|
338 |
-
public function set_archive_filename( $filename ) {
|
339 |
-
|
340 |
-
if ( empty( $filename ) || ! is_string( $filename ) ) {
|
341 |
-
return new \WP_Error( 'invalid_file_name', __( 'archive filename must be a non-empty string', 'backupwordpress' ) );
|
342 |
-
}
|
343 |
-
|
344 |
-
if ( pathinfo( $filename, PATHINFO_EXTENSION ) !== 'zip' ) {
|
345 |
-
return new \WP_Error( 'invalid_file_extension', sprintf( __( 'invalid file extension for archive filename <code>%s</code>', 'backupwordpress' ), $filename ) );
|
346 |
-
}
|
347 |
-
|
348 |
-
$this->archive_filename = strtolower( sanitize_file_name( remove_accents( $filename ) ) );
|
349 |
-
|
350 |
-
}
|
351 |
-
|
352 |
-
/**
|
353 |
-
* Get the full filepath to the database dump file.
|
354 |
-
*
|
355 |
-
* @return string
|
356 |
-
*/
|
357 |
-
public function get_database_dump_filepath() {
|
358 |
-
return trailingslashit( $this->get_path() ) . $this->get_database_dump_filename();
|
359 |
-
}
|
360 |
-
|
361 |
-
/**
|
362 |
-
* Get the filename of the database dump file
|
363 |
-
*
|
364 |
-
* @return string
|
365 |
-
*/
|
366 |
-
public function get_database_dump_filename() {
|
367 |
-
|
368 |
-
if ( empty( $this->database_dump_filename ) ) {
|
369 |
-
$this->set_database_dump_filename( 'database_' . DB_NAME . '.sql' );
|
370 |
-
}
|
371 |
-
|
372 |
-
return $this->database_dump_filename;
|
373 |
-
|
374 |
-
}
|
375 |
-
|
376 |
-
/**
|
377 |
-
* Set the filename of the database dump file
|
378 |
-
*
|
379 |
-
* @param string $filename
|
380 |
-
*
|
381 |
-
* @return \WP_Error|null
|
382 |
-
*/
|
383 |
-
public function set_database_dump_filename( $filename ) {
|
384 |
-
|
385 |
-
if ( empty( $filename ) || ! is_string( $filename ) ) {
|
386 |
-
return new \WP_Error( 'invalid_file_name', __( 'database dump filename must be a non-empty string', 'backupwordpress' ) );
|
387 |
-
}
|
388 |
-
|
389 |
-
if ( pathinfo( $filename, PATHINFO_EXTENSION ) !== 'sql' ) {
|
390 |
-
return new \WP_Error( 'invalid_file_extension', sprintf( __( 'invalid file extension for database dump filename <code>%s</code>', 'backupwordpress' ), $filename ) );
|
391 |
-
}
|
392 |
-
|
393 |
-
$this->database_dump_filename = strtolower( sanitize_file_name( remove_accents( $filename ) ) );
|
394 |
-
|
395 |
-
}
|
396 |
-
|
397 |
-
/**
|
398 |
-
* Get the root directory to backup from
|
399 |
-
*
|
400 |
-
* Defaults to the root of the path equivalent of your home_url
|
401 |
-
*
|
402 |
-
* @return string
|
403 |
-
*/
|
404 |
-
public function get_root() {
|
405 |
-
|
406 |
-
if ( empty( $this->root ) ) {
|
407 |
-
$this->set_root( wp_normalize_path( self::get_home_path() ) );
|
408 |
-
}
|
409 |
-
|
410 |
-
return $this->root;
|
411 |
-
|
412 |
-
}
|
413 |
-
|
414 |
-
/**
|
415 |
-
* Set the root directory to backup from
|
416 |
-
*
|
417 |
-
* @param string $path
|
418 |
-
*
|
419 |
-
* @return \WP_Error|null
|
420 |
-
*/
|
421 |
-
public function set_root( $path ) {
|
422 |
-
|
423 |
-
if ( empty( $path ) || ! is_string( $path ) || ! is_dir( $path ) ) {
|
424 |
-
return new \WP_Error( 'invalid_directory_path', sprintf( __( 'Invalid root path <code>%s</code> must be a valid directory path', 'backupwordpress' ), $path ) );
|
425 |
-
}
|
426 |
-
|
427 |
-
$this->root = wp_normalize_path( $path );
|
428 |
-
|
429 |
-
}
|
430 |
-
|
431 |
-
/**
|
432 |
-
* Get the filepath for the existing archive
|
433 |
-
*
|
434 |
-
* @return string
|
435 |
-
*/
|
436 |
-
public function get_existing_archive_filepath() {
|
437 |
-
return $this->existing_archive_filepath;
|
438 |
-
}
|
439 |
-
|
440 |
-
/**
|
441 |
-
* Set the filepath for the existing archive
|
442 |
-
*
|
443 |
-
* @param string $existing_archive_filepath
|
444 |
-
*
|
445 |
-
* @return null
|
446 |
-
*/
|
447 |
-
public function set_existing_archive_filepath( $existing_archive_filepath ) {
|
448 |
-
|
449 |
-
if ( empty( $existing_archive_filepath ) || ! is_string( $existing_archive_filepath ) ) {
|
450 |
-
return new \WP_Error( 'invalid_existing_archive_filepath', sprintf( __( 'Invalid existing archive filepath <code>%s</code> must be a non-empty (string)', 'backupwordpress' ), $existing_archive_filepath ) );
|
451 |
-
}
|
452 |
-
|
453 |
-
$this->existing_archive_filepath = wp_normalize_path( $existing_archive_filepath );
|
454 |
-
|
455 |
-
}
|
456 |
-
|
457 |
-
/**
|
458 |
-
* Get the archive method that was used for the backup
|
459 |
-
*
|
460 |
-
* Will be either zip, ZipArchive or PclZip
|
461 |
-
*
|
462 |
-
*/
|
463 |
-
public function get_archive_method() {
|
464 |
-
return $this->archive_method;
|
465 |
-
}
|
466 |
-
|
467 |
-
/**
|
468 |
-
* Get the database dump method that was used for the backup
|
469 |
-
*
|
470 |
-
* Will be either mysqldump or mysqldump_fallback
|
471 |
-
*
|
472 |
-
*/
|
473 |
-
public function get_mysqldump_method() {
|
474 |
-
return $this->mysqldump_method;
|
475 |
-
}
|
476 |
-
|
477 |
-
/**
|
478 |
-
* Get the backup type
|
479 |
-
*
|
480 |
-
* Defaults to complete
|
481 |
-
*
|
482 |
-
*/
|
483 |
-
public function get_type() {
|
484 |
-
|
485 |
-
if ( empty( $this->type ) ) {
|
486 |
-
$this->set_type( 'complete' );
|
487 |
-
}
|
488 |
-
|
489 |
-
return $this->type;
|
490 |
-
|
491 |
-
}
|
492 |
-
|
493 |
-
/**
|
494 |
-
* Set the backup type
|
495 |
-
*
|
496 |
-
* $type must be one of complete, database or file
|
497 |
-
*
|
498 |
-
* @param string $type
|
499 |
-
*
|
500 |
-
* @return \WP_Error|null
|
501 |
-
*/
|
502 |
-
public function set_type( $type ) {
|
503 |
-
|
504 |
-
if ( ! is_string( $type ) || ! in_array( $type, array( 'file', 'database', 'complete' ) ) ) {
|
505 |
-
return new \WP_Error( 'invalid_backup_type', sprintf( __( 'Invalid backup type <code>%s</code> must be one of (string) file, database or complete', 'backupwordpress' ), $type ) );
|
506 |
-
}
|
507 |
-
|
508 |
-
$this->type = $type;
|
509 |
-
|
510 |
-
}
|
511 |
-
|
512 |
-
/**
|
513 |
-
* Get the path to the mysqldump bin
|
514 |
-
*
|
515 |
-
* If not explicitly set will attempt to work
|
516 |
-
* it out by checking common locations
|
517 |
-
*
|
518 |
-
* @return string
|
519 |
-
*/
|
520 |
-
public function get_mysqldump_command_path() {
|
521 |
-
|
522 |
-
// Check shell_exec is available
|
523 |
-
if ( ! self::is_shell_exec_available() ) {
|
524 |
-
return '';
|
525 |
-
}
|
526 |
-
|
527 |
-
// Return now if it's already been set
|
528 |
-
if ( isset( $this->mysqldump_command_path ) ) {
|
529 |
-
return $this->mysqldump_command_path;
|
530 |
-
}
|
531 |
-
|
532 |
-
$this->mysqldump_command_path = '';
|
533 |
-
|
534 |
-
// Does mysqldump work
|
535 |
-
if ( is_null( shell_exec( 'hash mysqldump 2>&1' ) ) ) {
|
536 |
-
|
537 |
-
// If so store it for later
|
538 |
-
$this->set_mysqldump_command_path( 'mysqldump' );
|
539 |
-
|
540 |
-
// And return now
|
541 |
-
return $this->mysqldump_command_path;
|
542 |
-
|
543 |
-
}
|
544 |
-
|
545 |
-
// List of possible mysqldump locations
|
546 |
-
$mysqldump_locations = array(
|
547 |
-
'/usr/local/bin/mysqldump',
|
548 |
-
'/usr/local/mysql/bin/mysqldump',
|
549 |
-
'/usr/mysql/bin/mysqldump',
|
550 |
-
'/usr/bin/mysqldump',
|
551 |
-
'/opt/local/lib/mysql6/bin/mysqldump',
|
552 |
-
'/opt/local/lib/mysql5/bin/mysqldump',
|
553 |
-
'/opt/local/lib/mysql4/bin/mysqldump',
|
554 |
-
'/xampp/mysql/bin/mysqldump',
|
555 |
-
'/Program Files/xampp/mysql/bin/mysqldump',
|
556 |
-
'/Program Files/MySQL/MySQL Server 6.0/bin/mysqldump',
|
557 |
-
'/Program Files/MySQL/MySQL Server 5.7/bin/mysqldump',
|
558 |
-
'/Program Files/MySQL/MySQL Server 5.6/bin/mysqldump',
|
559 |
-
'/Program Files/MySQL/MySQL Server 5.5/bin/mysqldump',
|
560 |
-
'/Program Files/MySQL/MySQL Server 5.4/bin/mysqldump',
|
561 |
-
'/Program Files/MySQL/MySQL Server 5.1/bin/mysqldump',
|
562 |
-
'/Program Files/MySQL/MySQL Server 5.0/bin/mysqldump',
|
563 |
-
'/Program Files/MySQL/MySQL Server 4.1/bin/mysqldump',
|
564 |
-
'/opt/local/bin/mysqldump'
|
565 |
-
);
|
566 |
-
|
567 |
-
// Find the first one which works
|
568 |
-
foreach ( $mysqldump_locations as $location ) {
|
569 |
-
if ( (is_null( shell_exec( 'hash ' . wp_normalize_path( $location ) . ' 2>&1' ) ) ) && @is_executable( wp_normalize_path( $location ) ) ) {
|
570 |
-
$this->set_mysqldump_command_path( $location );
|
571 |
-
break; // Found one
|
572 |
-
}
|
573 |
-
}
|
574 |
-
|
575 |
-
return $this->mysqldump_command_path;
|
576 |
-
|
577 |
-
}
|
578 |
-
|
579 |
-
/**
|
580 |
-
* Set the path to the mysqldump bin
|
581 |
-
*
|
582 |
-
* Setting the path to false will cause the database
|
583 |
-
* dump to use the php fallback
|
584 |
-
*
|
585 |
-
* @param mixed $path
|
586 |
-
*/
|
587 |
-
public function set_mysqldump_command_path( $path ) {
|
588 |
-
$this->mysqldump_command_path = $path;
|
589 |
-
}
|
590 |
-
|
591 |
-
/**
|
592 |
-
* Get the path to the zip bin
|
593 |
-
*
|
594 |
-
* If not explicitly set will attempt to work
|
595 |
-
* it out by checking common locations
|
596 |
-
*
|
597 |
-
* @return string
|
598 |
-
*/
|
599 |
-
public function get_zip_command_path() {
|
600 |
-
|
601 |
-
// Check shell_exec is available
|
602 |
-
if ( ! self::is_shell_exec_available() ) {
|
603 |
-
return '';
|
604 |
-
}
|
605 |
-
|
606 |
-
// Return now if it's already been set
|
607 |
-
if ( isset( $this->zip_command_path ) ) {
|
608 |
-
return $this->zip_command_path;
|
609 |
-
}
|
610 |
-
|
611 |
-
$this->zip_command_path = '';
|
612 |
-
|
613 |
-
// Does zip work
|
614 |
-
if ( is_null( shell_exec( 'hash zip 2>&1' ) ) ) {
|
615 |
-
|
616 |
-
// If so store it for later
|
617 |
-
$this->set_zip_command_path( 'zip' );
|
618 |
-
|
619 |
-
// And return now
|
620 |
-
return $this->zip_command_path;
|
621 |
-
|
622 |
-
}
|
623 |
-
|
624 |
-
// List of possible zip locations
|
625 |
-
$zip_locations = array(
|
626 |
-
'/usr/bin/zip',
|
627 |
-
'/opt/local/bin/zip'
|
628 |
-
);
|
629 |
-
|
630 |
-
// Find the first one which works
|
631 |
-
foreach ( $zip_locations as $location ) {
|
632 |
-
if ( @is_executable( wp_normalize_path( $location ) ) ) {
|
633 |
-
$this->set_zip_command_path( $location );
|
634 |
-
break; // Found one
|
635 |
-
}
|
636 |
-
}
|
637 |
-
|
638 |
-
return $this->zip_command_path;
|
639 |
-
|
640 |
-
}
|
641 |
-
|
642 |
-
/**
|
643 |
-
* Set the path to the zip bin
|
644 |
-
*
|
645 |
-
* Setting the path to false will cause the database
|
646 |
-
* dump to use the php fallback
|
647 |
-
*
|
648 |
-
* @param mixed $path
|
649 |
-
*/
|
650 |
-
public function set_zip_command_path( $path ) {
|
651 |
-
$this->zip_command_path = $path;
|
652 |
-
}
|
653 |
-
|
654 |
-
/**
|
655 |
-
* Fire actions for the various backup stages
|
656 |
-
*
|
657 |
-
* Callers can register callbacks to be called using `set_action_callback`
|
658 |
-
* Both the action and the instance on Backup are then passed to the callback function
|
659 |
-
*
|
660 |
-
* @see set_action_callback
|
661 |
-
*
|
662 |
-
* @param string $action The event to fire
|
663 |
-
*/
|
664 |
-
protected function do_action( $action ) {
|
665 |
-
|
666 |
-
// If we have any callbacks then let's fire them
|
667 |
-
if ( ! empty( $this->action_callback ) ) {
|
668 |
-
|
669 |
-
// Order them by priority, lowest priority first
|
670 |
-
ksort( $this->action_callback );
|
671 |
-
|
672 |
-
foreach ( $this->action_callback as $priority ) {
|
673 |
-
foreach ( $priority as $callback ) {
|
674 |
-
call_user_func( $callback, $action, $this );
|
675 |
-
}
|
676 |
-
}
|
677 |
-
|
678 |
-
}
|
679 |
-
|
680 |
-
// Also fire a global WordPress action
|
681 |
-
do_action( $action, $this );
|
682 |
-
|
683 |
-
}
|
684 |
-
|
685 |
-
/**
|
686 |
-
* Allow the caller to set a callback function that will be invoked whenever
|
687 |
-
* an action fires
|
688 |
-
*
|
689 |
-
* @see do_action
|
690 |
-
* @see /do_action
|
691 |
-
*
|
692 |
-
* @param callable $callback The function or method to be called
|
693 |
-
* @param int $priority The priority of the callback
|
694 |
-
*/
|
695 |
-
public function set_action_callback( $callback, $priority = 10 ) {
|
696 |
-
$this->action_callback[ $priority ][] = $callback;
|
697 |
-
}
|
698 |
-
|
699 |
-
/**
|
700 |
-
* Kick off a backup
|
701 |
-
*
|
702 |
-
* @todo should be renamed so it's not same as class
|
703 |
-
* @return null
|
704 |
-
*/
|
705 |
-
public function backup() {
|
706 |
-
|
707 |
-
$this->do_action( 'hmbkp_backup_started' );
|
708 |
-
|
709 |
-
// Backup database
|
710 |
-
if ( $this->get_type() !== 'file' ) {
|
711 |
-
$this->dump_database();
|
712 |
-
}
|
713 |
-
|
714 |
-
// Zip everything up
|
715 |
-
$this->archive();
|
716 |
-
|
717 |
-
$this->do_action( 'hmbkp_backup_complete' );
|
718 |
-
|
719 |
-
}
|
720 |
-
|
721 |
-
/**
|
722 |
-
* Create the mysql backup
|
723 |
-
*
|
724 |
-
* Uses mysqldump if available, falls back to PHP
|
725 |
-
* if not.
|
726 |
-
*
|
727 |
-
*/
|
728 |
-
public function dump_database() {
|
729 |
-
|
730 |
-
// Attempt to use native mysqldump
|
731 |
-
if ( self::is_shell_exec_available() && $this->get_mysqldump_command_path() && ! is_wp_error( $this->user_can_connect() ) ) {
|
732 |
-
$this->mysqldump();
|
733 |
-
}
|
734 |
-
|
735 |
-
// If we cannot run mysqldump via CLI, fallback to PHP
|
736 |
-
if ( empty( $this->mysqldump_verified ) ) {
|
737 |
-
$this->mysqldump_fallback();
|
738 |
-
}
|
739 |
-
|
740 |
-
$this->do_action( 'hmbkp_mysqldump_finished' );
|
741 |
-
|
742 |
-
}
|
743 |
-
|
744 |
-
/**
|
745 |
-
* Export the database to an .sql file via the command line with mysqldump
|
746 |
-
*/
|
747 |
-
public function mysqldump() {
|
748 |
-
|
749 |
-
$this->mysqldump_method = 'mysqldump';
|
750 |
-
|
751 |
-
$this->do_action( 'hmbkp_mysqldump_started' );
|
752 |
-
|
753 |
-
// Guess port or socket connection type
|
754 |
-
$port_or_socket = strstr( DB_HOST, ':' );
|
755 |
-
|
756 |
-
$host = DB_HOST;
|
757 |
-
|
758 |
-
if ( ! empty( $port_or_socket ) ) {
|
759 |
-
|
760 |
-
$host = substr( DB_HOST, 0, strpos( DB_HOST, ':' ) );
|
761 |
-
|
762 |
-
$port_or_socket = substr( $port_or_socket, 1 );
|
763 |
-
|
764 |
-
if ( 0 !== strpos( $port_or_socket, '/' ) ) {
|
765 |
-
|
766 |
-
$port = intval( $port_or_socket );
|
767 |
-
|
768 |
-
$maybe_socket = strstr( $port_or_socket, ':' );
|
769 |
-
|
770 |
-
if ( ! empty( $maybe_socket ) ) {
|
771 |
-
|
772 |
-
$socket = substr( $maybe_socket, 1 );
|
773 |
-
|
774 |
-
}
|
775 |
-
|
776 |
-
} else {
|
777 |
-
|
778 |
-
$socket = $port_or_socket;
|
779 |
-
|
780 |
-
}
|
781 |
-
}
|
782 |
-
|
783 |
-
// Path to the mysqldump executable
|
784 |
-
$cmd = escapeshellarg( $this->get_mysqldump_command_path() );
|
785 |
-
|
786 |
-
// We don't want to create a new DB
|
787 |
-
$cmd .= ' --no-create-db';
|
788 |
-
|
789 |
-
// Allow lock-tables to be overridden
|
790 |
-
if ( ! defined( 'HMBKP_MYSQLDUMP_SINGLE_TRANSACTION' ) || false !== HMBKP_MYSQLDUMP_SINGLE_TRANSACTION ) {
|
791 |
-
$cmd .= ' --single-transaction';
|
792 |
-
}
|
793 |
-
|
794 |
-
// Make sure binary data is exported properly
|
795 |
-
$cmd .= ' --hex-blob';
|
796 |
-
|
797 |
-
// Username
|
798 |
-
$cmd .= ' -u ' . escapeshellarg( DB_USER );
|
799 |
-
|
800 |
-
// Don't pass the password if it's blank
|
801 |
-
if ( DB_PASSWORD ) {
|
802 |
-
$cmd .= ' -p' . escapeshellarg( DB_PASSWORD );
|
803 |
-
}
|
804 |
-
|
805 |
-
// Set the host
|
806 |
-
$cmd .= ' -h ' . escapeshellarg( $host );
|
807 |
-
|
808 |
-
// Set the port if it was set
|
809 |
-
if ( ! empty( $port ) && is_numeric( $port ) ) {
|
810 |
-
$cmd .= ' -P ' . $port;
|
811 |
-
}
|
812 |
-
|
813 |
-
// Set the socket path
|
814 |
-
if ( ! empty( $socket ) && ! is_numeric( $socket ) ) {
|
815 |
-
$cmd .= ' --protocol=socket -S ' . $socket;
|
816 |
-
}
|
817 |
-
|
818 |
-
// The file we're saving too
|
819 |
-
$cmd .= ' -r ' . escapeshellarg( $this->get_database_dump_filepath() );
|
820 |
-
|
821 |
-
// The database we're dumping
|
822 |
-
$cmd .= ' ' . escapeshellarg( DB_NAME );
|
823 |
-
|
824 |
-
// Pipe STDERR to STDOUT
|
825 |
-
$cmd .= ' 2>&1';
|
826 |
-
|
827 |
-
// Store any returned data in an error
|
828 |
-
$stderr = shell_exec( $cmd );
|
829 |
-
|
830 |
-
// Skip the new password warning that is output in mysql > 5.6 (@see http://bugs.mysql.com/bug.php?id=66546)
|
831 |
-
if ( 'Warning: Using a password on the command line interface can be insecure.' === trim( $stderr ) ) {
|
832 |
-
$stderr = '';
|
833 |
-
}
|
834 |
-
|
835 |
-
if ( $stderr ) {
|
836 |
-
$this->error( $this->get_mysqldump_method(), $stderr );
|
837 |
-
}
|
838 |
-
|
839 |
-
$this->verify_mysqldump();
|
840 |
-
|
841 |
-
}
|
842 |
-
|
843 |
-
/**
|
844 |
-
* PHP mysqldump fallback functions, exports the database to a .sql file
|
845 |
-
*
|
846 |
-
*/
|
847 |
-
public function mysqldump_fallback() {
|
848 |
-
|
849 |
-
$this->errors_to_warnings( $this->get_mysqldump_method() );
|
850 |
-
|
851 |
-
$this->mysqldump_method = 'mysqldump_fallback';
|
852 |
-
|
853 |
-
$this->do_action( 'hmbkp_mysqldump_started' );
|
854 |
-
|
855 |
-
// Guess port or socket connection type
|
856 |
-
$port_or_socket = strstr( DB_HOST, ':' );
|
857 |
-
|
858 |
-
$host = DB_HOST;
|
859 |
-
|
860 |
-
if ( ! empty( $port_or_socket ) ) {
|
861 |
-
|
862 |
-
$host = substr( DB_HOST, 0, strpos( DB_HOST, ':' ) );
|
863 |
-
|
864 |
-
$port_or_socket = substr( $port_or_socket, 1 );
|
865 |
-
|
866 |
-
if ( 0 !== strpos( $port_or_socket, '/' ) ) {
|
867 |
-
|
868 |
-
$port = intval( $port_or_socket );
|
869 |
-
|
870 |
-
$maybe_socket = strstr( $port_or_socket, ':' );
|
871 |
-
|
872 |
-
if ( ! empty( $maybe_socket ) ) {
|
873 |
-
|
874 |
-
$socket = substr( $maybe_socket, 1 );
|
875 |
-
|
876 |
-
}
|
877 |
-
|
878 |
-
} else {
|
879 |
-
|
880 |
-
$socket = $port_or_socket;
|
881 |
-
|
882 |
-
}
|
883 |
-
}
|
884 |
-
|
885 |
-
// PDO connection string formats:
|
886 |
-
// mysql:host=localhost;port=3307;dbname=testdb
|
887 |
-
// mysql:unix_socket=/tmp/mysql.sock;dbname=testdb
|
888 |
-
|
889 |
-
if ( $port_or_socket ) {
|
890 |
-
if ( isset( $port ) ) {
|
891 |
-
$dsn = 'mysql:host=' . DB_HOST . ';port=' . $port . ';dbname=' . DB_NAME;
|
892 |
-
} elseif ( isset( $socket ) ) {
|
893 |
-
$dsn = 'mysql:unix_socket=' . $socket . ';dbname=' . DB_NAME;
|
894 |
-
}
|
895 |
-
} else {
|
896 |
-
$dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME;
|
897 |
-
}
|
898 |
-
|
899 |
-
// Get character set from constant if it is declared.
|
900 |
-
if ( defined( 'DB_CHARSET' ) && DB_CHARSET ) {
|
901 |
-
$charset = DB_CHARSET;
|
902 |
-
} else {
|
903 |
-
$charset = 'utf8';
|
904 |
-
}
|
905 |
-
|
906 |
-
if ( defined( 'DB_PASSWORD' ) && DB_PASSWORD ) {
|
907 |
-
$pwd = DB_PASSWORD;
|
908 |
-
} else {
|
909 |
-
$pwd = '';
|
910 |
-
}
|
911 |
-
|
912 |
-
if ( ! defined( 'HMBKP_MYSQLDUMP_SINGLE_TRANSACTION' ) || false !== HMBKP_MYSQLDUMP_SINGLE_TRANSACTION ) {
|
913 |
-
$single_transaction = true;
|
914 |
-
} else {
|
915 |
-
$single_transaction = false;
|
916 |
-
}
|
917 |
-
|
918 |
-
$dump_settings = array(
|
919 |
-
'default-character-set' => $charset,
|
920 |
-
'hex-blob' => true,
|
921 |
-
'single-transaction' => $single_transaction,
|
922 |
-
);
|
923 |
-
|
924 |
-
try {
|
925 |
-
|
926 |
-
// Allow passing custom options to dump process.
|
927 |
-
$dump_settings = apply_filters( 'hmbkp_mysqldump_fallback_dump_settings', $dump_settings );
|
928 |
-
|
929 |
-
$dump = new IMysqldump\Mysqldump( $dsn, DB_USER, $pwd, $dump_settings );
|
930 |
-
|
931 |
-
$dump->start( $this->get_database_dump_filepath() );
|
932 |
-
|
933 |
-
} catch ( \Exception $e ) {
|
934 |
-
|
935 |
-
return new \WP_Error( 'mysql-fallback-error', sprintf( __( 'mysqldump fallback error %s', 'backupwordpress' ), $e->getMessage() ) );
|
936 |
-
|
937 |
-
}
|
938 |
-
|
939 |
-
}
|
940 |
-
|
941 |
-
/**
|
942 |
-
* Zip up all the files.
|
943 |
-
*
|
944 |
-
* Attempts to use the shell zip command, if
|
945 |
-
* thats not available then it falls back to
|
946 |
-
* PHP ZipArchive.
|
947 |
-
*
|
948 |
-
*/
|
949 |
-
public function archive() {
|
950 |
-
|
951 |
-
if ( defined( 'HMBKP_FORCE_ZIP_METHOD' ) ) {
|
952 |
-
switch ( HMBKP_FORCE_ZIP_METHOD ) {
|
953 |
-
case 'zip':
|
954 |
-
if ( $this->get_zip_command_path() ) {
|
955 |
-
$this->zip();
|
956 |
-
} else {
|
957 |
-
$this->warning( $this->get_archive_method(), __( 'Zip command is not available.', 'backupwordpress' ) );
|
958 |
-
}
|
959 |
-
break;
|
960 |
-
case 'ziparchive':
|
961 |
-
if ( class_exists( 'ZipArchive' ) ) {
|
962 |
-
$this->zip_archive();
|
963 |
-
} else {
|
964 |
-
$this->warning( $this->get_archive_method(), __( 'ZipArchive method is not available.', 'backupwordpress' ) );
|
965 |
-
}
|
966 |
-
break;
|
967 |
-
default:
|
968 |
-
$this->warning( $this->get_archive_method(), __( 'No valid archive method found.', 'backupwordpress' ) );
|
969 |
-
break;
|
970 |
-
}
|
971 |
-
} else {
|
972 |
-
// Is zip available
|
973 |
-
if ( $this->get_zip_command_path() ) {
|
974 |
-
$this->zip();
|
975 |
-
} else {
|
976 |
-
// If the shell zip failed then use ZipArchive
|
977 |
-
if ( empty( $this->archive_verified ) && class_exists( 'ZipArchive' ) ) {
|
978 |
-
$this->zip_archive();
|
979 |
-
} else {
|
980 |
-
$this->warning( $this->get_archive_method(), __( 'No valid archive method found.', 'backupwordpress' ) );
|
981 |
-
}
|
982 |
-
}
|
983 |
-
|
984 |
-
}
|
985 |
-
|
986 |
-
// Delete the database dump file
|
987 |
-
if ( file_exists( $this->get_database_dump_filepath() ) ) {
|
988 |
-
unlink( $this->get_database_dump_filepath() );
|
989 |
-
}
|
990 |
-
|
991 |
-
$this->do_action( 'hmbkp_archive_finished' );
|
992 |
-
|
993 |
-
}
|
994 |
-
|
995 |
-
/**
|
996 |
-
* Zip using the native zip command
|
997 |
-
*/
|
998 |
-
public function zip() {
|
999 |
-
|
1000 |
-
$this->archive_method = 'zip';
|
1001 |
-
|
1002 |
-
$this->do_action( 'hmbkp_archive_started' );
|
1003 |
-
|
1004 |
-
// Add the database dump to the archive
|
1005 |
-
if ( 'file' !== $this->get_type() && file_exists( $this->get_database_dump_filepath() ) ) {
|
1006 |
-
$stderr = shell_exec( 'cd ' . escapeshellarg( $this->get_path() ) . ' && ' . escapeshellcmd( $this->get_zip_command_path() ) . ' -q ' . escapeshellarg( $this->get_archive_filepath() ) . ' ' . escapeshellarg( $this->get_database_dump_filename() ) . ' 2>&1' );
|
1007 |
-
|
1008 |
-
if ( ! empty ( $stderr ) ) {
|
1009 |
-
$this->warning( $this->get_archive_method(), $stderr );
|
1010 |
-
}
|
1011 |
-
}
|
1012 |
-
|
1013 |
-
// Zip up $this->root
|
1014 |
-
if ( 'database' !== $this->get_type() ) {
|
1015 |
-
|
1016 |
-
// cd to the site root
|
1017 |
-
$command = 'cd ' . escapeshellarg( $this->get_root() );
|
1018 |
-
|
1019 |
-
// Run the zip command with the recursive and quiet flags
|
1020 |
-
$command .= ' && ' . escapeshellcmd( $this->get_zip_command_path() ) . ' -rq ';
|
1021 |
-
|
1022 |
-
if ( defined( 'HMBKP_ENABLE_SYNC' ) && HMBKP_ENABLE_SYNC ) {
|
1023 |
-
|
1024 |
-
// If the destination zip file already exists then let's just add changed files to save time
|
1025 |
-
if ( file_exists( $this->get_archive_filepath() ) && $this->get_existing_archive_filepath() ) {
|
1026 |
-
$command .= ' -FS ';
|
1027 |
-
}
|
1028 |
-
|
1029 |
-
}
|
1030 |
-
|
1031 |
-
// Save the zip file to the correct path
|
1032 |
-
$command .= escapeshellarg( $this->get_archive_filepath() ) . ' ./';
|
1033 |
-
|
1034 |
-
// Pass exclude rules in if we have them
|
1035 |
-
if ( $this->exclude_string( 'zip' ) ) {
|
1036 |
-
$command .= ' -x ' . $this->exclude_string( 'zip' );
|
1037 |
-
}
|
1038 |
-
|
1039 |
-
// Push all output to STDERR
|
1040 |
-
$command .= ' 2>&1';
|
1041 |
-
|
1042 |
-
$stderr = shell_exec( $command );
|
1043 |
-
|
1044 |
-
}
|
1045 |
-
|
1046 |
-
if ( ! empty( $stderr ) ) {
|
1047 |
-
$this->warning( $this->get_archive_method(), $stderr );
|
1048 |
-
}
|
1049 |
-
|
1050 |
-
$this->verify_archive();
|
1051 |
-
|
1052 |
-
}
|
1053 |
-
|
1054 |
-
/**
|
1055 |
-
* Fallback for creating zip archives if zip command is
|
1056 |
-
* unavailable.
|
1057 |
-
*/
|
1058 |
-
public function zip_archive() {
|
1059 |
-
|
1060 |
-
$this->errors_to_warnings( $this->get_archive_method() );
|
1061 |
-
$this->archive_method = 'ziparchive';
|
1062 |
-
|
1063 |
-
$this->do_action( 'hmbkp_archive_started' );
|
1064 |
-
|
1065 |
-
$zip = new \ZipArchive();
|
1066 |
-
|
1067 |
-
if ( ! class_exists( 'ZipArchive' ) || ! $zip->open( $this->get_archive_filepath(), \ZIPARCHIVE::CREATE ) ) {
|
1068 |
-
return;
|
1069 |
-
}
|
1070 |
-
|
1071 |
-
$excludes = $this->exclude_string( 'regex' );
|
1072 |
-
|
1073 |
-
// Add the database
|
1074 |
-
if ( $this->get_type() !== 'file' && file_exists( $this->get_database_dump_filepath() ) ) {
|
1075 |
-
$zip->addFile( $this->get_database_dump_filepath(), $this->get_database_dump_filename() );
|
1076 |
-
}
|
1077 |
-
|
1078 |
-
if ( $this->get_type() !== 'database' ) {
|
1079 |
-
|
1080 |
-
$files_added = 0;
|
1081 |
-
|
1082 |
-
foreach ( $this->get_files() as $file ) {
|
1083 |
-
|
1084 |
-
// Skip dot files, they should only exist on versions of PHP between 5.2.11 -> 5.3
|
1085 |
-
if ( method_exists( $file, 'isDot' ) && $file->isDot() ) {
|
1086 |
-
continue;
|
1087 |
-
}
|
1088 |
-
|
1089 |
-
// Skip unreadable files
|
1090 |
-
if ( ! @realpath( $file->getPathname() ) || ! $file->isReadable() ) {
|
1091 |
-
continue;
|
1092 |
-
}
|
1093 |
-
|
1094 |
-
// Excludes
|
1095 |
-
if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( trailingslashit( $this->get_root() ), '', wp_normalize_path( $file->getPathname() ) ) ) ) {
|
1096 |
-
continue;
|
1097 |
-
}
|
1098 |
-
|
1099 |
-
if ( $file->isDir() ) {
|
1100 |
-
$zip->addEmptyDir( trailingslashit( str_ireplace( trailingslashit( $this->get_root() ), '', wp_normalize_path( $file->getPathname() ) ) ) );
|
1101 |
-
} elseif ( $file->isFile() ) {
|
1102 |
-
$zip->addFile( $file->getPathname(), str_ireplace( trailingslashit( $this->get_root() ), '', wp_normalize_path( $file->getPathname() ) ) );
|
1103 |
-
}
|
1104 |
-
|
1105 |
-
if ( ++ $files_added % 500 === 0 ) {
|
1106 |
-
if ( ! $zip->close() || ! $zip->open( $this->get_archive_filepath(), \ZIPARCHIVE::CREATE ) ) {
|
1107 |
-
return;
|
1108 |
-
}
|
1109 |
-
}
|
1110 |
-
|
1111 |
-
}
|
1112 |
-
|
1113 |
-
}
|
1114 |
-
|
1115 |
-
if ( $zip->status ) {
|
1116 |
-
$this->warning( $this->get_archive_method(), $zip->status );
|
1117 |
-
}
|
1118 |
-
|
1119 |
-
if ( $zip->statusSys ) {
|
1120 |
-
$this->warning( $this->get_archive_method(), $zip->statusSys );
|
1121 |
-
}
|
1122 |
-
|
1123 |
-
$zip->close();
|
1124 |
-
|
1125 |
-
$this->verify_archive();
|
1126 |
-
|
1127 |
-
}
|
1128 |
-
|
1129 |
-
public function verify_mysqldump() {
|
1130 |
-
|
1131 |
-
$this->do_action( 'hmbkp_mysqldump_verify_started' );
|
1132 |
-
|
1133 |
-
// If we've already passed then no need to check again
|
1134 |
-
if ( ! empty( $this->mysqldump_verified ) ) {
|
1135 |
-
return true;
|
1136 |
-
}
|
1137 |
-
|
1138 |
-
// If there are mysqldump errors delete the database dump file as mysqldump will still have written one
|
1139 |
-
if ( $this->get_errors( $this->get_mysqldump_method() ) && file_exists( $this->get_database_dump_filepath() ) ) {
|
1140 |
-
unlink( $this->get_database_dump_filepath() );
|
1141 |
-
}
|
1142 |
-
|
1143 |
-
// If we have an empty file delete it
|
1144 |
-
if ( @filesize( $this->get_database_dump_filepath() ) === 0 ) {
|
1145 |
-
unlink( $this->get_database_dump_filepath() );
|
1146 |
-
}
|
1147 |
-
|
1148 |
-
// If the file still exists then it must be good
|
1149 |
-
if ( file_exists( $this->get_database_dump_filepath() ) ) {
|
1150 |
-
return $this->mysqldump_verified = true;
|
1151 |
-
}
|
1152 |
-
|
1153 |
-
return false;
|
1154 |
-
|
1155 |
-
}
|
1156 |
-
|
1157 |
-
/**
|
1158 |
-
* Verify that the archive is valid and contains all the files it should contain.
|
1159 |
-
*
|
1160 |
-
* @return bool
|
1161 |
-
*/
|
1162 |
-
public function verify_archive() {
|
1163 |
-
|
1164 |
-
$this->do_action( 'hmbkp_archive_verify_started' );
|
1165 |
-
|
1166 |
-
// If we've already passed then no need to check again
|
1167 |
-
if ( ! empty( $this->archive_verified ) ) {
|
1168 |
-
return true;
|
1169 |
-
}
|
1170 |
-
|
1171 |
-
// If there are errors delete the backup file.
|
1172 |
-
if ( $this->get_errors( $this->get_archive_method() ) && file_exists( $this->get_archive_filepath() ) ) {
|
1173 |
-
unlink( $this->get_archive_filepath() );
|
1174 |
-
}
|
1175 |
-
|
1176 |
-
// If the archive file still exists assume it's good
|
1177 |
-
if ( file_exists( $this->get_archive_filepath() ) ) {
|
1178 |
-
return $this->archive_verified = true;
|
1179 |
-
}
|
1180 |
-
|
1181 |
-
return false;
|
1182 |
-
|
1183 |
-
}
|
1184 |
-
|
1185 |
-
/**
|
1186 |
-
* Return an array of all files in the filesystem.
|
1187 |
-
*
|
1188 |
-
* @param bool $ignore_default_exclude_rules If true then will return all files under root. Otherwise returns all files except those matching default exclude rules.
|
1189 |
-
*
|
1190 |
-
* @return array
|
1191 |
-
*/
|
1192 |
-
public function get_files( $ignore_default_exclude_rules = false ) {
|
1193 |
-
|
1194 |
-
if ( ! empty( $this->files ) ) {
|
1195 |
-
return $this->files;
|
1196 |
-
}
|
1197 |
-
|
1198 |
-
$finder = new Finder();
|
1199 |
-
$finder->followLinks();
|
1200 |
-
$finder->ignoreDotFiles( false );
|
1201 |
-
$finder->ignoreUnreadableDirs();
|
1202 |
-
|
1203 |
-
if ( ! $ignore_default_exclude_rules ) {
|
1204 |
-
// Skips folders/files that match default exclude patterns
|
1205 |
-
foreach ( $this->default_excludes() as $exclude ) {
|
1206 |
-
$finder->notPath( $exclude );
|
1207 |
-
}
|
1208 |
-
}
|
1209 |
-
|
1210 |
-
foreach ( $finder->in( $this->get_root() ) as $entry ) {
|
1211 |
-
$this->files[] = $entry;
|
1212 |
-
}
|
1213 |
-
|
1214 |
-
return $this->files;
|
1215 |
-
|
1216 |
-
}
|
1217 |
-
|
1218 |
-
/**
|
1219 |
-
* Returns an array of files that will be included in the backup.
|
1220 |
-
*
|
1221 |
-
* @return array
|
1222 |
-
*/
|
1223 |
-
public function get_included_files() {
|
1224 |
-
|
1225 |
-
if ( ! empty( $this->included_files ) ) {
|
1226 |
-
return $this->included_files;
|
1227 |
-
}
|
1228 |
-
|
1229 |
-
$this->included_files = array();
|
1230 |
-
|
1231 |
-
$excludes = $this->exclude_string( 'regex' );
|
1232 |
-
|
1233 |
-
foreach ( $this->get_files( true ) as $file ) {
|
1234 |
-
|
1235 |
-
// Skip dot files, they should only exist on versions of PHP between 5.2.11 -> 5.3
|
1236 |
-
if ( method_exists( $file, 'isDot' ) && $file->isDot() ) {
|
1237 |
-
continue;
|
1238 |
-
}
|
1239 |
-
|
1240 |
-
// Skip unreadable files
|
1241 |
-
if ( ! @realpath( $file->getPathname() ) || ! $file->isReadable() ) {
|
1242 |
-
continue;
|
1243 |
-
}
|
1244 |
-
|
1245 |
-
// Excludes
|
1246 |
-
if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( trailingslashit( $this->get_root() ), '', wp_normalize_path( $file->getPathname() ) ) ) ) {
|
1247 |
-
continue;
|
1248 |
-
}
|
1249 |
-
|
1250 |
-
$this->included_files[] = $file;
|
1251 |
-
|
1252 |
-
}
|
1253 |
-
|
1254 |
-
return $this->included_files;
|
1255 |
-
|
1256 |
-
}
|
1257 |
-
|
1258 |
-
/**
|
1259 |
-
* Returns an array of files that match the exclude rules.
|
1260 |
-
*
|
1261 |
-
* @return array
|
1262 |
-
*/
|
1263 |
-
public function get_excluded_files() {
|
1264 |
-
|
1265 |
-
if ( ! empty( $this->excluded_files ) ) {
|
1266 |
-
return $this->excluded_files;
|
1267 |
-
}
|
1268 |
-
|
1269 |
-
$this->excluded_files = array();
|
1270 |
-
|
1271 |
-
$excludes = $this->exclude_string( 'regex' );
|
1272 |
-
|
1273 |
-
foreach ( $this->get_files( true ) as $file ) {
|
1274 |
-
|
1275 |
-
// Skip dot files, they should only exist on versions of PHP between 5.2.11 -> 5.3
|
1276 |
-
if ( method_exists( $file, 'isDot' ) && $file->isDot() ) {
|
1277 |
-
continue;
|
1278 |
-
}
|
1279 |
-
|
1280 |
-
// Skip unreadable files
|
1281 |
-
if ( ! @realpath( $file->getPathname() ) || ! $file->isReadable() ) {
|
1282 |
-
continue;
|
1283 |
-
}
|
1284 |
-
|
1285 |
-
// Excludes
|
1286 |
-
if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( trailingslashit( $this->get_root() ), '', wp_normalize_path( $file->getPathname() ) ) ) ) {
|
1287 |
-
$this->excluded_files[] = $file;
|
1288 |
-
}
|
1289 |
-
|
1290 |
-
}
|
1291 |
-
|
1292 |
-
return $this->excluded_files;
|
1293 |
-
|
1294 |
-
}
|
1295 |
-
|
1296 |
-
/**
|
1297 |
-
* Returns an array of unreadable files.
|
1298 |
-
*
|
1299 |
-
* @return array
|
1300 |
-
*/
|
1301 |
-
public function get_unreadable_files() {
|
1302 |
-
|
1303 |
-
if ( ! empty( $this->unreadable_files ) ) {
|
1304 |
-
return $this->unreadable_files;
|
1305 |
-
}
|
1306 |
-
|
1307 |
-
$this->unreadable_files = array();
|
1308 |
-
|
1309 |
-
foreach ( $this->get_files( true ) as $file ) {
|
1310 |
-
|
1311 |
-
// Skip dot files, they should only exist on versions of PHP between 5.2.11 -> 5.3
|
1312 |
-
if ( method_exists( $file, 'isDot' ) && $file->isDot() ) {
|
1313 |
-
continue;
|
1314 |
-
}
|
1315 |
-
|
1316 |
-
if ( ! @realpath( $file->getPathname() ) || ! $file->isReadable() ) {
|
1317 |
-
$this->unreadable_files[] = $file;
|
1318 |
-
}
|
1319 |
-
|
1320 |
-
}
|
1321 |
-
|
1322 |
-
return $this->unreadable_files;
|
1323 |
-
|
1324 |
-
}
|
1325 |
-
|
1326 |
-
/**
|
1327 |
-
* Get an array of exclude rules
|
1328 |
-
*
|
1329 |
-
* The backup path is automatically excluded
|
1330 |
-
*
|
1331 |
-
* @return array
|
1332 |
-
*/
|
1333 |
-
public function get_excludes() {
|
1334 |
-
|
1335 |
-
$excludes = array();
|
1336 |
-
|
1337 |
-
if ( isset( $this->excludes ) ) {
|
1338 |
-
$excludes = $this->excludes;
|
1339 |
-
}
|
1340 |
-
|
1341 |
-
// If path() is inside root(), exclude it
|
1342 |
-
if ( strpos( $this->get_path(), $this->get_root() ) !== false ) {
|
1343 |
-
array_unshift( $excludes, trailingslashit( $this->get_path() ) );
|
1344 |
-
}
|
1345 |
-
|
1346 |
-
return array_unique( $excludes );
|
1347 |
-
|
1348 |
-
}
|
1349 |
-
|
1350 |
-
/**
|
1351 |
-
* Set the excludes, expects and array
|
1352 |
-
*
|
1353 |
-
* @param Array $excludes
|
1354 |
-
* @param Bool $append
|
1355 |
-
*/
|
1356 |
-
public function set_excludes( $excludes, $append = false ) {
|
1357 |
-
|
1358 |
-
if ( is_string( $excludes ) ) {
|
1359 |
-
$excludes = explode( ',', $excludes );
|
1360 |
-
}
|
1361 |
-
|
1362 |
-
if ( $append ) {
|
1363 |
-
$excludes = array_merge( $this->excludes, $excludes );
|
1364 |
-
}
|
1365 |
-
|
1366 |
-
$this->excludes = array_filter( array_unique( array_map( 'trim', $excludes ) ) );
|
1367 |
-
|
1368 |
-
}
|
1369 |
-
|
1370 |
-
/**
|
1371 |
-
* Generate the exclude param string for the zip backup
|
1372 |
-
*
|
1373 |
-
* Takes the exclude rules and formats them for use with either
|
1374 |
-
* the shell zip command or pclzip
|
1375 |
-
*
|
1376 |
-
* @param string $context . (default: 'zip')
|
1377 |
-
*
|
1378 |
-
* @return string
|
1379 |
-
*/
|
1380 |
-
public function exclude_string( $context = 'zip' ) {
|
1381 |
-
|
1382 |
-
// Return a comma separated list by default
|
1383 |
-
$separator = ', ';
|
1384 |
-
$wildcard = '';
|
1385 |
-
|
1386 |
-
// The zip command
|
1387 |
-
if ( $context === 'zip' ) {
|
1388 |
-
$wildcard = '*';
|
1389 |
-
$separator = ' -x ';
|
1390 |
-
|
1391 |
-
// The PclZip fallback library
|
1392 |
-
} elseif ( $context === 'regex' ) {
|
1393 |
-
$wildcard = '([\s\S]*?)';
|
1394 |
-
$separator = '|';
|
1395 |
-
}
|
1396 |
-
|
1397 |
-
$excludes = $this->get_excludes();
|
1398 |
-
|
1399 |
-
foreach ( $excludes as $key => &$rule ) {
|
1400 |
-
|
1401 |
-
$file = $absolute = $fragment = false;
|
1402 |
-
|
1403 |
-
// Files don't end with /
|
1404 |
-
if ( ! in_array( substr( $rule, - 1 ), array( '\\', '/' ) ) ) {
|
1405 |
-
$file = true;
|
1406 |
-
} // If rule starts with a / then treat as absolute path
|
1407 |
-
elseif ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) ) {
|
1408 |
-
$absolute = true;
|
1409 |
-
} // Otherwise treat as dir fragment
|
1410 |
-
else {
|
1411 |
-
$fragment = true;
|
1412 |
-
}
|
1413 |
-
|
1414 |
-
// Strip $this->root and conform
|
1415 |
-
$rule = str_ireplace( $this->get_root(), '', untrailingslashit( wp_normalize_path( $rule ) ) );
|
1416 |
-
|
1417 |
-
// Strip the preceeding slash
|
1418 |
-
if ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) ) {
|
1419 |
-
$rule = substr( $rule, 1 );
|
1420 |
-
}
|
1421 |
-
|
1422 |
-
// Escape string for regex
|
1423 |
-
if ( $context === 'regex' ) {
|
1424 |
-
$rule = str_replace( '.', '\.', $rule );
|
1425 |
-
}
|
1426 |
-
|
1427 |
-
// Convert any existing wildcards
|
1428 |
-
if ( $wildcard !== '*' && false !== strpos( $rule, '*' ) ) {
|
1429 |
-
$rule = str_replace( '*', $wildcard, $rule );
|
1430 |
-
}
|
1431 |
-
|
1432 |
-
// Wrap directory fragments and files in wildcards for zip
|
1433 |
-
if ( 'zip' === $context && ( $fragment || $file ) ) {
|
1434 |
-
$rule = $wildcard . $rule . $wildcard;
|
1435 |
-
}
|
1436 |
-
|
1437 |
-
// Add a wildcard to the end of absolute url for zips
|
1438 |
-
if ( 'zip' === $context && $absolute ) {
|
1439 |
-
$rule .= $wildcard;
|
1440 |
-
}
|
1441 |
-
|
1442 |
-
// Add and end carrot to files for pclzip but only if it doesn't end in a wildcard
|
1443 |
-
if ( $file && 'regex' === $context ) {
|
1444 |
-
$rule .= '$';
|
1445 |
-
}
|
1446 |
-
|
1447 |
-
// Add a start carrot to absolute urls for pclzip
|
1448 |
-
if ( $absolute && 'regex' === $context ) {
|
1449 |
-
$rule = '^' . $rule;
|
1450 |
-
}
|
1451 |
-
|
1452 |
-
}
|
1453 |
-
|
1454 |
-
// Escape shell args for zip command
|
1455 |
-
if ( $context === 'zip' ) {
|
1456 |
-
$excludes = array_map( 'escapeshellarg', array_unique( $excludes ) );
|
1457 |
-
}
|
1458 |
-
|
1459 |
-
return implode( $separator, $excludes );
|
1460 |
-
|
1461 |
-
}
|
1462 |
-
|
1463 |
-
/**
|
1464 |
-
* Get the errors
|
1465 |
-
*
|
1466 |
-
*/
|
1467 |
-
public function get_errors( $context = null ) {
|
1468 |
-
|
1469 |
-
if ( ! empty( $context ) ) {
|
1470 |
-
return isset( $this->errors[ $context ] ) ? $this->errors[ $context ] : array();
|
1471 |
-
}
|
1472 |
-
|
1473 |
-
return $this->errors;
|
1474 |
-
|
1475 |
-
}
|
1476 |
-
|
1477 |
-
/**
|
1478 |
-
* Add an error to the errors stack
|
1479 |
-
*
|
1480 |
-
* @param string $context
|
1481 |
-
* @param mixed $error
|
1482 |
-
*/
|
1483 |
-
public function error( $context, $error ) {
|
1484 |
-
|
1485 |
-
if ( empty( $context ) || empty( $error ) ) {
|
1486 |
-
return;
|
1487 |
-
}
|
1488 |
-
|
1489 |
-
$this->do_action( 'hmbkp_error' );
|
1490 |
-
|
1491 |
-
$this->errors[ $context ][ $_key = md5( implode( ':', (array) $error ) ) ] = $error;
|
1492 |
-
|
1493 |
-
}
|
1494 |
-
|
1495 |
-
/**
|
1496 |
-
* Migrate errors to warnings
|
1497 |
-
*
|
1498 |
-
* @param null $context
|
1499 |
-
*/
|
1500 |
-
private function errors_to_warnings( $context = null ) {
|
1501 |
-
|
1502 |
-
$errors = empty( $context ) ? $this->get_errors() : array( $context => $this->get_errors( $context ) );
|
1503 |
-
|
1504 |
-
if ( empty( $errors ) ) {
|
1505 |
-
return;
|
1506 |
-
}
|
1507 |
-
|
1508 |
-
foreach ( $errors as $error_context => $context_errors ) {
|
1509 |
-
foreach ( $context_errors as $error ) {
|
1510 |
-
$this->warning( $error_context, $error );
|
1511 |
-
}
|
1512 |
-
}
|
1513 |
-
|
1514 |
-
if ( $context ) {
|
1515 |
-
unset( $this->errors[ $context ] );
|
1516 |
-
} else {
|
1517 |
-
$this->errors = array();
|
1518 |
-
}
|
1519 |
-
|
1520 |
-
}
|
1521 |
-
|
1522 |
-
/**
|
1523 |
-
* Get the warnings
|
1524 |
-
*
|
1525 |
-
*/
|
1526 |
-
public function get_warnings( $context = null ) {
|
1527 |
-
|
1528 |
-
if ( ! empty( $context ) ) {
|
1529 |
-
return isset( $this->warnings[ $context ] ) ? $this->warnings[ $context ] : array();
|
1530 |
-
}
|
1531 |
-
|
1532 |
-
return $this->warnings;
|
1533 |
-
|
1534 |
-
}
|
1535 |
-
|
1536 |
-
/**
|
1537 |
-
* Add an warning to the warnings stack
|
1538 |
-
*
|
1539 |
-
* @param string $context
|
1540 |
-
* @param mixed $warning
|
1541 |
-
*/
|
1542 |
-
private function warning( $context, $warning ) {
|
1543 |
-
|
1544 |
-
if ( empty( $context ) || empty( $warning ) ) {
|
1545 |
-
return;
|
1546 |
-
}
|
1547 |
-
|
1548 |
-
$this->do_action( 'hmbkp_warning' );
|
1549 |
-
|
1550 |
-
$this->warnings[ $context ][ $_key = md5( implode( ':', (array) $warning ) ) ] = $warning;
|
1551 |
-
|
1552 |
-
}
|
1553 |
-
|
1554 |
-
/**
|
1555 |
-
* Custom error handler for catching php errors
|
1556 |
-
*
|
1557 |
-
* @param $type
|
1558 |
-
*
|
1559 |
-
* @return bool
|
1560 |
-
*/
|
1561 |
-
public function error_handler( $type ) {
|
1562 |
-
|
1563 |
-
// Skip strict & deprecated warnings
|
1564 |
-
if ( ( defined( 'E_DEPRECATED' ) && $type === E_DEPRECATED ) || ( defined( 'E_STRICT' ) && $type === E_STRICT ) || error_reporting() === 0 ) {
|
1565 |
-
return false;
|
1566 |
-
}
|
1567 |
-
|
1568 |
-
$args = func_get_args();
|
1569 |
-
|
1570 |
-
array_shift( $args );
|
1571 |
-
|
1572 |
-
$this->warning( 'php', implode( ', ', array_splice( $args, 0, 3 ) ) );
|
1573 |
-
|
1574 |
-
return false;
|
1575 |
-
|
1576 |
-
}
|
1577 |
-
|
1578 |
-
/**
|
1579 |
-
* Determine if user can connect via the CLI
|
1580 |
-
*
|
1581 |
-
* @return \WP_Error
|
1582 |
-
*/
|
1583 |
-
public function user_can_connect() {
|
1584 |
-
|
1585 |
-
// mysql --host=localhost --user=myname --password=mypass mydb
|
1586 |
-
|
1587 |
-
// Guess port or socket connection type
|
1588 |
-
$port_or_socket = strstr( DB_HOST, ':' );
|
1589 |
-
|
1590 |
-
$host = DB_HOST;
|
1591 |
-
|
1592 |
-
if ( ! empty( $port_or_socket ) ) {
|
1593 |
-
|
1594 |
-
$host = substr( DB_HOST, 0, strpos( DB_HOST, ':' ) );
|
1595 |
-
|
1596 |
-
$port_or_socket = substr( $port_or_socket, 1 );
|
1597 |
-
|
1598 |
-
if ( 0 !== strpos( $port_or_socket, '/' ) ) {
|
1599 |
-
|
1600 |
-
$port = intval( $port_or_socket );
|
1601 |
-
|
1602 |
-
$maybe_socket = strstr( $port_or_socket, ':' );
|
1603 |
-
|
1604 |
-
if ( ! empty( $maybe_socket ) ) {
|
1605 |
-
|
1606 |
-
$socket = substr( $maybe_socket, 1 );
|
1607 |
-
|
1608 |
-
}
|
1609 |
-
|
1610 |
-
} else {
|
1611 |
-
|
1612 |
-
$socket = $port_or_socket;
|
1613 |
-
|
1614 |
-
}
|
1615 |
-
}
|
1616 |
-
|
1617 |
-
// Path to the mysqldump executable
|
1618 |
-
$cmd = 'mysql ';
|
1619 |
-
|
1620 |
-
// Username
|
1621 |
-
$cmd .= ' -u ' . escapeshellarg( DB_USER );
|
1622 |
-
|
1623 |
-
// Don't pass the password if it's blank
|
1624 |
-
if ( DB_PASSWORD ) {
|
1625 |
-
$cmd .= ' -p' . escapeshellarg( DB_PASSWORD );
|
1626 |
-
}
|
1627 |
-
|
1628 |
-
// Set the host
|
1629 |
-
$cmd .= ' -h ' . escapeshellarg( $host );
|
1630 |
-
|
1631 |
-
// Set the port if it was set
|
1632 |
-
if ( ! empty( $port ) && is_numeric( $port ) ) {
|
1633 |
-
$cmd .= ' -P ' . $port;
|
1634 |
-
}
|
1635 |
-
|
1636 |
-
// Set the socket path
|
1637 |
-
if ( ! empty( $socket ) && ! is_numeric( $socket ) ) {
|
1638 |
-
$cmd .= ' --protocol=socket -S ' . $socket;
|
1639 |
-
}
|
1640 |
-
|
1641 |
-
// The database we're dumping
|
1642 |
-
$cmd .= ' ' . escapeshellarg( DB_NAME );
|
1643 |
-
|
1644 |
-
// Quit immediately
|
1645 |
-
$cmd .= ' --execute="quit"';
|
1646 |
-
|
1647 |
-
// Pipe STDERR to STDOUT
|
1648 |
-
$cmd .= ' 2>&1';
|
1649 |
-
|
1650 |
-
// Store any returned data in an error
|
1651 |
-
$stderr = shell_exec( $cmd );
|
1652 |
-
|
1653 |
-
// Skip the new password warning that is output in mysql > 5.6 (@see http://bugs.mysql.com/bug.php?id=66546)
|
1654 |
-
if ( 'Warning: Using a password on the command line interface can be insecure.' === trim( $stderr ) ) {
|
1655 |
-
$stderr = '';
|
1656 |
-
}
|
1657 |
-
|
1658 |
-
if ( $stderr ) {
|
1659 |
-
return new \WP_Error( 'mysql-cli-connect-error', __( 'Could not connect to mysql', 'backupwordpress' ) );
|
1660 |
-
}
|
1661 |
-
}
|
1662 |
-
|
1663 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
classes/class-backupwordpress-wp-cli-command.php
CHANGED
@@ -1,5 +1,7 @@
|
|
1 |
<?php
|
2 |
|
|
|
|
|
3 |
/**
|
4 |
* Implement backup command
|
5 |
*
|
@@ -7,7 +9,7 @@
|
|
7 |
* @package wp-cli
|
8 |
* @subpackage commands/third-party
|
9 |
*/
|
10 |
-
class
|
11 |
|
12 |
/**
|
13 |
* Perform a Backup.
|
@@ -26,12 +28,6 @@ class BackUpWordPress_WP_CLI_Command extends WP_CLI_Command {
|
|
26 |
* [--root]
|
27 |
* : dir that should be backed up, defaults to site root.
|
28 |
*
|
29 |
-
* [--zip_command_path]
|
30 |
-
* : path to your zip binary, standard locations are automatically used
|
31 |
-
*
|
32 |
-
* [--mysqldump_command_path]
|
33 |
-
* : path to your mysqldump binary, standard locations are automatically used
|
34 |
-
*
|
35 |
* [--archive_filename]
|
36 |
* : filename for the resulting zip file
|
37 |
*
|
@@ -47,39 +43,41 @@ class BackUpWordPress_WP_CLI_Command extends WP_CLI_Command {
|
|
47 |
public function backup( $args, $assoc_args ) {
|
48 |
|
49 |
add_action( 'hmbkp_mysqldump_started', function () {
|
50 |
-
WP_CLI::line( __( 'Backup: Dumping database...', 'backupwordpress' ) );
|
51 |
} );
|
52 |
|
53 |
add_action( 'hmbkp_archive_started', function () {
|
54 |
-
WP_CLI::line( __( 'Backup: Zipping everything up...', 'backupwordpress' ) );
|
55 |
} );
|
56 |
|
57 |
-
$hm_backup = new HM\BackUpWordPress\Backup();
|
58 |
-
|
59 |
if ( ! empty( $assoc_args['destination'] ) ) {
|
60 |
-
|
61 |
}
|
62 |
|
63 |
-
|
64 |
|
65 |
if ( ! empty( $assoc_args['root'] ) ) {
|
66 |
-
|
67 |
}
|
68 |
|
69 |
-
if ( ( ! is_dir(
|
70 |
-
WP_CLI::error( __( 'Invalid backup path', 'backupwordpress' ) );
|
71 |
return false;
|
72 |
}
|
73 |
|
74 |
-
if ( ! is_dir(
|
75 |
-
WP_CLI::error( __( 'Invalid root path', 'backupwordpress' ) );
|
76 |
return false;
|
77 |
}
|
78 |
|
|
|
|
|
79 |
if ( isset( $assoc_args['archive_filename'] ) ) {
|
80 |
-
$
|
81 |
}
|
82 |
|
|
|
|
|
83 |
if ( ! empty( $assoc_args['files_only'] ) ) {
|
84 |
$hm_backup->set_type( 'file' );
|
85 |
}
|
@@ -88,28 +86,20 @@ class BackUpWordPress_WP_CLI_Command extends WP_CLI_Command {
|
|
88 |
$hm_backup->set_type( 'database' );
|
89 |
}
|
90 |
|
91 |
-
if ( isset( $assoc_args['mysqldump_command_path'] ) ) {
|
92 |
-
$hm_backup->set_mysqldump_command_path( $assoc_args['mysqldump_command_path'] );
|
93 |
-
}
|
94 |
-
|
95 |
-
if ( isset( $assoc_args['zip_command_path'] ) ) {
|
96 |
-
$hm_backup->set_zip_command_path( $assoc_args['zip_command_path'] );
|
97 |
-
}
|
98 |
-
|
99 |
if ( ! empty( $assoc_args['excludes'] ) ) {
|
100 |
$hm_backup->set_excludes( $assoc_args['excludes'] );
|
101 |
}
|
102 |
|
103 |
-
$hm_backup->
|
104 |
|
105 |
-
if ( file_exists( $hm_backup->
|
106 |
-
WP_CLI::success( __( 'Backup Complete: ', 'backupwordpress' ) . $hm_backup->
|
107 |
} else {
|
108 |
-
WP_CLI::error( __( 'Backup Failed', 'backupwordpress' ) );
|
109 |
}
|
110 |
|
111 |
}
|
112 |
|
113 |
}
|
114 |
|
115 |
-
WP_CLI::add_command( 'backupwordpress', '
|
1 |
<?php
|
2 |
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
/**
|
6 |
* Implement backup command
|
7 |
*
|
9 |
* @package wp-cli
|
10 |
* @subpackage commands/third-party
|
11 |
*/
|
12 |
+
class CLI extends \WP_CLI_Command {
|
13 |
|
14 |
/**
|
15 |
* Perform a Backup.
|
28 |
* [--root]
|
29 |
* : dir that should be backed up, defaults to site root.
|
30 |
*
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
* [--archive_filename]
|
32 |
* : filename for the resulting zip file
|
33 |
*
|
43 |
public function backup( $args, $assoc_args ) {
|
44 |
|
45 |
add_action( 'hmbkp_mysqldump_started', function () {
|
46 |
+
\WP_CLI::line( __( 'Backup: Dumping database...', 'backupwordpress' ) );
|
47 |
} );
|
48 |
|
49 |
add_action( 'hmbkp_archive_started', function () {
|
50 |
+
\WP_CLI::line( __( 'Backup: Zipping everything up...', 'backupwordpress' ) );
|
51 |
} );
|
52 |
|
|
|
|
|
53 |
if ( ! empty( $assoc_args['destination'] ) ) {
|
54 |
+
Path::get_instance()->set_path( $assoc_args['destination'] );
|
55 |
}
|
56 |
|
57 |
+
Path::get_instance()->cleanup();
|
58 |
|
59 |
if ( ! empty( $assoc_args['root'] ) ) {
|
60 |
+
Path::get_instance()->set_root( $assoc_args['root'] );
|
61 |
}
|
62 |
|
63 |
+
if ( ( ! is_dir( Path::get_path() ) ) ) {
|
64 |
+
\WP_CLI::error( __( 'Invalid backup path', 'backupwordpress' ) );
|
65 |
return false;
|
66 |
}
|
67 |
|
68 |
+
if ( ! is_dir( Path::get_root() ) || ! is_readable( Path::get_root() ) ) {
|
69 |
+
\WP_CLI::error( __( 'Invalid root path', 'backupwordpress' ) );
|
70 |
return false;
|
71 |
}
|
72 |
|
73 |
+
$filename = 'backup.zip';
|
74 |
+
|
75 |
if ( isset( $assoc_args['archive_filename'] ) ) {
|
76 |
+
$filename = $assoc_args['archive_filename'];
|
77 |
}
|
78 |
|
79 |
+
$hm_backup = new Backup( $filename );
|
80 |
+
|
81 |
if ( ! empty( $assoc_args['files_only'] ) ) {
|
82 |
$hm_backup->set_type( 'file' );
|
83 |
}
|
86 |
$hm_backup->set_type( 'database' );
|
87 |
}
|
88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
if ( ! empty( $assoc_args['excludes'] ) ) {
|
90 |
$hm_backup->set_excludes( $assoc_args['excludes'] );
|
91 |
}
|
92 |
|
93 |
+
$hm_backup->run();
|
94 |
|
95 |
+
if ( file_exists( $hm_backup->get_backup_filepath() ) ) {
|
96 |
+
\WP_CLI::success( __( 'Backup Complete: ', 'backupwordpress' ) . $hm_backup->get_backup_filepath() );
|
97 |
} else {
|
98 |
+
\WP_CLI::error( __( 'Backup Failed', 'backupwordpress' ) );
|
99 |
}
|
100 |
|
101 |
}
|
102 |
|
103 |
}
|
104 |
|
105 |
+
\WP_CLI::add_command( 'backupwordpress', 'HM\BackUpWordPress\CLI' );
|
classes/class-email-service.php
CHANGED
@@ -31,7 +31,7 @@ class Email_Service extends Service {
|
|
31 |
<td>
|
32 |
<input type="text" id="<?php echo esc_attr( $this->get_field_name( 'email' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'email' ) ); ?>" value="<?php echo esc_attr( $this->get_field_value( 'email' ) ); ?>" placeholder="name@youremail.com" />
|
33 |
|
34 |
-
<p class="description"><?php printf( __( 'Receive a notification email when a backup completes. If the backup is small enough (< %s), then it will be attached to the email. Separate multiple email addresses with a comma.', 'backupwordpress' ), '<code>' . size_format(
|
35 |
</td>
|
36 |
|
37 |
</tr>
|
@@ -154,7 +154,7 @@ class Email_Service extends Service {
|
|
154 |
|
155 |
if ( $action === 'hmbkp_backup_complete' && $this->get_email_address_array() ) {
|
156 |
|
157 |
-
$file = $backup->
|
158 |
|
159 |
$sent = false;
|
160 |
|
@@ -189,7 +189,7 @@ class Email_Service extends Service {
|
|
189 |
$subject = sprintf( __( 'Backup of %s', 'backupwordpress' ), $domain );
|
190 |
|
191 |
// If it's larger than the max attachment size limit assume it's not going to be able to send the backup
|
192 |
-
if ( @filesize( $file ) <
|
193 |
|
194 |
$message = sprintf( __( 'BackUpWordPress has completed a backup of your site %1$s.', 'backupwordpress' ) . "\n\n" . __( 'The backup file should be attached to this email.', 'backupwordpress' ) . "\n\n" . __( 'You can download the backup file by clicking the link below:', 'backupwordpress' ) . "\n\n" . '%2$s' . "\n\n" . __( "Kind Regards,\nThe Happy BackUpWordPress Backup Emailing Robot", 'backupwordpress' ), home_url(), $download );
|
195 |
|
31 |
<td>
|
32 |
<input type="text" id="<?php echo esc_attr( $this->get_field_name( 'email' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'email' ) ); ?>" value="<?php echo esc_attr( $this->get_field_value( 'email' ) ); ?>" placeholder="name@youremail.com" />
|
33 |
|
34 |
+
<p class="description"><?php printf( __( 'Receive a notification email when a backup completes. If the backup is small enough (< %s), then it will be attached to the email. Separate multiple email addresses with a comma.', 'backupwordpress' ), '<code>' . size_format( get_max_attachment_size() ) . '</code>' ); ?></p>
|
35 |
</td>
|
36 |
|
37 |
</tr>
|
154 |
|
155 |
if ( $action === 'hmbkp_backup_complete' && $this->get_email_address_array() ) {
|
156 |
|
157 |
+
$file = $backup->get_backup_filepath();
|
158 |
|
159 |
$sent = false;
|
160 |
|
189 |
$subject = sprintf( __( 'Backup of %s', 'backupwordpress' ), $domain );
|
190 |
|
191 |
// If it's larger than the max attachment size limit assume it's not going to be able to send the backup
|
192 |
+
if ( @filesize( $file ) < get_max_attachment_size() ) {
|
193 |
|
194 |
$message = sprintf( __( 'BackUpWordPress has completed a backup of your site %1$s.', 'backupwordpress' ) . "\n\n" . __( 'The backup file should be attached to this email.', 'backupwordpress' ) . "\n\n" . __( 'You can download the backup file by clicking the link below:', 'backupwordpress' ) . "\n\n" . '%2$s' . "\n\n" . __( "Kind Regards,\nThe Happy BackUpWordPress Backup Emailing Robot", 'backupwordpress' ), home_url(), $download );
|
195 |
|
classes/class-excludes.php
ADDED
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Manages exclude rules
|
7 |
+
*/
|
8 |
+
class Excludes {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* The array of exclude rules.
|
12 |
+
*
|
13 |
+
* @var array
|
14 |
+
*/
|
15 |
+
private $excludes;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* The array of default exclude rules
|
19 |
+
*
|
20 |
+
* @var array
|
21 |
+
*/
|
22 |
+
private $default_excludes = array(
|
23 |
+
'.svn',
|
24 |
+
'_svn',
|
25 |
+
'CVS',
|
26 |
+
'_darcs',
|
27 |
+
'.arch-params',
|
28 |
+
'.monotone',
|
29 |
+
'.bzr',
|
30 |
+
'.git',
|
31 |
+
'.hg',
|
32 |
+
'backwpup-*',
|
33 |
+
'updraft',
|
34 |
+
'wp-snapshots',
|
35 |
+
'backupbuddy_backups',
|
36 |
+
'pb_backupbuddy',
|
37 |
+
'backup-db',
|
38 |
+
'Envato-backups',
|
39 |
+
'managewp',
|
40 |
+
'backupwordpress-*-backups'
|
41 |
+
);
|
42 |
+
|
43 |
+
public function __construct( $excludes = array() ) {
|
44 |
+
$this->set_excludes( $excludes );
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Set the exclude rules.
|
49 |
+
*
|
50 |
+
* Excludes rules should be a complete or partial directory or file path.
|
51 |
+
* Wildcards can be specified with the * character.
|
52 |
+
*
|
53 |
+
* @param string|array $excludes The list of exclude rules, accepts either
|
54 |
+
* a comma separated list or an array.
|
55 |
+
*/
|
56 |
+
public function set_excludes( $excludes ) {
|
57 |
+
|
58 |
+
if ( is_string( $excludes ) ) {
|
59 |
+
$excludes = explode( ',', $excludes );
|
60 |
+
}
|
61 |
+
|
62 |
+
$this->excludes = $excludes;
|
63 |
+
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Get the excludes
|
68 |
+
*
|
69 |
+
* Returns any user set excludes as well as the default list.
|
70 |
+
*
|
71 |
+
* @return array The array of exclude rules.
|
72 |
+
*/
|
73 |
+
public function get_excludes() {
|
74 |
+
return array_merge( $this->get_default_excludes(), $this->get_user_excludes() );
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Get the excludes prepared for use with regex.
|
79 |
+
*
|
80 |
+
* The primary difference being that any wildcard (*) rules are converted to the regex
|
81 |
+
* fragment `[\s\S]*?`.
|
82 |
+
*
|
83 |
+
* @return array The array of exclude rules
|
84 |
+
*/
|
85 |
+
public function get_excludes_for_regex() {
|
86 |
+
|
87 |
+
$excludes = $this->get_excludes();
|
88 |
+
|
89 |
+
// Prepare the exclude rules
|
90 |
+
foreach ( $excludes as &$exclude ) {
|
91 |
+
|
92 |
+
if ( strpos( $exclude, '*' ) !== false ) {
|
93 |
+
|
94 |
+
// Escape slashes
|
95 |
+
$exclude = str_replace( '/', '\/', $exclude );
|
96 |
+
|
97 |
+
// Convert WildCards to regex
|
98 |
+
$exclude = str_replace( '*', '[\s\S]*?', $exclude );
|
99 |
+
|
100 |
+
// Wrap in slashes
|
101 |
+
$exclude = '/' . $exclude . '/';
|
102 |
+
|
103 |
+
}
|
104 |
+
|
105 |
+
}
|
106 |
+
|
107 |
+
return $excludes;
|
108 |
+
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Get the user defined excludes.
|
113 |
+
*
|
114 |
+
* @return array The array of excludes.
|
115 |
+
*/
|
116 |
+
public function get_user_excludes() {
|
117 |
+
|
118 |
+
$excludes = $this->excludes;
|
119 |
+
|
120 |
+
// If path() is inside root(), exclude it
|
121 |
+
if ( strpos( Path::get_path(), Path::get_root() ) !== false && Path::get_root() !== Path::get_path() ) {
|
122 |
+
array_unshift( $excludes, trailingslashit( Path::get_path() ) );
|
123 |
+
}
|
124 |
+
|
125 |
+
return $this->normalize( $excludes );
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Get the array of default excludes.
|
130 |
+
*
|
131 |
+
* @return array The array of excludes.
|
132 |
+
*/
|
133 |
+
public function get_default_excludes() {
|
134 |
+
|
135 |
+
$excludes = array();
|
136 |
+
|
137 |
+
// Back compat with the old Constant
|
138 |
+
if ( defined( 'HMBKP_EXCLUDE' ) && HMBKP_EXCLUDE ) {
|
139 |
+
$excludes = explode( ',', implode( ',', (array) HMBKP_EXCLUDE ) );
|
140 |
+
}
|
141 |
+
|
142 |
+
$excludes = array_merge( $this->default_excludes, $excludes );
|
143 |
+
|
144 |
+
/**
|
145 |
+
* Allow the default excludes list to be modified.
|
146 |
+
*
|
147 |
+
* @param $excludes The array of exclude rules.
|
148 |
+
*/
|
149 |
+
$excludes = apply_filters( 'hmbkp_default_excludes', $excludes );
|
150 |
+
|
151 |
+
return $this->normalize( $excludes );
|
152 |
+
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* normalise the exclude rules so they are ready to work with.
|
157 |
+
*
|
158 |
+
* @param array $excludes The array of exclude rules to normalise.
|
159 |
+
*
|
160 |
+
* @return array The array of normalised rules.
|
161 |
+
*/
|
162 |
+
public function normalize( $excludes ) {
|
163 |
+
|
164 |
+
$excludes = array_map( function( $exclude ) {
|
165 |
+
|
166 |
+
// Convert absolute paths to relative
|
167 |
+
$exclude = str_replace( PATH::get_root(), '', wp_normalize_path( $exclude ) );
|
168 |
+
|
169 |
+
// Trim the slashes
|
170 |
+
$exclude = trim( $exclude );
|
171 |
+
$exclude = ltrim( $exclude, '/' );
|
172 |
+
$exclude = untrailingslashit( $exclude );
|
173 |
+
|
174 |
+
return $exclude;
|
175 |
+
|
176 |
+
}, $excludes );
|
177 |
+
|
178 |
+
// Remove duplicate or empty rules
|
179 |
+
$excludes = array_unique( $excludes );
|
180 |
+
$excludes = array_filter( $excludes );
|
181 |
+
|
182 |
+
return $excludes;
|
183 |
+
|
184 |
+
}
|
185 |
+
|
186 |
+
}
|
classes/class-path.php
CHANGED
@@ -1,17 +1,12 @@
|
|
1 |
<?php
|
2 |
-
/**
|
3 |
-
* @package BackUpWordPress
|
4 |
-
* @subpackage BackUpWordPress/classes
|
5 |
-
*/
|
6 |
|
7 |
namespace HM\BackUpWordPress;
|
8 |
|
9 |
/**
|
10 |
-
*
|
11 |
*
|
12 |
* Handles calculating & protecting the directory that backups will be stored in
|
13 |
-
*
|
14 |
-
* @todo Should be a singleton?
|
15 |
*/
|
16 |
class Path {
|
17 |
|
@@ -20,15 +15,27 @@ class Path {
|
|
20 |
*
|
21 |
* @var string $this->path
|
22 |
*/
|
23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
|
25 |
/**
|
26 |
* The path to the directory that backup files are stored in
|
27 |
*
|
28 |
* @var string $this->path
|
29 |
*/
|
30 |
-
|
31 |
|
|
|
|
|
|
|
|
|
|
|
32 |
private static $instance;
|
33 |
|
34 |
/**
|
@@ -40,16 +47,12 @@ class Path {
|
|
40 |
/**
|
41 |
* Private clone method to prevent cloning of the instance of the
|
42 |
* *Singleton* instance.
|
43 |
-
*
|
44 |
-
* @return void
|
45 |
*/
|
46 |
private function __clone() {}
|
47 |
|
48 |
/**
|
49 |
* Private unserialize method to prevent unserializing of the *Singleton*
|
50 |
* instance.
|
51 |
-
*
|
52 |
-
* @return void
|
53 |
*/
|
54 |
private function __wakeup() {}
|
55 |
|
@@ -70,9 +73,54 @@ class Path {
|
|
70 |
}
|
71 |
|
72 |
/**
|
73 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
*/
|
75 |
-
|
76 |
|
77 |
// Calculate the path if needed
|
78 |
if ( empty( $this->path ) || ! wp_is_writable( $this->path ) ) {
|
@@ -100,6 +148,34 @@ class Path {
|
|
100 |
|
101 |
}
|
102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
public function reset_path() {
|
104 |
$this->set_path( false );
|
105 |
}
|
@@ -108,7 +184,7 @@ class Path {
|
|
108 |
* Get the path to the default backup location in wp-content
|
109 |
*/
|
110 |
public function get_default_path() {
|
111 |
-
return trailingslashit( WP_CONTENT_DIR ) . 'backupwordpress-' . substr( HMBKP_SECURE_KEY, 0, 10 ) . '-backups';
|
112 |
}
|
113 |
|
114 |
/**
|
@@ -118,7 +194,7 @@ class Path {
|
|
118 |
|
119 |
$upload_dir = wp_upload_dir();
|
120 |
|
121 |
-
return trailingslashit( $upload_dir['basedir'] ) . 'backupwordpress-' . substr( HMBKP_SECURE_KEY, 0, 10 ) . '-backups';
|
122 |
|
123 |
}
|
124 |
|
@@ -158,6 +234,8 @@ class Path {
|
|
158 |
|
159 |
$paths = array_merge( $default, $fallback );
|
160 |
|
|
|
|
|
161 |
return $paths;
|
162 |
|
163 |
}
|
@@ -208,18 +286,23 @@ class Path {
|
|
208 |
|
209 |
// Loop through possible paths, use the first one that exists/can be created and is writable
|
210 |
foreach ( $paths as $path ) {
|
211 |
-
if ( wp_mkdir_p( $path ) ) { // Also handles fixing perms / directory already exists
|
212 |
break;
|
213 |
}
|
214 |
}
|
215 |
|
216 |
-
if (
|
217 |
$this->path = $path;
|
218 |
}
|
219 |
|
220 |
}
|
221 |
|
222 |
/**
|
|
|
|
|
|
|
|
|
|
|
223 |
* @param string $reset
|
224 |
*/
|
225 |
public function protect_path( $reset = 'no' ) {
|
@@ -229,7 +312,7 @@ class Path {
|
|
229 |
// Protect against directory browsing by including an index.html file
|
230 |
$index = $this->path . '/index.html';
|
231 |
|
232 |
-
if (
|
233 |
@unlink( $index );
|
234 |
}
|
235 |
|
@@ -283,7 +366,6 @@ class Path {
|
|
283 |
* location
|
284 |
*
|
285 |
* @param string $path The path to move the backups from
|
286 |
-
* @return void
|
287 |
*/
|
288 |
public function move_old_backups( $from ) {
|
289 |
|
@@ -291,7 +373,7 @@ class Path {
|
|
291 |
return;
|
292 |
}
|
293 |
|
294 |
-
if ( ! wp_is_writable(
|
295 |
return;
|
296 |
}
|
297 |
|
@@ -305,11 +387,11 @@ class Path {
|
|
305 |
if ( 'zip' === pathinfo( $file, PATHINFO_EXTENSION ) ) {
|
306 |
|
307 |
// Try to move them
|
308 |
-
if ( ! @rename( trailingslashit( $from ) . $file, trailingslashit(
|
309 |
|
310 |
|
311 |
// If we can't move them then try to copy them
|
312 |
-
copy( trailingslashit( $from ) . $file, trailingslashit(
|
313 |
|
314 |
}
|
315 |
|
@@ -321,8 +403,8 @@ class Path {
|
|
321 |
}
|
322 |
|
323 |
// Delete the old directory if it's inside WP_CONTENT_DIR
|
324 |
-
if ( false !== strpos( $from, WP_CONTENT_DIR ) && $from !==
|
325 |
-
|
326 |
}
|
327 |
|
328 |
}
|
@@ -333,7 +415,7 @@ class Path {
|
|
333 |
public function cleanup() {
|
334 |
|
335 |
// Don't cleanup a custom path, who knows what other stuff is there
|
336 |
-
if (
|
337 |
return;
|
338 |
}
|
339 |
|
1 |
<?php
|
|
|
|
|
|
|
|
|
2 |
|
3 |
namespace HM\BackUpWordPress;
|
4 |
|
5 |
/**
|
6 |
+
* Manages both the backup path and site root
|
7 |
*
|
8 |
* Handles calculating & protecting the directory that backups will be stored in
|
9 |
+
* as well as the directory that is being backed up
|
|
|
10 |
*/
|
11 |
class Path {
|
12 |
|
15 |
*
|
16 |
* @var string $this->path
|
17 |
*/
|
18 |
+
private $path;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* The path to the directory that will be backed up
|
22 |
+
*
|
23 |
+
* @var string $this->root
|
24 |
+
*/
|
25 |
+
private $root;
|
26 |
|
27 |
/**
|
28 |
* The path to the directory that backup files are stored in
|
29 |
*
|
30 |
* @var string $this->path
|
31 |
*/
|
32 |
+
private $custom_path;
|
33 |
|
34 |
+
/**
|
35 |
+
* Contains the instantiated Path instance
|
36 |
+
*
|
37 |
+
* @var Path $this->instance
|
38 |
+
*/
|
39 |
private static $instance;
|
40 |
|
41 |
/**
|
47 |
/**
|
48 |
* Private clone method to prevent cloning of the instance of the
|
49 |
* *Singleton* instance.
|
|
|
|
|
50 |
*/
|
51 |
private function __clone() {}
|
52 |
|
53 |
/**
|
54 |
* Private unserialize method to prevent unserializing of the *Singleton*
|
55 |
* instance.
|
|
|
|
|
56 |
*/
|
57 |
private function __wakeup() {}
|
58 |
|
73 |
}
|
74 |
|
75 |
/**
|
76 |
+
* Convenience method for quickly grabbing the path
|
77 |
+
*/
|
78 |
+
public static function get_path() {
|
79 |
+
return self::get_instance()->get_calculated_path();
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Convenience method for quickly grabbing the root
|
84 |
+
*/
|
85 |
+
public static function get_root() {
|
86 |
+
return self::get_instance()->get_calculated_root();
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Calculate the path to the site "home" directory.
|
91 |
+
*
|
92 |
+
* The home directory is the path equivalent to the home_url. That is,
|
93 |
+
* the path to the true root of the website. In situations where WordPress is
|
94 |
+
* installed in a subdirectory the home path is different to ABSPATH
|
95 |
+
*
|
96 |
+
* @param string $site_path The site_path to use when calculating the home path, defaults to ABSPATH
|
97 |
+
*/
|
98 |
+
public static function get_home_path( $site_path = ABSPATH ) {
|
99 |
+
|
100 |
+
if ( defined( 'HMBKP_ROOT' ) && HMBKP_ROOT ) {
|
101 |
+
return wp_normalize_path( HMBKP_ROOT );
|
102 |
+
}
|
103 |
+
|
104 |
+
$home_path = $site_path;
|
105 |
+
|
106 |
+
// Handle wordpress installed in a subdirectory
|
107 |
+
if ( file_exists( dirname( $site_path ) . '/wp-config.php' ) && ! file_exists( $site_path . '/wp-config.php' ) && file_exists( dirname( $site_path ) . '/index.php' ) ) {
|
108 |
+
$home_path = dirname( $site_path );
|
109 |
+
}
|
110 |
+
|
111 |
+
// Handle wp-config.php being above site_path
|
112 |
+
if ( file_exists( dirname( $site_path ) . '/wp-config.php' ) && ! file_exists( $site_path . '/wp-config.php' ) && ! file_exists( dirname( $site_path ) . '/index.php' ) ) {
|
113 |
+
$home_path = $site_path;
|
114 |
+
}
|
115 |
+
|
116 |
+
return wp_normalize_path( untrailingslashit( $home_path ) );
|
117 |
+
|
118 |
+
}
|
119 |
+
|
120 |
+
/**
|
121 |
+
* get the calculated path to the directory where backups will be stored
|
122 |
*/
|
123 |
+
private function get_calculated_path() {
|
124 |
|
125 |
// Calculate the path if needed
|
126 |
if ( empty( $this->path ) || ! wp_is_writable( $this->path ) ) {
|
148 |
|
149 |
}
|
150 |
|
151 |
+
/**
|
152 |
+
* get the calculated path to the directory that will be backed up
|
153 |
+
*/
|
154 |
+
private function get_calculated_root() {
|
155 |
+
|
156 |
+
$root = self::get_home_path();
|
157 |
+
|
158 |
+
if ( defined( 'HMBKP_ROOT' ) && HMBKP_ROOT ) {
|
159 |
+
$root = HMBKP_ROOT;
|
160 |
+
}
|
161 |
+
|
162 |
+
if ( $this->root ) {
|
163 |
+
$root = $this->root;
|
164 |
+
}
|
165 |
+
|
166 |
+
return wp_normalize_path( $root );
|
167 |
+
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Set the root path directly, overriding the default
|
172 |
+
*
|
173 |
+
* @param $root
|
174 |
+
*/
|
175 |
+
public function set_root( $root ) {
|
176 |
+
$this->root = $root;
|
177 |
+
}
|
178 |
+
|
179 |
public function reset_path() {
|
180 |
$this->set_path( false );
|
181 |
}
|
184 |
* Get the path to the default backup location in wp-content
|
185 |
*/
|
186 |
public function get_default_path() {
|
187 |
+
return trailingslashit( wp_normalize_path( WP_CONTENT_DIR ) ) . 'backupwordpress-' . substr( HMBKP_SECURE_KEY, 0, 10 ) . '-backups';
|
188 |
}
|
189 |
|
190 |
/**
|
194 |
|
195 |
$upload_dir = wp_upload_dir();
|
196 |
|
197 |
+
return trailingslashit( wp_normalize_path( $upload_dir['basedir'] ) ) . 'backupwordpress-' . substr( HMBKP_SECURE_KEY, 0, 10 ) . '-backups';
|
198 |
|
199 |
}
|
200 |
|
234 |
|
235 |
$paths = array_merge( $default, $fallback );
|
236 |
|
237 |
+
$paths = array_map( 'wp_normalize_path', $paths );
|
238 |
+
|
239 |
return $paths;
|
240 |
|
241 |
}
|
286 |
|
287 |
// Loop through possible paths, use the first one that exists/can be created and is writable
|
288 |
foreach ( $paths as $path ) {
|
289 |
+
if ( wp_mkdir_p( $path ) && wp_is_writable( $path ) ) { // Also handles fixing perms / directory already exists
|
290 |
break;
|
291 |
}
|
292 |
}
|
293 |
|
294 |
+
if ( file_exists( $path ) && wp_is_writable( $path ) ) {
|
295 |
$this->path = $path;
|
296 |
}
|
297 |
|
298 |
}
|
299 |
|
300 |
/**
|
301 |
+
* Protect the directory that backups are stored in
|
302 |
+
*
|
303 |
+
* - Adds an index.html file in an attempt to disable directory browsing
|
304 |
+
* - Adds a .httaccess file to deny direct access if on Apache
|
305 |
+
*
|
306 |
* @param string $reset
|
307 |
*/
|
308 |
public function protect_path( $reset = 'no' ) {
|
312 |
// Protect against directory browsing by including an index.html file
|
313 |
$index = $this->path . '/index.html';
|
314 |
|
315 |
+
if ( 'reset' === $reset && file_exists( $index ) ) {
|
316 |
@unlink( $index );
|
317 |
}
|
318 |
|
366 |
* location
|
367 |
*
|
368 |
* @param string $path The path to move the backups from
|
|
|
369 |
*/
|
370 |
public function move_old_backups( $from ) {
|
371 |
|
373 |
return;
|
374 |
}
|
375 |
|
376 |
+
if ( ! wp_is_writable( Path::get_path() ) ) {
|
377 |
return;
|
378 |
}
|
379 |
|
387 |
if ( 'zip' === pathinfo( $file, PATHINFO_EXTENSION ) ) {
|
388 |
|
389 |
// Try to move them
|
390 |
+
if ( ! @rename( trailingslashit( $from ) . $file, trailingslashit( Path::get_path() ) . $file ) ) {
|
391 |
|
392 |
|
393 |
// If we can't move them then try to copy them
|
394 |
+
copy( trailingslashit( $from ) . $file, trailingslashit( Path::get_path() ) . $file );
|
395 |
|
396 |
}
|
397 |
|
403 |
}
|
404 |
|
405 |
// Delete the old directory if it's inside WP_CONTENT_DIR
|
406 |
+
if ( false !== strpos( $from, WP_CONTENT_DIR ) && $from !== Path::get_path() ) {
|
407 |
+
rmdirtree( $from );
|
408 |
}
|
409 |
|
410 |
}
|
415 |
public function cleanup() {
|
416 |
|
417 |
// Don't cleanup a custom path, who knows what other stuff is there
|
418 |
+
if ( Path::get_path() === $this->get_custom_path() ) {
|
419 |
return;
|
420 |
}
|
421 |
|
classes/class-plugin.php
CHANGED
@@ -6,7 +6,7 @@ namespace HM\BackUpWordPress;
|
|
6 |
* Class Plugin
|
7 |
*/
|
8 |
final class Plugin {
|
9 |
-
const PLUGIN_VERSION = '3.
|
10 |
|
11 |
/**
|
12 |
* @var Plugin The singleton instance.
|
@@ -131,12 +131,26 @@ final class Plugin {
|
|
131 |
require_once( HMBKP_PLUGIN_PATH . 'classes/class-requirement.php' );
|
132 |
|
133 |
require_once( HMBKP_PLUGIN_PATH . 'classes/class-path.php' );
|
|
|
|
|
134 |
|
135 |
-
|
136 |
-
require_once( HMBKP_PLUGIN_PATH . 'classes/class-backup.php' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
137 |
|
138 |
// Load the backup scheduling classes
|
139 |
-
require_once( HMBKP_PLUGIN_PATH . 'classes/class-
|
140 |
require_once( HMBKP_PLUGIN_PATH . 'classes/class-schedules.php' );
|
141 |
|
142 |
// Load the core functions
|
@@ -253,7 +267,7 @@ final class Plugin {
|
|
253 |
|
254 |
// Fire the update action
|
255 |
if ( self::PLUGIN_VERSION != get_option( 'hmbkp_plugin_version' ) ) {
|
256 |
-
|
257 |
}
|
258 |
|
259 |
}
|
@@ -319,7 +333,7 @@ final class Plugin {
|
|
319 |
*/
|
320 |
public function schedule_hook_run( $schedule_id ) {
|
321 |
|
322 |
-
if ( !
|
323 |
return;
|
324 |
}
|
325 |
|
@@ -399,4 +413,5 @@ final class Plugin {
|
|
399 |
if ( is_multisite() && ! is_main_site() ) {
|
400 |
return;
|
401 |
}
|
|
|
402 |
Plugin::get_instance();
|
6 |
* Class Plugin
|
7 |
*/
|
8 |
final class Plugin {
|
9 |
+
const PLUGIN_VERSION = '3.4.0';
|
10 |
|
11 |
/**
|
12 |
* @var Plugin The singleton instance.
|
131 |
require_once( HMBKP_PLUGIN_PATH . 'classes/class-requirement.php' );
|
132 |
|
133 |
require_once( HMBKP_PLUGIN_PATH . 'classes/class-path.php' );
|
134 |
+
require_once( HMBKP_PLUGIN_PATH . 'classes/class-excludes.php' );
|
135 |
+
require_once( HMBKP_PLUGIN_PATH . 'classes/class-site-size.php' );
|
136 |
|
137 |
+
require_once( HMBKP_PLUGIN_PATH . 'classes/backup/class-backup-utilities.php' );
|
138 |
+
require_once( HMBKP_PLUGIN_PATH . 'classes/backup/class-backup-status.php' );
|
139 |
+
|
140 |
+
require_once( HMBKP_PLUGIN_PATH . 'classes/backup/class-backup-engine.php' );
|
141 |
+
|
142 |
+
require_once( HMBKP_PLUGIN_PATH . 'classes/backup/class-backup-engine-database.php' );
|
143 |
+
require_once( HMBKP_PLUGIN_PATH . 'classes/backup/class-backup-engine-database-mysqldump.php' );
|
144 |
+
require_once( HMBKP_PLUGIN_PATH . 'classes/backup/class-backup-engine-database-imysqldump.php' );
|
145 |
+
|
146 |
+
require_once( HMBKP_PLUGIN_PATH . 'classes/backup/class-backup-engine-file.php' );
|
147 |
+
require_once( HMBKP_PLUGIN_PATH . 'classes/backup/class-backup-engine-file-zip.php' );
|
148 |
+
require_once( HMBKP_PLUGIN_PATH . 'classes/backup/class-backup-engine-file-zip-archive.php' );
|
149 |
+
|
150 |
+
require_once( HMBKP_PLUGIN_PATH . 'classes/backup/class-backup.php' );
|
151 |
|
152 |
// Load the backup scheduling classes
|
153 |
+
require_once( HMBKP_PLUGIN_PATH . 'classes/class-scheduled-backup.php' );
|
154 |
require_once( HMBKP_PLUGIN_PATH . 'classes/class-schedules.php' );
|
155 |
|
156 |
// Load the core functions
|
267 |
|
268 |
// Fire the update action
|
269 |
if ( self::PLUGIN_VERSION != get_option( 'hmbkp_plugin_version' ) ) {
|
270 |
+
update();
|
271 |
}
|
272 |
|
273 |
}
|
333 |
*/
|
334 |
public function schedule_hook_run( $schedule_id ) {
|
335 |
|
336 |
+
if ( ! is_backup_possible() ) {
|
337 |
return;
|
338 |
}
|
339 |
|
413 |
if ( is_multisite() && ! is_main_site() ) {
|
414 |
return;
|
415 |
}
|
416 |
+
|
417 |
Plugin::get_instance();
|
classes/class-requirement.php
CHANGED
@@ -126,9 +126,9 @@ class Requirement_Zip_Command_Path extends Requirement {
|
|
126 |
*/
|
127 |
protected function test() {
|
128 |
|
129 |
-
$
|
130 |
|
131 |
-
return $
|
132 |
|
133 |
}
|
134 |
|
@@ -152,9 +152,9 @@ class Requirement_Mysqldump_Command_Path extends Requirement {
|
|
152 |
*/
|
153 |
protected function test() {
|
154 |
|
155 |
-
$
|
156 |
|
157 |
-
return $
|
158 |
|
159 |
}
|
160 |
|
@@ -176,7 +176,7 @@ class Requirement_PHP_User extends Requirement {
|
|
176 |
*/
|
177 |
protected function test() {
|
178 |
|
179 |
-
if ( !
|
180 |
return '';
|
181 |
}
|
182 |
|
@@ -202,7 +202,7 @@ class Requirement_PHP_Group extends Requirement {
|
|
202 |
*/
|
203 |
protected function test() {
|
204 |
|
205 |
-
if ( !
|
206 |
return '';
|
207 |
}
|
208 |
|
@@ -308,7 +308,7 @@ class Requirement_Safe_Mode extends Requirement {
|
|
308 |
* @return bool
|
309 |
*/
|
310 |
protected function test() {
|
311 |
-
return
|
312 |
}
|
313 |
|
314 |
}
|
@@ -328,7 +328,7 @@ class Requirement_Shell_Exec extends Requirement {
|
|
328 |
* @return bool
|
329 |
*/
|
330 |
protected function test() {
|
331 |
-
return
|
332 |
}
|
333 |
|
334 |
}
|
@@ -368,7 +368,7 @@ class Requirement_Backup_Path extends Requirement {
|
|
368 |
* @return string
|
369 |
*/
|
370 |
protected function test() {
|
371 |
-
return Path::
|
372 |
}
|
373 |
|
374 |
}
|
@@ -388,7 +388,7 @@ class Requirement_Backup_Path_Permissions extends Requirement {
|
|
388 |
* @return string
|
389 |
*/
|
390 |
protected function test() {
|
391 |
-
return substr( sprintf( '%o', fileperms(
|
392 |
}
|
393 |
|
394 |
}
|
@@ -462,17 +462,13 @@ class Requirement_Backup_Root_Path extends Requirement {
|
|
462 |
/**
|
463 |
* @var string
|
464 |
*/
|
465 |
-
var $name = '
|
466 |
|
467 |
/**
|
468 |
* @return string
|
469 |
*/
|
470 |
protected function test() {
|
471 |
-
|
472 |
-
$hm_backup = new Backup();
|
473 |
-
|
474 |
-
return $hm_backup->get_root();
|
475 |
-
|
476 |
}
|
477 |
|
478 |
}
|
@@ -498,9 +494,13 @@ class Requirement_Calculated_Size extends Requirement {
|
|
498 |
$schedules = Schedules::get_instance();
|
499 |
|
500 |
foreach ( $schedules->get_schedules() as $schedule ) {
|
501 |
-
|
502 |
-
|
|
|
|
|
|
|
503 |
}
|
|
|
504 |
}
|
505 |
|
506 |
return $backup_sizes;
|
126 |
*/
|
127 |
protected function test() {
|
128 |
|
129 |
+
$backup = new Zip_File_Backup_Engine;
|
130 |
|
131 |
+
return $backup->get_zip_executable_path();
|
132 |
|
133 |
}
|
134 |
|
152 |
*/
|
153 |
protected function test() {
|
154 |
|
155 |
+
$backup = new Mysqldump_Database_Backup_Engine;
|
156 |
|
157 |
+
return $backup->get_mysqldump_executable_path();
|
158 |
|
159 |
}
|
160 |
|
176 |
*/
|
177 |
protected function test() {
|
178 |
|
179 |
+
if ( ! Backup_Utilities::is_exec_available() ) {
|
180 |
return '';
|
181 |
}
|
182 |
|
202 |
*/
|
203 |
protected function test() {
|
204 |
|
205 |
+
if ( ! Backup_Utilities::is_exec_available() ) {
|
206 |
return '';
|
207 |
}
|
208 |
|
308 |
* @return bool
|
309 |
*/
|
310 |
protected function test() {
|
311 |
+
return Backup_Utilities::is_safe_mode_on();
|
312 |
}
|
313 |
|
314 |
}
|
328 |
* @return bool
|
329 |
*/
|
330 |
protected function test() {
|
331 |
+
return Backup_Utilities::is_exec_available();
|
332 |
}
|
333 |
|
334 |
}
|
368 |
* @return string
|
369 |
*/
|
370 |
protected function test() {
|
371 |
+
return Path::get_path();
|
372 |
}
|
373 |
|
374 |
}
|
388 |
* @return string
|
389 |
*/
|
390 |
protected function test() {
|
391 |
+
return substr( sprintf( '%o', fileperms( Path::get_path() ) ), - 4 );
|
392 |
}
|
393 |
|
394 |
}
|
462 |
/**
|
463 |
* @var string
|
464 |
*/
|
465 |
+
var $name = 'Site Root Path';
|
466 |
|
467 |
/**
|
468 |
* @return string
|
469 |
*/
|
470 |
protected function test() {
|
471 |
+
return Path::get_root();
|
|
|
|
|
|
|
|
|
472 |
}
|
473 |
|
474 |
}
|
494 |
$schedules = Schedules::get_instance();
|
495 |
|
496 |
foreach ( $schedules->get_schedules() as $schedule ) {
|
497 |
+
|
498 |
+
$site_size = new Site_Size( $schedule->get_type(), $schedule->get_excludes() );
|
499 |
+
|
500 |
+
if ( $site_size->is_site_size_cached() ) {
|
501 |
+
$backup_sizes[ $schedule->get_type() ] = $site_size->get_formatted_site_size();
|
502 |
}
|
503 |
+
|
504 |
}
|
505 |
|
506 |
return $backup_sizes;
|
classes/class-schedule.php
DELETED
@@ -1,1173 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace HM\BackUpWordPress;
|
4 |
-
|
5 |
-
use Symfony\Component\Finder\Finder;
|
6 |
-
|
7 |
-
/**
|
8 |
-
* The Backup Scheduler
|
9 |
-
*
|
10 |
-
* Handles everything related to managing and running a backup schedule
|
11 |
-
*
|
12 |
-
* @uses Backup
|
13 |
-
* @uses
|
14 |
-
*/
|
15 |
-
class Scheduled_Backup {
|
16 |
-
|
17 |
-
/**
|
18 |
-
* The unique schedule id
|
19 |
-
*
|
20 |
-
* @var string
|
21 |
-
* @access private
|
22 |
-
*/
|
23 |
-
private $id = '';
|
24 |
-
|
25 |
-
/**
|
26 |
-
* The slugified version of the schedule name
|
27 |
-
*
|
28 |
-
* @var string
|
29 |
-
* @access private
|
30 |
-
*/
|
31 |
-
private $slug = '';
|
32 |
-
|
33 |
-
/**
|
34 |
-
* The raw schedule options from the database
|
35 |
-
*
|
36 |
-
* @var array
|
37 |
-
* @access private
|
38 |
-
*/
|
39 |
-
private $options = array();
|
40 |
-
|
41 |
-
/**
|
42 |
-
* The Backup instance
|
43 |
-
*
|
44 |
-
* @var Backup
|
45 |
-
*/
|
46 |
-
public $backup;
|
47 |
-
|
48 |
-
/**
|
49 |
-
* Setup the schedule object
|
50 |
-
* Loads the options from the database and populates properties
|
51 |
-
*
|
52 |
-
* @param string $id
|
53 |
-
*
|
54 |
-
* @throws Exception
|
55 |
-
*/
|
56 |
-
|
57 |
-
public function __construct( $id ) {
|
58 |
-
|
59 |
-
// Verify the schedule id
|
60 |
-
if ( ! is_string( $id ) || ! trim( $id ) ) {
|
61 |
-
throw new \Exception( 'Argument 1 for ' . __METHOD__ . ' must be a non-empty string' );
|
62 |
-
}
|
63 |
-
|
64 |
-
// Store id for later
|
65 |
-
$this->id = $id;
|
66 |
-
|
67 |
-
// Load the options
|
68 |
-
$this->options = array_filter( (array) get_option( 'hmbkp_schedule_' . $this->get_id() ) );
|
69 |
-
|
70 |
-
// Setup The Backup class
|
71 |
-
$this->backup = new Backup();
|
72 |
-
|
73 |
-
// Set the archive filename to site name + schedule slug + date
|
74 |
-
$this->backup->set_archive_filename( implode( '-', array(
|
75 |
-
sanitize_title( str_ireplace( array(
|
76 |
-
'http://',
|
77 |
-
'https://',
|
78 |
-
'www'
|
79 |
-
), '', home_url() ) ),
|
80 |
-
$this->get_id(),
|
81 |
-
$this->get_type(),
|
82 |
-
current_time( 'Y-m-d-H-i-s' )
|
83 |
-
) ) . '.zip' );
|
84 |
-
|
85 |
-
$this->backup->set_database_dump_filename( implode( '-', array(
|
86 |
-
'database',
|
87 |
-
sanitize_title( str_ireplace( array( 'http://', 'https://', 'www' ), '', home_url() ) ),
|
88 |
-
$this->get_id()
|
89 |
-
) ) . '.sql' );
|
90 |
-
|
91 |
-
$this->backup->set_type( $this->get_type() );
|
92 |
-
$this->backup->set_excludes( $this->backup->default_excludes(), true );
|
93 |
-
$this->backup->set_excludes( $this->get_excludes() );
|
94 |
-
$this->backup->set_action_callback( array( $this, 'do_action' ) );
|
95 |
-
|
96 |
-
if ( defined( 'HMBKP_SCHEDULE_START_TIME' ) && strtotime( 'HMBKP_SCHEDULE_START_TIME' ) ) {
|
97 |
-
$this->set_schedule_start_time( strtotime( 'HMBKP_SCHEDULE_START_TIME' ) );
|
98 |
-
}
|
99 |
-
|
100 |
-
// Setup the schedule if it isn't set
|
101 |
-
if ( ( ! $this->is_cron_scheduled() && $this->get_reoccurrence() !== 'manually' ) ) {
|
102 |
-
$this->schedule();
|
103 |
-
}
|
104 |
-
|
105 |
-
}
|
106 |
-
|
107 |
-
/**
|
108 |
-
* Simple class wrapper for Path::get_path()
|
109 |
-
*
|
110 |
-
* @return string
|
111 |
-
*/
|
112 |
-
private function get_path() {
|
113 |
-
return Path::get_instance()->get_path();
|
114 |
-
}
|
115 |
-
|
116 |
-
/**
|
117 |
-
* Get the id for this schedule
|
118 |
-
*
|
119 |
-
*/
|
120 |
-
public function get_id() {
|
121 |
-
return esc_attr( $this->id );
|
122 |
-
}
|
123 |
-
|
124 |
-
/**
|
125 |
-
* Get a slugified version of name
|
126 |
-
*
|
127 |
-
*/
|
128 |
-
public function get_slug() {
|
129 |
-
|
130 |
-
// We cache slug in $this to save expensive calls to sanitize_title
|
131 |
-
if ( ! empty( $this->slug ) ) {
|
132 |
-
return $this->slug;
|
133 |
-
}
|
134 |
-
|
135 |
-
return $this->slug = sanitize_title( $this->get_name() );
|
136 |
-
|
137 |
-
}
|
138 |
-
|
139 |
-
/**
|
140 |
-
* Returns the given option value or WP_Error if it doesn't exist
|
141 |
-
*
|
142 |
-
* @param $option_name
|
143 |
-
* @return \WP_Error
|
144 |
-
*/
|
145 |
-
public function get_schedule_option( $option_name ) {
|
146 |
-
|
147 |
-
if ( isset( $this->options[ $option_name ] ) ) {
|
148 |
-
return $this->options[ $option_name ];
|
149 |
-
} else {
|
150 |
-
return new \WP_Error( 'invalid_option_name', __( 'Invalid Option Name', 'backupwordpress' ) );
|
151 |
-
}
|
152 |
-
}
|
153 |
-
|
154 |
-
/**
|
155 |
-
* Get the name of this backup schedule
|
156 |
-
*
|
157 |
-
* @return string
|
158 |
-
*/
|
159 |
-
public function get_name() {
|
160 |
-
|
161 |
-
return ucwords( $this->get_type() ) . ' ' . $this->get_reoccurrence();
|
162 |
-
|
163 |
-
}
|
164 |
-
|
165 |
-
/**
|
166 |
-
* Get the type of backup
|
167 |
-
*
|
168 |
-
* @return string
|
169 |
-
*/
|
170 |
-
public function get_type() {
|
171 |
-
|
172 |
-
if ( empty( $this->options['type'] ) ) {
|
173 |
-
$this->set_type( 'complete' );
|
174 |
-
}
|
175 |
-
|
176 |
-
return $this->options['type'];
|
177 |
-
|
178 |
-
}
|
179 |
-
|
180 |
-
/**
|
181 |
-
* Set the type of backup
|
182 |
-
*
|
183 |
-
* @param string $type
|
184 |
-
*/
|
185 |
-
public function set_type( $type ) {
|
186 |
-
|
187 |
-
if ( isset( $this->options['type'] ) && $this->options['type'] === $type ) {
|
188 |
-
return;
|
189 |
-
}
|
190 |
-
|
191 |
-
$this->backup->set_type( $type );
|
192 |
-
|
193 |
-
$this->options['type'] = $type;
|
194 |
-
|
195 |
-
}
|
196 |
-
|
197 |
-
/**
|
198 |
-
* Get the exclude rules
|
199 |
-
*
|
200 |
-
* @return array
|
201 |
-
*/
|
202 |
-
public function get_excludes() {
|
203 |
-
|
204 |
-
if ( ! empty( $this->options['excludes'] ) ) {
|
205 |
-
$this->backup->set_excludes( $this->options['excludes'] );
|
206 |
-
}
|
207 |
-
|
208 |
-
return $this->backup->get_excludes();
|
209 |
-
|
210 |
-
}
|
211 |
-
|
212 |
-
/**
|
213 |
-
* Set the exclude rules
|
214 |
-
*
|
215 |
-
* @param mixed $excludes A comma separated list or array of exclude rules
|
216 |
-
* @param bool $append Whether to replace or append to existing rules
|
217 |
-
*
|
218 |
-
* @return string
|
219 |
-
*/
|
220 |
-
public function set_excludes( $excludes, $append = false ) {
|
221 |
-
|
222 |
-
// Use the validation from Backup::set_excludes
|
223 |
-
$this->backup->set_excludes( $excludes, $append );
|
224 |
-
|
225 |
-
// If these are valid excludes and they are different save them
|
226 |
-
if ( $this->backup->get_excludes() && ( empty( $this->options['excludes'] ) || $this->options['excludes'] !== $this->backup->get_excludes() ) ) {
|
227 |
-
|
228 |
-
$this->options['excludes'] = $append && ! empty( $this->options['excludes'] ) ? array_merge( (array) $this->options['excludes'], $this->backup->get_excludes() ) : $this->backup->get_excludes();;
|
229 |
-
|
230 |
-
$this->backup->set_excludes( $this->options['excludes'] );
|
231 |
-
|
232 |
-
}
|
233 |
-
|
234 |
-
}
|
235 |
-
|
236 |
-
/**
|
237 |
-
* Get the maximum number of backups to keep
|
238 |
-
*
|
239 |
-
* @return int
|
240 |
-
*/
|
241 |
-
public function get_max_backups() {
|
242 |
-
|
243 |
-
if ( empty( $this->options['max_backups'] ) ) {
|
244 |
-
$this->set_max_backups( 3 );
|
245 |
-
}
|
246 |
-
|
247 |
-
return (int) esc_attr( $this->options['max_backups'] );
|
248 |
-
|
249 |
-
}
|
250 |
-
|
251 |
-
/**
|
252 |
-
* Set the maximum number of backups to keep
|
253 |
-
*
|
254 |
-
* @param int $max
|
255 |
-
*
|
256 |
-
* @return WP_Error|boolean
|
257 |
-
*/
|
258 |
-
public function set_max_backups( $max ) {
|
259 |
-
|
260 |
-
if ( empty( $max ) || ! is_int( $max ) ) {
|
261 |
-
return new \WP_Error( 'hmbkp_invalid_type_error', sprintf( __( 'Argument 1 for %s must be a valid integer', 'backupwordpress' ), __METHOD__ ) );
|
262 |
-
}
|
263 |
-
|
264 |
-
$this->options['max_backups'] = $max;
|
265 |
-
|
266 |
-
return true;
|
267 |
-
}
|
268 |
-
|
269 |
-
/**
|
270 |
-
* Get the array of services options for this schedule
|
271 |
-
*
|
272 |
-
* @param $service
|
273 |
-
* @param null $option
|
274 |
-
*
|
275 |
-
* @return array
|
276 |
-
*/
|
277 |
-
public function get_service_options( $service, $option = null ) {
|
278 |
-
|
279 |
-
if ( ! is_null( $option ) ) {
|
280 |
-
|
281 |
-
if ( isset( $this->options[ $service ][ $option ] ) ) {
|
282 |
-
return $this->options[ $service ][ $option ];
|
283 |
-
}
|
284 |
-
|
285 |
-
return array();
|
286 |
-
|
287 |
-
}
|
288 |
-
|
289 |
-
if ( isset( $this->options[ $service ] ) ) {
|
290 |
-
return $this->options[ $service ];
|
291 |
-
}
|
292 |
-
|
293 |
-
return array();
|
294 |
-
|
295 |
-
}
|
296 |
-
|
297 |
-
/**
|
298 |
-
* Set the service options for this schedule
|
299 |
-
*
|
300 |
-
* @param $service
|
301 |
-
* @param array $options
|
302 |
-
*/
|
303 |
-
public function set_service_options( $service, Array $options ) {
|
304 |
-
|
305 |
-
$this->options[ $service ] = $options;
|
306 |
-
}
|
307 |
-
|
308 |
-
/**
|
309 |
-
* Calculate the size total size of the database + files
|
310 |
-
*
|
311 |
-
* Doesn't account for compression
|
312 |
-
*
|
313 |
-
* @return string
|
314 |
-
*/
|
315 |
-
public function get_site_size( $skip_excluded_files = false ) {
|
316 |
-
|
317 |
-
$size = 0;
|
318 |
-
|
319 |
-
// Include database size except for file only schedule.
|
320 |
-
if ( 'file' !== $this->get_type() ) {
|
321 |
-
|
322 |
-
global $wpdb;
|
323 |
-
|
324 |
-
$tables = $wpdb->get_results( 'SHOW TABLE STATUS FROM `' . DB_NAME . '`', ARRAY_A );
|
325 |
-
|
326 |
-
foreach ( $tables as $table ) {
|
327 |
-
$size += (float) $table['Data_length'];
|
328 |
-
}
|
329 |
-
}
|
330 |
-
|
331 |
-
// Include total size of dirs/files except for database only schedule.
|
332 |
-
if ( 'database' !== $this->get_type() ) {
|
333 |
-
|
334 |
-
$root = new \SplFileInfo( $this->backup->get_root() );
|
335 |
-
|
336 |
-
$size += $this->filesize( $root, $skip_excluded_files );
|
337 |
-
|
338 |
-
}
|
339 |
-
|
340 |
-
return $size;
|
341 |
-
|
342 |
-
}
|
343 |
-
|
344 |
-
/**
|
345 |
-
* Convenience function to format the file size
|
346 |
-
*
|
347 |
-
* @param bool $cached
|
348 |
-
*
|
349 |
-
* @return bool|string
|
350 |
-
*/
|
351 |
-
public function get_formatted_site_size( $skip_excluded_files = false ) {
|
352 |
-
return size_format( $this->get_site_size( $skip_excluded_files ) );
|
353 |
-
}
|
354 |
-
|
355 |
-
/**
|
356 |
-
* Whether the total filesize is being calculated
|
357 |
-
*
|
358 |
-
* @return int The total of the file or directory
|
359 |
-
*/
|
360 |
-
public function is_site_size_being_calculated() {
|
361 |
-
return false !== get_transient( 'hmbkp_directory_filesizes_running' );
|
362 |
-
}
|
363 |
-
|
364 |
-
/**
|
365 |
-
* Whether the total filesize is being calculated
|
366 |
-
*
|
367 |
-
* @return bool The total of the file or directory
|
368 |
-
*/
|
369 |
-
public function is_site_size_cached() {
|
370 |
-
return false !== get_transient( 'hmbkp_directory_filesizes' );
|
371 |
-
}
|
372 |
-
|
373 |
-
/**
|
374 |
-
* Return the single depth list of files and subdirectories in $directory ordered by total filesize
|
375 |
-
*
|
376 |
-
* Will schedule background threads to recursively calculate the filesize of subdirectories.
|
377 |
-
* The total filesize of each directory and subdirectory is cached in a transient for 1 week.
|
378 |
-
*
|
379 |
-
* @param string $directory The directory to scan
|
380 |
-
*
|
381 |
-
* @return array returns an array of files ordered by filesize
|
382 |
-
*/
|
383 |
-
public function list_directory_by_total_filesize( $directory ) {
|
384 |
-
|
385 |
-
$files = $files_with_no_size = $empty_files = $files_with_size = $unreadable_files = array();
|
386 |
-
|
387 |
-
if ( ! is_dir( $directory ) ) {
|
388 |
-
return $files;
|
389 |
-
}
|
390 |
-
|
391 |
-
$found = array();
|
392 |
-
|
393 |
-
if ( ! empty( $this->files ) ) {
|
394 |
-
return $this->files;
|
395 |
-
}
|
396 |
-
|
397 |
-
$default_excludes = $this->backup->default_excludes();
|
398 |
-
|
399 |
-
$finder = new Finder();
|
400 |
-
$finder->ignoreDotFiles( false );
|
401 |
-
$finder->ignoreUnreadableDirs();
|
402 |
-
$finder->followLinks();
|
403 |
-
$finder->depth( '== 0' );
|
404 |
-
|
405 |
-
foreach ( $default_excludes as $exclude ) {
|
406 |
-
$finder->notPath( $exclude );
|
407 |
-
}
|
408 |
-
|
409 |
-
foreach ( $finder->in( $directory ) as $entry ) {
|
410 |
-
$files[] = $entry;
|
411 |
-
// Get the total filesize for each file and directory
|
412 |
-
$filesize = $this->filesize( $entry );
|
413 |
-
|
414 |
-
if ( $filesize ) {
|
415 |
-
|
416 |
-
// If there is already a file with exactly the same filesize then let's keep increasing the filesize of this one until we don't have a clash
|
417 |
-
while ( array_key_exists( $filesize, $files_with_size ) ) {
|
418 |
-
$filesize ++;
|
419 |
-
}
|
420 |
-
|
421 |
-
$files_with_size[ $filesize ] = $entry;
|
422 |
-
|
423 |
-
} elseif ( 0 === $filesize ) {
|
424 |
-
|
425 |
-
$empty_files[] = $entry;
|
426 |
-
|
427 |
-
} else {
|
428 |
-
|
429 |
-
$files_with_no_size[] = $entry;
|
430 |
-
|
431 |
-
}
|
432 |
-
}
|
433 |
-
|
434 |
-
// Add 0 byte files / directories to the bottom
|
435 |
-
$files = $files_with_size + array_merge( $empty_files, $unreadable_files );
|
436 |
-
|
437 |
-
// Add directories that are still calculating to the top
|
438 |
-
if ( $files_with_no_size ) {
|
439 |
-
|
440 |
-
// We have to loop as merging or concatenating the array would re-flow the keys which we don't want because the filesize is stored in the key
|
441 |
-
foreach ( $files_with_no_size as $entry ) {
|
442 |
-
array_unshift( $files, $entry );
|
443 |
-
}
|
444 |
-
}
|
445 |
-
|
446 |
-
return $files;
|
447 |
-
|
448 |
-
}
|
449 |
-
|
450 |
-
/**
|
451 |
-
* Recursively scans a directory to calculate the total filesize
|
452 |
-
*
|
453 |
-
* Locks should be set by the caller with `set_transient( 'hmbkp_directory_filesizes_running', true, HOUR_IN_SECONDS );`
|
454 |
-
*
|
455 |
-
* @return array $directory_sizes An array of directory paths => filesize sum of all files in directory
|
456 |
-
*/
|
457 |
-
public function recursive_filesize_scanner() {
|
458 |
-
|
459 |
-
// Use the cached array directory sizes if available
|
460 |
-
$directory_sizes = get_transient( 'hmbkp_directory_filesizes' );
|
461 |
-
|
462 |
-
// If we do have it in cache then let's use it and also clear the lock
|
463 |
-
if ( is_array( $directory_sizes ) ) {
|
464 |
-
|
465 |
-
delete_transient( 'hmbkp_directory_filesizes_running' );
|
466 |
-
|
467 |
-
return $directory_sizes;
|
468 |
-
|
469 |
-
}
|
470 |
-
|
471 |
-
// If we don't have it cached then we'll need to re-calculate
|
472 |
-
$files = $this->backup->get_files();
|
473 |
-
|
474 |
-
foreach ( $files as $file ) {
|
475 |
-
|
476 |
-
if ( $file->isReadable() ) {
|
477 |
-
$directory_sizes[ wp_normalize_path( $file->getRealpath() ) ] = $file->getSize();
|
478 |
-
} else {
|
479 |
-
$directory_sizes[ wp_normalize_path( $file->getRealpath() ) ] = 0;
|
480 |
-
}
|
481 |
-
|
482 |
-
}
|
483 |
-
|
484 |
-
set_transient( 'hmbkp_directory_filesizes', $directory_sizes, DAY_IN_SECONDS );
|
485 |
-
|
486 |
-
delete_transient( 'hmbkp_directory_filesizes_running' );
|
487 |
-
|
488 |
-
return $directory_sizes;
|
489 |
-
|
490 |
-
}
|
491 |
-
|
492 |
-
/**
|
493 |
-
* Get the total filesize for a given file or directory
|
494 |
-
*
|
495 |
-
* If $file is a file then just return the result of `filesize()`.
|
496 |
-
* If $file is a directory then schedule a recursive filesize scan.
|
497 |
-
*
|
498 |
-
* @param \SplFileInfo $file The file or directory you want to know the size of
|
499 |
-
* @param bool $skip_excluded_files Skip excluded files when calculating a directories total size
|
500 |
-
*
|
501 |
-
* @return int The total of the file or directory
|
502 |
-
*/
|
503 |
-
public function filesize( \SplFileInfo $file, $skip_excluded_files = false ) {
|
504 |
-
|
505 |
-
// Skip missing or unreadable files
|
506 |
-
if ( ! file_exists( $file->getPathname() ) || ! $file->getRealpath() || ! $file->isReadable() ) {
|
507 |
-
return 0;
|
508 |
-
}
|
509 |
-
|
510 |
-
// If it's a file then just pass back the filesize
|
511 |
-
if ( $file->isFile() && $file->isReadable() ) {
|
512 |
-
return $file->getSize();
|
513 |
-
}
|
514 |
-
|
515 |
-
// If it's a directory then pull it from the cached filesize array
|
516 |
-
if ( $file->isDir() ) {
|
517 |
-
|
518 |
-
// If we haven't calculated the site size yet then kick it off in a thread
|
519 |
-
$directory_sizes = get_transient( 'hmbkp_directory_filesizes' );
|
520 |
-
|
521 |
-
if ( ! is_array( $directory_sizes ) ) {
|
522 |
-
|
523 |
-
if ( ! $this->is_site_size_being_calculated() ) {
|
524 |
-
|
525 |
-
// Mark the filesize as being calculated
|
526 |
-
set_transient( 'hmbkp_directory_filesizes_running', true, HOUR_IN_SECONDS );
|
527 |
-
|
528 |
-
// Schedule a Backdrop task to trigger a recalculation
|
529 |
-
$task = new \HM\Backdrop\Task( array( $this, 'recursive_filesize_scanner' ) );
|
530 |
-
$task->schedule();
|
531 |
-
|
532 |
-
}
|
533 |
-
|
534 |
-
return 0;
|
535 |
-
|
536 |
-
}
|
537 |
-
|
538 |
-
$current_pathname = trailingslashit( $file->getPathname() );
|
539 |
-
$root = trailingslashit( $this->backup->get_root() );
|
540 |
-
|
541 |
-
foreach ( $directory_sizes as $path => $size ) {
|
542 |
-
|
543 |
-
// Remove any files that aren't part of the current tree
|
544 |
-
if ( false === strpos( $path, $current_pathname ) ) {
|
545 |
-
unset( $directory_sizes[ $path ] );
|
546 |
-
}
|
547 |
-
|
548 |
-
}
|
549 |
-
|
550 |
-
if ( $skip_excluded_files ) {
|
551 |
-
|
552 |
-
$excludes = $this->backup->exclude_string( 'regex' );
|
553 |
-
|
554 |
-
foreach ( $directory_sizes as $path => $size ) {
|
555 |
-
|
556 |
-
// Skip excluded files if we have excludes
|
557 |
-
if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( $root, '', wp_normalize_path( $path ) ) ) ) {
|
558 |
-
unset( $directory_sizes[ $path ] );
|
559 |
-
}
|
560 |
-
|
561 |
-
}
|
562 |
-
|
563 |
-
}
|
564 |
-
|
565 |
-
// Directory size is now just a sum of all files across all sub directories
|
566 |
-
return absint( array_sum( $directory_sizes ) );
|
567 |
-
|
568 |
-
}
|
569 |
-
|
570 |
-
}
|
571 |
-
|
572 |
-
/**
|
573 |
-
* Get the start time for the schedule
|
574 |
-
*
|
575 |
-
* @return int timestamp || 0 for manual only schedules
|
576 |
-
*/
|
577 |
-
public function get_schedule_start_time( $gmt = true ) {
|
578 |
-
|
579 |
-
if ( 'manually' === $this->get_reoccurrence() ) {
|
580 |
-
return 0;
|
581 |
-
}
|
582 |
-
|
583 |
-
if ( ! $gmt ) {
|
584 |
-
$offset = get_option( 'gmt_offset' ) * 3600;
|
585 |
-
} else {
|
586 |
-
$offset = 0;
|
587 |
-
}
|
588 |
-
if ( ! empty( $this->options['schedule_start_time'] ) ) {
|
589 |
-
return $this->options['schedule_start_time'] + $offset;
|
590 |
-
}
|
591 |
-
|
592 |
-
$this->set_schedule_start_time( time() );
|
593 |
-
|
594 |
-
return time() + $offset;
|
595 |
-
|
596 |
-
}
|
597 |
-
|
598 |
-
/**
|
599 |
-
* Set the schedule start time.
|
600 |
-
*
|
601 |
-
* @param array $args
|
602 |
-
*/
|
603 |
-
public function set_schedule_start_time( $time ) {
|
604 |
-
|
605 |
-
// Don't allow setting the start time in the past
|
606 |
-
if ( (int) $time <= time() ) {
|
607 |
-
return new \WP_Error( 'hmbkp_invalid_argument_error', sprintf( __( 'Argument 1 for %s must be a valid future timestamp', 'backupwordpress' ), __METHOD__ ) );
|
608 |
-
}
|
609 |
-
|
610 |
-
$this->options['schedule_start_time'] = $time;
|
611 |
-
|
612 |
-
$this->schedule();
|
613 |
-
|
614 |
-
}
|
615 |
-
|
616 |
-
/**
|
617 |
-
* Get the schedule reoccurrence
|
618 |
-
*
|
619 |
-
*/
|
620 |
-
public function get_reoccurrence() {
|
621 |
-
|
622 |
-
// Default to no reoccurrence
|
623 |
-
if ( empty( $this->options['reoccurrence'] ) ) {
|
624 |
-
$this->set_reoccurrence( 'manually' );
|
625 |
-
}
|
626 |
-
|
627 |
-
return $this->options['reoccurrence'];
|
628 |
-
|
629 |
-
}
|
630 |
-
|
631 |
-
/**
|
632 |
-
* Set the schedule reoccurrence
|
633 |
-
*
|
634 |
-
* @param string $reoccurrence
|
635 |
-
*
|
636 |
-
* @return \WP_Error|null|boolean
|
637 |
-
*/
|
638 |
-
public function set_reoccurrence( $reoccurrence ) {
|
639 |
-
|
640 |
-
$hmbkp_schedules = $this->get_cron_schedules();
|
641 |
-
|
642 |
-
// Check it's valid
|
643 |
-
if ( ! is_string( $reoccurrence ) || ! trim( $reoccurrence ) || ( ! in_array( $reoccurrence, array_keys( $hmbkp_schedules ) ) ) && 'manually' !== $reoccurrence ) {
|
644 |
-
return new \WP_Error( 'hmbkp_invalid_argument_error', sprintf( __( 'Argument 1 for %s must be a valid cron recurrence or "manually"', 'backupwordpress' ), __METHOD__ ) );
|
645 |
-
}
|
646 |
-
|
647 |
-
// If the recurrence is already set to the same thing then there's no need to continue
|
648 |
-
if ( isset( $this->options['reoccurrence'] ) && $this->options['reoccurrence'] === $reoccurrence && $this->is_cron_scheduled() ) {
|
649 |
-
return;
|
650 |
-
}
|
651 |
-
|
652 |
-
|
653 |
-
$this->options['reoccurrence'] = $reoccurrence;
|
654 |
-
|
655 |
-
if ( 'manually' === $reoccurrence ) {
|
656 |
-
$this->unschedule();
|
657 |
-
} else {
|
658 |
-
$this->schedule();
|
659 |
-
}
|
660 |
-
|
661 |
-
return true;
|
662 |
-
|
663 |
-
}
|
664 |
-
|
665 |
-
/**
|
666 |
-
* Get the interval between backups
|
667 |
-
*
|
668 |
-
* @return int
|
669 |
-
*/
|
670 |
-
public function get_interval() {
|
671 |
-
|
672 |
-
$hmbkp_schedules = $this->get_cron_schedules();
|
673 |
-
|
674 |
-
if ( 'manually' === $this->get_reoccurrence() ) {
|
675 |
-
return 0;
|
676 |
-
}
|
677 |
-
|
678 |
-
return $hmbkp_schedules[ $this->get_reoccurrence() ]['interval'];
|
679 |
-
|
680 |
-
}
|
681 |
-
|
682 |
-
/**
|
683 |
-
* Return an array of BackUpWordPress cron schedules
|
684 |
-
*
|
685 |
-
* @return array
|
686 |
-
*/
|
687 |
-
public static function get_cron_schedules() {
|
688 |
-
return hmbkp_cron_schedules();
|
689 |
-
}
|
690 |
-
|
691 |
-
/**
|
692 |
-
* Get the next occurrence of this scheduled backup
|
693 |
-
*
|
694 |
-
*/
|
695 |
-
public function get_next_occurrence( $gmt = true ) {
|
696 |
-
|
697 |
-
$time = wp_next_scheduled( 'hmbkp_schedule_hook', array( 'id' => $this->get_id() ) );
|
698 |
-
|
699 |
-
if ( ! $time ) {
|
700 |
-
$time = 0;
|
701 |
-
}
|
702 |
-
|
703 |
-
|
704 |
-
if ( ! $gmt ) {
|
705 |
-
$time += get_option( 'gmt_offset' ) * 3600;
|
706 |
-
}
|
707 |
-
|
708 |
-
return $time;
|
709 |
-
|
710 |
-
}
|
711 |
-
|
712 |
-
public function is_cron_scheduled() {
|
713 |
-
return (bool) $this->get_next_occurrence();
|
714 |
-
}
|
715 |
-
|
716 |
-
|
717 |
-
/**
|
718 |
-
* Get the path to the backup running file that stores the running backup status
|
719 |
-
*
|
720 |
-
* @return string
|
721 |
-
*/
|
722 |
-
public function get_schedule_running_path() {
|
723 |
-
return $this->get_path() . '/.schedule-' . $this->get_id() . '-running';
|
724 |
-
}
|
725 |
-
|
726 |
-
/**
|
727 |
-
* Schedule the backup cron
|
728 |
-
*
|
729 |
-
*/
|
730 |
-
public function schedule() {
|
731 |
-
|
732 |
-
// Clear any existing hooks
|
733 |
-
$this->unschedule();
|
734 |
-
|
735 |
-
$schedule_timestamp = $this->get_schedule_start_time();
|
736 |
-
|
737 |
-
wp_schedule_event( $schedule_timestamp, $this->get_reoccurrence(), 'hmbkp_schedule_hook', array( 'id' => $this->get_id() ) );
|
738 |
-
|
739 |
-
}
|
740 |
-
|
741 |
-
|
742 |
-
/**
|
743 |
-
* Unschedule the backup cron.
|
744 |
-
*
|
745 |
-
* @return void
|
746 |
-
*/
|
747 |
-
public function unschedule() {
|
748 |
-
wp_clear_scheduled_hook( 'hmbkp_schedule_hook', array( 'id' => $this->get_id() ) );
|
749 |
-
}
|
750 |
-
|
751 |
-
/**
|
752 |
-
* Run the backup
|
753 |
-
*
|
754 |
-
*/
|
755 |
-
public function run() {
|
756 |
-
|
757 |
-
// Don't run if this schedule is already running
|
758 |
-
if ( $this->get_running_backup_filename() ) {
|
759 |
-
return;
|
760 |
-
}
|
761 |
-
|
762 |
-
// Mark the backup as started
|
763 |
-
$this->set_status( __( 'Starting Backup', 'backupwordpress' ) );
|
764 |
-
|
765 |
-
// Delete old backups now in-case we fatal error during the backup process
|
766 |
-
$this->delete_old_backups();
|
767 |
-
|
768 |
-
if ( $this->get_backups() ) {
|
769 |
-
|
770 |
-
// If we already have a previous backup then pass it in so it can be re-used
|
771 |
-
list( $existing_backup ) = array_values( $this->get_backups() );
|
772 |
-
|
773 |
-
if ( $existing_backup && file_exists( $existing_backup ) ) {
|
774 |
-
$this->backup->set_existing_archive_filepath( $existing_backup );
|
775 |
-
}
|
776 |
-
|
777 |
-
}
|
778 |
-
|
779 |
-
$this->backup->backup();
|
780 |
-
|
781 |
-
// Delete the backup running file
|
782 |
-
if ( file_exists( $this->get_schedule_running_path() ) ) {
|
783 |
-
unlink( $this->get_schedule_running_path() );
|
784 |
-
}
|
785 |
-
|
786 |
-
// Delete old backups again
|
787 |
-
$this->delete_old_backups();
|
788 |
-
|
789 |
-
}
|
790 |
-
|
791 |
-
/**
|
792 |
-
* Get the filename that the running status is stored in.
|
793 |
-
*
|
794 |
-
* @return string
|
795 |
-
*/
|
796 |
-
public function get_running_backup_filename() {
|
797 |
-
|
798 |
-
if ( ! file_exists( $this->get_schedule_running_path() ) ) {
|
799 |
-
return '';
|
800 |
-
}
|
801 |
-
|
802 |
-
$status = json_decode( file_get_contents( $this->get_schedule_running_path() ) );
|
803 |
-
|
804 |
-
if ( ! empty( $status->filename ) ) {
|
805 |
-
return $status->filename;
|
806 |
-
}
|
807 |
-
|
808 |
-
return '';
|
809 |
-
|
810 |
-
}
|
811 |
-
|
812 |
-
/**
|
813 |
-
* Get the status of the running backup.
|
814 |
-
*
|
815 |
-
* @return string
|
816 |
-
*/
|
817 |
-
public function get_status() {
|
818 |
-
|
819 |
-
if ( ! file_exists( $this->get_schedule_running_path() ) ) {
|
820 |
-
return '';
|
821 |
-
}
|
822 |
-
|
823 |
-
|
824 |
-
$status = json_decode( file_get_contents( $this->get_schedule_running_path() ) );
|
825 |
-
|
826 |
-
if ( ! empty( $status->status ) ) {
|
827 |
-
return $status->status;
|
828 |
-
}
|
829 |
-
|
830 |
-
return '';
|
831 |
-
|
832 |
-
}
|
833 |
-
|
834 |
-
/**
|
835 |
-
* Set the status of the running backup
|
836 |
-
*
|
837 |
-
* @param string $message
|
838 |
-
*
|
839 |
-
* @return null
|
840 |
-
*/
|
841 |
-
public function set_status( $message ) {
|
842 |
-
|
843 |
-
$status = json_encode( (object) array(
|
844 |
-
'filename' => $this->backup->get_archive_filename(),
|
845 |
-
'started' => $this->get_schedule_running_start_time(),
|
846 |
-
'status' => $message,
|
847 |
-
) );
|
848 |
-
|
849 |
-
if ( false === @file_put_contents( $this->get_schedule_running_path(), $status ) ) {
|
850 |
-
throw new \RuntimeException( sprintf( __( 'Error writing to file. (%s)', 'backupwordpress' ), $this->get_schedule_running_path() ) );
|
851 |
-
}
|
852 |
-
|
853 |
-
}
|
854 |
-
|
855 |
-
/**
|
856 |
-
* Set the time that the current running backup was started
|
857 |
-
*
|
858 |
-
* @return int $timestamp
|
859 |
-
*/
|
860 |
-
public function get_schedule_running_start_time() {
|
861 |
-
|
862 |
-
if ( ! file_exists( $this->get_schedule_running_path() ) ) {
|
863 |
-
return 0;
|
864 |
-
}
|
865 |
-
|
866 |
-
$status = json_decode( file_get_contents( $this->get_schedule_running_path() ) );
|
867 |
-
|
868 |
-
if ( ! empty( $status->started ) && (int) (string) $status->started === $status->started ) {
|
869 |
-
return $status->started;
|
870 |
-
}
|
871 |
-
|
872 |
-
return time();
|
873 |
-
|
874 |
-
}
|
875 |
-
|
876 |
-
/**
|
877 |
-
* Hook into the actions fired in the Backup class and set the status
|
878 |
-
*
|
879 |
-
* @param $action
|
880 |
-
*/
|
881 |
-
public function do_action( $action, Backup $backup ) {
|
882 |
-
|
883 |
-
// Pass the actions to all the services
|
884 |
-
// Todo should be decoupled into the service class
|
885 |
-
foreach ( Services::get_services( $this ) as $service ) {
|
886 |
-
if ( is_wp_error( $service ) ) {
|
887 |
-
return $service;
|
888 |
-
}
|
889 |
-
$service->action( $action, $backup );
|
890 |
-
}
|
891 |
-
|
892 |
-
switch ( $action ) :
|
893 |
-
|
894 |
-
case 'hmbkp_backup_started':
|
895 |
-
case 'hmbkp_mysqldump_finished':
|
896 |
-
case 'hmbkp_archive_finished':
|
897 |
-
break;
|
898 |
-
|
899 |
-
case 'hmbkp_mysqldump_started' :
|
900 |
-
|
901 |
-
$this->set_status( sprintf( __( 'Dumping Database %s', 'backupwordpress' ), '(<code>' . $this->backup->get_mysqldump_method() . '</code>)' ) );
|
902 |
-
break;
|
903 |
-
|
904 |
-
case 'hmbkp_mysqldump_verify_started' :
|
905 |
-
|
906 |
-
$this->set_status( sprintf( __( 'Verifying Database Dump %s', 'backupwordpress' ), '(<code>' . $this->backup->get_mysqldump_method() . '</code>)' ) );
|
907 |
-
break;
|
908 |
-
|
909 |
-
case 'hmbkp_archive_started' :
|
910 |
-
|
911 |
-
$this->set_status( sprintf( __( 'Creating zip archive %s', 'backupwordpress' ), '(<code>' . $this->backup->get_archive_method() . '</code>)' ) );
|
912 |
-
break;
|
913 |
-
|
914 |
-
case 'hmbkp_archive_verify_started' :
|
915 |
-
|
916 |
-
$this->set_status( sprintf( __( 'Verifying Zip Archive %s', 'backupwordpress' ), '(<code>' . $this->backup->get_archive_method() . '</code>)' ) );
|
917 |
-
break;
|
918 |
-
|
919 |
-
case 'hmbkp_backup_complete' :
|
920 |
-
|
921 |
-
$this->set_status( __( 'Finishing Backup', 'backupwordpress' ) );
|
922 |
-
$this->update_average_schedule_run_time( $this->get_schedule_running_start_time(), time() );
|
923 |
-
|
924 |
-
break;
|
925 |
-
|
926 |
-
case 'hmbkp_error' :
|
927 |
-
|
928 |
-
if ( $this->backup->get_errors() ) {
|
929 |
-
|
930 |
-
$file = $this->get_path() . '/.backup_errors';
|
931 |
-
|
932 |
-
if ( file_exists( $file ) ) {
|
933 |
-
@unlink( $file );
|
934 |
-
}
|
935 |
-
|
936 |
-
if ( ! $handle = @fopen( $file, 'w' ) ) {
|
937 |
-
return;
|
938 |
-
}
|
939 |
-
|
940 |
-
fwrite( $handle, json_encode( $this->backup->get_errors() ) );
|
941 |
-
|
942 |
-
fclose( $handle );
|
943 |
-
|
944 |
-
}
|
945 |
-
|
946 |
-
break;
|
947 |
-
|
948 |
-
case 'hmbkp_warning' :
|
949 |
-
|
950 |
-
if ( $this->backup->get_warnings() ) {
|
951 |
-
|
952 |
-
$file = $this->get_path() . '/.backup_warnings';
|
953 |
-
|
954 |
-
if ( file_exists( $file ) ) {
|
955 |
-
@unlink( $file );
|
956 |
-
}
|
957 |
-
|
958 |
-
if ( ! $handle = @fopen( $file, 'w' ) ) {
|
959 |
-
return;
|
960 |
-
}
|
961 |
-
|
962 |
-
fwrite( $handle, json_encode( $this->backup->get_warnings() ) );
|
963 |
-
|
964 |
-
fclose( $handle );
|
965 |
-
|
966 |
-
}
|
967 |
-
|
968 |
-
break;
|
969 |
-
|
970 |
-
default:
|
971 |
-
|
972 |
-
return new \WP_Error( 'unexpected-error', __( 'An unexpected error occurred', 'backupwordpress' ) );
|
973 |
-
|
974 |
-
endswitch;
|
975 |
-
|
976 |
-
}
|
977 |
-
|
978 |
-
/**
|
979 |
-
* Calculate schedule run time.
|
980 |
-
*
|
981 |
-
* @param int Timestamp $end
|
982 |
-
*/
|
983 |
-
public function update_average_schedule_run_time( $start, $end ) {
|
984 |
-
|
985 |
-
if ( $end <= $start ) {
|
986 |
-
// Something went wrong, ignore.
|
987 |
-
return;
|
988 |
-
}
|
989 |
-
|
990 |
-
$diff = (int) abs( $end - $start );
|
991 |
-
|
992 |
-
if ( isset( $this->options['duration_total'] ) && isset( $this->options['backup_run_count'] ) ) {
|
993 |
-
|
994 |
-
$this->options['duration_total'] += $diff;
|
995 |
-
$this->options['backup_run_count'] ++;
|
996 |
-
|
997 |
-
} else {
|
998 |
-
|
999 |
-
$this->options['duration_total'] = $diff;
|
1000 |
-
$this->options['backup_run_count'] = 1;
|
1001 |
-
|
1002 |
-
}
|
1003 |
-
|
1004 |
-
$this->save();
|
1005 |
-
}
|
1006 |
-
|
1007 |
-
/**
|
1008 |
-
* Calculates the average run time for this schedule.
|
1009 |
-
*
|
1010 |
-
* @return string
|
1011 |
-
*/
|
1012 |
-
public function get_schedule_average_duration() {
|
1013 |
-
|
1014 |
-
$duration = 'Unknown';
|
1015 |
-
|
1016 |
-
if ( ! isset( $this->options['duration_total'] ) || ! isset( $this->options['backup_run_count'] ) ) {
|
1017 |
-
return $duration;
|
1018 |
-
}
|
1019 |
-
|
1020 |
-
if ( 0 === (int) $this->options['backup_run_count'] ) {
|
1021 |
-
return $duration;
|
1022 |
-
}
|
1023 |
-
|
1024 |
-
$average_run_time = (int) $this->options['duration_total'] / (int) $this->options['backup_run_count'];
|
1025 |
-
|
1026 |
-
if ( $average_run_time < HOUR_IN_SECONDS ) {
|
1027 |
-
|
1028 |
-
$mins = round( $average_run_time / MINUTE_IN_SECONDS );
|
1029 |
-
|
1030 |
-
if ( $mins <= 1 ) {
|
1031 |
-
$mins = 1;
|
1032 |
-
}
|
1033 |
-
|
1034 |
-
/* translators: min=minute */
|
1035 |
-
$duration = sprintf( _n( '%s min', '%s mins', $mins, 'backupwordpress' ), $mins );
|
1036 |
-
|
1037 |
-
} elseif ( $average_run_time < DAY_IN_SECONDS && $average_run_time >= HOUR_IN_SECONDS ) {
|
1038 |
-
|
1039 |
-
$hours = round( $average_run_time / HOUR_IN_SECONDS );
|
1040 |
-
|
1041 |
-
if ( $hours <= 1 ) {
|
1042 |
-
$hours = 1;
|
1043 |
-
}
|
1044 |
-
|
1045 |
-
$duration = sprintf( _n( '%s hour', '%s hours', $hours, 'backupwordpress' ), $hours );
|
1046 |
-
}
|
1047 |
-
|
1048 |
-
return $duration;
|
1049 |
-
}
|
1050 |
-
|
1051 |
-
/**
|
1052 |
-
* Get the backups created by this schedule
|
1053 |
-
*
|
1054 |
-
* @todo look into using recursiveDirectoryIterator and recursiveRegexIterator
|
1055 |
-
* @return string[] - file paths of the backups
|
1056 |
-
*/
|
1057 |
-
public function get_backups() {
|
1058 |
-
|
1059 |
-
$files = array();
|
1060 |
-
|
1061 |
-
if ( $handle = @opendir( $this->get_path() ) ) {
|
1062 |
-
|
1063 |
-
while ( false !== ( $file = readdir( $handle ) ) ) {
|
1064 |
-
|
1065 |
-
if ( pathinfo( $file, PATHINFO_EXTENSION ) === 'zip' && strpos( $file, $this->get_id() ) !== false && $this->get_running_backup_filename() !== $file ) {
|
1066 |
-
$files[ @filemtime( trailingslashit( $this->get_path() ) . $file ) ] = trailingslashit( $this->get_path() ) . $file;
|
1067 |
-
}
|
1068 |
-
|
1069 |
-
}
|
1070 |
-
|
1071 |
-
closedir( $handle );
|
1072 |
-
|
1073 |
-
}
|
1074 |
-
|
1075 |
-
krsort( $files );
|
1076 |
-
|
1077 |
-
return $files;
|
1078 |
-
|
1079 |
-
}
|
1080 |
-
|
1081 |
-
/**
|
1082 |
-
* Delete old backups
|
1083 |
-
*
|
1084 |
-
* @access private
|
1085 |
-
*/
|
1086 |
-
public function delete_old_backups() {
|
1087 |
-
|
1088 |
-
if ( count( $this->get_backups() ) <= $this->get_max_backups() ) {
|
1089 |
-
return;
|
1090 |
-
}
|
1091 |
-
|
1092 |
-
array_map( array( $this, 'delete_backup' ), array_slice( $this->get_backups(), $this->get_max_backups() ) );
|
1093 |
-
|
1094 |
-
}
|
1095 |
-
|
1096 |
-
/**
|
1097 |
-
* Delete a specific back up file created by this schedule
|
1098 |
-
*
|
1099 |
-
* @param string $filepath
|
1100 |
-
*
|
1101 |
-
* @return \WP_Error|boolean
|
1102 |
-
*/
|
1103 |
-
public function delete_backup( $filepath ) {
|
1104 |
-
|
1105 |
-
// Check that it's a valid filepath
|
1106 |
-
if ( empty( $filepath ) || ! is_string( $filepath ) ) {
|
1107 |
-
return new \WP_Error( 'hmbkp_empty_string_error', sprintf( __( 'Argument 1 for %s must be a non-empty string', 'backupwordpress' ), __METHOD__ ) );
|
1108 |
-
}
|
1109 |
-
|
1110 |
-
// Make sure it exists
|
1111 |
-
if ( ! file_exists( $filepath ) ) {
|
1112 |
-
return new \WP_Error( 'hmbkp_file_error', sprintf( __( '%s doesn\'t exist', 'backupwordpress' ), $filepath ) );
|
1113 |
-
}
|
1114 |
-
|
1115 |
-
// Make sure it was created by this schedule
|
1116 |
-
if ( strpos( $filepath, $this->get_id() ) === false ) {
|
1117 |
-
return new \WP_Error( 'hmbkp_backup_error', __( 'That backup wasn\'t created by this schedule', 'backupwordpress' ) );
|
1118 |
-
}
|
1119 |
-
|
1120 |
-
unlink( $filepath );
|
1121 |
-
|
1122 |
-
return true;
|
1123 |
-
|
1124 |
-
}
|
1125 |
-
|
1126 |
-
/**
|
1127 |
-
* Delete all back up files created by this schedule
|
1128 |
-
*
|
1129 |
-
*/
|
1130 |
-
public function delete_backups() {
|
1131 |
-
|
1132 |
-
array_map( array( $this, 'delete_backup' ), $this->get_backups() );
|
1133 |
-
|
1134 |
-
}
|
1135 |
-
|
1136 |
-
/**
|
1137 |
-
* Save the schedules options.
|
1138 |
-
*
|
1139 |
-
*/
|
1140 |
-
public function save() {
|
1141 |
-
|
1142 |
-
// Only save them if they have changed
|
1143 |
-
if ( $this->options !== get_option( 'hmbkp_schedule_' . $this->get_id() ) ) {
|
1144 |
-
update_option( 'hmbkp_schedule_' . $this->get_id(), $this->options );
|
1145 |
-
}
|
1146 |
-
|
1147 |
-
}
|
1148 |
-
|
1149 |
-
/**
|
1150 |
-
* Cancel this schedule
|
1151 |
-
*
|
1152 |
-
* Cancels the cron job, removes the schedules options
|
1153 |
-
* and optionally deletes all backups created by
|
1154 |
-
* this schedule.
|
1155 |
-
*
|
1156 |
-
*/
|
1157 |
-
public function cancel( $delete_backups = false ) {
|
1158 |
-
|
1159 |
-
// Delete the schedule options
|
1160 |
-
delete_option( 'hmbkp_schedule_' . $this->get_id() );
|
1161 |
-
|
1162 |
-
// Clear any existing schedules
|
1163 |
-
$this->unschedule();
|
1164 |
-
|
1165 |
-
// Delete it's backups
|
1166 |
-
if ( $delete_backups ) {
|
1167 |
-
$this->delete_backups();
|
1168 |
-
}
|
1169 |
-
|
1170 |
-
}
|
1171 |
-
|
1172 |
-
}
|
1173 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
classes/class-scheduled-backup.php
ADDED
@@ -0,0 +1,680 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* The Backup Scheduler
|
7 |
+
*
|
8 |
+
* Handles everything related to managing and running a backup schedule
|
9 |
+
*
|
10 |
+
* @uses Backup
|
11 |
+
* @uses
|
12 |
+
*/
|
13 |
+
class Scheduled_Backup {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* The unique schedule id
|
17 |
+
*
|
18 |
+
* @var string
|
19 |
+
* @access private
|
20 |
+
*/
|
21 |
+
private $id = '';
|
22 |
+
|
23 |
+
/**
|
24 |
+
* The slugified version of the schedule name
|
25 |
+
*
|
26 |
+
* @var string
|
27 |
+
* @access private
|
28 |
+
*/
|
29 |
+
private $slug = '';
|
30 |
+
|
31 |
+
/**
|
32 |
+
* The raw schedule options from the database
|
33 |
+
*
|
34 |
+
* @var array
|
35 |
+
* @access private
|
36 |
+
*/
|
37 |
+
private $options = array(
|
38 |
+
'max_backups' => 3,
|
39 |
+
'excludes' => array(),
|
40 |
+
'type' => 'complete',
|
41 |
+
'reoccurrence' => 'manually'
|
42 |
+
);
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Setup the schedule object
|
46 |
+
* Loads the options from the database and populates properties
|
47 |
+
*
|
48 |
+
* @param string $id
|
49 |
+
*
|
50 |
+
* @throws Exception
|
51 |
+
*/
|
52 |
+
|
53 |
+
public function __construct( $id ) {
|
54 |
+
|
55 |
+
// Verify the schedule id
|
56 |
+
if ( ! is_string( $id ) || ! trim( $id ) ) {
|
57 |
+
throw new \Exception( 'Argument 1 for ' . __METHOD__ . ' must be a non-empty string' );
|
58 |
+
}
|
59 |
+
|
60 |
+
// Store id for later
|
61 |
+
$this->id = $id;
|
62 |
+
|
63 |
+
// Load the options
|
64 |
+
$this->options = array_merge( $this->options, array_filter( (array) get_option( 'hmbkp_schedule_' . $this->get_id() ) ) );
|
65 |
+
|
66 |
+
if ( defined( 'HMBKP_SCHEDULE_START_TIME' ) && strtotime( 'HMBKP_SCHEDULE_START_TIME' ) ) {
|
67 |
+
$this->set_schedule_start_time( strtotime( 'HMBKP_SCHEDULE_START_TIME' ) );
|
68 |
+
}
|
69 |
+
|
70 |
+
// Setup the schedule if it isn't set
|
71 |
+
if ( ( ! $this->is_cron_scheduled() && $this->get_reoccurrence() !== 'manually' ) ) {
|
72 |
+
$this->schedule();
|
73 |
+
}
|
74 |
+
|
75 |
+
$this->backup_filename = implode( '-', array(
|
76 |
+
sanitize_title( str_ireplace( array(
|
77 |
+
'http://',
|
78 |
+
'https://',
|
79 |
+
'www'
|
80 |
+
), '', home_url() ) ),
|
81 |
+
$this->get_id(),
|
82 |
+
$this->get_type(),
|
83 |
+
current_time( 'Y-m-d-H-i-s' )
|
84 |
+
) ) . '.zip';
|
85 |
+
|
86 |
+
$this->database_dump_filename = implode( '-', array(
|
87 |
+
'database',
|
88 |
+
sanitize_title( str_ireplace( array( 'http://', 'https://', 'www' ), '', home_url() ) ),
|
89 |
+
$this->get_id()
|
90 |
+
) ) . '.sql';
|
91 |
+
|
92 |
+
$this->status = new Backup_Status( $this->get_id() );
|
93 |
+
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Get the id for this schedule
|
98 |
+
*/
|
99 |
+
public function get_id() {
|
100 |
+
return esc_attr( $this->id );
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Get a slugified version of name
|
105 |
+
*/
|
106 |
+
public function get_slug() {
|
107 |
+
|
108 |
+
// We cache slug in $this to save expensive calls to sanitize_title
|
109 |
+
if ( ! empty( $this->slug ) ) {
|
110 |
+
return $this->slug;
|
111 |
+
}
|
112 |
+
|
113 |
+
return $this->slug = sanitize_title( $this->get_name() );
|
114 |
+
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Returns the given option value
|
119 |
+
*
|
120 |
+
* @param $option_name
|
121 |
+
* @return mixed The option value
|
122 |
+
*/
|
123 |
+
public function get_schedule_option( $option_name ) {
|
124 |
+
if ( isset( $this->options[ $option_name ] ) ) {
|
125 |
+
return $this->options[ $option_name ];
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Get the name of this backup schedule
|
131 |
+
*
|
132 |
+
* @return string
|
133 |
+
*/
|
134 |
+
public function get_name() {
|
135 |
+
return ucwords( $this->get_type() ) . ' ' . $this->get_reoccurrence();
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* Get the type of backup
|
140 |
+
*
|
141 |
+
* @return string
|
142 |
+
*/
|
143 |
+
public function get_type() {
|
144 |
+
return $this->options['type'];
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Set the type of backup
|
149 |
+
*
|
150 |
+
* @param string $type
|
151 |
+
*/
|
152 |
+
public function set_type( $type ) {
|
153 |
+
if ( ! isset( $this->options['type'] ) || $this->options['type'] !== $type ) {
|
154 |
+
$this->options['type'] = $type;
|
155 |
+
}
|
156 |
+
}
|
157 |
+
|
158 |
+
/**
|
159 |
+
* Get the exclude rules
|
160 |
+
*
|
161 |
+
* @return array
|
162 |
+
*/
|
163 |
+
public function get_excludes() {
|
164 |
+
return new Excludes( $this->options['excludes'] );
|
165 |
+
}
|
166 |
+
|
167 |
+
/**
|
168 |
+
* Set the exclude rules
|
169 |
+
*
|
170 |
+
* @param mixed $excludes A comma separated list or array of exclude rules
|
171 |
+
* @param bool $append Whether to replace or append to existing rules
|
172 |
+
*
|
173 |
+
* @return string
|
174 |
+
*/
|
175 |
+
public function set_excludes( $exclude_rules, $append = false ) {
|
176 |
+
|
177 |
+
// Normalize the exclude rules before we save them
|
178 |
+
$excludes = new Excludes;
|
179 |
+
$excludes = $excludes->normalize( (array) $exclude_rules );
|
180 |
+
|
181 |
+
// If these are valid excludes and they are different save them
|
182 |
+
if ( empty( $this->options['excludes'] ) || $this->options['excludes'] !== $excludes ) {
|
183 |
+
$this->options['excludes'] = $append && ! empty( $this->options['excludes'] ) ? array_merge( (array) $this->options['excludes'], (array) $excludes ) : (array) $excludes;
|
184 |
+
}
|
185 |
+
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Get the maximum number of backups to keep
|
190 |
+
*
|
191 |
+
* @return int
|
192 |
+
*/
|
193 |
+
public function get_max_backups() {
|
194 |
+
return (int) $this->options['max_backups'];
|
195 |
+
}
|
196 |
+
|
197 |
+
/**
|
198 |
+
* Set the maximum number of backups to keep
|
199 |
+
*
|
200 |
+
* @param int $max
|
201 |
+
*
|
202 |
+
* @return WP_Error|boolean
|
203 |
+
*/
|
204 |
+
public function set_max_backups( $max ) {
|
205 |
+
$this->options['max_backups'] = $max;
|
206 |
+
}
|
207 |
+
|
208 |
+
public function get_status() {
|
209 |
+
return $this->status;
|
210 |
+
}
|
211 |
+
|
212 |
+
/**
|
213 |
+
* Back compat with old set_status mathod
|
214 |
+
*
|
215 |
+
* @deprecated 3.4 Backup->status->set_status()
|
216 |
+
*/
|
217 |
+
public function set_status( $message ) {
|
218 |
+
_deprecated_function( __FUNCTION__, '3.4', 'Backup->status->set_status()' );
|
219 |
+
$this->status->set_status( $message );
|
220 |
+
}
|
221 |
+
|
222 |
+
/**
|
223 |
+
* Get the array of services options for this schedule
|
224 |
+
*
|
225 |
+
* @param $service
|
226 |
+
* @param null $option
|
227 |
+
*
|
228 |
+
* @return array
|
229 |
+
*/
|
230 |
+
public function get_service_options( $service, $option = null ) {
|
231 |
+
|
232 |
+
if ( ! is_null( $option ) ) {
|
233 |
+
|
234 |
+
if ( isset( $this->options[ $service ][ $option ] ) ) {
|
235 |
+
return $this->options[ $service ][ $option ];
|
236 |
+
}
|
237 |
+
|
238 |
+
return array();
|
239 |
+
|
240 |
+
}
|
241 |
+
|
242 |
+
if ( isset( $this->options[ $service ] ) ) {
|
243 |
+
return $this->options[ $service ];
|
244 |
+
}
|
245 |
+
|
246 |
+
return array();
|
247 |
+
|
248 |
+
}
|
249 |
+
|
250 |
+
/**
|
251 |
+
* Set the service options for this schedule
|
252 |
+
*
|
253 |
+
* @param $service
|
254 |
+
* @param array $options
|
255 |
+
*/
|
256 |
+
public function set_service_options( $service, Array $options ) {
|
257 |
+
$this->options[ $service ] = $options;
|
258 |
+
}
|
259 |
+
|
260 |
+
/**
|
261 |
+
* Get the start time for the schedule
|
262 |
+
*
|
263 |
+
* @return int timestamp || 0 for manual only schedules
|
264 |
+
*/
|
265 |
+
public function get_schedule_start_time( $gmt = true ) {
|
266 |
+
|
267 |
+
if ( 'manually' === $this->get_reoccurrence() ) {
|
268 |
+
return 0;
|
269 |
+
}
|
270 |
+
|
271 |
+
if ( ! $gmt ) {
|
272 |
+
$offset = get_option( 'gmt_offset' ) * 3600;
|
273 |
+
} else {
|
274 |
+
$offset = 0;
|
275 |
+
}
|
276 |
+
|
277 |
+
if ( ! empty( $this->options['schedule_start_time'] ) ) {
|
278 |
+
return $this->options['schedule_start_time'] + $offset;
|
279 |
+
}
|
280 |
+
|
281 |
+
$this->set_schedule_start_time( time() );
|
282 |
+
|
283 |
+
return time() + $offset;
|
284 |
+
|
285 |
+
}
|
286 |
+
|
287 |
+
/**
|
288 |
+
* Set the schedule start time.
|
289 |
+
*
|
290 |
+
* @param timestamp $time
|
291 |
+
*/
|
292 |
+
public function set_schedule_start_time( $time ) {
|
293 |
+
|
294 |
+
$this->options['schedule_start_time'] = $time;
|
295 |
+
|
296 |
+
$this->schedule();
|
297 |
+
|
298 |
+
}
|
299 |
+
|
300 |
+
/**
|
301 |
+
* Get the schedule reoccurrence
|
302 |
+
*
|
303 |
+
*/
|
304 |
+
public function get_reoccurrence() {
|
305 |
+
return $this->options['reoccurrence'];
|
306 |
+
}
|
307 |
+
|
308 |
+
/**
|
309 |
+
* Set the schedule reoccurrence
|
310 |
+
*
|
311 |
+
* @param string $reoccurrence
|
312 |
+
*
|
313 |
+
* @return \WP_Error|null|boolean
|
314 |
+
*/
|
315 |
+
public function set_reoccurrence( $reoccurrence ) {
|
316 |
+
|
317 |
+
$hmbkp_schedules = cron_schedules();
|
318 |
+
|
319 |
+
// Check it's valid
|
320 |
+
if ( ! is_string( $reoccurrence ) || ! trim( $reoccurrence ) || ( ! in_array( $reoccurrence, array_keys( $hmbkp_schedules ) ) ) && 'manually' !== $reoccurrence ) {
|
321 |
+
return new \WP_Error( 'hmbkp_invalid_argument_error', sprintf( __( 'Argument 1 for %s must be a valid cron recurrence or "manually"', 'backupwordpress' ), __METHOD__ ) );
|
322 |
+
}
|
323 |
+
|
324 |
+
// If the recurrence is already set to the same thing then there's no need to continue
|
325 |
+
if ( isset( $this->options['reoccurrence'] ) && $this->options['reoccurrence'] === $reoccurrence && $this->is_cron_scheduled() ) {
|
326 |
+
return;
|
327 |
+
}
|
328 |
+
|
329 |
+
|
330 |
+
$this->options['reoccurrence'] = $reoccurrence;
|
331 |
+
|
332 |
+
if ( 'manually' === $reoccurrence ) {
|
333 |
+
$this->unschedule();
|
334 |
+
|
335 |
+
} else {
|
336 |
+
$this->schedule();
|
337 |
+
}
|
338 |
+
|
339 |
+
return true;
|
340 |
+
|
341 |
+
}
|
342 |
+
|
343 |
+
/**
|
344 |
+
* Get the interval between backups
|
345 |
+
*
|
346 |
+
* @return int
|
347 |
+
*/
|
348 |
+
public function get_interval() {
|
349 |
+
|
350 |
+
$hmbkp_schedules = cron_schedules();
|
351 |
+
|
352 |
+
if ( 'manually' === $this->get_reoccurrence() ) {
|
353 |
+
return 0;
|
354 |
+
}
|
355 |
+
|
356 |
+
return $hmbkp_schedules[ $this->get_reoccurrence() ]['interval'];
|
357 |
+
|
358 |
+
}
|
359 |
+
|
360 |
+
/**
|
361 |
+
* Get the next occurrence of this scheduled backup
|
362 |
+
*
|
363 |
+
*/
|
364 |
+
public function get_next_occurrence( $gmt = true ) {
|
365 |
+
|
366 |
+
$time = wp_next_scheduled( 'hmbkp_schedule_hook', array( 'id' => $this->get_id() ) );
|
367 |
+
|
368 |
+
if ( ! $time ) {
|
369 |
+
$time = 0;
|
370 |
+
}
|
371 |
+
|
372 |
+
if ( ! $gmt ) {
|
373 |
+
$time += get_option( 'gmt_offset' ) * 3600;
|
374 |
+
}
|
375 |
+
|
376 |
+
return $time;
|
377 |
+
|
378 |
+
}
|
379 |
+
|
380 |
+
public function is_cron_scheduled() {
|
381 |
+
return (bool) $this->get_next_occurrence();
|
382 |
+
}
|
383 |
+
|
384 |
+
/**
|
385 |
+
* Schedule the backup cron
|
386 |
+
*
|
387 |
+
*/
|
388 |
+
public function schedule() {
|
389 |
+
|
390 |
+
// Clear any existing hooks
|
391 |
+
$this->unschedule();
|
392 |
+
|
393 |
+
$schedule_timestamp = $this->get_schedule_start_time();
|
394 |
+
|
395 |
+
wp_schedule_event( $schedule_timestamp, $this->get_reoccurrence(), 'hmbkp_schedule_hook', array( 'id' => $this->get_id() ) );
|
396 |
+
|
397 |
+
}
|
398 |
+
|
399 |
+
|
400 |
+
/**
|
401 |
+
* Unschedule the backup cron.
|
402 |
+
*
|
403 |
+
* @return void
|
404 |
+
*/
|
405 |
+
public function unschedule() {
|
406 |
+
wp_clear_scheduled_hook( 'hmbkp_schedule_hook', array( 'id' => $this->get_id() ) );
|
407 |
+
}
|
408 |
+
|
409 |
+
/**
|
410 |
+
* Run the backup
|
411 |
+
*
|
412 |
+
*/
|
413 |
+
public function run() {
|
414 |
+
|
415 |
+
// Don't run if this schedule is already running
|
416 |
+
if ( $this->status->is_started() ) {
|
417 |
+
return;
|
418 |
+
}
|
419 |
+
|
420 |
+
// Setup our Site Backup Object
|
421 |
+
$backup = new Backup( $this->get_backup_filename(), $this->get_database_dump_filename() );
|
422 |
+
$backup->set_type( $this->get_type() );
|
423 |
+
$backup->set_excludes( $this->get_excludes() );
|
424 |
+
$backup->set_status( $this->status );
|
425 |
+
|
426 |
+
$this->do_action( 'hmbkp_backup_started', $backup );
|
427 |
+
|
428 |
+
$this->status->start( $this->get_backup_filename(), __( 'Starting backup...', 'backupwordpress' ) );
|
429 |
+
|
430 |
+
$this->status->set_status( __( 'Deleting old backups...', 'backupwordpress' ) );
|
431 |
+
|
432 |
+
// Delete old backups now in-case we fatal error during the backup process
|
433 |
+
$this->delete_old_backups();
|
434 |
+
|
435 |
+
$backup->run();
|
436 |
+
|
437 |
+
$errors = array_merge( $backup->errors, $backup->warnings );
|
438 |
+
$notices = array();
|
439 |
+
foreach ( $errors as $key => $error ) {
|
440 |
+
$key = str_replace( array( __NAMESPACE__ . '\\', '_File_Backup_Engine', '_Database_Backup_Engine' ), array( '', '', '' ), $key );
|
441 |
+
$notices[] = $key . ': ' . implode( ', ', $error );
|
442 |
+
}
|
443 |
+
Notices::get_instance()->set_notices( 'backup_errors', $notices );
|
444 |
+
|
445 |
+
$this->status->set_status( __( 'Deleting old backups...', 'backupwordpress' ) );
|
446 |
+
|
447 |
+
// Delete old backups again
|
448 |
+
$this->delete_old_backups();
|
449 |
+
|
450 |
+
$this->do_action( 'hmbkp_backup_complete', $backup );
|
451 |
+
|
452 |
+
$this->status->finish();
|
453 |
+
$this->update_average_schedule_run_time( $this->status->get_start_time(), time() );
|
454 |
+
|
455 |
+
}
|
456 |
+
|
457 |
+
public function get_backup_filename() {
|
458 |
+
|
459 |
+
if ( $this->status->is_started() ) {
|
460 |
+
$this->backup_filename = $this->status->get_backup_filename();
|
461 |
+
}
|
462 |
+
|
463 |
+
return $this->backup_filename;
|
464 |
+
}
|
465 |
+
|
466 |
+
public function get_database_dump_filename() {
|
467 |
+
return $this->database_dump_filename;
|
468 |
+
}
|
469 |
+
|
470 |
+
/**
|
471 |
+
* Hook into the actions fired in the Backup class and set the status
|
472 |
+
*
|
473 |
+
* @param $action
|
474 |
+
*/
|
475 |
+
public function do_action( $action, Backup $backup ) {
|
476 |
+
|
477 |
+
// Pass the actions to all the services
|
478 |
+
// Todo should be decoupled into the service class
|
479 |
+
foreach ( Services::get_services( $this ) as $service ) {
|
480 |
+
if ( is_wp_error( $service ) ) {
|
481 |
+
return $service;
|
482 |
+
}
|
483 |
+
$service->action( $action, $backup );
|
484 |
+
}
|
485 |
+
|
486 |
+
}
|
487 |
+
|
488 |
+
/**
|
489 |
+
* Calculate schedule run time.
|
490 |
+
*
|
491 |
+
* @param int Timestamp $end
|
492 |
+
*/
|
493 |
+
public function update_average_schedule_run_time( $start, $end ) {
|
494 |
+
|
495 |
+
if ( $end <= $start ) {
|
496 |
+
// Something went wrong, ignore.
|
497 |
+
return;
|
498 |
+
}
|
499 |
+
|
500 |
+
$diff = (int) abs( $end - $start );
|
501 |
+
|
502 |
+
if ( isset( $this->options['duration_total'] ) && isset( $this->options['backup_run_count'] ) ) {
|
503 |
+
|
504 |
+
$this->options['duration_total'] += $diff;
|
505 |
+
$this->options['backup_run_count'] ++;
|
506 |
+
|
507 |
+
} else {
|
508 |
+
|
509 |
+
$this->options['duration_total'] = $diff;
|
510 |
+
$this->options['backup_run_count'] = 1;
|
511 |
+
|
512 |
+
}
|
513 |
+
|
514 |
+
$this->save();
|
515 |
+
}
|
516 |
+
|
517 |
+
/**
|
518 |
+
* Calculates the average run time for this schedule.
|
519 |
+
*
|
520 |
+
* @return string
|
521 |
+
*/
|
522 |
+
public function get_schedule_average_duration() {
|
523 |
+
|
524 |
+
$duration = 'Unknown';
|
525 |
+
|
526 |
+
if ( ! isset( $this->options['duration_total'] ) || ! isset( $this->options['backup_run_count'] ) ) {
|
527 |
+
return $duration;
|
528 |
+
}
|
529 |
+
|
530 |
+
if ( 0 === (int) $this->options['backup_run_count'] ) {
|
531 |
+
return $duration;
|
532 |
+
}
|
533 |
+
|
534 |
+
$average_run_time = (int) $this->options['duration_total'] / (int) $this->options['backup_run_count'];
|
535 |
+
|
536 |
+
if ( $average_run_time < HOUR_IN_SECONDS ) {
|
537 |
+
|
538 |
+
$mins = round( $average_run_time / MINUTE_IN_SECONDS );
|
539 |
+
|
540 |
+
if ( $mins <= 1 ) {
|
541 |
+
$mins = 1;
|
542 |
+
}
|
543 |
+
|
544 |
+
/* translators: min=minute */
|
545 |
+
$duration = sprintf( _n( '%s min', '%s mins', $mins, 'backupwordpress' ), $mins );
|
546 |
+
|
547 |
+
} elseif ( $average_run_time < DAY_IN_SECONDS && $average_run_time >= HOUR_IN_SECONDS ) {
|
548 |
+
|
549 |
+
$hours = round( $average_run_time / HOUR_IN_SECONDS );
|
550 |
+
|
551 |
+
if ( $hours <= 1 ) {
|
552 |
+
$hours = 1;
|
553 |
+
}
|
554 |
+
|
555 |
+
$duration = sprintf( _n( '%s hour', '%s hours', $hours, 'backupwordpress' ), $hours );
|
556 |
+
}
|
557 |
+
|
558 |
+
return $duration;
|
559 |
+
}
|
560 |
+
|
561 |
+
/**
|
562 |
+
* Get the backups created by this schedule
|
563 |
+
*
|
564 |
+
* @todo look into using recursiveDirectoryIterator and recursiveRegexIterator
|
565 |
+
* @return string[] - file paths of the backups
|
566 |
+
*/
|
567 |
+
public function get_backups() {
|
568 |
+
|
569 |
+
$files = array();
|
570 |
+
|
571 |
+
if ( $handle = @opendir( Path::get_path() ) ) {
|
572 |
+
|
573 |
+
while ( false !== ( $file = readdir( $handle ) ) ) {
|
574 |
+
|
575 |
+
if ( pathinfo( $file, PATHINFO_EXTENSION ) === 'zip' && strpos( $file, $this->get_id() ) !== false && ( isset( $this->status ) && $this->get_backup_filename() !== $file ) ) {
|
576 |
+
$files[ @filemtime( trailingslashit( Path::get_path() ) . $file ) ] = trailingslashit( Path::get_path() ) . $file;
|
577 |
+
}
|
578 |
+
|
579 |
+
}
|
580 |
+
|
581 |
+
closedir( $handle );
|
582 |
+
|
583 |
+
}
|
584 |
+
|
585 |
+
krsort( $files );
|
586 |
+
|
587 |
+
return $files;
|
588 |
+
|
589 |
+
}
|
590 |
+
|
591 |
+
/**
|
592 |
+
* Delete old backups
|
593 |
+
*
|
594 |
+
* @access private
|
595 |
+
*/
|
596 |
+
public function delete_old_backups() {
|
597 |
+
|
598 |
+
if ( count( $this->get_backups() ) <= $this->get_max_backups() ) {
|
599 |
+
return;
|
600 |
+
}
|
601 |
+
|
602 |
+
array_map( array( $this, 'delete_backup' ), array_slice( $this->get_backups(), $this->get_max_backups() ) );
|
603 |
+
|
604 |
+
}
|
605 |
+
|
606 |
+
/**
|
607 |
+
* Delete a specific back up file created by this schedule
|
608 |
+
*
|
609 |
+
* @param string $filepath
|
610 |
+
*
|
611 |
+
* @return \WP_Error|boolean
|
612 |
+
*/
|
613 |
+
public function delete_backup( $filepath ) {
|
614 |
+
|
615 |
+
// Check that it's a valid filepath
|
616 |
+
if ( empty( $filepath ) || ! is_string( $filepath ) ) {
|
617 |
+
return new \WP_Error( 'hmbkp_empty_string_error', sprintf( __( 'Argument 1 for %s must be a non-empty string', 'backupwordpress' ), __METHOD__ ) );
|
618 |
+
}
|
619 |
+
|
620 |
+
// Make sure it exists
|
621 |
+
if ( ! file_exists( $filepath ) ) {
|
622 |
+
return new \WP_Error( 'hmbkp_file_error', sprintf( __( '%s doesn\'t exist', 'backupwordpress' ), $filepath ) );
|
623 |
+
}
|
624 |
+
|
625 |
+
// Make sure it was created by this schedule
|
626 |
+
if ( strpos( $filepath, $this->get_id() ) === false ) {
|
627 |
+
return new \WP_Error( 'hmbkp_backup_error', __( 'That backup wasn\'t created by this schedule', 'backupwordpress' ) );
|
628 |
+
}
|
629 |
+
|
630 |
+
unlink( $filepath );
|
631 |
+
|
632 |
+
return true;
|
633 |
+
|
634 |
+
}
|
635 |
+
|
636 |
+
/**
|
637 |
+
* Delete all back up files created by this schedule
|
638 |
+
*
|
639 |
+
*/
|
640 |
+
public function delete_backups() {
|
641 |
+
array_map( array( $this, 'delete_backup' ), $this->get_backups() );
|
642 |
+
}
|
643 |
+
|
644 |
+
/**
|
645 |
+
* Save the schedules options.
|
646 |
+
*
|
647 |
+
*/
|
648 |
+
public function save() {
|
649 |
+
|
650 |
+
// Only save them if they have changed
|
651 |
+
if ( $this->options !== get_option( 'hmbkp_schedule_' . $this->get_id() ) ) {
|
652 |
+
update_option( 'hmbkp_schedule_' . $this->get_id(), $this->options );
|
653 |
+
}
|
654 |
+
|
655 |
+
}
|
656 |
+
|
657 |
+
/**
|
658 |
+
* Cancel this schedule
|
659 |
+
*
|
660 |
+
* Cancels the cron job, removes the schedules options
|
661 |
+
* and optionally deletes all backups created by
|
662 |
+
* this schedule.
|
663 |
+
*
|
664 |
+
*/
|
665 |
+
public function cancel( $delete_backups = false ) {
|
666 |
+
|
667 |
+
// Delete the schedule options
|
668 |
+
delete_option( 'hmbkp_schedule_' . $this->get_id() );
|
669 |
+
|
670 |
+
// Clear any existing schedules
|
671 |
+
$this->unschedule();
|
672 |
+
|
673 |
+
// Delete it's backups
|
674 |
+
if ( $delete_backups ) {
|
675 |
+
$this->delete_backups();
|
676 |
+
}
|
677 |
+
|
678 |
+
}
|
679 |
+
|
680 |
+
}
|
classes/class-service.php
CHANGED
@@ -86,7 +86,7 @@ abstract class Service {
|
|
86 |
*
|
87 |
* @return mixed
|
88 |
*/
|
89 |
-
|
90 |
|
91 |
public function get_slug() {
|
92 |
return sanitize_key( $this->name );
|
86 |
*
|
87 |
* @return mixed
|
88 |
*/
|
89 |
+
public function action( $action, Backup $backup ) {}
|
90 |
|
91 |
public function get_slug() {
|
92 |
return sanitize_key( $this->name );
|
classes/class-services.php
CHANGED
@@ -123,4 +123,4 @@ class Services {
|
|
123 |
|
124 |
}
|
125 |
|
126 |
-
}
|
123 |
|
124 |
}
|
125 |
|
126 |
+
}
|
classes/class-site-size.php
ADDED
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
+
use HM\Backdrop\Task;
|
6 |
+
use Symfony\Component\Finder\Finder;
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Site Size class
|
10 |
+
*
|
11 |
+
* Use to calculate the total or partial size of the sites database and files.
|
12 |
+
*/
|
13 |
+
class Site_Size {
|
14 |
+
|
15 |
+
private $size = 0;
|
16 |
+
private $type = '';
|
17 |
+
private $excludes = array();
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Constructor
|
21 |
+
*
|
22 |
+
* Set up some initial conditions including whether we want to calculate the
|
23 |
+
* size of the database, files or both and whether to exclude any files from
|
24 |
+
* the file size calculation.
|
25 |
+
*
|
26 |
+
* @param string $type Whether to calculate the size of the database, files
|
27 |
+
* or both. Should be one of 'file', 'database' or 'complete'
|
28 |
+
* @param array $excludes An array of exclude rules
|
29 |
+
*/
|
30 |
+
public function __construct( $type = 'complete', Excludes $excludes = null ) {
|
31 |
+
$this->type = $type;
|
32 |
+
$this->excludes = $excludes;
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Calculate the size total size of the database + files.
|
37 |
+
*
|
38 |
+
* Doesn't account for any compression that would be gained by zipping.
|
39 |
+
*
|
40 |
+
* @return string
|
41 |
+
*/
|
42 |
+
public function get_site_size() {
|
43 |
+
|
44 |
+
if ( $this->size ) {
|
45 |
+
return $this->size;
|
46 |
+
}
|
47 |
+
|
48 |
+
$size = 0;
|
49 |
+
|
50 |
+
// Include database size except for file only schedule.
|
51 |
+
if ( 'file' !== $this->type ) {
|
52 |
+
|
53 |
+
global $wpdb;
|
54 |
+
$tables = $wpdb->get_results( 'SHOW TABLE STATUS FROM `' . DB_NAME . '`', ARRAY_A );
|
55 |
+
|
56 |
+
foreach ( $tables as $table ) {
|
57 |
+
$size += (float) $table['Data_length'];
|
58 |
+
}
|
59 |
+
}
|
60 |
+
|
61 |
+
// Include total size of dirs/files except for database only schedule.
|
62 |
+
if ( 'database' !== $this->type ) {
|
63 |
+
|
64 |
+
$root = new \SplFileInfo( Path::get_root() );
|
65 |
+
$size += $this->filesize( $root );
|
66 |
+
|
67 |
+
}
|
68 |
+
|
69 |
+
$this->size = $size;
|
70 |
+
|
71 |
+
return $size;
|
72 |
+
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Get the site size formatted
|
77 |
+
*
|
78 |
+
* @see size_format
|
79 |
+
*
|
80 |
+
* @return string
|
81 |
+
*/
|
82 |
+
public function get_formatted_site_size() {
|
83 |
+
return size_format( $this->get_site_size() );
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Whether the total filesize is being calculated
|
88 |
+
*
|
89 |
+
* @return bool
|
90 |
+
*/
|
91 |
+
public static function is_site_size_being_calculated() {
|
92 |
+
return false !== get_transient( 'hmbkp_directory_filesizes_running' );
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Whether the total filesize is cached
|
97 |
+
*
|
98 |
+
* @return bool
|
99 |
+
*/
|
100 |
+
public static function is_site_size_cached() {
|
101 |
+
return false !== get_transient( 'hmbkp_directory_filesizes' );
|
102 |
+
}
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Recursively scans a directory to calculate the total filesize
|
106 |
+
*
|
107 |
+
* Locks should be set by the caller with `set_transient( 'hmbkp_directory_filesizes_running', true, HOUR_IN_SECONDS );`
|
108 |
+
*
|
109 |
+
* @return array $directory_sizes An array of directory paths => filesize sum of all files in directory
|
110 |
+
*/
|
111 |
+
public function recursive_filesize_scanner() {
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Raise the `memory_limit` and `max_execution time`
|
115 |
+
*
|
116 |
+
* Respects the WP_MAX_MEMORY_LIMIT Constant and the `admin_memory_limit`
|
117 |
+
* filter.
|
118 |
+
*/
|
119 |
+
@ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
|
120 |
+
@set_time_limit( 0 );
|
121 |
+
|
122 |
+
// Use the cached array directory sizes if available
|
123 |
+
$directory_sizes = get_transient( 'hmbkp_directory_filesizes' );
|
124 |
+
|
125 |
+
// If we do have it in cache then let's use it and also clear the lock
|
126 |
+
if ( is_array( $directory_sizes ) ) {
|
127 |
+
delete_transient( 'hmbkp_directory_filesizes_running' );
|
128 |
+
return $directory_sizes;
|
129 |
+
}
|
130 |
+
|
131 |
+
// If we don't have it cached then we'll need to re-calculate
|
132 |
+
$finder = new Finder();
|
133 |
+
$finder->followLinks();
|
134 |
+
$finder->ignoreDotFiles( false );
|
135 |
+
$finder->ignoreUnreadableDirs( true );
|
136 |
+
|
137 |
+
$files = $finder->in( Path::get_root() );
|
138 |
+
|
139 |
+
foreach ( $files as $file ) {
|
140 |
+
|
141 |
+
if ( $file->isReadable() ) {
|
142 |
+
$directory_sizes[ wp_normalize_path( $file->getRealpath() ) ] = $file->getSize();
|
143 |
+
} else {
|
144 |
+
$directory_sizes[ wp_normalize_path( $file->getRealpath() ) ] = 0;
|
145 |
+
}
|
146 |
+
|
147 |
+
}
|
148 |
+
|
149 |
+
set_transient( 'hmbkp_directory_filesizes', $directory_sizes, DAY_IN_SECONDS );
|
150 |
+
|
151 |
+
// Remove the lock
|
152 |
+
delete_transient( 'hmbkp_directory_filesizes_running' );
|
153 |
+
|
154 |
+
return $directory_sizes;
|
155 |
+
|
156 |
+
}
|
157 |
+
|
158 |
+
/**
|
159 |
+
* Get the total filesize for a given file or directory
|
160 |
+
*
|
161 |
+
* If $file is a file then just return the result of `filesize()`.
|
162 |
+
* If $file is a directory then recursively calculate the size.
|
163 |
+
*
|
164 |
+
* @param \SplFileInfo $file The file or directory you want to know the size of
|
165 |
+
*
|
166 |
+
* @return int The total filesize of the file or directory
|
167 |
+
*/
|
168 |
+
public function filesize( \SplFileInfo $file ) {
|
169 |
+
|
170 |
+
// Skip missing or unreadable files
|
171 |
+
if ( ! file_exists( $file->getPathname() ) || ! $file->getRealpath() || ! $file->isReadable() ) {
|
172 |
+
return 0;
|
173 |
+
}
|
174 |
+
|
175 |
+
// If it's a file then just pass back the filesize
|
176 |
+
if ( $file->isFile() ) {
|
177 |
+
return $file->getSize();
|
178 |
+
}
|
179 |
+
|
180 |
+
// If it's a directory then pull it from the cached filesize array
|
181 |
+
if ( $file->isDir() ) {
|
182 |
+
return $this->directory_filesize( $file );
|
183 |
+
}
|
184 |
+
|
185 |
+
}
|
186 |
+
|
187 |
+
public function directory_filesize( \SplFileInfo $file ) {
|
188 |
+
|
189 |
+
// If we haven't calculated the site size yet then kick it off in a thread
|
190 |
+
$directory_sizes = get_transient( 'hmbkp_directory_filesizes' );
|
191 |
+
|
192 |
+
|
193 |
+
if ( ! is_array( $directory_sizes ) ) {
|
194 |
+
$this->rebuild_directory_filesizes();
|
195 |
+
|
196 |
+
// Intentionally return null so the caller can tell that the size is being calculated
|
197 |
+
return null;
|
198 |
+
}
|
199 |
+
|
200 |
+
// The filepaths are stored in keys so we need to flip for use with preg_grep
|
201 |
+
$directory_sizes = array_flip( preg_grep( '(' . wp_normalize_path( $file->getRealPath() ) . ')', array_flip( $directory_sizes ) ) );
|
202 |
+
|
203 |
+
if ( $this->excludes ) {
|
204 |
+
$excludes = implode( '|', $this->excludes->get_excludes_for_regex() );
|
205 |
+
if ( $excludes ) {
|
206 |
+
// Use PREG_GREP_INVERT to remove any filepaths which match an exclude rule
|
207 |
+
$directory_sizes = array_flip( preg_grep( '(' . $excludes . ')', array_flip( $directory_sizes ), PREG_GREP_INVERT ) );
|
208 |
+
}
|
209 |
+
}
|
210 |
+
|
211 |
+
// Directory size is now just a sum of all files across all sub directories
|
212 |
+
return absint( array_sum( $directory_sizes ) );
|
213 |
+
|
214 |
+
}
|
215 |
+
|
216 |
+
public function rebuild_directory_filesizes() {
|
217 |
+
|
218 |
+
if ( $this->is_site_size_being_calculated() ) {
|
219 |
+
return false;
|
220 |
+
}
|
221 |
+
|
222 |
+
// Mark the filesize as being calculated
|
223 |
+
set_transient( 'hmbkp_directory_filesizes_running', true, HOUR_IN_SECONDS );
|
224 |
+
|
225 |
+
// Schedule a Backdrop task to trigger a recalculation
|
226 |
+
$task = new Task( array( $this, 'recursive_filesize_scanner' ) );
|
227 |
+
$task->schedule();
|
228 |
+
|
229 |
+
}
|
230 |
+
|
231 |
+
}
|
classes/class-webhook-service.php
CHANGED
@@ -39,7 +39,7 @@ abstract class Webhook_Service extends Service {
|
|
39 |
}
|
40 |
|
41 |
$webhook_url = $this->get_url();
|
42 |
-
$file = $backup->
|
43 |
$download = add_query_arg( 'hmbkp_download', base64_encode( $file ), HMBKP_ADMIN_URL );
|
44 |
$domain = parse_url( home_url(), PHP_URL_HOST ) . parse_url( home_url(), PHP_URL_PATH );
|
45 |
|
@@ -100,7 +100,7 @@ abstract class Webhook_Service extends Service {
|
|
100 |
$ret = wp_remote_post( $webhook_url, $webhook_args );
|
101 |
|
102 |
if ( is_wp_error( $ret ) ) {
|
103 |
-
$backup->
|
104 |
}
|
105 |
|
106 |
}
|
39 |
}
|
40 |
|
41 |
$webhook_url = $this->get_url();
|
42 |
+
$file = $backup->get_backup_filepath();
|
43 |
$download = add_query_arg( 'hmbkp_download', base64_encode( $file ), HMBKP_ADMIN_URL );
|
44 |
$domain = parse_url( home_url(), PHP_URL_HOST ) . parse_url( home_url(), PHP_URL_PATH );
|
45 |
|
100 |
$ret = wp_remote_post( $webhook_url, $webhook_args );
|
101 |
|
102 |
if ( is_wp_error( $ret ) ) {
|
103 |
+
$backup->warning( 'Webhook', sprintf( __( 'Error: %s', 'backupwordpress' ), $ret->get_error_message() ) );
|
104 |
}
|
105 |
|
106 |
}
|
classes/class-wpremote-webhook-service.php
CHANGED
@@ -69,4 +69,4 @@ class WPRemote_Webhook_Service extends Webhook_Service {
|
|
69 |
}
|
70 |
|
71 |
// Register the service
|
72 |
-
Services::register( __FILE__, 'HM\BackUpWordPress\WPRemote_Webhook_Service' );
|
69 |
}
|
70 |
|
71 |
// Register the service
|
72 |
+
Services::register( __FILE__, 'HM\BackUpWordPress\WPRemote_Webhook_Service' );
|
composer.json
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name" : "humanmade/backupwordpress",
|
3 |
+
"description": "Simple automated backups of your WordPress powered website.",
|
4 |
+
"keywords" : [
|
5 |
+
"wordpress",
|
6 |
+
"backup"
|
7 |
+
],
|
8 |
+
"type" : "wordpress-plugin",
|
9 |
+
"homepage" : "https://github.com/humanmade/backupwordpress",
|
10 |
+
"license" : "GPL-3.0",
|
11 |
+
"authors" : [
|
12 |
+
{
|
13 |
+
"name" : "Human Made Limited",
|
14 |
+
"email" : "backupwordpress@hmn.md",
|
15 |
+
"homepage": "https://bwp.hmn.md/"
|
16 |
+
}
|
17 |
+
],
|
18 |
+
"support" : {
|
19 |
+
"issues": "https://github.com/humanmade/backupwordpress/issues"
|
20 |
+
},
|
21 |
+
"require": {
|
22 |
+
"symfony/finder": "~2.6",
|
23 |
+
"ifsnop/mysqldump-php":"2.*"
|
24 |
+
}
|
25 |
+
}
|
composer.lock
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"_readme": [
|
3 |
+
"This file locks the dependencies of your project to a known state",
|
4 |
+
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
5 |
+
"This file is @generated automatically"
|
6 |
+
],
|
7 |
+
"hash": "a5d481f4e8a2c50cc0c488d199f4c83e",
|
8 |
+
"content-hash": "77f3dd81e4007d746a29f10fd5dce8af",
|
9 |
+
"packages": [
|
10 |
+
{
|
11 |
+
"name": "ifsnop/mysqldump-php",
|
12 |
+
"version": "v2.1",
|
13 |
+
"source": {
|
14 |
+
"type": "git",
|
15 |
+
"url": "https://github.com/ifsnop/mysqldump-php.git",
|
16 |
+
"reference": "701024dd160f15796bed8130c3bdeb26c634785a"
|
17 |
+
},
|
18 |
+
"dist": {
|
19 |
+
"type": "zip",
|
20 |
+
"url": "https://api.github.com/repos/ifsnop/mysqldump-php/zipball/701024dd160f15796bed8130c3bdeb26c634785a",
|
21 |
+
"reference": "701024dd160f15796bed8130c3bdeb26c634785a",
|
22 |
+
"shasum": ""
|
23 |
+
},
|
24 |
+
"require": {
|
25 |
+
"php": ">=5.3.0"
|
26 |
+
},
|
27 |
+
"require-dev": {
|
28 |
+
"phpunit/phpunit": "3.7.*",
|
29 |
+
"squizlabs/php_codesniffer": "1.*"
|
30 |
+
},
|
31 |
+
"type": "library",
|
32 |
+
"autoload": {
|
33 |
+
"psr-4": {
|
34 |
+
"Ifsnop\\": "src/Ifsnop/"
|
35 |
+
}
|
36 |
+
},
|
37 |
+
"notification-url": "https://packagist.org/downloads/",
|
38 |
+
"license": [
|
39 |
+
"MIT"
|
40 |
+
],
|
41 |
+
"authors": [
|
42 |
+
{
|
43 |
+
"name": "Diego Torres",
|
44 |
+
"homepage": "https://github.com/ifsnop",
|
45 |
+
"role": "Developer"
|
46 |
+
}
|
47 |
+
],
|
48 |
+
"description": "This is a php version of linux's mysqldump in terminal \"$ mysqldump -u username -p...\"",
|
49 |
+
"homepage": "https://github.com/ifsnop/mysqldump-php",
|
50 |
+
"keywords": [
|
51 |
+
"backup",
|
52 |
+
"database",
|
53 |
+
"dump",
|
54 |
+
"export",
|
55 |
+
"mysql",
|
56 |
+
"mysqldump",
|
57 |
+
"pdo",
|
58 |
+
"sqlite"
|
59 |
+
],
|
60 |
+
"time": "2015-10-19 15:58:11"
|
61 |
+
},
|
62 |
+
{
|
63 |
+
"name": "symfony/finder",
|
64 |
+
"version": "v2.8.2",
|
65 |
+
"source": {
|
66 |
+
"type": "git",
|
67 |
+
"url": "https://github.com/symfony/finder.git",
|
68 |
+
"reference": "c90fabdd97e431ee19b6383999cf35334dff27da"
|
69 |
+
},
|
70 |
+
"dist": {
|
71 |
+
"type": "zip",
|
72 |
+
"url": "https://api.github.com/repos/symfony/finder/zipball/c90fabdd97e431ee19b6383999cf35334dff27da",
|
73 |
+
"reference": "c90fabdd97e431ee19b6383999cf35334dff27da",
|
74 |
+
"shasum": ""
|
75 |
+
},
|
76 |
+
"require": {
|
77 |
+
"php": ">=5.3.9"
|
78 |
+
},
|
79 |
+
"type": "library",
|
80 |
+
"extra": {
|
81 |
+
"branch-alias": {
|
82 |
+
"dev-master": "2.8-dev"
|
83 |
+
}
|
84 |
+
},
|
85 |
+
"autoload": {
|
86 |
+
"psr-4": {
|
87 |
+
"Symfony\\Component\\Finder\\": ""
|
88 |
+
},
|
89 |
+
"exclude-from-classmap": [
|
90 |
+
"/Tests/"
|
91 |
+
]
|
92 |
+
},
|
93 |
+
"notification-url": "https://packagist.org/downloads/",
|
94 |
+
"license": [
|
95 |
+
"MIT"
|
96 |
+
],
|
97 |
+
"authors": [
|
98 |
+
{
|
99 |
+
"name": "Fabien Potencier",
|
100 |
+
"email": "fabien@symfony.com"
|
101 |
+
},
|
102 |
+
{
|
103 |
+
"name": "Symfony Community",
|
104 |
+
"homepage": "https://symfony.com/contributors"
|
105 |
+
}
|
106 |
+
],
|
107 |
+
"description": "Symfony Finder Component",
|
108 |
+
"homepage": "https://symfony.com",
|
109 |
+
"time": "2016-01-14 08:26:52"
|
110 |
+
}
|
111 |
+
],
|
112 |
+
"packages-dev": [],
|
113 |
+
"aliases": [],
|
114 |
+
"minimum-stability": "stable",
|
115 |
+
"stability-flags": [],
|
116 |
+
"prefer-stable": false,
|
117 |
+
"prefer-lowest": false,
|
118 |
+
"platform": [],
|
119 |
+
"platform-dev": []
|
120 |
+
}
|
functions/core.php
CHANGED
@@ -1,20 +1,12 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
|
4 |
-
* Returns the backup path
|
5 |
-
*
|
6 |
-
* @see Path
|
7 |
-
* @todo remove the need for this
|
8 |
-
*/
|
9 |
-
function hmbkp_path() {
|
10 |
-
return HM\BackUpWordPress\Path::get_instance()->get_path();
|
11 |
-
}
|
12 |
|
13 |
/**
|
14 |
* Handles anything that needs to be
|
15 |
* done when the plugin is updated
|
16 |
*/
|
17 |
-
function
|
18 |
|
19 |
// Update from backUpWordPress 0.4.5
|
20 |
if ( get_option( 'bkpwp_max_backups' ) ) {
|
@@ -63,7 +55,7 @@ function hmbkp_update() {
|
|
63 |
/**
|
64 |
* Setup a backwards compatible schedule
|
65 |
*/
|
66 |
-
$legacy_schedule = new
|
67 |
|
68 |
// Backup type
|
69 |
if ( ( defined( 'HMBKP_FILES_ONLY' ) && HMBKP_FILES_ONLY ) || get_option( 'hmbkp_files_only' ) ) {
|
@@ -254,7 +246,7 @@ function hmbkp_update() {
|
|
254 |
// Update from PRIOR_VERSION
|
255 |
if ( get_option( 'hmbkp_plugin_version' ) && version_compare( '3.3.0', get_option( 'hmbkp_plugin_version' ), '>' ) ) {
|
256 |
|
257 |
-
$schedules =
|
258 |
|
259 |
// Loop through all schedules and re-set the reccurrence to include hmbkp_
|
260 |
foreach ( $schedules->get_schedules() as $schedule ) {
|
@@ -272,17 +264,17 @@ function hmbkp_update() {
|
|
272 |
}
|
273 |
|
274 |
// Every update
|
275 |
-
if ( get_option( 'hmbkp_plugin_version' ) && version_compare(
|
276 |
|
277 |
-
|
278 |
|
279 |
-
|
280 |
|
281 |
}
|
282 |
|
283 |
// Update the stored version
|
284 |
-
if ( get_option( 'hmbkp_plugin_version' ) !==
|
285 |
-
update_option( 'hmbkp_plugin_version',
|
286 |
}
|
287 |
|
288 |
}
|
@@ -290,9 +282,9 @@ function hmbkp_update() {
|
|
290 |
/**
|
291 |
* Setup the default backup schedules
|
292 |
*/
|
293 |
-
function
|
294 |
|
295 |
-
$schedules =
|
296 |
|
297 |
if ( $schedules->get_schedules() ) {
|
298 |
return;
|
@@ -302,9 +294,9 @@ function hmbkp_setup_default_schedules() {
|
|
302 |
* Schedule a database backup daily and store backups
|
303 |
* for the last 2 weeks
|
304 |
*/
|
305 |
-
$database_daily = new
|
306 |
$database_daily->set_type( 'database' );
|
307 |
-
$database_daily->set_schedule_start_time(
|
308 |
$database_daily->set_reoccurrence( 'daily' );
|
309 |
$database_daily->set_max_backups( 7 );
|
310 |
$database_daily->save();
|
@@ -313,9 +305,9 @@ function hmbkp_setup_default_schedules() {
|
|
313 |
* Schedule a complete backup to run weekly and store backups for
|
314 |
* the last 3 months
|
315 |
*/
|
316 |
-
$complete_weekly = new
|
317 |
$complete_weekly->set_type( 'complete' );
|
318 |
-
$complete_weekly->set_schedule_start_time(
|
319 |
$complete_weekly->set_reoccurrence( 'weekly' );
|
320 |
$complete_weekly->set_max_backups( 3 );
|
321 |
$complete_weekly->save();
|
@@ -328,7 +320,7 @@ function hmbkp_setup_default_schedules() {
|
|
328 |
|
329 |
}
|
330 |
|
331 |
-
add_action( 'admin_init', '
|
332 |
|
333 |
/**
|
334 |
* Return an array of cron schedules
|
@@ -336,7 +328,7 @@ add_action( 'admin_init', 'hmbkp_setup_default_schedules' );
|
|
336 |
* @param $schedules
|
337 |
* @return array $reccurrences
|
338 |
*/
|
339 |
-
function
|
340 |
|
341 |
$schedules += array(
|
342 |
'hourly' => array( 'interval' => HOUR_IN_SECONDS, 'display' => __( 'Once Hourly', 'backupwordpress' ) ),
|
@@ -350,7 +342,7 @@ function hmbkp_cron_schedules( $schedules = array() ) {
|
|
350 |
return $schedules;
|
351 |
}
|
352 |
|
353 |
-
add_filter( 'cron_schedules', '
|
354 |
|
355 |
/**
|
356 |
* Recursively delete a directory including
|
@@ -360,26 +352,31 @@ add_filter( 'cron_schedules', 'hmbkp_cron_schedules' );
|
|
360 |
* @return bool
|
361 |
* @return bool|WP_Error
|
362 |
*/
|
363 |
-
function
|
364 |
|
365 |
-
if ( false !== strpos(
|
366 |
return new WP_Error( 'hmbkp_invalid_action_error', sprintf( __( 'You can only delete directories inside your WordPress installation', 'backupwordpress' ) ) );
|
|
|
367 |
|
368 |
-
if ( is_file( $dir ) )
|
369 |
@unlink( $dir );
|
|
|
370 |
|
371 |
-
if ( ! is_dir( $dir ) || ! is_readable( $dir ) )
|
372 |
return false;
|
|
|
373 |
|
374 |
-
$files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dir ), RecursiveIteratorIterator::CHILD_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD );
|
375 |
|
376 |
foreach ( $files as $file ) {
|
377 |
|
378 |
-
if ( $file->isDir() )
|
379 |
@rmdir( $file->getPathname() );
|
|
|
380 |
|
381 |
-
else
|
382 |
@unlink( $file->getPathname() );
|
|
|
383 |
|
384 |
}
|
385 |
|
@@ -394,15 +391,13 @@ function hmbkp_rmdirtree( $dir ) {
|
|
394 |
*
|
395 |
* @return bool
|
396 |
*/
|
397 |
-
function
|
398 |
|
399 |
-
if ( ! wp_is_writable(
|
400 |
return false;
|
401 |
}
|
402 |
|
403 |
-
|
404 |
-
|
405 |
-
if ( ! is_readable( $test_backup->get_root() ) ) {
|
406 |
return false;
|
407 |
}
|
408 |
|
@@ -416,7 +411,7 @@ function hmbkp_possible() {
|
|
416 |
*
|
417 |
* return int the filesize
|
418 |
*/
|
419 |
-
function
|
420 |
|
421 |
$max_size = '10mb';
|
422 |
|
@@ -427,10 +422,10 @@ function hmbkp_get_max_attachment_size() {
|
|
427 |
|
428 |
}
|
429 |
|
430 |
-
function
|
431 |
|
432 |
// Path is inaccessible
|
433 |
-
if ( strpos( $dir,
|
434 |
return false;
|
435 |
}
|
436 |
|
@@ -442,8 +437,8 @@ function hmbkp_is_path_accessible( $dir ) {
|
|
442 |
*
|
443 |
* @return array
|
444 |
*/
|
445 |
-
function
|
446 |
-
return
|
447 |
}
|
448 |
|
449 |
/**
|
@@ -464,7 +459,7 @@ function hmbkp_get_cron_schedules() {
|
|
464 |
* }
|
465 |
* @return int $timestamp Returns the resulting timestamp on success and Int 0 on failure
|
466 |
*/
|
467 |
-
function
|
468 |
|
469 |
// Default to in 10 minutes
|
470 |
if ( ! empty( $times['now'] ) ) {
|
@@ -484,7 +479,7 @@ function hmbkp_determine_start_time( $type, $times = array() ) {
|
|
484 |
|
485 |
$args = wp_parse_args( $times, $default_times );
|
486 |
|
487 |
-
$intervals =
|
488 |
|
489 |
// Allow the hours and minutes to be overwritten by a constant
|
490 |
if ( defined( 'HMBKP_SCHEDULE_TIME' ) && HMBKP_SCHEDULE_TIME ) {
|
@@ -558,9 +553,100 @@ function hmbkp_determine_start_time( $type, $times = array() ) {
|
|
558 |
*
|
559 |
* @return string
|
560 |
*/
|
561 |
-
function
|
562 |
|
563 |
$query_args = array_merge( $query_args, array( 'action' => 'hmbkp_' . $action ) );
|
564 |
|
565 |
return esc_url( wp_nonce_url( add_query_arg( $query_args, admin_url( 'admin-post.php' ) ), 'hmbkp_' . $action, 'hmbkp-' . $action . '_nonce' ) );
|
566 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<?php
|
2 |
|
3 |
+
namespace HM\BackUpWordPress;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
/**
|
6 |
* Handles anything that needs to be
|
7 |
* done when the plugin is updated
|
8 |
*/
|
9 |
+
function update() {
|
10 |
|
11 |
// Update from backUpWordPress 0.4.5
|
12 |
if ( get_option( 'bkpwp_max_backups' ) ) {
|
55 |
/**
|
56 |
* Setup a backwards compatible schedule
|
57 |
*/
|
58 |
+
$legacy_schedule = new Scheduled_Backup( 'backup' );
|
59 |
|
60 |
// Backup type
|
61 |
if ( ( defined( 'HMBKP_FILES_ONLY' ) && HMBKP_FILES_ONLY ) || get_option( 'hmbkp_files_only' ) ) {
|
246 |
// Update from PRIOR_VERSION
|
247 |
if ( get_option( 'hmbkp_plugin_version' ) && version_compare( '3.3.0', get_option( 'hmbkp_plugin_version' ), '>' ) ) {
|
248 |
|
249 |
+
$schedules = Schedules::get_instance();
|
250 |
|
251 |
// Loop through all schedules and re-set the reccurrence to include hmbkp_
|
252 |
foreach ( $schedules->get_schedules() as $schedule ) {
|
264 |
}
|
265 |
|
266 |
// Every update
|
267 |
+
if ( get_option( 'hmbkp_plugin_version' ) && version_compare( Plugin::PLUGIN_VERSION, get_option( 'hmbkp_plugin_version' ), '>' ) ) {
|
268 |
|
269 |
+
Setup::deactivate();
|
270 |
|
271 |
+
Path::get_instance()->protect_path( 'reset' );
|
272 |
|
273 |
}
|
274 |
|
275 |
// Update the stored version
|
276 |
+
if ( get_option( 'hmbkp_plugin_version' ) !== Plugin::PLUGIN_VERSION ) {
|
277 |
+
update_option( 'hmbkp_plugin_version', Plugin::PLUGIN_VERSION );
|
278 |
}
|
279 |
|
280 |
}
|
282 |
/**
|
283 |
* Setup the default backup schedules
|
284 |
*/
|
285 |
+
function setup_default_schedules() {
|
286 |
|
287 |
+
$schedules = Schedules::get_instance();
|
288 |
|
289 |
if ( $schedules->get_schedules() ) {
|
290 |
return;
|
294 |
* Schedule a database backup daily and store backups
|
295 |
* for the last 2 weeks
|
296 |
*/
|
297 |
+
$database_daily = new Scheduled_Backup( (string) time() );
|
298 |
$database_daily->set_type( 'database' );
|
299 |
+
$database_daily->set_schedule_start_time( determine_start_time( 'daily', array( 'hours' => '23', 'minutes' => '0' ) ) );
|
300 |
$database_daily->set_reoccurrence( 'daily' );
|
301 |
$database_daily->set_max_backups( 7 );
|
302 |
$database_daily->save();
|
305 |
* Schedule a complete backup to run weekly and store backups for
|
306 |
* the last 3 months
|
307 |
*/
|
308 |
+
$complete_weekly = new Scheduled_Backup( (string) ( time() + 1 ) );
|
309 |
$complete_weekly->set_type( 'complete' );
|
310 |
+
$complete_weekly->set_schedule_start_time( determine_start_time( 'weekly', array( 'day_of_week' => 'sunday', 'hours' => '3', 'minutes' => '0' ) ) );
|
311 |
$complete_weekly->set_reoccurrence( 'weekly' );
|
312 |
$complete_weekly->set_max_backups( 3 );
|
313 |
$complete_weekly->save();
|
320 |
|
321 |
}
|
322 |
|
323 |
+
add_action( 'admin_init', '\HM\BackUpWordPress\setup_default_schedules' );
|
324 |
|
325 |
/**
|
326 |
* Return an array of cron schedules
|
328 |
* @param $schedules
|
329 |
* @return array $reccurrences
|
330 |
*/
|
331 |
+
function cron_schedules( $schedules = array() ) {
|
332 |
|
333 |
$schedules += array(
|
334 |
'hourly' => array( 'interval' => HOUR_IN_SECONDS, 'display' => __( 'Once Hourly', 'backupwordpress' ) ),
|
342 |
return $schedules;
|
343 |
}
|
344 |
|
345 |
+
add_filter( 'cron_schedules', '\HM\BackUpWordPress\cron_schedules' );
|
346 |
|
347 |
/**
|
348 |
* Recursively delete a directory including
|
352 |
* @return bool
|
353 |
* @return bool|WP_Error
|
354 |
*/
|
355 |
+
function rmdirtree( $dir ) {
|
356 |
|
357 |
+
if ( false !== strpos( Path::get_home_path(), $dir ) ) {
|
358 |
return new WP_Error( 'hmbkp_invalid_action_error', sprintf( __( 'You can only delete directories inside your WordPress installation', 'backupwordpress' ) ) );
|
359 |
+
}
|
360 |
|
361 |
+
if ( is_file( $dir ) ){
|
362 |
@unlink( $dir );
|
363 |
+
}
|
364 |
|
365 |
+
if ( ! is_dir( $dir ) || ! is_readable( $dir ) ){
|
366 |
return false;
|
367 |
+
}
|
368 |
|
369 |
+
$files = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( $dir, \RecursiveDirectoryIterator::SKIP_DOTS ), \RecursiveIteratorIterator::CHILD_FIRST, \RecursiveIteratorIterator::CATCH_GET_CHILD );
|
370 |
|
371 |
foreach ( $files as $file ) {
|
372 |
|
373 |
+
if ( $file->isDir() ){
|
374 |
@rmdir( $file->getPathname() );
|
375 |
+
}
|
376 |
|
377 |
+
else{
|
378 |
@unlink( $file->getPathname() );
|
379 |
+
}
|
380 |
|
381 |
}
|
382 |
|
391 |
*
|
392 |
* @return bool
|
393 |
*/
|
394 |
+
function is_backup_possible() {
|
395 |
|
396 |
+
if ( ! wp_is_writable( Path::get_path() ) || ! is_dir( Path::get_path() ) ) {
|
397 |
return false;
|
398 |
}
|
399 |
|
400 |
+
if ( ! is_readable( Path::get_root() ) ) {
|
|
|
|
|
401 |
return false;
|
402 |
}
|
403 |
|
411 |
*
|
412 |
* return int the filesize
|
413 |
*/
|
414 |
+
function get_max_attachment_size() {
|
415 |
|
416 |
$max_size = '10mb';
|
417 |
|
422 |
|
423 |
}
|
424 |
|
425 |
+
function is_path_accessible( $dir ) {
|
426 |
|
427 |
// Path is inaccessible
|
428 |
+
if ( strpos( $dir, Path::get_home_path() ) === false ) {
|
429 |
return false;
|
430 |
}
|
431 |
|
437 |
*
|
438 |
* @return array
|
439 |
*/
|
440 |
+
function get_cron_schedules() {
|
441 |
+
return cron_schedules();
|
442 |
}
|
443 |
|
444 |
/**
|
459 |
* }
|
460 |
* @return int $timestamp Returns the resulting timestamp on success and Int 0 on failure
|
461 |
*/
|
462 |
+
function determine_start_time( $type, $times = array() ) {
|
463 |
|
464 |
// Default to in 10 minutes
|
465 |
if ( ! empty( $times['now'] ) ) {
|
479 |
|
480 |
$args = wp_parse_args( $times, $default_times );
|
481 |
|
482 |
+
$intervals = get_cron_schedules();
|
483 |
|
484 |
// Allow the hours and minutes to be overwritten by a constant
|
485 |
if ( defined( 'HMBKP_SCHEDULE_TIME' ) && HMBKP_SCHEDULE_TIME ) {
|
553 |
*
|
554 |
* @return string
|
555 |
*/
|
556 |
+
function admin_action_url( $action, array $query_args = array() ) {
|
557 |
|
558 |
$query_args = array_merge( $query_args, array( 'action' => 'hmbkp_' . $action ) );
|
559 |
|
560 |
return esc_url( wp_nonce_url( add_query_arg( $query_args, admin_url( 'admin-post.php' ) ), 'hmbkp_' . $action, 'hmbkp-' . $action . '_nonce' ) );
|
561 |
}
|
562 |
+
|
563 |
+
/**
|
564 |
+
* OS dependant way to pipe stderr to null
|
565 |
+
*
|
566 |
+
* @return string The exec argument to pipe stderr to null
|
567 |
+
*/
|
568 |
+
function ignore_stderr() {
|
569 |
+
|
570 |
+
// If we're on Windows
|
571 |
+
if ( DIRECTORY_SEPARATOR == '\\' ) {
|
572 |
+
return '2>nul';
|
573 |
+
}
|
574 |
+
|
575 |
+
// Or Unix
|
576 |
+
return '2>/dev/null';
|
577 |
+
|
578 |
+
}
|
579 |
+
|
580 |
+
/**
|
581 |
+
* Return the contents of `$directory` as a single depth list ordered by total filesize.
|
582 |
+
*
|
583 |
+
* Will schedule background threads to recursively calculate the filesize of subdirectories.
|
584 |
+
* The total filesize of each directory and subdirectory is cached in a transient for 1 week.
|
585 |
+
*
|
586 |
+
* @param string $directory The directory to list
|
587 |
+
*
|
588 |
+
* @todo doesn't really belong in this class, should just be a function
|
589 |
+
* @return array returns an array of files ordered by filesize
|
590 |
+
*/
|
591 |
+
function list_directory_by_total_filesize( $directory ) {
|
592 |
+
|
593 |
+
$files = $files_with_no_size = $empty_files = $files_with_size = $unreadable_files = array();
|
594 |
+
|
595 |
+
if ( ! is_dir( $directory ) ) {
|
596 |
+
return $files;
|
597 |
+
}
|
598 |
+
|
599 |
+
$finder = new \Symfony\Component\Finder\Finder();
|
600 |
+
$finder->followLinks();
|
601 |
+
$finder->ignoreDotFiles( false );
|
602 |
+
$finder->ignoreUnreadableDirs();
|
603 |
+
$finder->depth( '== 0' );
|
604 |
+
|
605 |
+
$site_size = new Site_Size;
|
606 |
+
|
607 |
+
$files = $finder->in( $directory );
|
608 |
+
|
609 |
+
foreach ( $files as $entry ) {
|
610 |
+
|
611 |
+
// Get the total filesize for each file and directory
|
612 |
+
$filesize = $site_size->filesize( $entry );
|
613 |
+
|
614 |
+
if ( $filesize ) {
|
615 |
+
|
616 |
+
// If there is already a file with exactly the same filesize then let's keep increasing the filesize of this one until we don't have a clash
|
617 |
+
while ( array_key_exists( $filesize, $files_with_size ) ) {
|
618 |
+
$filesize ++;
|
619 |
+
}
|
620 |
+
|
621 |
+
$files_with_size[ $filesize ] = $entry;
|
622 |
+
|
623 |
+
} elseif ( 0 === $filesize ) {
|
624 |
+
|
625 |
+
$empty_files[] = $entry;
|
626 |
+
|
627 |
+
} else {
|
628 |
+
|
629 |
+
$files_with_no_size[] = $entry;
|
630 |
+
|
631 |
+
}
|
632 |
+
|
633 |
+
}
|
634 |
+
|
635 |
+
// Sort files by filesize, largest first
|
636 |
+
krsort( $files_with_size );
|
637 |
+
|
638 |
+
// Add 0 byte files / directories to the bottom
|
639 |
+
$files = $files_with_size + array_merge( $empty_files, $unreadable_files );
|
640 |
+
|
641 |
+
// Add directories that are still calculating to the top
|
642 |
+
if ( $files_with_no_size ) {
|
643 |
+
|
644 |
+
// We have to loop as merging or concatenating the array would re-flow the keys which we don't want because the filesize is stored in the key
|
645 |
+
foreach ( $files_with_no_size as $entry ) {
|
646 |
+
array_unshift( $files, $entry );
|
647 |
+
}
|
648 |
+
}
|
649 |
+
|
650 |
+
return $files;
|
651 |
+
|
652 |
+
}
|
functions/interface.php
CHANGED
@@ -1,12 +1,14 @@
|
|
1 |
<?php
|
2 |
|
|
|
|
|
3 |
/**
|
4 |
* Displays a row in the manage backups table
|
5 |
*
|
6 |
* @param string $file
|
7 |
-
* @param
|
8 |
*/
|
9 |
-
function
|
10 |
|
11 |
$encoded_file = urlencode( base64_encode( $file ) );
|
12 |
$offset = get_option( 'gmt_offset' ) * 3600;
|
@@ -23,11 +25,11 @@ function hmbkp_get_backup_row( $file, HM\BackUpWordPress\Scheduled_Backup $sched
|
|
23 |
<?php echo esc_html( size_format( @filesize( $file ) ) ); ?>
|
24 |
</td>
|
25 |
|
26 |
-
<td><?php echo esc_html(
|
27 |
|
28 |
<td>
|
29 |
|
30 |
-
<?php if (
|
31 |
<a href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'hmbkp_backup_archive' => $encoded_file, 'hmbkp_schedule_id' => $schedule->get_id(), 'action' => 'hmbkp_request_download_backup' ), admin_url( 'admin-post.php' ) ), 'hmbkp_download_backup', 'hmbkp_download_backup_nonce' ) ); ?>" class="download-action"><?php _e( 'Download', 'backupwordpress' ); ?></a> |
|
32 |
<?php endif; ?>
|
33 |
|
@@ -45,7 +47,7 @@ function hmbkp_get_backup_row( $file, HM\BackUpWordPress\Scheduled_Backup $sched
|
|
45 |
*
|
46 |
* @return void
|
47 |
*/
|
48 |
-
function
|
49 |
|
50 |
$current_screen = get_current_screen();
|
51 |
|
@@ -58,7 +60,7 @@ function hmbkp_admin_notices() {
|
|
58 |
return;
|
59 |
}
|
60 |
|
61 |
-
$notices =
|
62 |
|
63 |
if ( empty( $notices ) ) {
|
64 |
return;
|
@@ -71,9 +73,6 @@ function hmbkp_admin_notices() {
|
|
71 |
<div id="hmbkp-warning-backup" class="error notice is-dismissible">
|
72 |
<p>
|
73 |
<strong><?php _e( 'BackUpWordPress detected issues with your last backup.', 'backupwordpress' ); ?></strong>
|
74 |
-
<a href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'hmbkp_dismiss_error' ), admin_url( 'admin-post.php' ) ), 'hmbkp_dismiss_error', 'hmbkp_dismiss_error_nonce' ) ); ?>" style="float: right;" class="button">
|
75 |
-
<?php _e( 'Dismiss', 'backupwordpress' ); ?>
|
76 |
-
</a>
|
77 |
</p>
|
78 |
|
79 |
<ul>
|
@@ -126,9 +125,10 @@ function hmbkp_admin_notices() {
|
|
126 |
|
127 |
<p><?php echo wp_kses_data( $msg ); ?></p>
|
128 |
|
129 |
-
<button type="button" class="notice-dismiss"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'backupwordpress' ); ?></span></button>
|
130 |
-
|
131 |
<?php endforeach; ?>
|
|
|
|
|
|
|
132 |
</div>
|
133 |
|
134 |
<?php endif; ?>
|
@@ -140,16 +140,16 @@ function hmbkp_admin_notices() {
|
|
140 |
<?php echo ob_get_clean();
|
141 |
|
142 |
}
|
143 |
-
add_action( 'admin_notices', '
|
144 |
-
add_action( 'network_admin_notices', '
|
145 |
|
146 |
-
function
|
147 |
|
148 |
-
$notices =
|
149 |
|
150 |
$messages = array();
|
151 |
|
152 |
-
if ( !
|
153 |
$php_user = '<PHP USER>';
|
154 |
$php_group = '<PHP GROUP>';
|
155 |
} else {
|
@@ -158,15 +158,15 @@ function hmbkp_set_server_config_notices() {
|
|
158 |
$php_group = reset( $groups );
|
159 |
}
|
160 |
|
161 |
-
if ( ! is_dir(
|
162 |
-
$messages[] = sprintf( __( 'The backups directory can\'t be created because your %1$s directory isn\'t writable. Run %2$s or %3$s or create the folder yourself.', 'backupwordpress' ), '<code>' . esc_html( dirname(
|
163 |
}
|
164 |
|
165 |
-
if ( is_dir(
|
166 |
-
$messages[] = sprintf( __( 'Your backups directory isn\'t writable. Run %1$s or %2$s or set the permissions yourself.', 'backupwordpress' ), '<code>chown -R ' . esc_html( $php_user ) . ':' . esc_html( $php_group ) . ' ' . esc_html(
|
167 |
}
|
168 |
|
169 |
-
if (
|
170 |
$messages[] = sprintf( __( '%1$s is running in %2$s, please contact your host and ask them to disable it. BackUpWordPress may not work correctly whilst %3$s is on.', 'backupwordpress' ), '<code>PHP</code>', sprintf( '<a href="%1$s">%2$s</a>', __( 'http://php.net/manual/en/features.safe-mode.php', 'backupwordpress' ), __( 'Safe Mode', 'backupwordpress' ) ), '<code>' . __( 'Safe Mode', 'backupwordpress' ) . '</code>' );
|
171 |
}
|
172 |
|
@@ -177,27 +177,25 @@ function hmbkp_set_server_config_notices() {
|
|
177 |
|
178 |
$messages[] = sprintf( __( 'Your custom path does not exist', 'backupwordpress' ) );
|
179 |
|
180 |
-
} elseif (
|
181 |
|
182 |
$messages[] = sprintf( __( 'Your custom path is unreachable due to a restriction set in your PHP configuration (open_basedir)', 'backupwordpress' ) );
|
183 |
|
184 |
} else {
|
185 |
|
186 |
if ( ! @is_dir( HMBKP_PATH ) ) {
|
187 |
-
$messages[] = sprintf( __( 'Your custom backups directory %1$s doesn\'t exist and can\'t be created, your backups will be saved to %2$s instead.', 'backupwordpress' ), '<code>' . esc_html( HMBKP_PATH ) . '</code>', '<code>' . esc_html(
|
188 |
}
|
189 |
|
190 |
if ( @is_dir( HMBKP_PATH ) && ! wp_is_writable( HMBKP_PATH ) ) {
|
191 |
-
$messages[] = sprintf( __( 'Your custom backups directory %1$s isn\'t writable, new backups will be saved to %2$s instead.', 'backupwordpress' ), '<code>' . esc_html( HMBKP_PATH ) . '</code>', '<code>' . esc_html(
|
192 |
|
193 |
}
|
194 |
}
|
195 |
}
|
196 |
|
197 |
-
|
198 |
-
|
199 |
-
if ( ! is_readable( $test_backup->get_root() ) ) {
|
200 |
-
$messages[] = sprintf( __( 'Your site root path %s isn\'t readable.', 'backupwordpress' ), '<code>' . $test_backup->get_root() . '</code>' );
|
201 |
}
|
202 |
|
203 |
if ( count( $messages ) > 0 ) {
|
@@ -205,7 +203,7 @@ function hmbkp_set_server_config_notices() {
|
|
205 |
}
|
206 |
|
207 |
}
|
208 |
-
add_action( 'admin_init', '
|
209 |
|
210 |
/**
|
211 |
* Hook in an change the plugin description when BackUpWordPress is activated
|
@@ -213,50 +211,29 @@ add_action( 'admin_init', 'hmbkp_set_server_config_notices' );
|
|
213 |
* @param array $plugins
|
214 |
* @return array $plugins
|
215 |
*/
|
216 |
-
function
|
217 |
|
218 |
$menu = is_multisite() ? 'Settings' : 'Tools';
|
219 |
|
220 |
if ( isset( $plugins[HMBKP_PLUGIN_SLUG . '/backupwordpress.php'] ) ) {
|
221 |
-
$plugins[HMBKP_PLUGIN_SLUG . '/backupwordpress.php']['Description'] = str_replace( 'Once activated you\'ll find me under <strong>' . $menu . ' → Backups</strong>', 'Find me under <strong><a href="' . esc_url(
|
222 |
}
|
223 |
|
224 |
return $plugins;
|
225 |
|
226 |
}
|
227 |
|
228 |
-
add_filter( 'all_plugins', '
|
229 |
-
|
230 |
-
/**
|
231 |
-
* Parse the json string of errors and
|
232 |
-
* output as a human readable message
|
233 |
-
*
|
234 |
-
* @access public
|
235 |
-
* @return null
|
236 |
-
*/
|
237 |
-
function hmbkp_backup_errors_message() {
|
238 |
-
|
239 |
-
$message = '';
|
240 |
-
|
241 |
-
foreach ( (array) json_decode( hmbkp_backup_errors() ) as $key => $errors ) {
|
242 |
-
foreach ( $errors as $error ) {
|
243 |
-
$message .= '<p><strong>' . esc_html( $key ) . '</strong>: <code>' . implode( ':', array_map( 'esc_html', (array) $error ) ) . '</code></p>';
|
244 |
-
}
|
245 |
-
}
|
246 |
-
|
247 |
-
return $message;
|
248 |
-
|
249 |
-
}
|
250 |
|
251 |
/**
|
252 |
* Get the human readable backup type in.
|
253 |
*
|
254 |
* @access public
|
255 |
* @param string $type
|
256 |
-
* @param
|
257 |
* @return string
|
258 |
*/
|
259 |
-
function
|
260 |
|
261 |
if ( strpos( $type, 'complete' ) !== false ) {
|
262 |
return __( 'Database and Files', 'backupwordpress' );
|
@@ -271,7 +248,7 @@ function hmbkp_human_get_type( $type, HM\BackUpWordPress\Scheduled_Backup $sched
|
|
271 |
}
|
272 |
|
273 |
if ( ! is_null( $schedule ) ) {
|
274 |
-
return
|
275 |
}
|
276 |
|
277 |
return __( 'Legacy', 'backupwordpress' );
|
@@ -282,16 +259,18 @@ function hmbkp_human_get_type( $type, HM\BackUpWordPress\Scheduled_Backup $sched
|
|
282 |
* Display the row of actions for a schedule
|
283 |
*
|
284 |
* @access public
|
285 |
-
* @param
|
286 |
* @return void
|
287 |
*/
|
288 |
-
function
|
|
|
|
|
289 |
|
290 |
ob_start(); ?>
|
291 |
|
292 |
-
<span class="hmbkp-status"<?php if ( $
|
293 |
-
<?php echo $
|
294 |
-
<a href="<?php echo
|
295 |
</span>
|
296 |
|
297 |
<?php $output = ob_get_clean();
|
@@ -304,37 +283,7 @@ function hmbkp_schedule_status( HM\BackUpWordPress\Scheduled_Backup $schedule, $
|
|
304 |
|
305 |
}
|
306 |
|
307 |
-
|
308 |
-
* Load the backup errors file
|
309 |
-
*
|
310 |
-
* @return string
|
311 |
-
*/
|
312 |
-
function hmbkp_backup_errors() {
|
313 |
-
|
314 |
-
if ( ! file_exists( hmbkp_path() . '/.backup_errors' ) ) {
|
315 |
-
return '';
|
316 |
-
}
|
317 |
-
|
318 |
-
return file_get_contents( hmbkp_path() . '/.backup_errors' );
|
319 |
-
|
320 |
-
}
|
321 |
-
|
322 |
-
/**
|
323 |
-
* Load the backup warnings file
|
324 |
-
*
|
325 |
-
* @return string
|
326 |
-
*/
|
327 |
-
function hmbkp_backup_warnings() {
|
328 |
-
|
329 |
-
if ( ! file_exists( hmbkp_path() . '/.backup_warnings' ) ) {
|
330 |
-
return '';
|
331 |
-
}
|
332 |
-
|
333 |
-
return file_get_contents( hmbkp_path() . '/.backup_warnings' );
|
334 |
-
|
335 |
-
}
|
336 |
-
|
337 |
-
function hmbkp_backups_number( \HM\BackUpWordPress\Scheduled_Backup $schedule ) {
|
338 |
|
339 |
$number = count( $schedule->get_backups() );
|
340 |
|
@@ -347,7 +296,7 @@ function hmbkp_backups_number( \HM\BackUpWordPress\Scheduled_Backup $schedule )
|
|
347 |
echo apply_filters( 'hmbkp_backups_number', $output, $number );
|
348 |
}
|
349 |
|
350 |
-
function
|
351 |
|
352 |
$titles = array(
|
353 |
'complete-hourly' => esc_html__( 'Complete Hourly', 'backupwordpress' ),
|
@@ -381,13 +330,13 @@ function hmbkp_translated_schedule_title( $slug, $title ) {
|
|
381 |
|
382 |
}
|
383 |
|
384 |
-
function
|
385 |
|
386 |
$url = is_multisite() ? network_admin_url( 'settings.php?page=' . HMBKP_PLUGIN_SLUG ) : admin_url( 'tools.php?page=' . HMBKP_PLUGIN_SLUG );
|
387 |
|
388 |
-
|
389 |
|
390 |
-
if ( ! empty( $_REQUEST['hmbkp_schedule_id'] ) &&
|
391 |
$url = add_query_arg( 'hmbkp_schedule_id', sanitize_text_field( $_REQUEST['hmbkp_schedule_id'] ), $url );
|
392 |
}
|
393 |
|
@@ -400,7 +349,7 @@ function hmbkp_get_settings_url() {
|
|
400 |
*
|
401 |
* @param $error_message
|
402 |
*/
|
403 |
-
function
|
404 |
|
405 |
$hmbkp_settings_errors = get_transient( 'hmbkp_settings_errors' );
|
406 |
|
@@ -413,12 +362,22 @@ function hmbkp_add_settings_error( $error_message ){
|
|
413 |
|
414 |
}
|
415 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
416 |
/**
|
417 |
* Fetch the form submission errors for display.
|
418 |
*
|
419 |
* @return mixed
|
420 |
*/
|
421 |
-
function
|
422 |
return get_transient( 'hmbkp_settings_errors' );
|
423 |
}
|
424 |
|
@@ -427,11 +386,11 @@ function hmbkp_get_settings_errors() {
|
|
427 |
*
|
428 |
* @return bool
|
429 |
*/
|
430 |
-
function
|
431 |
return delete_transient( 'hmbkp_settings_errors' );
|
432 |
}
|
433 |
|
434 |
-
function
|
435 |
|
436 |
$open_basedir = @ini_get( 'open_basedir' );
|
437 |
|
1 |
<?php
|
2 |
|
3 |
+
namespace HM\BackUpWordPress;
|
4 |
+
|
5 |
/**
|
6 |
* Displays a row in the manage backups table
|
7 |
*
|
8 |
* @param string $file
|
9 |
+
* @param Scheduled_Backup $schedule
|
10 |
*/
|
11 |
+
function get_backup_row( $file, Scheduled_Backup $schedule ) {
|
12 |
|
13 |
$encoded_file = urlencode( base64_encode( $file ) );
|
14 |
$offset = get_option( 'gmt_offset' ) * 3600;
|
25 |
<?php echo esc_html( size_format( @filesize( $file ) ) ); ?>
|
26 |
</td>
|
27 |
|
28 |
+
<td><?php echo esc_html( human_get_type( $file, $schedule ) ); ?></td>
|
29 |
|
30 |
<td>
|
31 |
|
32 |
+
<?php if ( is_path_accessible( Path::get_path() ) ) : ?>
|
33 |
<a href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'hmbkp_backup_archive' => $encoded_file, 'hmbkp_schedule_id' => $schedule->get_id(), 'action' => 'hmbkp_request_download_backup' ), admin_url( 'admin-post.php' ) ), 'hmbkp_download_backup', 'hmbkp_download_backup_nonce' ) ); ?>" class="download-action"><?php _e( 'Download', 'backupwordpress' ); ?></a> |
|
34 |
<?php endif; ?>
|
35 |
|
47 |
*
|
48 |
* @return void
|
49 |
*/
|
50 |
+
function admin_notices() {
|
51 |
|
52 |
$current_screen = get_current_screen();
|
53 |
|
60 |
return;
|
61 |
}
|
62 |
|
63 |
+
$notices = Notices::get_instance()->get_notices();
|
64 |
|
65 |
if ( empty( $notices ) ) {
|
66 |
return;
|
73 |
<div id="hmbkp-warning-backup" class="error notice is-dismissible">
|
74 |
<p>
|
75 |
<strong><?php _e( 'BackUpWordPress detected issues with your last backup.', 'backupwordpress' ); ?></strong>
|
|
|
|
|
|
|
76 |
</p>
|
77 |
|
78 |
<ul>
|
125 |
|
126 |
<p><?php echo wp_kses_data( $msg ); ?></p>
|
127 |
|
|
|
|
|
128 |
<?php endforeach; ?>
|
129 |
+
|
130 |
+
<button type="button" class="notice-dismiss"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'backupwordpress' ); ?></span></button>
|
131 |
+
|
132 |
</div>
|
133 |
|
134 |
<?php endif; ?>
|
140 |
<?php echo ob_get_clean();
|
141 |
|
142 |
}
|
143 |
+
add_action( 'admin_notices', 'HM\BackUpWordPress\admin_notices' );
|
144 |
+
add_action( 'network_admin_notices', 'HM\BackUpWordPress\admin_notices' );
|
145 |
|
146 |
+
function set_server_config_notices() {
|
147 |
|
148 |
+
$notices = Notices::get_instance();
|
149 |
|
150 |
$messages = array();
|
151 |
|
152 |
+
if ( ! Backup_Utilities::is_exec_available() ) {
|
153 |
$php_user = '<PHP USER>';
|
154 |
$php_group = '<PHP GROUP>';
|
155 |
} else {
|
158 |
$php_group = reset( $groups );
|
159 |
}
|
160 |
|
161 |
+
if ( ! is_dir( Path::get_path() ) ) {
|
162 |
+
$messages[] = sprintf( __( 'The backups directory can\'t be created because your %1$s directory isn\'t writable. Run %2$s or %3$s or create the folder yourself.', 'backupwordpress' ), '<code>' . esc_html( dirname( Path::get_path() ) ) . '</code>', '<code>chown ' . esc_html( $php_user ) . ':' . esc_html( $php_group ) . ' ' . esc_html( dirname( Path::get_path() ) ) . '</code>', '<code>chmod 777 ' . esc_html( dirname( Path::get_path() ) ) . '</code>' );
|
163 |
}
|
164 |
|
165 |
+
if ( is_dir( Path::get_path() ) && ! wp_is_writable( Path::get_path() ) ) {
|
166 |
+
$messages[] = sprintf( __( 'Your backups directory isn\'t writable. Run %1$s or %2$s or set the permissions yourself.', 'backupwordpress' ), '<code>chown -R ' . esc_html( $php_user ) . ':' . esc_html( $php_group ) . ' ' . esc_html( Path::get_path() ) . '</code>', '<code>chmod -R 777 ' . esc_html( Path::get_path() ) . '</code>' );
|
167 |
}
|
168 |
|
169 |
+
if ( Backup_Utilities::is_safe_mode_on() ) {
|
170 |
$messages[] = sprintf( __( '%1$s is running in %2$s, please contact your host and ask them to disable it. BackUpWordPress may not work correctly whilst %3$s is on.', 'backupwordpress' ), '<code>PHP</code>', sprintf( '<a href="%1$s">%2$s</a>', __( 'http://php.net/manual/en/features.safe-mode.php', 'backupwordpress' ), __( 'Safe Mode', 'backupwordpress' ) ), '<code>' . __( 'Safe Mode', 'backupwordpress' ) . '</code>' );
|
171 |
}
|
172 |
|
177 |
|
178 |
$messages[] = sprintf( __( 'Your custom path does not exist', 'backupwordpress' ) );
|
179 |
|
180 |
+
} elseif ( is_restricted_custom_path() ) {
|
181 |
|
182 |
$messages[] = sprintf( __( 'Your custom path is unreachable due to a restriction set in your PHP configuration (open_basedir)', 'backupwordpress' ) );
|
183 |
|
184 |
} else {
|
185 |
|
186 |
if ( ! @is_dir( HMBKP_PATH ) ) {
|
187 |
+
$messages[] = sprintf( __( 'Your custom backups directory %1$s doesn\'t exist and can\'t be created, your backups will be saved to %2$s instead.', 'backupwordpress' ), '<code>' . esc_html( HMBKP_PATH ) . '</code>', '<code>' . esc_html( Path::get_path() ) . '</code>' );
|
188 |
}
|
189 |
|
190 |
if ( @is_dir( HMBKP_PATH ) && ! wp_is_writable( HMBKP_PATH ) ) {
|
191 |
+
$messages[] = sprintf( __( 'Your custom backups directory %1$s isn\'t writable, new backups will be saved to %2$s instead.', 'backupwordpress' ), '<code>' . esc_html( HMBKP_PATH ) . '</code>', '<code>' . esc_html( Path::get_path() ) . '</code>' );
|
192 |
|
193 |
}
|
194 |
}
|
195 |
}
|
196 |
|
197 |
+
if ( ! is_readable( Path::get_root() ) ) {
|
198 |
+
$messages[] = sprintf( __( 'Your site root path %s isn\'t readable.', 'backupwordpress' ), '<code>' . Path::get_root() . '</code>' );
|
|
|
|
|
199 |
}
|
200 |
|
201 |
if ( count( $messages ) > 0 ) {
|
203 |
}
|
204 |
|
205 |
}
|
206 |
+
add_action( 'admin_init', 'HM\BackUpWordPress\set_server_config_notices' );
|
207 |
|
208 |
/**
|
209 |
* Hook in an change the plugin description when BackUpWordPress is activated
|
211 |
* @param array $plugins
|
212 |
* @return array $plugins
|
213 |
*/
|
214 |
+
function plugin_row( $plugins ) {
|
215 |
|
216 |
$menu = is_multisite() ? 'Settings' : 'Tools';
|
217 |
|
218 |
if ( isset( $plugins[HMBKP_PLUGIN_SLUG . '/backupwordpress.php'] ) ) {
|
219 |
+
$plugins[HMBKP_PLUGIN_SLUG . '/backupwordpress.php']['Description'] = str_replace( 'Once activated you\'ll find me under <strong>' . $menu . ' → Backups</strong>', 'Find me under <strong><a href="' . esc_url( get_settings_url() ) . '">' . $menu . ' → Backups</a></strong>', $plugins[HMBKP_PLUGIN_SLUG . '/backupwordpress.php']['Description'] );
|
220 |
}
|
221 |
|
222 |
return $plugins;
|
223 |
|
224 |
}
|
225 |
|
226 |
+
add_filter( 'all_plugins', 'HM\BackUpWordPress\plugin_row', 10 );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
227 |
|
228 |
/**
|
229 |
* Get the human readable backup type in.
|
230 |
*
|
231 |
* @access public
|
232 |
* @param string $type
|
233 |
+
* @param Scheduled_Backup $schedule (default: null)
|
234 |
* @return string
|
235 |
*/
|
236 |
+
function human_get_type( $type, Scheduled_Backup $schedule = null ) {
|
237 |
|
238 |
if ( strpos( $type, 'complete' ) !== false ) {
|
239 |
return __( 'Database and Files', 'backupwordpress' );
|
248 |
}
|
249 |
|
250 |
if ( ! is_null( $schedule ) ) {
|
251 |
+
return human_get_type( $schedule->get_type() );
|
252 |
}
|
253 |
|
254 |
return __( 'Legacy', 'backupwordpress' );
|
259 |
* Display the row of actions for a schedule
|
260 |
*
|
261 |
* @access public
|
262 |
+
* @param Scheduled_Backup $schedule
|
263 |
* @return void
|
264 |
*/
|
265 |
+
function schedule_status( Scheduled_Backup $schedule, $echo = true ) {
|
266 |
+
|
267 |
+
$status = new Backup_Status( $schedule->get_id() );
|
268 |
|
269 |
ob_start(); ?>
|
270 |
|
271 |
+
<span class="hmbkp-status"<?php if ( $status->get_status() ) { ?> title="<?php printf( __( 'Started %s ago', 'backupwordpress' ), human_time_diff( $status->get_start_time() ) ); ?>"<?php } ?>>
|
272 |
+
<?php echo $status->get_status() ? wp_kses_data( $status->get_status() ) : __( 'Starting backup...', 'backupwordpress' ); ?>
|
273 |
+
<a href="<?php echo admin_action_url( 'request_cancel_backup', array( 'hmbkp_schedule_id' => $schedule->get_id() ) ); ?>"><?php _e( 'cancel', 'backupwordpress' ); ?></a>
|
274 |
</span>
|
275 |
|
276 |
<?php $output = ob_get_clean();
|
283 |
|
284 |
}
|
285 |
|
286 |
+
function backups_number( Scheduled_Backup $schedule ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
287 |
|
288 |
$number = count( $schedule->get_backups() );
|
289 |
|
296 |
echo apply_filters( 'hmbkp_backups_number', $output, $number );
|
297 |
}
|
298 |
|
299 |
+
function translated_schedule_title( $slug, $title ) {
|
300 |
|
301 |
$titles = array(
|
302 |
'complete-hourly' => esc_html__( 'Complete Hourly', 'backupwordpress' ),
|
330 |
|
331 |
}
|
332 |
|
333 |
+
function get_settings_url() {
|
334 |
|
335 |
$url = is_multisite() ? network_admin_url( 'settings.php?page=' . HMBKP_PLUGIN_SLUG ) : admin_url( 'tools.php?page=' . HMBKP_PLUGIN_SLUG );
|
336 |
|
337 |
+
schedules::get_instance()->refresh_schedules();
|
338 |
|
339 |
+
if ( ! empty( $_REQUEST['hmbkp_schedule_id'] ) && schedules::get_instance()->get_schedule( sanitize_text_field( $_REQUEST['hmbkp_schedule_id'] ) ) ) {
|
340 |
$url = add_query_arg( 'hmbkp_schedule_id', sanitize_text_field( $_REQUEST['hmbkp_schedule_id'] ), $url );
|
341 |
}
|
342 |
|
349 |
*
|
350 |
* @param $error_message
|
351 |
*/
|
352 |
+
function add_settings_error( $error_message ) {
|
353 |
|
354 |
$hmbkp_settings_errors = get_transient( 'hmbkp_settings_errors' );
|
355 |
|
362 |
|
363 |
}
|
364 |
|
365 |
+
/**
|
366 |
+
* Back compat version of add_settings_error
|
367 |
+
*
|
368 |
+
* @deprecated 3.4 add_settings_error()
|
369 |
+
*/
|
370 |
+
function hmbkp_add_settings_error( $error_message ) {
|
371 |
+
_deprecated_function( __FUNCTION__, '3.4', 'add_settings_error()' );
|
372 |
+
add_settings_error( $error_message );
|
373 |
+
}
|
374 |
+
|
375 |
/**
|
376 |
* Fetch the form submission errors for display.
|
377 |
*
|
378 |
* @return mixed
|
379 |
*/
|
380 |
+
function get_settings_errors() {
|
381 |
return get_transient( 'hmbkp_settings_errors' );
|
382 |
}
|
383 |
|
386 |
*
|
387 |
* @return bool
|
388 |
*/
|
389 |
+
function clear_settings_errors(){
|
390 |
return delete_transient( 'hmbkp_settings_errors' );
|
391 |
}
|
392 |
|
393 |
+
function is_restricted_custom_path() {
|
394 |
|
395 |
$open_basedir = @ini_get( 'open_basedir' );
|
396 |
|
languages/backupwordpress.pot
CHANGED
@@ -1,78 +1,78 @@
|
|
1 |
-
# Copyright (C)
|
2 |
# This file is distributed under the GPL-2+.
|
3 |
msgid ""
|
4 |
msgstr ""
|
5 |
-
"Project-Id-Version: BackUpWordPress 3.
|
6 |
"Report-Msgid-Bugs-To: backupwordpress@hmn.md\n"
|
7 |
-
"POT-Creation-Date:
|
8 |
"MIME-Version: 1.0\n"
|
9 |
"Content-Type: text/plain; charset=utf-8\n"
|
10 |
"Content-Transfer-Encoding: 8bit\n"
|
11 |
-
"PO-Revision-Date:
|
12 |
"Last-Translator: Human Made Limited\n"
|
13 |
"Language-Team: Human Made Limited\n"
|
14 |
-
"X-Generator: grunt-wp-i18n 0.
|
15 |
|
16 |
-
#: admin/actions.php:
|
17 |
msgid "The schedule ID was not provided. Aborting."
|
18 |
msgstr ""
|
19 |
|
20 |
-
#: admin/actions.php:
|
21 |
msgid "Backup type cannot be empty"
|
22 |
msgstr ""
|
23 |
|
24 |
-
#: admin/actions.php:
|
25 |
msgid "Invalid backup type"
|
26 |
msgstr ""
|
27 |
|
28 |
-
#: admin/actions.php:
|
29 |
msgid "Schedule cannot be empty"
|
30 |
msgstr ""
|
31 |
|
32 |
-
#: admin/actions.php:
|
33 |
msgid "Invalid schedule"
|
34 |
msgstr ""
|
35 |
|
36 |
-
#: admin/actions.php:
|
37 |
msgid "Day of the week must be a valid, lowercase day name"
|
38 |
msgstr ""
|
39 |
|
40 |
-
#: admin/actions.php:
|
41 |
msgid "Day of month must be between 1 and 31"
|
42 |
msgstr ""
|
43 |
|
44 |
-
#: admin/actions.php:
|
45 |
msgid "Hours must be between 0 and 23"
|
46 |
msgstr ""
|
47 |
|
48 |
-
#: admin/actions.php:
|
49 |
msgid "Minutes must be between 0 and 59"
|
50 |
msgstr ""
|
51 |
|
52 |
-
#: admin/actions.php:
|
53 |
msgid "Max backups can't be empty"
|
54 |
msgstr ""
|
55 |
|
56 |
-
#: admin/actions.php:
|
57 |
msgid "Max backups must be a number"
|
58 |
msgstr ""
|
59 |
|
60 |
-
#: admin/actions.php:
|
61 |
msgid "Max backups must be greater than 0"
|
62 |
msgstr ""
|
63 |
|
64 |
-
#: admin/actions.php:
|
65 |
msgid "BackUpWordPress has detected a problem."
|
66 |
msgstr ""
|
67 |
|
68 |
-
#: admin/actions.php:
|
69 |
msgid ""
|
70 |
"%1$s is returning a %2$s response which could mean cron jobs aren't getting "
|
71 |
"fired properly. BackUpWordPress relies on wp-cron to run scheduled backups. "
|
72 |
"See the %3$s for more details."
|
73 |
msgstr ""
|
74 |
|
75 |
-
#: admin/actions.php:
|
76 |
msgid ""
|
77 |
"%1$s is returning a %2$s response which could mean cron jobs aren't getting "
|
78 |
"fired properly. BackUpWordPress relies on wp-cron to run scheduled backups, "
|
@@ -80,93 +80,93 @@ msgid ""
|
|
80 |
"for manual backups. See the %3$s for more details."
|
81 |
msgstr ""
|
82 |
|
83 |
-
#: admin/backups-table.php:
|
84 |
msgid "Size"
|
85 |
msgstr ""
|
86 |
|
87 |
-
#: admin/backups-table.php:
|
88 |
msgid "Type"
|
89 |
msgstr ""
|
90 |
|
91 |
-
#: admin/backups-table.php:
|
92 |
msgid "Actions"
|
93 |
msgstr ""
|
94 |
|
95 |
-
#: admin/backups-table.php:
|
96 |
msgid "This is where your backups will appear once you have some."
|
97 |
msgstr ""
|
98 |
|
99 |
-
#: admin/backups.php:
|
100 |
msgid "add schedule"
|
101 |
msgstr ""
|
102 |
|
103 |
-
#: admin/constants.php:
|
104 |
msgid ""
|
105 |
"You can %1$s any of the following %2$s in your %3$s to control advanced "
|
106 |
"settings. %4$s. Defined %5$s will be highlighted."
|
107 |
msgstr ""
|
108 |
|
109 |
-
#: admin/constants.php:
|
110 |
msgid "Constants"
|
111 |
msgstr ""
|
112 |
|
113 |
-
#: admin/constants.php:
|
114 |
msgid "The Codex can help"
|
115 |
msgstr ""
|
116 |
|
117 |
-
#: admin/constants.php:
|
118 |
-
#: admin/constants.php:
|
119 |
-
#: admin/constants.php:
|
120 |
msgid "You've set it to: %s"
|
121 |
msgstr ""
|
122 |
|
123 |
-
#: admin/constants.php:
|
124 |
msgid ""
|
125 |
"The path to the folder you would like to store your backup files in, "
|
126 |
"defaults to %s."
|
127 |
msgstr ""
|
128 |
|
129 |
-
#: admin/constants.php:
|
130 |
-
#: admin/constants.php:
|
131 |
-
#: admin/constants.php:
|
132 |
msgid "e.g."
|
133 |
msgstr ""
|
134 |
|
135 |
-
#: admin/constants.php:
|
136 |
msgid ""
|
137 |
"The path to your %1$s executable. Will be used for the %2$s part of the "
|
138 |
"back up if available."
|
139 |
msgstr ""
|
140 |
|
141 |
-
#: admin/constants.php:
|
142 |
msgid "database"
|
143 |
msgstr ""
|
144 |
|
145 |
-
#: admin/constants.php:
|
146 |
msgid ""
|
147 |
"The path to your %1$s executable. Will be used to zip up your %2$s and %3$s "
|
148 |
"if available."
|
149 |
msgstr ""
|
150 |
|
151 |
-
#: admin/constants.php:
|
152 |
msgid "files"
|
153 |
msgstr ""
|
154 |
|
155 |
-
#: admin/constants.php:
|
156 |
msgid ""
|
157 |
"Comma separated list of files or directories to exclude, the backups "
|
158 |
"directory is automatically excluded."
|
159 |
msgstr ""
|
160 |
|
161 |
-
#: admin/constants.php:
|
162 |
msgid "The capability to use when calling %1$s. Defaults to %2$s."
|
163 |
msgstr ""
|
164 |
|
165 |
-
#: admin/constants.php:
|
166 |
msgid "The root directory that is backed up. Defaults to %s."
|
167 |
msgstr ""
|
168 |
|
169 |
-
#: admin/constants.php:
|
170 |
msgid "The time that your schedules should run. Defaults to %s."
|
171 |
msgstr ""
|
172 |
|
@@ -366,315 +366,311 @@ msgid ""
|
|
366 |
"emailing backupwordpress@hmn.md"
|
367 |
msgstr ""
|
368 |
|
369 |
-
#: admin/menu.php:
|
370 |
msgid "Manage Backups"
|
371 |
msgstr ""
|
372 |
|
373 |
-
#: admin/menu.php:
|
374 |
msgid "Backups"
|
375 |
msgstr ""
|
376 |
|
377 |
-
#: admin/menu.php:
|
378 |
msgid "FAQ"
|
379 |
msgstr ""
|
380 |
|
381 |
-
#: admin/menu.php:
|
382 |
msgid "Server Info"
|
383 |
msgstr ""
|
384 |
|
385 |
-
#: admin/menu.php:
|
386 |
msgid "For more information:"
|
387 |
msgstr ""
|
388 |
|
389 |
-
#: admin/menu.php:
|
390 |
msgid "Support Forums"
|
391 |
msgstr ""
|
392 |
|
393 |
-
#: admin/menu.php:
|
394 |
msgid "Help with translation"
|
395 |
msgstr ""
|
396 |
|
397 |
-
#: admin/page.php:
|
398 |
msgid "Support"
|
399 |
msgstr ""
|
400 |
|
401 |
-
#: admin/page.php:
|
402 |
msgid "Enable Support"
|
403 |
msgstr ""
|
404 |
|
405 |
-
#: admin/page.php:
|
406 |
msgid ""
|
407 |
"If you're finding BackUpWordPress useful, please %1$s rate it on the plugin "
|
408 |
"directory%2$s."
|
409 |
msgstr ""
|
410 |
|
411 |
-
#: admin/schedule-form-excludes.php:
|
412 |
msgid "Currently Excluded"
|
413 |
msgstr ""
|
414 |
|
415 |
-
#: admin/schedule-form-excludes.php:
|
416 |
msgid ""
|
417 |
"We automatically detect and ignore common <abbr title=\"Version Control "
|
418 |
"Systems\">VCS</abbr> folders and other backup plugin folders."
|
419 |
msgstr ""
|
420 |
|
421 |
-
#: admin/schedule-form-excludes.php:
|
422 |
msgid "Default rule"
|
423 |
msgstr ""
|
424 |
|
425 |
-
#: admin/schedule-form-excludes.php:
|
426 |
msgid "Defined in wp-config.php"
|
427 |
msgstr ""
|
428 |
|
429 |
-
#: admin/schedule-form-excludes.php:
|
430 |
msgid "Stop excluding"
|
431 |
msgstr ""
|
432 |
|
433 |
-
#: admin/schedule-form-excludes.php:
|
434 |
msgid "Your Site"
|
435 |
msgstr ""
|
436 |
|
437 |
-
#: admin/schedule-form-excludes.php:
|
438 |
msgid ""
|
439 |
"Here's a directory listing of all files on your site, you can browse "
|
440 |
"through and exclude files or folders that you don't want included in your "
|
441 |
"backup."
|
442 |
msgstr ""
|
443 |
|
444 |
-
#: admin/schedule-form-excludes.php:
|
445 |
msgid "Name"
|
446 |
msgstr ""
|
447 |
|
448 |
-
#: admin/schedule-form-excludes.php:
|
449 |
msgid "Permissions"
|
450 |
msgstr ""
|
451 |
|
452 |
-
#: admin/schedule-form-excludes.php:
|
453 |
msgid "Status"
|
454 |
msgstr ""
|
455 |
|
456 |
-
#: admin/schedule-form-excludes.php:
|
457 |
msgid "Refresh"
|
458 |
msgstr ""
|
459 |
|
460 |
-
#: admin/schedule-form-excludes.php:
|
461 |
msgid "Symlink"
|
462 |
msgstr ""
|
463 |
|
464 |
-
#: admin/schedule-form-excludes.php:
|
465 |
msgid "Folder"
|
466 |
msgstr ""
|
467 |
|
468 |
-
#: admin/schedule-form-excludes.php:
|
469 |
msgid "Recalculate the size of this directory"
|
470 |
msgstr ""
|
471 |
|
472 |
-
#: admin/schedule-form-excludes.php:
|
473 |
msgid "File"
|
474 |
msgstr ""
|
475 |
|
476 |
-
#: admin/schedule-form-excludes.php:
|
477 |
msgid "Unreadable files won't be backed up."
|
478 |
msgstr ""
|
479 |
|
480 |
-
#: admin/schedule-form-excludes.php:
|
481 |
msgid "Unreadable"
|
482 |
msgstr ""
|
483 |
|
484 |
-
#: admin/schedule-form-excludes.php:
|
485 |
msgid "Excluded"
|
486 |
msgstr ""
|
487 |
|
488 |
-
#: admin/schedule-form-excludes.php:
|
489 |
msgid "Exclude →"
|
490 |
msgstr ""
|
491 |
|
492 |
-
#: admin/schedule-form-excludes.php:
|
493 |
msgid "This folder is empty"
|
494 |
msgstr ""
|
495 |
|
496 |
-
#: admin/schedule-form-excludes.php:
|
497 |
-
#: admin/schedule-settings.php:
|
498 |
msgid "Done"
|
499 |
msgstr ""
|
500 |
|
501 |
-
#: admin/schedule-form.php:
|
502 |
msgid "Settings"
|
503 |
msgstr ""
|
504 |
|
505 |
-
#: admin/schedule-form.php:
|
506 |
msgid "Backup"
|
507 |
msgstr ""
|
508 |
|
509 |
-
#: admin/schedule-form.php:
|
510 |
msgid "Both Database & files"
|
511 |
msgstr ""
|
512 |
|
513 |
-
#: admin/schedule-form.php:
|
514 |
msgid "Files only"
|
515 |
msgstr ""
|
516 |
|
517 |
-
#: admin/schedule-form.php:
|
518 |
msgid "Database only"
|
519 |
msgstr ""
|
520 |
|
521 |
-
#: admin/schedule-form.php:
|
522 |
msgid "Schedule"
|
523 |
msgstr ""
|
524 |
|
525 |
-
#: admin/schedule-form.php:
|
526 |
msgid "Manual Only"
|
527 |
msgstr ""
|
528 |
|
529 |
-
#: admin/schedule-form.php:
|
530 |
msgid "Start Day"
|
531 |
msgstr ""
|
532 |
|
533 |
-
#: admin/schedule-form.php:
|
534 |
msgid "Monday"
|
535 |
msgstr ""
|
536 |
|
537 |
-
#: admin/schedule-form.php:
|
538 |
msgid "Tuesday"
|
539 |
msgstr ""
|
540 |
|
541 |
-
#: admin/schedule-form.php:
|
542 |
msgid "Wednesday"
|
543 |
msgstr ""
|
544 |
|
545 |
-
#: admin/schedule-form.php:
|
546 |
msgid "Thursday"
|
547 |
msgstr ""
|
548 |
|
549 |
-
#: admin/schedule-form.php:
|
550 |
msgid "Friday"
|
551 |
msgstr ""
|
552 |
|
553 |
-
#: admin/schedule-form.php:
|
554 |
msgid "Saturday"
|
555 |
msgstr ""
|
556 |
|
557 |
-
#: admin/schedule-form.php:
|
558 |
msgid "Sunday"
|
559 |
msgstr ""
|
560 |
|
561 |
-
#: admin/schedule-form.php:
|
562 |
msgid "Start Day of Month"
|
563 |
msgstr ""
|
564 |
|
565 |
-
#: admin/schedule-form.php:
|
566 |
msgid "Start Time"
|
567 |
msgstr ""
|
568 |
|
569 |
-
#: admin/schedule-form.php:
|
570 |
msgid "Hours"
|
571 |
msgstr ""
|
572 |
|
573 |
-
#: admin/schedule-form.php:
|
574 |
msgid "Minutes"
|
575 |
msgstr ""
|
576 |
|
577 |
-
#: admin/schedule-form.php:
|
578 |
msgid "24-hour format."
|
579 |
msgstr ""
|
580 |
|
581 |
-
#: admin/schedule-form.php:
|
582 |
msgid "The second backup will run 12 hours after the first."
|
583 |
msgstr ""
|
584 |
|
585 |
-
#: admin/schedule-form.php:
|
586 |
msgid "Number of backups to store on this server"
|
587 |
msgstr ""
|
588 |
|
589 |
-
#: admin/schedule-form.php:
|
590 |
msgid "Past this limit older backups will be deleted automatically."
|
591 |
msgstr ""
|
592 |
|
593 |
-
#: admin/schedule-form.php:
|
594 |
msgid "This schedule will store a maximum of %s of backups."
|
595 |
msgstr ""
|
596 |
|
597 |
-
#: admin/schedule-sentence.php:
|
598 |
msgid "The next backup will be on %1$s at %2$s %3$s"
|
599 |
msgstr ""
|
600 |
|
601 |
-
#: admin/schedule-sentence.php:
|
602 |
msgid "hourly on the hour"
|
603 |
msgstr ""
|
604 |
|
605 |
-
#: admin/schedule-sentence.php:
|
606 |
msgid "hourly at %s minutes past the hour"
|
607 |
msgstr ""
|
608 |
|
609 |
-
#: admin/schedule-sentence.php:
|
610 |
msgid "daily at %s"
|
611 |
msgstr ""
|
612 |
|
613 |
-
#: admin/schedule-sentence.php:
|
614 |
msgid "every 12 hours at %1$s & %2$s"
|
615 |
msgstr ""
|
616 |
|
617 |
-
#: admin/schedule-sentence.php:
|
618 |
msgid "weekly on %1$s at %2$s"
|
619 |
msgstr ""
|
620 |
|
621 |
-
#: admin/schedule-sentence.php:
|
622 |
msgid "every two weeks on %1$s at %2$s"
|
623 |
msgstr ""
|
624 |
|
625 |
-
#: admin/schedule-sentence.php:
|
626 |
msgid "on the %1$s of each month at %2$s"
|
627 |
msgstr ""
|
628 |
|
629 |
-
#: admin/schedule-sentence.php:
|
630 |
msgid "manually"
|
631 |
msgstr ""
|
632 |
|
633 |
-
#: admin/schedule-sentence.php:
|
634 |
msgid "this server"
|
635 |
msgstr ""
|
636 |
|
637 |
-
#: admin/schedule-sentence.php:
|
638 |
msgid "store the most recent backup in %s"
|
639 |
msgstr ""
|
640 |
|
641 |
-
#: admin/schedule-sentence.php:
|
642 |
msgid "don't store any backups in on this server"
|
643 |
msgstr ""
|
644 |
|
645 |
-
#: admin/schedule-sentence.php:
|
646 |
msgid "store the last %1$s backups in %2$s"
|
647 |
msgstr ""
|
648 |
|
649 |
-
#: admin/schedule-sentence.php:
|
650 |
-
msgid "%s. "
|
651 |
-
msgstr ""
|
652 |
-
|
653 |
-
#: admin/schedule-sentence.php:125
|
654 |
msgid "Send a copy of each backup to %s."
|
655 |
msgstr ""
|
656 |
|
657 |
-
#: admin/schedule-sentence.php:
|
658 |
msgid "Backups will be compressed and should be smaller than this."
|
659 |
msgstr ""
|
660 |
|
661 |
-
#: admin/schedule-sentence.php:
|
662 |
msgid "this shouldn't take long…"
|
663 |
msgstr ""
|
664 |
|
665 |
-
#: admin/schedule-sentence.php:
|
666 |
-
msgid "calculating the size of your
|
667 |
msgstr ""
|
668 |
|
669 |
-
#: admin/schedule-settings.php:
|
670 |
msgid "Run now"
|
671 |
msgstr ""
|
672 |
|
673 |
-
#: admin/schedule-settings.php:
|
674 |
msgid "Excludes"
|
675 |
msgstr ""
|
676 |
|
677 |
-
#: admin/schedule-settings.php:
|
678 |
msgid "Delete"
|
679 |
msgstr ""
|
680 |
|
@@ -696,79 +692,35 @@ msgstr ""
|
|
696 |
msgid "BackUpWordPress Error"
|
697 |
msgstr ""
|
698 |
|
699 |
-
#: classes/class-backup.php:
|
700 |
-
msgid "
|
701 |
msgstr ""
|
702 |
|
703 |
-
#: classes/class-backup.php:
|
704 |
-
msgid "
|
705 |
msgstr ""
|
706 |
|
707 |
-
#: classes/class-
|
708 |
-
msgid "database dump filename must be a non-empty string"
|
709 |
-
msgstr ""
|
710 |
-
|
711 |
-
#: classes/class-backup.php:390
|
712 |
-
msgid "invalid file extension for database dump filename <code>%s</code>"
|
713 |
-
msgstr ""
|
714 |
-
|
715 |
-
#: classes/class-backup.php:424
|
716 |
-
msgid "Invalid root path <code>%s</code> must be a valid directory path"
|
717 |
-
msgstr ""
|
718 |
-
|
719 |
-
#: classes/class-backup.php:450
|
720 |
-
msgid ""
|
721 |
-
"Invalid existing archive filepath <code>%s</code> must be a non-empty "
|
722 |
-
"(string)"
|
723 |
-
msgstr ""
|
724 |
-
|
725 |
-
#: classes/class-backup.php:505
|
726 |
-
msgid ""
|
727 |
-
"Invalid backup type <code>%s</code> must be one of (string) file, database "
|
728 |
-
"or complete"
|
729 |
-
msgstr ""
|
730 |
-
|
731 |
-
#: classes/class-backup.php:935
|
732 |
-
msgid "mysqldump fallback error %s"
|
733 |
-
msgstr ""
|
734 |
-
|
735 |
-
#: classes/class-backup.php:957
|
736 |
-
msgid "Zip command is not available."
|
737 |
-
msgstr ""
|
738 |
-
|
739 |
-
#: classes/class-backup.php:964
|
740 |
-
msgid "ZipArchive method is not available."
|
741 |
-
msgstr ""
|
742 |
-
|
743 |
-
#: classes/class-backup.php:968 classes/class-backup.php:980
|
744 |
-
msgid "No valid archive method found."
|
745 |
-
msgstr ""
|
746 |
-
|
747 |
-
#: classes/class-backup.php:1659
|
748 |
-
msgid "Could not connect to mysql"
|
749 |
-
msgstr ""
|
750 |
-
|
751 |
-
#: classes/class-backupwordpress-wp-cli-command.php:50
|
752 |
msgid "Backup: Dumping database..."
|
753 |
msgstr ""
|
754 |
|
755 |
-
#: classes/class-backupwordpress-wp-cli-command.php:
|
756 |
msgid "Backup: Zipping everything up..."
|
757 |
msgstr ""
|
758 |
|
759 |
-
#: classes/class-backupwordpress-wp-cli-command.php:
|
760 |
msgid "Invalid backup path"
|
761 |
msgstr ""
|
762 |
|
763 |
-
#: classes/class-backupwordpress-wp-cli-command.php:
|
764 |
msgid "Invalid root path"
|
765 |
msgstr ""
|
766 |
|
767 |
-
#: classes/class-backupwordpress-wp-cli-command.php:
|
768 |
msgid "Backup Complete: "
|
769 |
msgstr ""
|
770 |
|
771 |
-
#: classes/class-backupwordpress-wp-cli-command.php:
|
772 |
msgid "Backup Failed"
|
773 |
msgstr ""
|
774 |
|
@@ -847,114 +799,79 @@ msgstr ""
|
|
847 |
msgid "Unfortunately, the backup file was too large to attach to this email."
|
848 |
msgstr ""
|
849 |
|
850 |
-
#: classes/class-path.php:
|
851 |
msgid "This %s file ensures that other people cannot download your backup files."
|
852 |
msgstr ""
|
853 |
|
854 |
-
#: classes/class-plugin.php:
|
855 |
msgid "Update"
|
856 |
msgstr ""
|
857 |
|
858 |
-
#: classes/class-plugin.php:
|
859 |
msgid "Cancel"
|
860 |
msgstr ""
|
861 |
|
862 |
-
#: classes/class-plugin.php:
|
863 |
msgid ""
|
864 |
"Are you sure you want to delete this schedule? All of its backups will also "
|
865 |
"be deleted."
|
866 |
msgstr ""
|
867 |
|
868 |
-
#: classes/class-plugin.php:
|
869 |
-
#: classes/class-plugin.php:
|
870 |
msgid "'Cancel' to go back, 'OK' to delete."
|
871 |
msgstr ""
|
872 |
|
873 |
-
#: classes/class-plugin.php:
|
874 |
msgid "Are you sure you want to delete this backup?"
|
875 |
msgstr ""
|
876 |
|
877 |
-
#: classes/class-plugin.php:
|
878 |
msgid "Are you sure you want to remove this exclude rule?"
|
879 |
msgstr ""
|
880 |
|
881 |
-
#: classes/class-plugin.php:
|
882 |
msgid ""
|
883 |
"Reducing the number of backups that are stored on this server will cause "
|
884 |
"some of your existing backups to be deleted. Are you sure that's what you "
|
885 |
"want?"
|
886 |
msgstr ""
|
887 |
|
888 |
-
#: classes/class-
|
889 |
-
msgid "Invalid Option Name"
|
890 |
-
msgstr ""
|
891 |
-
|
892 |
-
#: classes/class-schedule.php:261
|
893 |
-
msgid "Argument 1 for %s must be a valid integer"
|
894 |
-
msgstr ""
|
895 |
-
|
896 |
-
#: classes/class-schedule.php:607
|
897 |
-
msgid "Argument 1 for %s must be a valid future timestamp"
|
898 |
-
msgstr ""
|
899 |
-
|
900 |
-
#: classes/class-schedule.php:644
|
901 |
msgid "Argument 1 for %s must be a valid cron recurrence or \"manually\""
|
902 |
msgstr ""
|
903 |
|
904 |
-
#: classes/class-
|
905 |
-
msgid "Starting
|
906 |
msgstr ""
|
907 |
|
908 |
-
#: classes/class-
|
909 |
-
|
|
|
910 |
msgstr ""
|
911 |
|
912 |
-
#: classes/class-
|
913 |
-
msgid "Dumping Database %s"
|
914 |
-
msgstr ""
|
915 |
-
|
916 |
-
#: classes/class-schedule.php:906
|
917 |
-
msgid "Verifying Database Dump %s"
|
918 |
-
msgstr ""
|
919 |
-
|
920 |
-
#: classes/class-schedule.php:911
|
921 |
-
msgid "Creating zip archive %s"
|
922 |
-
msgstr ""
|
923 |
-
|
924 |
-
#: classes/class-schedule.php:916
|
925 |
-
msgid "Verifying Zip Archive %s"
|
926 |
-
msgstr ""
|
927 |
-
|
928 |
-
#: classes/class-schedule.php:921
|
929 |
-
msgid "Finishing Backup"
|
930 |
-
msgstr ""
|
931 |
-
|
932 |
-
#: classes/class-schedule.php:972
|
933 |
-
msgid "An unexpected error occurred"
|
934 |
-
msgstr ""
|
935 |
-
|
936 |
-
#: classes/class-schedule.php:1035
|
937 |
#. translators: min=minute
|
938 |
msgid "%s min"
|
939 |
msgid_plural "%s mins"
|
940 |
msgstr[0] ""
|
941 |
msgstr[1] ""
|
942 |
|
943 |
-
#: classes/class-
|
944 |
msgid "%s hour"
|
945 |
msgid_plural "%s hours"
|
946 |
msgstr[0] ""
|
947 |
msgstr[1] ""
|
948 |
|
949 |
-
#: classes/class-
|
950 |
msgid "Argument 1 for %s must be a non-empty string"
|
951 |
msgstr ""
|
952 |
|
953 |
-
#: classes/class-
|
954 |
msgid "%s doesn't exist"
|
955 |
msgstr ""
|
956 |
|
957 |
-
#: classes/class-
|
958 |
msgid "That backup wasn't created by this schedule"
|
959 |
msgstr ""
|
960 |
|
@@ -984,58 +901,54 @@ msgstr ""
|
|
984 |
msgid "Error: %s"
|
985 |
msgstr ""
|
986 |
|
987 |
-
#: functions/core.php:
|
988 |
msgid "BackUpWordPress has set up your default schedules."
|
989 |
msgstr ""
|
990 |
|
991 |
-
#: functions/core.php:
|
992 |
msgid ""
|
993 |
"By default BackUpWordPress performs a daily backup of your database and a "
|
994 |
"weekly backup of your database & files. You can modify these schedules."
|
995 |
msgstr ""
|
996 |
|
997 |
-
#: functions/core.php:
|
998 |
msgid "Once Hourly"
|
999 |
msgstr ""
|
1000 |
|
1001 |
-
#: functions/core.php:
|
1002 |
msgid "Twice Daily"
|
1003 |
msgstr ""
|
1004 |
|
1005 |
-
#: functions/core.php:
|
1006 |
msgid "Once Daily"
|
1007 |
msgstr ""
|
1008 |
|
1009 |
-
#: functions/core.php:
|
1010 |
msgid "Once Weekly"
|
1011 |
msgstr ""
|
1012 |
|
1013 |
-
#: functions/core.php:
|
1014 |
msgid "Once Every Two Weeks"
|
1015 |
msgstr ""
|
1016 |
|
1017 |
-
#: functions/core.php:
|
1018 |
msgid "Once Monthly"
|
1019 |
msgstr ""
|
1020 |
|
1021 |
-
#: functions/core.php:
|
1022 |
msgid "You can only delete directories inside your WordPress installation"
|
1023 |
msgstr ""
|
1024 |
|
1025 |
-
#: functions/interface.php:
|
1026 |
msgid "Download"
|
1027 |
msgstr ""
|
1028 |
|
1029 |
-
#: functions/interface.php:73
|
1030 |
-
msgid "BackUpWordPress detected issues with your last backup."
|
1031 |
-
msgstr ""
|
1032 |
-
|
1033 |
#: functions/interface.php:75
|
1034 |
-
msgid "
|
1035 |
msgstr ""
|
1036 |
|
1037 |
-
#: functions/interface.php:
|
1038 |
-
#: functions/interface.php:
|
1039 |
msgid "Dismiss this notice."
|
1040 |
msgstr ""
|
1041 |
|
@@ -1087,119 +1000,119 @@ msgid ""
|
|
1087 |
"saved to %2$s instead."
|
1088 |
msgstr ""
|
1089 |
|
1090 |
-
#: functions/interface.php:
|
1091 |
msgid "Your site root path %s isn't readable."
|
1092 |
msgstr ""
|
1093 |
|
1094 |
-
#: functions/interface.php:
|
1095 |
msgid "Database and Files"
|
1096 |
msgstr ""
|
1097 |
|
1098 |
-
#: functions/interface.php:
|
1099 |
msgid "Files"
|
1100 |
msgstr ""
|
1101 |
|
1102 |
-
#: functions/interface.php:
|
1103 |
msgid "Database"
|
1104 |
msgstr ""
|
1105 |
|
1106 |
-
#: functions/interface.php:
|
1107 |
msgid "Legacy"
|
1108 |
msgstr ""
|
1109 |
|
1110 |
-
#: functions/interface.php:
|
1111 |
msgid "Started %s ago"
|
1112 |
msgstr ""
|
1113 |
|
1114 |
-
#: functions/interface.php:
|
1115 |
msgid "cancel"
|
1116 |
msgstr ""
|
1117 |
|
1118 |
-
#: functions/interface.php:
|
1119 |
msgid "No backups completed"
|
1120 |
msgstr ""
|
1121 |
|
1122 |
-
#: functions/interface.php:
|
1123 |
msgid "Complete Hourly"
|
1124 |
msgstr ""
|
1125 |
|
1126 |
-
#: functions/interface.php:
|
1127 |
msgid "File Hourly"
|
1128 |
msgstr ""
|
1129 |
|
1130 |
-
#: functions/interface.php:
|
1131 |
msgid "Database Hourly"
|
1132 |
msgstr ""
|
1133 |
|
1134 |
-
#: functions/interface.php:
|
1135 |
msgid "Complete Twice Daily"
|
1136 |
msgstr ""
|
1137 |
|
1138 |
-
#: functions/interface.php:
|
1139 |
msgid "File Twice Daily"
|
1140 |
msgstr ""
|
1141 |
|
1142 |
-
#: functions/interface.php:
|
1143 |
msgid "Database Twice Daily"
|
1144 |
msgstr ""
|
1145 |
|
1146 |
-
#: functions/interface.php:
|
1147 |
msgid "Complete Daily"
|
1148 |
msgstr ""
|
1149 |
|
1150 |
-
#: functions/interface.php:
|
1151 |
msgid "File Daily"
|
1152 |
msgstr ""
|
1153 |
|
1154 |
-
#: functions/interface.php:
|
1155 |
msgid "Database Daily"
|
1156 |
msgstr ""
|
1157 |
|
1158 |
-
#: functions/interface.php:
|
1159 |
msgid "Complete Weekly"
|
1160 |
msgstr ""
|
1161 |
|
1162 |
-
#: functions/interface.php:
|
1163 |
msgid "File Weekly"
|
1164 |
msgstr ""
|
1165 |
|
1166 |
-
#: functions/interface.php:
|
1167 |
msgid "Database Weekly"
|
1168 |
msgstr ""
|
1169 |
|
1170 |
-
#: functions/interface.php:
|
1171 |
msgid "Complete Every Two Weeks"
|
1172 |
msgstr ""
|
1173 |
|
1174 |
-
#: functions/interface.php:
|
1175 |
msgid "File Every Two Weeks"
|
1176 |
msgstr ""
|
1177 |
|
1178 |
-
#: functions/interface.php:
|
1179 |
msgid "Database Every Two Weeks"
|
1180 |
msgstr ""
|
1181 |
|
1182 |
-
#: functions/interface.php:
|
1183 |
msgid "Complete Monthly"
|
1184 |
msgstr ""
|
1185 |
|
1186 |
-
#: functions/interface.php:
|
1187 |
msgid "File Monthly"
|
1188 |
msgstr ""
|
1189 |
|
1190 |
-
#: functions/interface.php:
|
1191 |
msgid "Database Monthly"
|
1192 |
msgstr ""
|
1193 |
|
1194 |
-
#: functions/interface.php:
|
1195 |
msgid "Complete Manually"
|
1196 |
msgstr ""
|
1197 |
|
1198 |
-
#: functions/interface.php:
|
1199 |
msgid "File Manually"
|
1200 |
msgstr ""
|
1201 |
|
1202 |
-
#: functions/interface.php:
|
1203 |
msgid "Database Manually"
|
1204 |
msgstr ""
|
1205 |
|
@@ -1222,14 +1135,14 @@ msgstr ""
|
|
1222 |
msgid "http://hmn.md/"
|
1223 |
msgstr ""
|
1224 |
|
1225 |
-
#: admin/schedule-sentence.php:
|
1226 |
msgctxt ""
|
1227 |
"1: Backup Type 2: Total size of backup 3: Schedule 4: Number of backups to "
|
1228 |
"store"
|
1229 |
msgid "Backup my %1$s %2$s %3$s, %4$s."
|
1230 |
msgstr ""
|
1231 |
|
1232 |
-
#: functions/interface.php:
|
1233 |
msgctxt "backups count"
|
1234 |
msgid "One backup completed"
|
1235 |
msgid_plural "%1$s backups completed"
|
1 |
+
# Copyright (C) 2016 Human Made Limited
|
2 |
# This file is distributed under the GPL-2+.
|
3 |
msgid ""
|
4 |
msgstr ""
|
5 |
+
"Project-Id-Version: BackUpWordPress 3.4.0\n"
|
6 |
"Report-Msgid-Bugs-To: backupwordpress@hmn.md\n"
|
7 |
+
"POT-Creation-Date: 2016-01-20 16:44:43+00:00\n"
|
8 |
"MIME-Version: 1.0\n"
|
9 |
"Content-Type: text/plain; charset=utf-8\n"
|
10 |
"Content-Transfer-Encoding: 8bit\n"
|
11 |
+
"PO-Revision-Date: 2016-MO-DA HO:MI+ZONE\n"
|
12 |
"Last-Translator: Human Made Limited\n"
|
13 |
"Language-Team: Human Made Limited\n"
|
14 |
+
"X-Generator: grunt-wp-i18n 0.5.3\n"
|
15 |
|
16 |
+
#: admin/actions.php:180
|
17 |
msgid "The schedule ID was not provided. Aborting."
|
18 |
msgstr ""
|
19 |
|
20 |
+
#: admin/actions.php:236
|
21 |
msgid "Backup type cannot be empty"
|
22 |
msgstr ""
|
23 |
|
24 |
+
#: admin/actions.php:240
|
25 |
msgid "Invalid backup type"
|
26 |
msgstr ""
|
27 |
|
28 |
+
#: admin/actions.php:254
|
29 |
msgid "Schedule cannot be empty"
|
30 |
msgstr ""
|
31 |
|
32 |
+
#: admin/actions.php:258
|
33 |
msgid "Invalid schedule"
|
34 |
msgstr ""
|
35 |
|
36 |
+
#: admin/actions.php:272
|
37 |
msgid "Day of the week must be a valid, lowercase day name"
|
38 |
msgstr ""
|
39 |
|
40 |
+
#: admin/actions.php:291
|
41 |
msgid "Day of month must be between 1 and 31"
|
42 |
msgstr ""
|
43 |
|
44 |
+
#: admin/actions.php:310
|
45 |
msgid "Hours must be between 0 and 23"
|
46 |
msgstr ""
|
47 |
|
48 |
+
#: admin/actions.php:329
|
49 |
msgid "Minutes must be between 0 and 59"
|
50 |
msgstr ""
|
51 |
|
52 |
+
#: admin/actions.php:343
|
53 |
msgid "Max backups can't be empty"
|
54 |
msgstr ""
|
55 |
|
56 |
+
#: admin/actions.php:347
|
57 |
msgid "Max backups must be a number"
|
58 |
msgstr ""
|
59 |
|
60 |
+
#: admin/actions.php:351
|
61 |
msgid "Max backups must be greater than 0"
|
62 |
msgstr ""
|
63 |
|
64 |
+
#: admin/actions.php:695 admin/actions.php:701
|
65 |
msgid "BackUpWordPress has detected a problem."
|
66 |
msgstr ""
|
67 |
|
68 |
+
#: admin/actions.php:695
|
69 |
msgid ""
|
70 |
"%1$s is returning a %2$s response which could mean cron jobs aren't getting "
|
71 |
"fired properly. BackUpWordPress relies on wp-cron to run scheduled backups. "
|
72 |
"See the %3$s for more details."
|
73 |
msgstr ""
|
74 |
|
75 |
+
#: admin/actions.php:701
|
76 |
msgid ""
|
77 |
"%1$s is returning a %2$s response which could mean cron jobs aren't getting "
|
78 |
"fired properly. BackUpWordPress relies on wp-cron to run scheduled backups, "
|
80 |
"for manual backups. See the %3$s for more details."
|
81 |
msgstr ""
|
82 |
|
83 |
+
#: admin/backups-table.php:14 admin/schedule-form-excludes.php:109
|
84 |
msgid "Size"
|
85 |
msgstr ""
|
86 |
|
87 |
+
#: admin/backups-table.php:15 admin/schedule-form-excludes.php:111
|
88 |
msgid "Type"
|
89 |
msgstr ""
|
90 |
|
91 |
+
#: admin/backups-table.php:16
|
92 |
msgid "Actions"
|
93 |
msgstr ""
|
94 |
|
95 |
+
#: admin/backups-table.php:41
|
96 |
msgid "This is where your backups will appear once you have some."
|
97 |
msgstr ""
|
98 |
|
99 |
+
#: admin/backups.php:25
|
100 |
msgid "add schedule"
|
101 |
msgstr ""
|
102 |
|
103 |
+
#: admin/constants.php:9
|
104 |
msgid ""
|
105 |
"You can %1$s any of the following %2$s in your %3$s to control advanced "
|
106 |
"settings. %4$s. Defined %5$s will be highlighted."
|
107 |
msgstr ""
|
108 |
|
109 |
+
#: admin/constants.php:9 admin/menu.php:80
|
110 |
msgid "Constants"
|
111 |
msgstr ""
|
112 |
|
113 |
+
#: admin/constants.php:9
|
114 |
msgid "The Codex can help"
|
115 |
msgstr ""
|
116 |
|
117 |
+
#: admin/constants.php:20 admin/constants.php:36 admin/constants.php:52
|
118 |
+
#: admin/constants.php:68 admin/constants.php:84 admin/constants.php:100
|
119 |
+
#: admin/constants.php:116 classes/class-email-service.php:60
|
120 |
msgid "You've set it to: %s"
|
121 |
msgstr ""
|
122 |
|
123 |
+
#: admin/constants.php:23
|
124 |
msgid ""
|
125 |
"The path to the folder you would like to store your backup files in, "
|
126 |
"defaults to %s."
|
127 |
msgstr ""
|
128 |
|
129 |
+
#: admin/constants.php:23 admin/constants.php:39 admin/constants.php:55
|
130 |
+
#: admin/constants.php:71 admin/constants.php:87 admin/constants.php:103
|
131 |
+
#: admin/constants.php:119 classes/class-email-service.php:63
|
132 |
msgid "e.g."
|
133 |
msgstr ""
|
134 |
|
135 |
+
#: admin/constants.php:39
|
136 |
msgid ""
|
137 |
"The path to your %1$s executable. Will be used for the %2$s part of the "
|
138 |
"back up if available."
|
139 |
msgstr ""
|
140 |
|
141 |
+
#: admin/constants.php:39 admin/constants.php:55
|
142 |
msgid "database"
|
143 |
msgstr ""
|
144 |
|
145 |
+
#: admin/constants.php:55
|
146 |
msgid ""
|
147 |
"The path to your %1$s executable. Will be used to zip up your %2$s and %3$s "
|
148 |
"if available."
|
149 |
msgstr ""
|
150 |
|
151 |
+
#: admin/constants.php:55
|
152 |
msgid "files"
|
153 |
msgstr ""
|
154 |
|
155 |
+
#: admin/constants.php:71
|
156 |
msgid ""
|
157 |
"Comma separated list of files or directories to exclude, the backups "
|
158 |
"directory is automatically excluded."
|
159 |
msgstr ""
|
160 |
|
161 |
+
#: admin/constants.php:87
|
162 |
msgid "The capability to use when calling %1$s. Defaults to %2$s."
|
163 |
msgstr ""
|
164 |
|
165 |
+
#: admin/constants.php:103
|
166 |
msgid "The root directory that is backed up. Defaults to %s."
|
167 |
msgstr ""
|
168 |
|
169 |
+
#: admin/constants.php:119
|
170 |
msgid "The time that your schedules should run. Defaults to %s."
|
171 |
msgstr ""
|
172 |
|
366 |
"emailing backupwordpress@hmn.md"
|
367 |
msgstr ""
|
368 |
|
369 |
+
#: admin/menu.php:14 admin/menu.php:16
|
370 |
msgid "Manage Backups"
|
371 |
msgstr ""
|
372 |
|
373 |
+
#: admin/menu.php:14 admin/menu.php:16 admin/menu.php:44
|
374 |
msgid "Backups"
|
375 |
msgstr ""
|
376 |
|
377 |
+
#: admin/menu.php:75
|
378 |
msgid "FAQ"
|
379 |
msgstr ""
|
380 |
|
381 |
+
#: admin/menu.php:93
|
382 |
msgid "Server Info"
|
383 |
msgstr ""
|
384 |
|
385 |
+
#: admin/menu.php:100
|
386 |
msgid "For more information:"
|
387 |
msgstr ""
|
388 |
|
389 |
+
#: admin/menu.php:100
|
390 |
msgid "Support Forums"
|
391 |
msgstr ""
|
392 |
|
393 |
+
#: admin/menu.php:100
|
394 |
msgid "Help with translation"
|
395 |
msgstr ""
|
396 |
|
397 |
+
#: admin/page.php:13
|
398 |
msgid "Support"
|
399 |
msgstr ""
|
400 |
|
401 |
+
#: admin/page.php:16
|
402 |
msgid "Enable Support"
|
403 |
msgstr ""
|
404 |
|
405 |
+
#: admin/page.php:25
|
406 |
msgid ""
|
407 |
"If you're finding BackUpWordPress useful, please %1$s rate it on the plugin "
|
408 |
"directory%2$s."
|
409 |
msgstr ""
|
410 |
|
411 |
+
#: admin/schedule-form-excludes.php:11
|
412 |
msgid "Currently Excluded"
|
413 |
msgstr ""
|
414 |
|
415 |
+
#: admin/schedule-form-excludes.php:14
|
416 |
msgid ""
|
417 |
"We automatically detect and ignore common <abbr title=\"Version Control "
|
418 |
"Systems\">VCS</abbr> folders and other backup plugin folders."
|
419 |
msgstr ""
|
420 |
|
421 |
+
#: admin/schedule-form-excludes.php:50
|
422 |
msgid "Default rule"
|
423 |
msgstr ""
|
424 |
|
425 |
+
#: admin/schedule-form-excludes.php:54
|
426 |
msgid "Defined in wp-config.php"
|
427 |
msgstr ""
|
428 |
|
429 |
+
#: admin/schedule-form-excludes.php:61
|
430 |
msgid "Stop excluding"
|
431 |
msgstr ""
|
432 |
|
433 |
+
#: admin/schedule-form-excludes.php:75
|
434 |
msgid "Your Site"
|
435 |
msgstr ""
|
436 |
|
437 |
+
#: admin/schedule-form-excludes.php:77
|
438 |
msgid ""
|
439 |
"Here's a directory listing of all files on your site, you can browse "
|
440 |
"through and exclude files or folders that you don't want included in your "
|
441 |
"backup."
|
442 |
msgstr ""
|
443 |
|
444 |
+
#: admin/schedule-form-excludes.php:108
|
445 |
msgid "Name"
|
446 |
msgstr ""
|
447 |
|
448 |
+
#: admin/schedule-form-excludes.php:110
|
449 |
msgid "Permissions"
|
450 |
msgstr ""
|
451 |
|
452 |
+
#: admin/schedule-form-excludes.php:112
|
453 |
msgid "Status"
|
454 |
msgstr ""
|
455 |
|
456 |
+
#: admin/schedule-form-excludes.php:172 admin/schedule-form-excludes.php:290
|
457 |
msgid "Refresh"
|
458 |
msgstr ""
|
459 |
|
460 |
+
#: admin/schedule-form-excludes.php:189 admin/schedule-form-excludes.php:314
|
461 |
msgid "Symlink"
|
462 |
msgstr ""
|
463 |
|
464 |
+
#: admin/schedule-form-excludes.php:193 admin/schedule-form-excludes.php:318
|
465 |
msgid "Folder"
|
466 |
msgstr ""
|
467 |
|
468 |
+
#: admin/schedule-form-excludes.php:288
|
469 |
msgid "Recalculate the size of this directory"
|
470 |
msgstr ""
|
471 |
|
472 |
+
#: admin/schedule-form-excludes.php:322
|
473 |
msgid "File"
|
474 |
msgstr ""
|
475 |
|
476 |
+
#: admin/schedule-form-excludes.php:333
|
477 |
msgid "Unreadable files won't be backed up."
|
478 |
msgstr ""
|
479 |
|
480 |
+
#: admin/schedule-form-excludes.php:333
|
481 |
msgid "Unreadable"
|
482 |
msgstr ""
|
483 |
|
484 |
+
#: admin/schedule-form-excludes.php:337
|
485 |
msgid "Excluded"
|
486 |
msgstr ""
|
487 |
|
488 |
+
#: admin/schedule-form-excludes.php:353
|
489 |
msgid "Exclude →"
|
490 |
msgstr ""
|
491 |
|
492 |
+
#: admin/schedule-form-excludes.php:366
|
493 |
msgid "This folder is empty"
|
494 |
msgstr ""
|
495 |
|
496 |
+
#: admin/schedule-form-excludes.php:378 admin/schedule-form.php:204
|
497 |
+
#: admin/schedule-settings.php:90
|
498 |
msgid "Done"
|
499 |
msgstr ""
|
500 |
|
501 |
+
#: admin/schedule-form.php:7 admin/schedule-settings.php:11
|
502 |
msgid "Settings"
|
503 |
msgstr ""
|
504 |
|
505 |
+
#: admin/schedule-form.php:42
|
506 |
msgid "Backup"
|
507 |
msgstr ""
|
508 |
|
509 |
+
#: admin/schedule-form.php:49
|
510 |
msgid "Both Database & files"
|
511 |
msgstr ""
|
512 |
|
513 |
+
#: admin/schedule-form.php:51
|
514 |
msgid "Files only"
|
515 |
msgstr ""
|
516 |
|
517 |
+
#: admin/schedule-form.php:53
|
518 |
msgid "Database only"
|
519 |
msgstr ""
|
520 |
|
521 |
+
#: admin/schedule-form.php:64
|
522 |
msgid "Schedule"
|
523 |
msgstr ""
|
524 |
|
525 |
+
#: admin/schedule-form.php:71
|
526 |
msgid "Manual Only"
|
527 |
msgstr ""
|
528 |
|
529 |
+
#: admin/schedule-form.php:98
|
530 |
msgid "Start Day"
|
531 |
msgstr ""
|
532 |
|
533 |
+
#: admin/schedule-form.php:106
|
534 |
msgid "Monday"
|
535 |
msgstr ""
|
536 |
|
537 |
+
#: admin/schedule-form.php:107
|
538 |
msgid "Tuesday"
|
539 |
msgstr ""
|
540 |
|
541 |
+
#: admin/schedule-form.php:108
|
542 |
msgid "Wednesday"
|
543 |
msgstr ""
|
544 |
|
545 |
+
#: admin/schedule-form.php:109
|
546 |
msgid "Thursday"
|
547 |
msgstr ""
|
548 |
|
549 |
+
#: admin/schedule-form.php:110
|
550 |
msgid "Friday"
|
551 |
msgstr ""
|
552 |
|
553 |
+
#: admin/schedule-form.php:111
|
554 |
msgid "Saturday"
|
555 |
msgstr ""
|
556 |
|
557 |
+
#: admin/schedule-form.php:112
|
558 |
msgid "Sunday"
|
559 |
msgstr ""
|
560 |
|
561 |
+
#: admin/schedule-form.php:130
|
562 |
msgid "Start Day of Month"
|
563 |
msgstr ""
|
564 |
|
565 |
+
#: admin/schedule-form.php:142
|
566 |
msgid "Start Time"
|
567 |
msgstr ""
|
568 |
|
569 |
+
#: admin/schedule-form.php:151
|
570 |
msgid "Hours"
|
571 |
msgstr ""
|
572 |
|
573 |
+
#: admin/schedule-form.php:155
|
574 |
msgid "Minutes"
|
575 |
msgstr ""
|
576 |
|
577 |
+
#: admin/schedule-form.php:160
|
578 |
msgid "24-hour format."
|
579 |
msgstr ""
|
580 |
|
581 |
+
#: admin/schedule-form.php:161
|
582 |
msgid "The second backup will run 12 hours after the first."
|
583 |
msgstr ""
|
584 |
|
585 |
+
#: admin/schedule-form.php:171
|
586 |
msgid "Number of backups to store on this server"
|
587 |
msgstr ""
|
588 |
|
589 |
+
#: admin/schedule-form.php:180
|
590 |
msgid "Past this limit older backups will be deleted automatically."
|
591 |
msgstr ""
|
592 |
|
593 |
+
#: admin/schedule-form.php:187
|
594 |
msgid "This schedule will store a maximum of %s of backups."
|
595 |
msgstr ""
|
596 |
|
597 |
+
#: admin/schedule-sentence.php:14
|
598 |
msgid "The next backup will be on %1$s at %2$s %3$s"
|
599 |
msgstr ""
|
600 |
|
601 |
+
#: admin/schedule-sentence.php:24
|
602 |
msgid "hourly on the hour"
|
603 |
msgstr ""
|
604 |
|
605 |
+
#: admin/schedule-sentence.php:24
|
606 |
msgid "hourly at %s minutes past the hour"
|
607 |
msgstr ""
|
608 |
|
609 |
+
#: admin/schedule-sentence.php:30
|
610 |
msgid "daily at %s"
|
611 |
msgstr ""
|
612 |
|
613 |
+
#: admin/schedule-sentence.php:41
|
614 |
msgid "every 12 hours at %1$s & %2$s"
|
615 |
msgstr ""
|
616 |
|
617 |
+
#: admin/schedule-sentence.php:47
|
618 |
msgid "weekly on %1$s at %2$s"
|
619 |
msgstr ""
|
620 |
|
621 |
+
#: admin/schedule-sentence.php:53
|
622 |
msgid "every two weeks on %1$s at %2$s"
|
623 |
msgstr ""
|
624 |
|
625 |
+
#: admin/schedule-sentence.php:59
|
626 |
msgid "on the %1$s of each month at %2$s"
|
627 |
msgstr ""
|
628 |
|
629 |
+
#: admin/schedule-sentence.php:65 admin/schedule-sentence.php:71
|
630 |
msgid "manually"
|
631 |
msgstr ""
|
632 |
|
633 |
+
#: admin/schedule-sentence.php:76
|
634 |
msgid "this server"
|
635 |
msgstr ""
|
636 |
|
637 |
+
#: admin/schedule-sentence.php:84
|
638 |
msgid "store the most recent backup in %s"
|
639 |
msgstr ""
|
640 |
|
641 |
+
#: admin/schedule-sentence.php:90
|
642 |
msgid "don't store any backups in on this server"
|
643 |
msgstr ""
|
644 |
|
645 |
+
#: admin/schedule-sentence.php:96
|
646 |
msgid "store the last %1$s backups in %2$s"
|
647 |
msgstr ""
|
648 |
|
649 |
+
#: admin/schedule-sentence.php:131
|
|
|
|
|
|
|
|
|
650 |
msgid "Send a copy of each backup to %s."
|
651 |
msgstr ""
|
652 |
|
653 |
+
#: admin/schedule-sentence.php:164
|
654 |
msgid "Backups will be compressed and should be smaller than this."
|
655 |
msgstr ""
|
656 |
|
657 |
+
#: admin/schedule-sentence.php:168
|
658 |
msgid "this shouldn't take long…"
|
659 |
msgstr ""
|
660 |
|
661 |
+
#: admin/schedule-sentence.php:168
|
662 |
+
msgid "calculating the size of your site…"
|
663 |
msgstr ""
|
664 |
|
665 |
+
#: admin/schedule-settings.php:9
|
666 |
msgid "Run now"
|
667 |
msgstr ""
|
668 |
|
669 |
+
#: admin/schedule-settings.php:17
|
670 |
msgid "Excludes"
|
671 |
msgstr ""
|
672 |
|
673 |
+
#: admin/schedule-settings.php:29 functions/interface.php:36
|
674 |
msgid "Delete"
|
675 |
msgstr ""
|
676 |
|
692 |
msgid "BackUpWordPress Error"
|
693 |
msgstr ""
|
694 |
|
695 |
+
#: classes/backup/class-backup.php:53
|
696 |
+
msgid "Backing up database..."
|
697 |
msgstr ""
|
698 |
|
699 |
+
#: classes/backup/class-backup.php:107
|
700 |
+
msgid "Backing up files..."
|
701 |
msgstr ""
|
702 |
|
703 |
+
#: classes/class-backupwordpress-wp-cli-command.php:46
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
704 |
msgid "Backup: Dumping database..."
|
705 |
msgstr ""
|
706 |
|
707 |
+
#: classes/class-backupwordpress-wp-cli-command.php:50
|
708 |
msgid "Backup: Zipping everything up..."
|
709 |
msgstr ""
|
710 |
|
711 |
+
#: classes/class-backupwordpress-wp-cli-command.php:64
|
712 |
msgid "Invalid backup path"
|
713 |
msgstr ""
|
714 |
|
715 |
+
#: classes/class-backupwordpress-wp-cli-command.php:69
|
716 |
msgid "Invalid root path"
|
717 |
msgstr ""
|
718 |
|
719 |
+
#: classes/class-backupwordpress-wp-cli-command.php:96
|
720 |
msgid "Backup Complete: "
|
721 |
msgstr ""
|
722 |
|
723 |
+
#: classes/class-backupwordpress-wp-cli-command.php:98
|
724 |
msgid "Backup Failed"
|
725 |
msgstr ""
|
726 |
|
799 |
msgid "Unfortunately, the backup file was too large to attach to this email."
|
800 |
msgstr ""
|
801 |
|
802 |
+
#: classes/class-path.php:332
|
803 |
msgid "This %s file ensures that other people cannot download your backup files."
|
804 |
msgstr ""
|
805 |
|
806 |
+
#: classes/class-plugin.php:228
|
807 |
msgid "Update"
|
808 |
msgstr ""
|
809 |
|
810 |
+
#: classes/class-plugin.php:229
|
811 |
msgid "Cancel"
|
812 |
msgstr ""
|
813 |
|
814 |
+
#: classes/class-plugin.php:230
|
815 |
msgid ""
|
816 |
"Are you sure you want to delete this schedule? All of its backups will also "
|
817 |
"be deleted."
|
818 |
msgstr ""
|
819 |
|
820 |
+
#: classes/class-plugin.php:230 classes/class-plugin.php:231
|
821 |
+
#: classes/class-plugin.php:232 classes/class-plugin.php:233
|
822 |
msgid "'Cancel' to go back, 'OK' to delete."
|
823 |
msgstr ""
|
824 |
|
825 |
+
#: classes/class-plugin.php:231
|
826 |
msgid "Are you sure you want to delete this backup?"
|
827 |
msgstr ""
|
828 |
|
829 |
+
#: classes/class-plugin.php:232
|
830 |
msgid "Are you sure you want to remove this exclude rule?"
|
831 |
msgstr ""
|
832 |
|
833 |
+
#: classes/class-plugin.php:233
|
834 |
msgid ""
|
835 |
"Reducing the number of backups that are stored on this server will cause "
|
836 |
"some of your existing backups to be deleted. Are you sure that's what you "
|
837 |
"want?"
|
838 |
msgstr ""
|
839 |
|
840 |
+
#: classes/class-scheduled-backup.php:321
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
841 |
msgid "Argument 1 for %s must be a valid cron recurrence or \"manually\""
|
842 |
msgstr ""
|
843 |
|
844 |
+
#: classes/class-scheduled-backup.php:428 functions/interface.php:272
|
845 |
+
msgid "Starting backup..."
|
846 |
msgstr ""
|
847 |
|
848 |
+
#: classes/class-scheduled-backup.php:430
|
849 |
+
#: classes/class-scheduled-backup.php:445
|
850 |
+
msgid "Deleting old backups..."
|
851 |
msgstr ""
|
852 |
|
853 |
+
#: classes/class-scheduled-backup.php:545
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
854 |
#. translators: min=minute
|
855 |
msgid "%s min"
|
856 |
msgid_plural "%s mins"
|
857 |
msgstr[0] ""
|
858 |
msgstr[1] ""
|
859 |
|
860 |
+
#: classes/class-scheduled-backup.php:555
|
861 |
msgid "%s hour"
|
862 |
msgid_plural "%s hours"
|
863 |
msgstr[0] ""
|
864 |
msgstr[1] ""
|
865 |
|
866 |
+
#: classes/class-scheduled-backup.php:617
|
867 |
msgid "Argument 1 for %s must be a non-empty string"
|
868 |
msgstr ""
|
869 |
|
870 |
+
#: classes/class-scheduled-backup.php:622
|
871 |
msgid "%s doesn't exist"
|
872 |
msgstr ""
|
873 |
|
874 |
+
#: classes/class-scheduled-backup.php:627
|
875 |
msgid "That backup wasn't created by this schedule"
|
876 |
msgstr ""
|
877 |
|
901 |
msgid "Error: %s"
|
902 |
msgstr ""
|
903 |
|
904 |
+
#: functions/core.php:318
|
905 |
msgid "BackUpWordPress has set up your default schedules."
|
906 |
msgstr ""
|
907 |
|
908 |
+
#: functions/core.php:318
|
909 |
msgid ""
|
910 |
"By default BackUpWordPress performs a daily backup of your database and a "
|
911 |
"weekly backup of your database & files. You can modify these schedules."
|
912 |
msgstr ""
|
913 |
|
914 |
+
#: functions/core.php:334
|
915 |
msgid "Once Hourly"
|
916 |
msgstr ""
|
917 |
|
918 |
+
#: functions/core.php:335
|
919 |
msgid "Twice Daily"
|
920 |
msgstr ""
|
921 |
|
922 |
+
#: functions/core.php:336
|
923 |
msgid "Once Daily"
|
924 |
msgstr ""
|
925 |
|
926 |
+
#: functions/core.php:337
|
927 |
msgid "Once Weekly"
|
928 |
msgstr ""
|
929 |
|
930 |
+
#: functions/core.php:338
|
931 |
msgid "Once Every Two Weeks"
|
932 |
msgstr ""
|
933 |
|
934 |
+
#: functions/core.php:339
|
935 |
msgid "Once Monthly"
|
936 |
msgstr ""
|
937 |
|
938 |
+
#: functions/core.php:358
|
939 |
msgid "You can only delete directories inside your WordPress installation"
|
940 |
msgstr ""
|
941 |
|
942 |
+
#: functions/interface.php:33
|
943 |
msgid "Download"
|
944 |
msgstr ""
|
945 |
|
|
|
|
|
|
|
|
|
946 |
#: functions/interface.php:75
|
947 |
+
msgid "BackUpWordPress detected issues with your last backup."
|
948 |
msgstr ""
|
949 |
|
950 |
+
#: functions/interface.php:88 functions/interface.php:108
|
951 |
+
#: functions/interface.php:130
|
952 |
msgid "Dismiss this notice."
|
953 |
msgstr ""
|
954 |
|
1000 |
"saved to %2$s instead."
|
1001 |
msgstr ""
|
1002 |
|
1003 |
+
#: functions/interface.php:198
|
1004 |
msgid "Your site root path %s isn't readable."
|
1005 |
msgstr ""
|
1006 |
|
1007 |
+
#: functions/interface.php:239
|
1008 |
msgid "Database and Files"
|
1009 |
msgstr ""
|
1010 |
|
1011 |
+
#: functions/interface.php:243
|
1012 |
msgid "Files"
|
1013 |
msgstr ""
|
1014 |
|
1015 |
+
#: functions/interface.php:247
|
1016 |
msgid "Database"
|
1017 |
msgstr ""
|
1018 |
|
1019 |
+
#: functions/interface.php:254
|
1020 |
msgid "Legacy"
|
1021 |
msgstr ""
|
1022 |
|
1023 |
+
#: functions/interface.php:271
|
1024 |
msgid "Started %s ago"
|
1025 |
msgstr ""
|
1026 |
|
1027 |
+
#: functions/interface.php:273
|
1028 |
msgid "cancel"
|
1029 |
msgstr ""
|
1030 |
|
1031 |
+
#: functions/interface.php:291
|
1032 |
msgid "No backups completed"
|
1033 |
msgstr ""
|
1034 |
|
1035 |
+
#: functions/interface.php:302
|
1036 |
msgid "Complete Hourly"
|
1037 |
msgstr ""
|
1038 |
|
1039 |
+
#: functions/interface.php:303
|
1040 |
msgid "File Hourly"
|
1041 |
msgstr ""
|
1042 |
|
1043 |
+
#: functions/interface.php:304
|
1044 |
msgid "Database Hourly"
|
1045 |
msgstr ""
|
1046 |
|
1047 |
+
#: functions/interface.php:305
|
1048 |
msgid "Complete Twice Daily"
|
1049 |
msgstr ""
|
1050 |
|
1051 |
+
#: functions/interface.php:306
|
1052 |
msgid "File Twice Daily"
|
1053 |
msgstr ""
|
1054 |
|
1055 |
+
#: functions/interface.php:307
|
1056 |
msgid "Database Twice Daily"
|
1057 |
msgstr ""
|
1058 |
|
1059 |
+
#: functions/interface.php:308
|
1060 |
msgid "Complete Daily"
|
1061 |
msgstr ""
|
1062 |
|
1063 |
+
#: functions/interface.php:309
|
1064 |
msgid "File Daily"
|
1065 |
msgstr ""
|
1066 |
|
1067 |
+
#: functions/interface.php:310
|
1068 |
msgid "Database Daily"
|
1069 |
msgstr ""
|
1070 |
|
1071 |
+
#: functions/interface.php:311
|
1072 |
msgid "Complete Weekly"
|
1073 |
msgstr ""
|
1074 |
|
1075 |
+
#: functions/interface.php:312
|
1076 |
msgid "File Weekly"
|
1077 |
msgstr ""
|
1078 |
|
1079 |
+
#: functions/interface.php:313
|
1080 |
msgid "Database Weekly"
|
1081 |
msgstr ""
|
1082 |
|
1083 |
+
#: functions/interface.php:314
|
1084 |
msgid "Complete Every Two Weeks"
|
1085 |
msgstr ""
|
1086 |
|
1087 |
+
#: functions/interface.php:315
|
1088 |
msgid "File Every Two Weeks"
|
1089 |
msgstr ""
|
1090 |
|
1091 |
+
#: functions/interface.php:316
|
1092 |
msgid "Database Every Two Weeks"
|
1093 |
msgstr ""
|
1094 |
|
1095 |
+
#: functions/interface.php:317
|
1096 |
msgid "Complete Monthly"
|
1097 |
msgstr ""
|
1098 |
|
1099 |
+
#: functions/interface.php:318
|
1100 |
msgid "File Monthly"
|
1101 |
msgstr ""
|
1102 |
|
1103 |
+
#: functions/interface.php:319
|
1104 |
msgid "Database Monthly"
|
1105 |
msgstr ""
|
1106 |
|
1107 |
+
#: functions/interface.php:320
|
1108 |
msgid "Complete Manually"
|
1109 |
msgstr ""
|
1110 |
|
1111 |
+
#: functions/interface.php:321
|
1112 |
msgid "File Manually"
|
1113 |
msgstr ""
|
1114 |
|
1115 |
+
#: functions/interface.php:322
|
1116 |
msgid "Database Manually"
|
1117 |
msgstr ""
|
1118 |
|
1135 |
msgid "http://hmn.md/"
|
1136 |
msgstr ""
|
1137 |
|
1138 |
+
#: admin/schedule-sentence.php:124
|
1139 |
msgctxt ""
|
1140 |
"1: Backup Type 2: Total size of backup 3: Schedule 4: Number of backups to "
|
1141 |
"store"
|
1142 |
msgid "Backup my %1$s %2$s %3$s, %4$s."
|
1143 |
msgstr ""
|
1144 |
|
1145 |
+
#: functions/interface.php:293
|
1146 |
msgctxt "backups count"
|
1147 |
msgid "One backup completed"
|
1148 |
msgid_plural "%1$s backups completed"
|
readme.md
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<table width="100%">
|
2 |
+
<tr>
|
3 |
+
<td align="left" width="70">
|
4 |
+
<strong><a href="https://bwp.hmn.md/">BackUpWordPress</a></strong><br />
|
5 |
+
Simple automated backups of your WordPress powered website.
|
6 |
+
</td>
|
7 |
+
<td align="right" width="20%">
|
8 |
+
<a href="https://travis-ci.org/humanmade/backupwordpress">
|
9 |
+
<img src="https://travis-ci.org/humanmade/backupwordpress.svg?branch=master" alt="Build status">
|
10 |
+
</a>
|
11 |
+
<a href="https://scrutinizer-ci.com/g/humanmade/backupwordpress/">
|
12 |
+
<img src="https://scrutinizer-ci.com/g/humanmade/backupwordpress/badges/coverage.png?b=master" alt="Coverage via Scrutiniser" />
|
13 |
+
</a>
|
14 |
+
</td>
|
15 |
+
</tr>
|
16 |
+
<tr>
|
17 |
+
<td>
|
18 |
+
A <strong><a href="https://hmn.md/">Human Made</a></strong> project. Maintained by @pdewouters.
|
19 |
+
</td>
|
20 |
+
<td align="center">
|
21 |
+
<img src="https://hmn.md/content/themes/hmnmd/assets/images/hm-logo.svg" width="100" />
|
22 |
+
</td>
|
23 |
+
</tr>
|
24 |
+
</table>
|
25 |
+
|
26 |
+
BackUpWordPress is a well tested, onsite backup plugin for WordPress. It's supports sending backups to cloud services through premium extensions
|
27 |
+
|
28 |
+
Stop using outdated practices, and start making sense.
|
29 |
+
|
30 |
+
## Requirements
|
31 |
+
BackUpWordPress requires WordPress 3.9 or newer and requires PHP 5.3+ due to the use of namespaced code.
|
32 |
+
|
33 |
+
## Installation
|
34 |
+
Just install like any other plugin
|
35 |
+
|
36 |
+
## Contributing
|
37 |
+
Read our [contributing.md](https://github.com/humanmade/backupwordpress/blob/master/CONTRIBUTING.md) file
|
38 |
+
|
39 |
+
|
40 |
+
## License
|
41 |
+
BackUpWordPress is licensed under the GPLv2 or later.
|
42 |
+
|
43 |
+
## Credits
|
44 |
+
Created by Human Made for high volume and large-scale sites. BackUpWordPress is used on over 200,000 sites worldwide.
|
45 |
+
|
46 |
+
Written and maintained by [Tom Willmot](https://github.com/willmot) & [Paul De Wouters](https://github.com/pdwouters). Thanks to all our [contributors](https://github.com/humanmade/backupwordpress/graphs/contributors).
|
47 |
+
|
48 |
+
BackUpWordPress was originally developed by [wpdprx](http://profiles.wordpress.org/users/wpdprx/) before being taken over by Human Made.
|
49 |
+
|
50 |
+
---
|
51 |
+
|
52 |
+
Interested in joining in on the fun? [Join us, and become human!](https://hmn.md/is/hiring/)
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ Contributors: humanmade, willmot, pauldewouters, joehoyle, mattheu, tcrsavage, c
|
|
3 |
Tags: back up, backup, backups, database, zip, db, files, archive, wp-cli, humanmade
|
4 |
Requires at least: 3.9
|
5 |
Tested up to: 4.4
|
6 |
-
Stable tag: 3.
|
7 |
|
8 |
Simple automated backups of your WordPress-powered website.
|
9 |
|
@@ -118,6 +118,12 @@ You can also tweet <a href="http://twitter.com/humanmadeltd">@humanmadeltd</a> o
|
|
118 |
|
119 |
== Upgrade Notice ==
|
120 |
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
= 3.3.4 =
|
122 |
|
123 |
* WordPress 4.4 compatibility.
|
@@ -152,6 +158,54 @@ You can also tweet <a href="http://twitter.com/humanmadeltd">@humanmadeltd</a> o
|
|
152 |
|
153 |
== Changelog ==
|
154 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
### 3.3.4 / 2015-12-10
|
156 |
|
157 |
* Fixes styling issues with WordPress 4.4
|
3 |
Tags: back up, backup, backups, database, zip, db, files, archive, wp-cli, humanmade
|
4 |
Requires at least: 3.9
|
5 |
Tested up to: 4.4
|
6 |
+
Stable tag: 3.4.0
|
7 |
|
8 |
Simple automated backups of your WordPress-powered website.
|
9 |
|
118 |
|
119 |
== Upgrade Notice ==
|
120 |
|
121 |
+
= 3.4 =
|
122 |
+
|
123 |
+
This version introduces a major refactoring code responsible for the files and database backup. We made sure to write
|
124 |
+
unit tests for the new code, and we have tested it on several user's sites. It fixes a lot of old bugs, and Windows
|
125 |
+
users should see major improvments to reliablity.
|
126 |
+
|
127 |
= 3.3.4 =
|
128 |
|
129 |
* WordPress 4.4 compatibility.
|
158 |
|
159 |
== Changelog ==
|
160 |
|
161 |
+
### 3.4 / 2016/01/20
|
162 |
+
|
163 |
+
* Updated composer packages
|
164 |
+
* Strip empty services from the schedule sentence.
|
165 |
+
* Back compat pass
|
166 |
+
* Ensure row actions always show
|
167 |
+
* don't hardcode byte sizes in unit tests
|
168 |
+
* correct namespaced Finder call
|
169 |
+
* allow for more variance when comparing filesizes
|
170 |
+
* Add unit tests for Site Size
|
171 |
+
* fixup the full-backup tests
|
172 |
+
* Add tests for the Backup Status class
|
173 |
+
* Unit tests now pass on Windows
|
174 |
+
* correctly ignore the backup running file when zipping the database.
|
175 |
+
* Normalize a bunch of paths to fix issues on windows
|
176 |
+
* Don't declare Service::action() as abstract
|
177 |
+
* use submit button function
|
178 |
+
* Close the service settings page when clicking done as long as there are no errors
|
179 |
+
* Remove the old .backup_errors and .backup_warnings files and associated functions as they are no longer used.
|
180 |
+
* Fixup the email and webhook services
|
181 |
+
* Delete the backups class and fix a recursion issue in mysqldump
|
182 |
+
* Re-organise the tests and fixup the failing ones.
|
183 |
+
* fix excludes
|
184 |
+
* Fixup the backup status.
|
185 |
+
* ensure excludes are correctly passed through the backups director
|
186 |
+
* Ensure unwritable backup paths are never chosen
|
187 |
+
* Return methods directly instead of storing in unneeded variables
|
188 |
+
* Fix several bugs in the site size functionality
|
189 |
+
* add a test to confirm backups exclude backups, currently failing
|
190 |
+
* Hook the new Site_Backup class up the scheduled backups
|
191 |
+
* Introduce `Site_Size`, `Excludes` & `Site_Backup`.
|
192 |
+
* fix some global state issues in the Path tests
|
193 |
+
* Fixup excludes functionality
|
194 |
+
* Fix the backup director unit tests
|
195 |
+
* More namespacing and renaming.
|
196 |
+
* Start using namespaces in a lot more places.
|
197 |
+
* start integrating with main plugin
|
198 |
+
* Add in tests for unreadable directories and account for how zip uniquely handles them
|
199 |
+
* Skip dots in hmbkp_rmdirtree
|
200 |
+
* Introduce `Backup_Utilities` and move the static methods from `Backup_Engine` too it.
|
201 |
+
* backcompat version of assertNotWPError for when tests run on old versions of WordPress
|
202 |
+
* More unit test fixes
|
203 |
+
* Update to the latest version of symfony/Finder
|
204 |
+
* Fix a fatal error in the tests
|
205 |
+
* remove uneeded code copy paste
|
206 |
+
* The major backups refactor of 2015
|
207 |
+
|
208 |
+
|
209 |
### 3.3.4 / 2015-12-10
|
210 |
|
211 |
* Fixes styling issues with WordPress 4.4
|
vendor/composer/installed.json
CHANGED
@@ -55,34 +55,37 @@
|
|
55 |
},
|
56 |
{
|
57 |
"name": "symfony/finder",
|
58 |
-
"version": "v2.
|
59 |
-
"version_normalized": "2.
|
60 |
"source": {
|
61 |
"type": "git",
|
62 |
"url": "https://github.com/symfony/finder.git",
|
63 |
-
"reference": "
|
64 |
},
|
65 |
"dist": {
|
66 |
"type": "zip",
|
67 |
-
"url": "https://api.github.com/repos/symfony/finder/zipball/
|
68 |
-
"reference": "
|
69 |
"shasum": ""
|
70 |
},
|
71 |
"require": {
|
72 |
"php": ">=5.3.9"
|
73 |
},
|
74 |
-
"time": "
|
75 |
"type": "library",
|
76 |
"extra": {
|
77 |
"branch-alias": {
|
78 |
-
"dev-master": "2.
|
79 |
}
|
80 |
},
|
81 |
"installation-source": "dist",
|
82 |
"autoload": {
|
83 |
"psr-4": {
|
84 |
"Symfony\\Component\\Finder\\": ""
|
85 |
-
}
|
|
|
|
|
|
|
86 |
},
|
87 |
"notification-url": "https://packagist.org/downloads/",
|
88 |
"license": [
|
55 |
},
|
56 |
{
|
57 |
"name": "symfony/finder",
|
58 |
+
"version": "v2.8.2",
|
59 |
+
"version_normalized": "2.8.2.0",
|
60 |
"source": {
|
61 |
"type": "git",
|
62 |
"url": "https://github.com/symfony/finder.git",
|
63 |
+
"reference": "c90fabdd97e431ee19b6383999cf35334dff27da"
|
64 |
},
|
65 |
"dist": {
|
66 |
"type": "zip",
|
67 |
+
"url": "https://api.github.com/repos/symfony/finder/zipball/c90fabdd97e431ee19b6383999cf35334dff27da",
|
68 |
+
"reference": "c90fabdd97e431ee19b6383999cf35334dff27da",
|
69 |
"shasum": ""
|
70 |
},
|
71 |
"require": {
|
72 |
"php": ">=5.3.9"
|
73 |
},
|
74 |
+
"time": "2016-01-14 08:26:52",
|
75 |
"type": "library",
|
76 |
"extra": {
|
77 |
"branch-alias": {
|
78 |
+
"dev-master": "2.8-dev"
|
79 |
}
|
80 |
},
|
81 |
"installation-source": "dist",
|
82 |
"autoload": {
|
83 |
"psr-4": {
|
84 |
"Symfony\\Component\\Finder\\": ""
|
85 |
+
},
|
86 |
+
"exclude-from-classmap": [
|
87 |
+
"/Tests/"
|
88 |
+
]
|
89 |
},
|
90 |
"notification-url": "https://packagist.org/downloads/",
|
91 |
"license": [
|
vendor/symfony/finder/Adapter/AbstractAdapter.php
CHANGED
@@ -11,10 +11,14 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Adapter;
|
13 |
|
|
|
|
|
14 |
/**
|
15 |
* Interface for finder engine implementations.
|
16 |
*
|
17 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
|
|
|
|
18 |
*/
|
19 |
abstract class AbstractAdapter implements AdapterInterface
|
20 |
{
|
11 |
|
12 |
namespace Symfony\Component\Finder\Adapter;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\AbstractAdapter class is deprecated since version 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
/**
|
17 |
* Interface for finder engine implementations.
|
18 |
*
|
19 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
20 |
+
*
|
21 |
+
* @deprecated since 2.8, to be removed in 3.0. Use Finder instead.
|
22 |
*/
|
23 |
abstract class AbstractAdapter implements AdapterInterface
|
24 |
{
|
vendor/symfony/finder/Adapter/AbstractFindAdapter.php
CHANGED
@@ -11,6 +11,8 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Adapter;
|
13 |
|
|
|
|
|
14 |
use Symfony\Component\Finder\Exception\AccessDeniedException;
|
15 |
use Symfony\Component\Finder\Iterator;
|
16 |
use Symfony\Component\Finder\Shell\Shell;
|
@@ -23,6 +25,8 @@ use Symfony\Component\Finder\Comparator\DateComparator;
|
|
23 |
* Shell engine implementation using GNU find command.
|
24 |
*
|
25 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
|
|
|
|
26 |
*/
|
27 |
abstract class AbstractFindAdapter extends AbstractAdapter
|
28 |
{
|
11 |
|
12 |
namespace Symfony\Component\Finder\Adapter;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\AbstractFindAdapter class is deprecated since version 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
use Symfony\Component\Finder\Exception\AccessDeniedException;
|
17 |
use Symfony\Component\Finder\Iterator;
|
18 |
use Symfony\Component\Finder\Shell\Shell;
|
25 |
* Shell engine implementation using GNU find command.
|
26 |
*
|
27 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
28 |
+
*
|
29 |
+
* @deprecated since 2.8, to be removed in 3.0. Use Finder instead.
|
30 |
*/
|
31 |
abstract class AbstractFindAdapter extends AbstractAdapter
|
32 |
{
|
vendor/symfony/finder/Adapter/AdapterInterface.php
CHANGED
@@ -13,6 +13,8 @@ namespace Symfony\Component\Finder\Adapter;
|
|
13 |
|
14 |
/**
|
15 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
|
|
|
|
16 |
*/
|
17 |
interface AdapterInterface
|
18 |
{
|
13 |
|
14 |
/**
|
15 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
16 |
+
*
|
17 |
+
* @deprecated since 2.8, to be removed in 3.0.
|
18 |
*/
|
19 |
interface AdapterInterface
|
20 |
{
|
vendor/symfony/finder/Adapter/BsdFindAdapter.php
CHANGED
@@ -11,6 +11,8 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Adapter;
|
13 |
|
|
|
|
|
14 |
use Symfony\Component\Finder\Shell\Shell;
|
15 |
use Symfony\Component\Finder\Shell\Command;
|
16 |
use Symfony\Component\Finder\Iterator\SortableIterator;
|
@@ -20,6 +22,8 @@ use Symfony\Component\Finder\Expression\Expression;
|
|
20 |
* Shell engine implementation using BSD find command.
|
21 |
*
|
22 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
|
|
|
|
23 |
*/
|
24 |
class BsdFindAdapter extends AbstractFindAdapter
|
25 |
{
|
11 |
|
12 |
namespace Symfony\Component\Finder\Adapter;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\BsdFindAdapter class is deprecated since version 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
use Symfony\Component\Finder\Shell\Shell;
|
17 |
use Symfony\Component\Finder\Shell\Command;
|
18 |
use Symfony\Component\Finder\Iterator\SortableIterator;
|
22 |
* Shell engine implementation using BSD find command.
|
23 |
*
|
24 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
25 |
+
*
|
26 |
+
* @deprecated since 2.8, to be removed in 3.0. Use Finder instead.
|
27 |
*/
|
28 |
class BsdFindAdapter extends AbstractFindAdapter
|
29 |
{
|
vendor/symfony/finder/Adapter/GnuFindAdapter.php
CHANGED
@@ -11,6 +11,8 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Adapter;
|
13 |
|
|
|
|
|
14 |
use Symfony\Component\Finder\Shell\Shell;
|
15 |
use Symfony\Component\Finder\Shell\Command;
|
16 |
use Symfony\Component\Finder\Iterator\SortableIterator;
|
@@ -20,6 +22,8 @@ use Symfony\Component\Finder\Expression\Expression;
|
|
20 |
* Shell engine implementation using GNU find command.
|
21 |
*
|
22 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
|
|
|
|
23 |
*/
|
24 |
class GnuFindAdapter extends AbstractFindAdapter
|
25 |
{
|
11 |
|
12 |
namespace Symfony\Component\Finder\Adapter;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\GnuFindAdapter class is deprecated since version 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
use Symfony\Component\Finder\Shell\Shell;
|
17 |
use Symfony\Component\Finder\Shell\Command;
|
18 |
use Symfony\Component\Finder\Iterator\SortableIterator;
|
22 |
* Shell engine implementation using GNU find command.
|
23 |
*
|
24 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
25 |
+
*
|
26 |
+
* @deprecated since 2.8, to be removed in 3.0. Use Finder instead.
|
27 |
*/
|
28 |
class GnuFindAdapter extends AbstractFindAdapter
|
29 |
{
|
vendor/symfony/finder/Adapter/PhpAdapter.php
CHANGED
@@ -11,12 +11,16 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Adapter;
|
13 |
|
|
|
|
|
14 |
use Symfony\Component\Finder\Iterator;
|
15 |
|
16 |
/**
|
17 |
* PHP finder engine implementation.
|
18 |
*
|
19 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
|
|
|
|
20 |
*/
|
21 |
class PhpAdapter extends AbstractAdapter
|
22 |
{
|
11 |
|
12 |
namespace Symfony\Component\Finder\Adapter;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\PhpAdapter class is deprecated since version 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
use Symfony\Component\Finder\Iterator;
|
17 |
|
18 |
/**
|
19 |
* PHP finder engine implementation.
|
20 |
*
|
21 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
22 |
+
*
|
23 |
+
* @deprecated since 2.8, to be removed in 3.0. Use Finder instead.
|
24 |
*/
|
25 |
class PhpAdapter extends AbstractAdapter
|
26 |
{
|
vendor/symfony/finder/CHANGELOG.md
CHANGED
@@ -1,6 +1,11 @@
|
|
1 |
CHANGELOG
|
2 |
=========
|
3 |
|
|
|
|
|
|
|
|
|
|
|
4 |
2.5.0
|
5 |
-----
|
6 |
* added support for GLOB_BRACE in the paths passed to Finder::in()
|
1 |
CHANGELOG
|
2 |
=========
|
3 |
|
4 |
+
2.8.0
|
5 |
+
-----
|
6 |
+
|
7 |
+
* deprecated adapters and related classes
|
8 |
+
|
9 |
2.5.0
|
10 |
-----
|
11 |
* added support for GLOB_BRACE in the paths passed to Finder::in()
|
vendor/symfony/finder/Exception/AdapterFailureException.php
CHANGED
@@ -11,12 +11,16 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Exception;
|
13 |
|
|
|
|
|
14 |
use Symfony\Component\Finder\Adapter\AdapterInterface;
|
15 |
|
16 |
/**
|
17 |
* Base exception for all adapter failures.
|
18 |
*
|
19 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
|
|
|
|
20 |
*/
|
21 |
class AdapterFailureException extends \RuntimeException implements ExceptionInterface
|
22 |
{
|
11 |
|
12 |
namespace Symfony\Component\Finder\Exception;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\AdapterFailureException class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
use Symfony\Component\Finder\Adapter\AdapterInterface;
|
17 |
|
18 |
/**
|
19 |
* Base exception for all adapter failures.
|
20 |
*
|
21 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
22 |
+
*
|
23 |
+
* @deprecated since 2.8, to be removed in 3.0.
|
24 |
*/
|
25 |
class AdapterFailureException extends \RuntimeException implements ExceptionInterface
|
26 |
{
|
vendor/symfony/finder/Exception/OperationNotPermitedException.php
CHANGED
@@ -11,8 +11,12 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Exception;
|
13 |
|
|
|
|
|
14 |
/**
|
15 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
|
|
|
|
16 |
*/
|
17 |
class OperationNotPermitedException extends AdapterFailureException
|
18 |
{
|
11 |
|
12 |
namespace Symfony\Component\Finder\Exception;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\OperationNotPermitedException class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
/**
|
17 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
18 |
+
*
|
19 |
+
* @deprecated since 2.8, to be removed in 3.0.
|
20 |
*/
|
21 |
class OperationNotPermitedException extends AdapterFailureException
|
22 |
{
|
vendor/symfony/finder/Exception/ShellCommandFailureException.php
CHANGED
@@ -11,11 +11,15 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Exception;
|
13 |
|
|
|
|
|
14 |
use Symfony\Component\Finder\Adapter\AdapterInterface;
|
15 |
use Symfony\Component\Finder\Shell\Command;
|
16 |
|
17 |
/**
|
18 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
|
|
|
|
19 |
*/
|
20 |
class ShellCommandFailureException extends AdapterFailureException
|
21 |
{
|
11 |
|
12 |
namespace Symfony\Component\Finder\Exception;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\ShellCommandFailureException class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
use Symfony\Component\Finder\Adapter\AdapterInterface;
|
17 |
use Symfony\Component\Finder\Shell\Command;
|
18 |
|
19 |
/**
|
20 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
21 |
+
*
|
22 |
+
* @deprecated since 2.8, to be removed in 3.0.
|
23 |
*/
|
24 |
class ShellCommandFailureException extends AdapterFailureException
|
25 |
{
|
vendor/symfony/finder/Expression/Expression.php
CHANGED
@@ -11,6 +11,8 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Expression;
|
13 |
|
|
|
|
|
14 |
/**
|
15 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
16 |
*/
|
11 |
|
12 |
namespace Symfony\Component\Finder\Expression;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\Expression class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
/**
|
17 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
18 |
*/
|
vendor/symfony/finder/Expression/Glob.php
CHANGED
@@ -11,6 +11,8 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Expression;
|
13 |
|
|
|
|
|
14 |
use Symfony\Component\Finder\Glob as FinderGlob;
|
15 |
|
16 |
/**
|
11 |
|
12 |
namespace Symfony\Component\Finder\Expression;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\Glob class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
use Symfony\Component\Finder\Glob as FinderGlob;
|
17 |
|
18 |
/**
|
vendor/symfony/finder/Expression/Regex.php
CHANGED
@@ -11,6 +11,8 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Expression;
|
13 |
|
|
|
|
|
14 |
/**
|
15 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
16 |
*/
|
11 |
|
12 |
namespace Symfony\Component\Finder\Expression;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\Regex class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
/**
|
17 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
18 |
*/
|
vendor/symfony/finder/Expression/ValueInterface.php
CHANGED
@@ -11,6 +11,8 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Expression;
|
13 |
|
|
|
|
|
14 |
/**
|
15 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
16 |
*/
|
11 |
|
12 |
namespace Symfony\Component\Finder\Expression;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\ValueInterface interface is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
/**
|
17 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
18 |
*/
|
vendor/symfony/finder/Finder.php
CHANGED
@@ -60,7 +60,7 @@ class Finder implements \IteratorAggregate, \Countable
|
|
60 |
private $iterators = array();
|
61 |
private $contains = array();
|
62 |
private $notContains = array();
|
63 |
-
private $adapters =
|
64 |
private $paths = array();
|
65 |
private $notPaths = array();
|
66 |
private $ignoreUnreadableDirs = false;
|
@@ -73,13 +73,6 @@ class Finder implements \IteratorAggregate, \Countable
|
|
73 |
public function __construct()
|
74 |
{
|
75 |
$this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
|
76 |
-
|
77 |
-
$this
|
78 |
-
->addAdapter(new GnuFindAdapter())
|
79 |
-
->addAdapter(new BsdFindAdapter())
|
80 |
-
->addAdapter(new PhpAdapter(), -50)
|
81 |
-
->setAdapter('php')
|
82 |
-
;
|
83 |
}
|
84 |
|
85 |
/**
|
@@ -99,9 +92,15 @@ class Finder implements \IteratorAggregate, \Countable
|
|
99 |
* @param int $priority Highest is selected first
|
100 |
*
|
101 |
* @return Finder The current Finder instance
|
|
|
|
|
102 |
*/
|
103 |
public function addAdapter(AdapterInterface $adapter, $priority = 0)
|
104 |
{
|
|
|
|
|
|
|
|
|
105 |
$this->adapters[$adapter->getName()] = array(
|
106 |
'adapter' => $adapter,
|
107 |
'priority' => $priority,
|
@@ -115,9 +114,15 @@ class Finder implements \IteratorAggregate, \Countable
|
|
115 |
* Sets the selected adapter to the best one according to the current platform the code is run on.
|
116 |
*
|
117 |
* @return Finder The current Finder instance
|
|
|
|
|
118 |
*/
|
119 |
public function useBestAdapter()
|
120 |
{
|
|
|
|
|
|
|
|
|
121 |
$this->resetAdapterSelection();
|
122 |
|
123 |
return $this->sortAdapters();
|
@@ -131,9 +136,15 @@ class Finder implements \IteratorAggregate, \Countable
|
|
131 |
* @throws \InvalidArgumentException
|
132 |
*
|
133 |
* @return Finder The current Finder instance
|
|
|
|
|
134 |
*/
|
135 |
public function setAdapter($name)
|
136 |
{
|
|
|
|
|
|
|
|
|
137 |
if (!isset($this->adapters[$name])) {
|
138 |
throw new \InvalidArgumentException(sprintf('Adapter "%s" does not exist.', $name));
|
139 |
}
|
@@ -148,9 +159,13 @@ class Finder implements \IteratorAggregate, \Countable
|
|
148 |
* Removes all adapters registered in the finder.
|
149 |
*
|
150 |
* @return Finder The current Finder instance
|
|
|
|
|
151 |
*/
|
152 |
public function removeAdapters()
|
153 |
{
|
|
|
|
|
154 |
$this->adapters = array();
|
155 |
|
156 |
return $this;
|
@@ -160,9 +175,15 @@ class Finder implements \IteratorAggregate, \Countable
|
|
160 |
* Returns registered adapters ordered by priority without extra information.
|
161 |
*
|
162 |
* @return AdapterInterface[]
|
|
|
|
|
163 |
*/
|
164 |
public function getAdapters()
|
165 |
{
|
|
|
|
|
|
|
|
|
166 |
return array_values(array_map(function (array $adapter) {
|
167 |
return $adapter['adapter'];
|
168 |
}, $this->adapters));
|
@@ -732,8 +753,6 @@ class Finder implements \IteratorAggregate, \Countable
|
|
732 |
* @param $dir
|
733 |
*
|
734 |
* @return \Iterator
|
735 |
-
*
|
736 |
-
* @throws \RuntimeException When none of the adapters are supported
|
737 |
*/
|
738 |
private function searchInDirectory($dir)
|
739 |
{
|
@@ -745,18 +764,93 @@ class Finder implements \IteratorAggregate, \Countable
|
|
745 |
$this->notPaths[] = '#(^|/)\..+(/|$)#';
|
746 |
}
|
747 |
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
|
|
|
|
|
755 |
}
|
756 |
}
|
757 |
}
|
758 |
|
759 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
760 |
}
|
761 |
|
762 |
/**
|
@@ -795,4 +889,17 @@ class Finder implements \IteratorAggregate, \Countable
|
|
795 |
return $properties;
|
796 |
}, $this->adapters);
|
797 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
798 |
}
|
60 |
private $iterators = array();
|
61 |
private $contains = array();
|
62 |
private $notContains = array();
|
63 |
+
private $adapters = null;
|
64 |
private $paths = array();
|
65 |
private $notPaths = array();
|
66 |
private $ignoreUnreadableDirs = false;
|
73 |
public function __construct()
|
74 |
{
|
75 |
$this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
}
|
77 |
|
78 |
/**
|
92 |
* @param int $priority Highest is selected first
|
93 |
*
|
94 |
* @return Finder The current Finder instance
|
95 |
+
*
|
96 |
+
* @deprecated since 2.8, to be removed in 3.0.
|
97 |
*/
|
98 |
public function addAdapter(AdapterInterface $adapter, $priority = 0)
|
99 |
{
|
100 |
+
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
101 |
+
|
102 |
+
$this->initDefaultAdapters();
|
103 |
+
|
104 |
$this->adapters[$adapter->getName()] = array(
|
105 |
'adapter' => $adapter,
|
106 |
'priority' => $priority,
|
114 |
* Sets the selected adapter to the best one according to the current platform the code is run on.
|
115 |
*
|
116 |
* @return Finder The current Finder instance
|
117 |
+
*
|
118 |
+
* @deprecated since 2.8, to be removed in 3.0.
|
119 |
*/
|
120 |
public function useBestAdapter()
|
121 |
{
|
122 |
+
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
123 |
+
|
124 |
+
$this->initDefaultAdapters();
|
125 |
+
|
126 |
$this->resetAdapterSelection();
|
127 |
|
128 |
return $this->sortAdapters();
|
136 |
* @throws \InvalidArgumentException
|
137 |
*
|
138 |
* @return Finder The current Finder instance
|
139 |
+
*
|
140 |
+
* @deprecated since 2.8, to be removed in 3.0.
|
141 |
*/
|
142 |
public function setAdapter($name)
|
143 |
{
|
144 |
+
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
145 |
+
|
146 |
+
$this->initDefaultAdapters();
|
147 |
+
|
148 |
if (!isset($this->adapters[$name])) {
|
149 |
throw new \InvalidArgumentException(sprintf('Adapter "%s" does not exist.', $name));
|
150 |
}
|
159 |
* Removes all adapters registered in the finder.
|
160 |
*
|
161 |
* @return Finder The current Finder instance
|
162 |
+
*
|
163 |
+
* @deprecated since 2.8, to be removed in 3.0.
|
164 |
*/
|
165 |
public function removeAdapters()
|
166 |
{
|
167 |
+
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
168 |
+
|
169 |
$this->adapters = array();
|
170 |
|
171 |
return $this;
|
175 |
* Returns registered adapters ordered by priority without extra information.
|
176 |
*
|
177 |
* @return AdapterInterface[]
|
178 |
+
*
|
179 |
+
* @deprecated since 2.8, to be removed in 3.0.
|
180 |
*/
|
181 |
public function getAdapters()
|
182 |
{
|
183 |
+
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
184 |
+
|
185 |
+
$this->initDefaultAdapters();
|
186 |
+
|
187 |
return array_values(array_map(function (array $adapter) {
|
188 |
return $adapter['adapter'];
|
189 |
}, $this->adapters));
|
753 |
* @param $dir
|
754 |
*
|
755 |
* @return \Iterator
|
|
|
|
|
756 |
*/
|
757 |
private function searchInDirectory($dir)
|
758 |
{
|
764 |
$this->notPaths[] = '#(^|/)\..+(/|$)#';
|
765 |
}
|
766 |
|
767 |
+
if ($this->adapters) {
|
768 |
+
foreach ($this->adapters as $adapter) {
|
769 |
+
if ($adapter['adapter']->isSupported()) {
|
770 |
+
try {
|
771 |
+
return $this
|
772 |
+
->buildAdapter($adapter['adapter'])
|
773 |
+
->searchInDirectory($dir);
|
774 |
+
} catch (ExceptionInterface $e) {
|
775 |
+
}
|
776 |
}
|
777 |
}
|
778 |
}
|
779 |
|
780 |
+
$minDepth = 0;
|
781 |
+
$maxDepth = PHP_INT_MAX;
|
782 |
+
|
783 |
+
foreach ($this->depths as $comparator) {
|
784 |
+
switch ($comparator->getOperator()) {
|
785 |
+
case '>':
|
786 |
+
$minDepth = $comparator->getTarget() + 1;
|
787 |
+
break;
|
788 |
+
case '>=':
|
789 |
+
$minDepth = $comparator->getTarget();
|
790 |
+
break;
|
791 |
+
case '<':
|
792 |
+
$maxDepth = $comparator->getTarget() - 1;
|
793 |
+
break;
|
794 |
+
case '<=':
|
795 |
+
$maxDepth = $comparator->getTarget();
|
796 |
+
break;
|
797 |
+
default:
|
798 |
+
$minDepth = $maxDepth = $comparator->getTarget();
|
799 |
+
}
|
800 |
+
}
|
801 |
+
|
802 |
+
$flags = \RecursiveDirectoryIterator::SKIP_DOTS;
|
803 |
+
|
804 |
+
if ($this->followLinks) {
|
805 |
+
$flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
|
806 |
+
}
|
807 |
+
|
808 |
+
$iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);
|
809 |
+
|
810 |
+
if ($this->exclude) {
|
811 |
+
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
|
812 |
+
}
|
813 |
+
|
814 |
+
$iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
|
815 |
+
|
816 |
+
if ($minDepth > 0 || $maxDepth < PHP_INT_MAX) {
|
817 |
+
$iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth);
|
818 |
+
}
|
819 |
+
|
820 |
+
if ($this->mode) {
|
821 |
+
$iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
|
822 |
+
}
|
823 |
+
|
824 |
+
if ($this->names || $this->notNames) {
|
825 |
+
$iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
|
826 |
+
}
|
827 |
+
|
828 |
+
if ($this->contains || $this->notContains) {
|
829 |
+
$iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
|
830 |
+
}
|
831 |
+
|
832 |
+
if ($this->sizes) {
|
833 |
+
$iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
|
834 |
+
}
|
835 |
+
|
836 |
+
if ($this->dates) {
|
837 |
+
$iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
|
838 |
+
}
|
839 |
+
|
840 |
+
if ($this->filters) {
|
841 |
+
$iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
|
842 |
+
}
|
843 |
+
|
844 |
+
if ($this->paths || $this->notPaths) {
|
845 |
+
$iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
|
846 |
+
}
|
847 |
+
|
848 |
+
if ($this->sort) {
|
849 |
+
$iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
|
850 |
+
$iterator = $iteratorAggregate->getIterator();
|
851 |
+
}
|
852 |
+
|
853 |
+
return $iterator;
|
854 |
}
|
855 |
|
856 |
/**
|
889 |
return $properties;
|
890 |
}, $this->adapters);
|
891 |
}
|
892 |
+
|
893 |
+
private function initDefaultAdapters()
|
894 |
+
{
|
895 |
+
if (null === $this->adapters) {
|
896 |
+
$this->adapters = array();
|
897 |
+
$this
|
898 |
+
->addAdapter(new GnuFindAdapter())
|
899 |
+
->addAdapter(new BsdFindAdapter())
|
900 |
+
->addAdapter(new PhpAdapter(), -50)
|
901 |
+
->setAdapter('php')
|
902 |
+
;
|
903 |
+
}
|
904 |
+
}
|
905 |
}
|
vendor/symfony/finder/Iterator/FilePathsIterator.php
CHANGED
@@ -11,12 +11,16 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Iterator;
|
13 |
|
|
|
|
|
14 |
use Symfony\Component\Finder\SplFileInfo;
|
15 |
|
16 |
/**
|
17 |
* Iterate over shell command result.
|
18 |
*
|
19 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
|
|
|
|
20 |
*/
|
21 |
class FilePathsIterator extends \ArrayIterator
|
22 |
{
|
11 |
|
12 |
namespace Symfony\Component\Finder\Iterator;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\FilePathsIterator class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
use Symfony\Component\Finder\SplFileInfo;
|
17 |
|
18 |
/**
|
19 |
* Iterate over shell command result.
|
20 |
*
|
21 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
22 |
+
*
|
23 |
+
* @deprecated since 2.8, to be removed in 3.0.
|
24 |
*/
|
25 |
class FilePathsIterator extends \ArrayIterator
|
26 |
{
|
vendor/symfony/finder/Iterator/FilecontentFilterIterator.php
CHANGED
@@ -41,25 +41,7 @@ class FilecontentFilterIterator extends MultiplePcreFilterIterator
|
|
41 |
return false;
|
42 |
}
|
43 |
|
44 |
-
|
45 |
-
foreach ($this->noMatchRegexps as $regex) {
|
46 |
-
if (preg_match($regex, $content)) {
|
47 |
-
return false;
|
48 |
-
}
|
49 |
-
}
|
50 |
-
|
51 |
-
// should at least match one rule
|
52 |
-
$match = true;
|
53 |
-
if ($this->matchRegexps) {
|
54 |
-
$match = false;
|
55 |
-
foreach ($this->matchRegexps as $regex) {
|
56 |
-
if (preg_match($regex, $content)) {
|
57 |
-
return true;
|
58 |
-
}
|
59 |
-
}
|
60 |
-
}
|
61 |
-
|
62 |
-
return $match;
|
63 |
}
|
64 |
|
65 |
/**
|
41 |
return false;
|
42 |
}
|
43 |
|
44 |
+
return $this->isAccepted($content);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
}
|
46 |
|
47 |
/**
|
vendor/symfony/finder/Iterator/FilenameFilterIterator.php
CHANGED
@@ -11,7 +11,7 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Iterator;
|
13 |
|
14 |
-
use Symfony\Component\Finder\
|
15 |
|
16 |
/**
|
17 |
* FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string).
|
@@ -27,27 +27,7 @@ class FilenameFilterIterator extends MultiplePcreFilterIterator
|
|
27 |
*/
|
28 |
public function accept()
|
29 |
{
|
30 |
-
|
31 |
-
|
32 |
-
// should at least not match one rule to exclude
|
33 |
-
foreach ($this->noMatchRegexps as $regex) {
|
34 |
-
if (preg_match($regex, $filename)) {
|
35 |
-
return false;
|
36 |
-
}
|
37 |
-
}
|
38 |
-
|
39 |
-
// should at least match one rule
|
40 |
-
$match = true;
|
41 |
-
if ($this->matchRegexps) {
|
42 |
-
$match = false;
|
43 |
-
foreach ($this->matchRegexps as $regex) {
|
44 |
-
if (preg_match($regex, $filename)) {
|
45 |
-
return true;
|
46 |
-
}
|
47 |
-
}
|
48 |
-
}
|
49 |
-
|
50 |
-
return $match;
|
51 |
}
|
52 |
|
53 |
/**
|
@@ -62,6 +42,6 @@ class FilenameFilterIterator extends MultiplePcreFilterIterator
|
|
62 |
*/
|
63 |
protected function toRegex($str)
|
64 |
{
|
65 |
-
return
|
66 |
}
|
67 |
}
|
11 |
|
12 |
namespace Symfony\Component\Finder\Iterator;
|
13 |
|
14 |
+
use Symfony\Component\Finder\Glob;
|
15 |
|
16 |
/**
|
17 |
* FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string).
|
27 |
*/
|
28 |
public function accept()
|
29 |
{
|
30 |
+
return $this->isAccepted($this->current()->getFilename());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
}
|
32 |
|
33 |
/**
|
42 |
*/
|
43 |
protected function toRegex($str)
|
44 |
{
|
45 |
+
return $this->isRegex($str) ? $str : Glob::toRegex($str);
|
46 |
}
|
47 |
}
|
vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php
CHANGED
@@ -11,8 +11,6 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Iterator;
|
13 |
|
14 |
-
use Symfony\Component\Finder\Expression\Expression;
|
15 |
-
|
16 |
/**
|
17 |
* MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings).
|
18 |
*
|
@@ -43,6 +41,41 @@ abstract class MultiplePcreFilterIterator extends FilterIterator
|
|
43 |
parent::__construct($iterator);
|
44 |
}
|
45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
/**
|
47 |
* Checks whether the string is a regex.
|
48 |
*
|
@@ -52,7 +85,22 @@ abstract class MultiplePcreFilterIterator extends FilterIterator
|
|
52 |
*/
|
53 |
protected function isRegex($str)
|
54 |
{
|
55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
}
|
57 |
|
58 |
/**
|
11 |
|
12 |
namespace Symfony\Component\Finder\Iterator;
|
13 |
|
|
|
|
|
14 |
/**
|
15 |
* MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings).
|
16 |
*
|
41 |
parent::__construct($iterator);
|
42 |
}
|
43 |
|
44 |
+
/**
|
45 |
+
* Checks whether the string is accepted by the regex filters.
|
46 |
+
*
|
47 |
+
* If there is no regexps defined in the class, this method will accept the string.
|
48 |
+
* Such case can be handled by child classes before calling the method if they want to
|
49 |
+
* apply a different behavior.
|
50 |
+
*
|
51 |
+
* @param string $string The string to be matched against filters
|
52 |
+
*
|
53 |
+
* @return bool
|
54 |
+
*/
|
55 |
+
protected function isAccepted($string)
|
56 |
+
{
|
57 |
+
// should at least not match one rule to exclude
|
58 |
+
foreach ($this->noMatchRegexps as $regex) {
|
59 |
+
if (preg_match($regex, $string)) {
|
60 |
+
return false;
|
61 |
+
}
|
62 |
+
}
|
63 |
+
|
64 |
+
// should at least match one rule
|
65 |
+
if ($this->matchRegexps) {
|
66 |
+
foreach ($this->matchRegexps as $regex) {
|
67 |
+
if (preg_match($regex, $string)) {
|
68 |
+
return true;
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
return false;
|
73 |
+
}
|
74 |
+
|
75 |
+
// If there is no match rules, the file is accepted
|
76 |
+
return true;
|
77 |
+
}
|
78 |
+
|
79 |
/**
|
80 |
* Checks whether the string is a regex.
|
81 |
*
|
85 |
*/
|
86 |
protected function isRegex($str)
|
87 |
{
|
88 |
+
if (preg_match('/^(.{3,}?)[imsxuADU]*$/', $str, $m)) {
|
89 |
+
$start = substr($m[1], 0, 1);
|
90 |
+
$end = substr($m[1], -1);
|
91 |
+
|
92 |
+
if ($start === $end) {
|
93 |
+
return !preg_match('/[*?[:alnum:] \\\\]/', $start);
|
94 |
+
}
|
95 |
+
|
96 |
+
foreach (array(array('{', '}'), array('(', ')'), array('[', ']'), array('<', '>')) as $delimiters) {
|
97 |
+
if ($start === $delimiters[0] && $end === $delimiters[1]) {
|
98 |
+
return true;
|
99 |
+
}
|
100 |
+
}
|
101 |
+
}
|
102 |
+
|
103 |
+
return false;
|
104 |
}
|
105 |
|
106 |
/**
|
vendor/symfony/finder/Iterator/PathFilterIterator.php
CHANGED
@@ -32,25 +32,7 @@ class PathFilterIterator extends MultiplePcreFilterIterator
|
|
32 |
$filename = str_replace('\\', '/', $filename);
|
33 |
}
|
34 |
|
35 |
-
|
36 |
-
foreach ($this->noMatchRegexps as $regex) {
|
37 |
-
if (preg_match($regex, $filename)) {
|
38 |
-
return false;
|
39 |
-
}
|
40 |
-
}
|
41 |
-
|
42 |
-
// should at least match one rule
|
43 |
-
$match = true;
|
44 |
-
if ($this->matchRegexps) {
|
45 |
-
$match = false;
|
46 |
-
foreach ($this->matchRegexps as $regex) {
|
47 |
-
if (preg_match($regex, $filename)) {
|
48 |
-
return true;
|
49 |
-
}
|
50 |
-
}
|
51 |
-
}
|
52 |
-
|
53 |
-
return $match;
|
54 |
}
|
55 |
|
56 |
/**
|
32 |
$filename = str_replace('\\', '/', $filename);
|
33 |
}
|
34 |
|
35 |
+
return $this->isAccepted($filename);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
}
|
37 |
|
38 |
/**
|
vendor/symfony/finder/Iterator/SortableIterator.php
CHANGED
@@ -55,15 +55,15 @@ class SortableIterator implements \IteratorAggregate
|
|
55 |
};
|
56 |
} elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
|
57 |
$this->sort = function ($a, $b) {
|
58 |
-
return
|
59 |
};
|
60 |
} elseif (self::SORT_BY_CHANGED_TIME === $sort) {
|
61 |
$this->sort = function ($a, $b) {
|
62 |
-
return
|
63 |
};
|
64 |
} elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
|
65 |
$this->sort = function ($a, $b) {
|
66 |
-
return
|
67 |
};
|
68 |
} elseif (is_callable($sort)) {
|
69 |
$this->sort = $sort;
|
55 |
};
|
56 |
} elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
|
57 |
$this->sort = function ($a, $b) {
|
58 |
+
return $a->getATime() - $b->getATime();
|
59 |
};
|
60 |
} elseif (self::SORT_BY_CHANGED_TIME === $sort) {
|
61 |
$this->sort = function ($a, $b) {
|
62 |
+
return $a->getCTime() - $b->getCTime();
|
63 |
};
|
64 |
} elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
|
65 |
$this->sort = function ($a, $b) {
|
66 |
+
return $a->getMTime() - $b->getMTime();
|
67 |
};
|
68 |
} elseif (is_callable($sort)) {
|
69 |
$this->sort = $sort;
|
vendor/symfony/finder/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
Copyright (c) 2004-
|
2 |
|
3 |
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4 |
of this software and associated documentation files (the "Software"), to deal
|
1 |
+
Copyright (c) 2004-2016 Fabien Potencier
|
2 |
|
3 |
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4 |
of this software and associated documentation files (the "Software"), to deal
|
vendor/symfony/finder/Shell/Command.php
CHANGED
@@ -11,8 +11,12 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Shell;
|
13 |
|
|
|
|
|
14 |
/**
|
15 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
|
|
|
|
16 |
*/
|
17 |
class Command
|
18 |
{
|
11 |
|
12 |
namespace Symfony\Component\Finder\Shell;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\Command class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
/**
|
17 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
18 |
+
*
|
19 |
+
* @deprecated since 2.8, to be removed in 3.0.
|
20 |
*/
|
21 |
class Command
|
22 |
{
|
vendor/symfony/finder/Shell/Shell.php
CHANGED
@@ -11,8 +11,12 @@
|
|
11 |
|
12 |
namespace Symfony\Component\Finder\Shell;
|
13 |
|
|
|
|
|
14 |
/**
|
15 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
|
|
|
|
16 |
*/
|
17 |
class Shell
|
18 |
{
|
11 |
|
12 |
namespace Symfony\Component\Finder\Shell;
|
13 |
|
14 |
+
@trigger_error('The '.__NAMESPACE__.'\Shell class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
|
15 |
+
|
16 |
/**
|
17 |
* @author Jean-François Simon <contact@jfsimon.fr>
|
18 |
+
*
|
19 |
+
* @deprecated since 2.8, to be removed in 3.0.
|
20 |
*/
|
21 |
class Shell
|
22 |
{
|
vendor/symfony/finder/Symfony/Component/Finder/Adapter/AbstractAdapter.php
DELETED
@@ -1,236 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Adapter;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Interface for finder engine implementations.
|
16 |
-
*
|
17 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
18 |
-
*/
|
19 |
-
abstract class AbstractAdapter implements AdapterInterface
|
20 |
-
{
|
21 |
-
protected $followLinks = false;
|
22 |
-
protected $mode = 0;
|
23 |
-
protected $minDepth = 0;
|
24 |
-
protected $maxDepth = PHP_INT_MAX;
|
25 |
-
protected $exclude = array();
|
26 |
-
protected $names = array();
|
27 |
-
protected $notNames = array();
|
28 |
-
protected $contains = array();
|
29 |
-
protected $notContains = array();
|
30 |
-
protected $sizes = array();
|
31 |
-
protected $dates = array();
|
32 |
-
protected $filters = array();
|
33 |
-
protected $sort = false;
|
34 |
-
protected $paths = array();
|
35 |
-
protected $notPaths = array();
|
36 |
-
protected $ignoreUnreadableDirs = false;
|
37 |
-
|
38 |
-
private static $areSupported = array();
|
39 |
-
|
40 |
-
/**
|
41 |
-
* {@inheritdoc}
|
42 |
-
*/
|
43 |
-
public function isSupported()
|
44 |
-
{
|
45 |
-
$name = $this->getName();
|
46 |
-
|
47 |
-
if (!array_key_exists($name, self::$areSupported)) {
|
48 |
-
self::$areSupported[$name] = $this->canBeUsed();
|
49 |
-
}
|
50 |
-
|
51 |
-
return self::$areSupported[$name];
|
52 |
-
}
|
53 |
-
|
54 |
-
/**
|
55 |
-
* {@inheritdoc}
|
56 |
-
*/
|
57 |
-
public function setFollowLinks($followLinks)
|
58 |
-
{
|
59 |
-
$this->followLinks = $followLinks;
|
60 |
-
|
61 |
-
return $this;
|
62 |
-
}
|
63 |
-
|
64 |
-
/**
|
65 |
-
* {@inheritdoc}
|
66 |
-
*/
|
67 |
-
public function setMode($mode)
|
68 |
-
{
|
69 |
-
$this->mode = $mode;
|
70 |
-
|
71 |
-
return $this;
|
72 |
-
}
|
73 |
-
|
74 |
-
/**
|
75 |
-
* {@inheritdoc}
|
76 |
-
*/
|
77 |
-
public function setDepths(array $depths)
|
78 |
-
{
|
79 |
-
$this->minDepth = 0;
|
80 |
-
$this->maxDepth = PHP_INT_MAX;
|
81 |
-
|
82 |
-
foreach ($depths as $comparator) {
|
83 |
-
switch ($comparator->getOperator()) {
|
84 |
-
case '>':
|
85 |
-
$this->minDepth = $comparator->getTarget() + 1;
|
86 |
-
break;
|
87 |
-
case '>=':
|
88 |
-
$this->minDepth = $comparator->getTarget();
|
89 |
-
break;
|
90 |
-
case '<':
|
91 |
-
$this->maxDepth = $comparator->getTarget() - 1;
|
92 |
-
break;
|
93 |
-
case '<=':
|
94 |
-
$this->maxDepth = $comparator->getTarget();
|
95 |
-
break;
|
96 |
-
default:
|
97 |
-
$this->minDepth = $this->maxDepth = $comparator->getTarget();
|
98 |
-
}
|
99 |
-
}
|
100 |
-
|
101 |
-
return $this;
|
102 |
-
}
|
103 |
-
|
104 |
-
/**
|
105 |
-
* {@inheritdoc}
|
106 |
-
*/
|
107 |
-
public function setExclude(array $exclude)
|
108 |
-
{
|
109 |
-
$this->exclude = $exclude;
|
110 |
-
|
111 |
-
return $this;
|
112 |
-
}
|
113 |
-
|
114 |
-
/**
|
115 |
-
* {@inheritdoc}
|
116 |
-
*/
|
117 |
-
public function setNames(array $names)
|
118 |
-
{
|
119 |
-
$this->names = $names;
|
120 |
-
|
121 |
-
return $this;
|
122 |
-
}
|
123 |
-
|
124 |
-
/**
|
125 |
-
* {@inheritdoc}
|
126 |
-
*/
|
127 |
-
public function setNotNames(array $notNames)
|
128 |
-
{
|
129 |
-
$this->notNames = $notNames;
|
130 |
-
|
131 |
-
return $this;
|
132 |
-
}
|
133 |
-
|
134 |
-
/**
|
135 |
-
* {@inheritdoc}
|
136 |
-
*/
|
137 |
-
public function setContains(array $contains)
|
138 |
-
{
|
139 |
-
$this->contains = $contains;
|
140 |
-
|
141 |
-
return $this;
|
142 |
-
}
|
143 |
-
|
144 |
-
/**
|
145 |
-
* {@inheritdoc}
|
146 |
-
*/
|
147 |
-
public function setNotContains(array $notContains)
|
148 |
-
{
|
149 |
-
$this->notContains = $notContains;
|
150 |
-
|
151 |
-
return $this;
|
152 |
-
}
|
153 |
-
|
154 |
-
/**
|
155 |
-
* {@inheritdoc}
|
156 |
-
*/
|
157 |
-
public function setSizes(array $sizes)
|
158 |
-
{
|
159 |
-
$this->sizes = $sizes;
|
160 |
-
|
161 |
-
return $this;
|
162 |
-
}
|
163 |
-
|
164 |
-
/**
|
165 |
-
* {@inheritdoc}
|
166 |
-
*/
|
167 |
-
public function setDates(array $dates)
|
168 |
-
{
|
169 |
-
$this->dates = $dates;
|
170 |
-
|
171 |
-
return $this;
|
172 |
-
}
|
173 |
-
|
174 |
-
/**
|
175 |
-
* {@inheritdoc}
|
176 |
-
*/
|
177 |
-
public function setFilters(array $filters)
|
178 |
-
{
|
179 |
-
$this->filters = $filters;
|
180 |
-
|
181 |
-
return $this;
|
182 |
-
}
|
183 |
-
|
184 |
-
/**
|
185 |
-
* {@inheritdoc}
|
186 |
-
*/
|
187 |
-
public function setSort($sort)
|
188 |
-
{
|
189 |
-
$this->sort = $sort;
|
190 |
-
|
191 |
-
return $this;
|
192 |
-
}
|
193 |
-
|
194 |
-
/**
|
195 |
-
* {@inheritdoc}
|
196 |
-
*/
|
197 |
-
public function setPath(array $paths)
|
198 |
-
{
|
199 |
-
$this->paths = $paths;
|
200 |
-
|
201 |
-
return $this;
|
202 |
-
}
|
203 |
-
|
204 |
-
/**
|
205 |
-
* {@inheritdoc}
|
206 |
-
*/
|
207 |
-
public function setNotPath(array $notPaths)
|
208 |
-
{
|
209 |
-
$this->notPaths = $notPaths;
|
210 |
-
|
211 |
-
return $this;
|
212 |
-
}
|
213 |
-
|
214 |
-
/**
|
215 |
-
* {@inheritdoc}
|
216 |
-
*/
|
217 |
-
public function ignoreUnreadableDirs($ignore = true)
|
218 |
-
{
|
219 |
-
$this->ignoreUnreadableDirs = (bool) $ignore;
|
220 |
-
|
221 |
-
return $this;
|
222 |
-
}
|
223 |
-
|
224 |
-
/**
|
225 |
-
* Returns whether the adapter is supported in the current environment.
|
226 |
-
*
|
227 |
-
* This method should be implemented in all adapters. Do not implement
|
228 |
-
* isSupported in the adapters as the generic implementation provides a cache
|
229 |
-
* layer.
|
230 |
-
*
|
231 |
-
* @see isSupported()
|
232 |
-
*
|
233 |
-
* @return bool Whether the adapter is supported
|
234 |
-
*/
|
235 |
-
abstract protected function canBeUsed();
|
236 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Adapter/AbstractFindAdapter.php
DELETED
@@ -1,327 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Adapter;
|
13 |
-
|
14 |
-
use Symfony\Component\Finder\Exception\AccessDeniedException;
|
15 |
-
use Symfony\Component\Finder\Iterator;
|
16 |
-
use Symfony\Component\Finder\Shell\Shell;
|
17 |
-
use Symfony\Component\Finder\Expression\Expression;
|
18 |
-
use Symfony\Component\Finder\Shell\Command;
|
19 |
-
use Symfony\Component\Finder\Comparator\NumberComparator;
|
20 |
-
use Symfony\Component\Finder\Comparator\DateComparator;
|
21 |
-
|
22 |
-
/**
|
23 |
-
* Shell engine implementation using GNU find command.
|
24 |
-
*
|
25 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
26 |
-
*/
|
27 |
-
abstract class AbstractFindAdapter extends AbstractAdapter
|
28 |
-
{
|
29 |
-
/**
|
30 |
-
* @var Shell
|
31 |
-
*/
|
32 |
-
protected $shell;
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Constructor.
|
36 |
-
*/
|
37 |
-
public function __construct()
|
38 |
-
{
|
39 |
-
$this->shell = new Shell();
|
40 |
-
}
|
41 |
-
|
42 |
-
/**
|
43 |
-
* {@inheritdoc}
|
44 |
-
*/
|
45 |
-
public function searchInDirectory($dir)
|
46 |
-
{
|
47 |
-
// having "/../" in path make find fail
|
48 |
-
$dir = realpath($dir);
|
49 |
-
|
50 |
-
// searching directories containing or not containing strings leads to no result
|
51 |
-
if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode && ($this->contains || $this->notContains)) {
|
52 |
-
return new Iterator\FilePathsIterator(array(), $dir);
|
53 |
-
}
|
54 |
-
|
55 |
-
$command = Command::create();
|
56 |
-
$find = $this->buildFindCommand($command, $dir);
|
57 |
-
|
58 |
-
if ($this->followLinks) {
|
59 |
-
$find->add('-follow');
|
60 |
-
}
|
61 |
-
|
62 |
-
$find->add('-mindepth')->add($this->minDepth + 1);
|
63 |
-
|
64 |
-
if (PHP_INT_MAX !== $this->maxDepth) {
|
65 |
-
$find->add('-maxdepth')->add($this->maxDepth + 1);
|
66 |
-
}
|
67 |
-
|
68 |
-
if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode) {
|
69 |
-
$find->add('-type d');
|
70 |
-
} elseif (Iterator\FileTypeFilterIterator::ONLY_FILES === $this->mode) {
|
71 |
-
$find->add('-type f');
|
72 |
-
}
|
73 |
-
|
74 |
-
$this->buildNamesFiltering($find, $this->names);
|
75 |
-
$this->buildNamesFiltering($find, $this->notNames, true);
|
76 |
-
$this->buildPathsFiltering($find, $dir, $this->paths);
|
77 |
-
$this->buildPathsFiltering($find, $dir, $this->notPaths, true);
|
78 |
-
$this->buildSizesFiltering($find, $this->sizes);
|
79 |
-
$this->buildDatesFiltering($find, $this->dates);
|
80 |
-
|
81 |
-
$useGrep = $this->shell->testCommand('grep') && $this->shell->testCommand('xargs');
|
82 |
-
$useSort = is_int($this->sort) && $this->shell->testCommand('sort') && $this->shell->testCommand('cut');
|
83 |
-
|
84 |
-
if ($useGrep && ($this->contains || $this->notContains)) {
|
85 |
-
$grep = $command->ins('grep');
|
86 |
-
$this->buildContentFiltering($grep, $this->contains);
|
87 |
-
$this->buildContentFiltering($grep, $this->notContains, true);
|
88 |
-
}
|
89 |
-
|
90 |
-
if ($useSort) {
|
91 |
-
$this->buildSorting($command, $this->sort);
|
92 |
-
}
|
93 |
-
|
94 |
-
$command->setErrorHandler(
|
95 |
-
$this->ignoreUnreadableDirs
|
96 |
-
// If directory is unreadable and finder is set to ignore it, `stderr` is ignored.
|
97 |
-
? function ($stderr) { return; }
|
98 |
-
: function ($stderr) { throw new AccessDeniedException($stderr); }
|
99 |
-
);
|
100 |
-
|
101 |
-
$paths = $this->shell->testCommand('uniq') ? $command->add('| uniq')->execute() : array_unique($command->execute());
|
102 |
-
$iterator = new Iterator\FilePathsIterator($paths, $dir);
|
103 |
-
|
104 |
-
if ($this->exclude) {
|
105 |
-
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
|
106 |
-
}
|
107 |
-
|
108 |
-
if (!$useGrep && ($this->contains || $this->notContains)) {
|
109 |
-
$iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
|
110 |
-
}
|
111 |
-
|
112 |
-
if ($this->filters) {
|
113 |
-
$iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
|
114 |
-
}
|
115 |
-
|
116 |
-
if (!$useSort && $this->sort) {
|
117 |
-
$iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
|
118 |
-
$iterator = $iteratorAggregate->getIterator();
|
119 |
-
}
|
120 |
-
|
121 |
-
return $iterator;
|
122 |
-
}
|
123 |
-
|
124 |
-
/**
|
125 |
-
* {@inheritdoc}
|
126 |
-
*/
|
127 |
-
protected function canBeUsed()
|
128 |
-
{
|
129 |
-
return $this->shell->testCommand('find');
|
130 |
-
}
|
131 |
-
|
132 |
-
/**
|
133 |
-
* @param Command $command
|
134 |
-
* @param string $dir
|
135 |
-
*
|
136 |
-
* @return Command
|
137 |
-
*/
|
138 |
-
protected function buildFindCommand(Command $command, $dir)
|
139 |
-
{
|
140 |
-
return $command
|
141 |
-
->ins('find')
|
142 |
-
->add('find ')
|
143 |
-
->arg($dir)
|
144 |
-
->add('-noleaf'); // the -noleaf option is required for filesystems that don't follow the '.' and '..' conventions
|
145 |
-
}
|
146 |
-
|
147 |
-
/**
|
148 |
-
* @param Command $command
|
149 |
-
* @param string[] $names
|
150 |
-
* @param bool $not
|
151 |
-
*/
|
152 |
-
private function buildNamesFiltering(Command $command, array $names, $not = false)
|
153 |
-
{
|
154 |
-
if (0 === count($names)) {
|
155 |
-
return;
|
156 |
-
}
|
157 |
-
|
158 |
-
$command->add($not ? '-not' : null)->cmd('(');
|
159 |
-
|
160 |
-
foreach ($names as $i => $name) {
|
161 |
-
$expr = Expression::create($name);
|
162 |
-
|
163 |
-
// Find does not support expandable globs ("*.{a,b}" syntax).
|
164 |
-
if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
|
165 |
-
$expr = Expression::create($expr->getGlob()->toRegex(false));
|
166 |
-
}
|
167 |
-
|
168 |
-
// Fixes 'not search' and 'full path matching' regex problems.
|
169 |
-
// - Jokers '.' are replaced by [^/].
|
170 |
-
// - We add '[^/]*' before and after regex (if no ^|$ flags are present).
|
171 |
-
if ($expr->isRegex()) {
|
172 |
-
$regex = $expr->getRegex();
|
173 |
-
$regex->prepend($regex->hasStartFlag() ? '/' : '/[^/]*')
|
174 |
-
->setStartFlag(false)
|
175 |
-
->setStartJoker(true)
|
176 |
-
->replaceJokers('[^/]');
|
177 |
-
if (!$regex->hasEndFlag() || $regex->hasEndJoker()) {
|
178 |
-
$regex->setEndJoker(false)->append('[^/]*');
|
179 |
-
}
|
180 |
-
}
|
181 |
-
|
182 |
-
$command
|
183 |
-
->add($i > 0 ? '-or' : null)
|
184 |
-
->add($expr->isRegex()
|
185 |
-
? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
|
186 |
-
: ($expr->isCaseSensitive() ? '-name' : '-iname')
|
187 |
-
)
|
188 |
-
->arg($expr->renderPattern());
|
189 |
-
}
|
190 |
-
|
191 |
-
$command->cmd(')');
|
192 |
-
}
|
193 |
-
|
194 |
-
/**
|
195 |
-
* @param Command $command
|
196 |
-
* @param string $dir
|
197 |
-
* @param string[] $paths
|
198 |
-
* @param bool $not
|
199 |
-
*/
|
200 |
-
private function buildPathsFiltering(Command $command, $dir, array $paths, $not = false)
|
201 |
-
{
|
202 |
-
if (0 === count($paths)) {
|
203 |
-
return;
|
204 |
-
}
|
205 |
-
|
206 |
-
$command->add($not ? '-not' : null)->cmd('(');
|
207 |
-
|
208 |
-
foreach ($paths as $i => $path) {
|
209 |
-
$expr = Expression::create($path);
|
210 |
-
|
211 |
-
// Find does not support expandable globs ("*.{a,b}" syntax).
|
212 |
-
if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
|
213 |
-
$expr = Expression::create($expr->getGlob()->toRegex(false));
|
214 |
-
}
|
215 |
-
|
216 |
-
// Fixes 'not search' regex problems.
|
217 |
-
if ($expr->isRegex()) {
|
218 |
-
$regex = $expr->getRegex();
|
219 |
-
$regex->prepend($regex->hasStartFlag() ? preg_quote($dir).DIRECTORY_SEPARATOR : '.*')->setEndJoker(!$regex->hasEndFlag());
|
220 |
-
} else {
|
221 |
-
$expr->prepend('*')->append('*');
|
222 |
-
}
|
223 |
-
|
224 |
-
$command
|
225 |
-
->add($i > 0 ? '-or' : null)
|
226 |
-
->add($expr->isRegex()
|
227 |
-
? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
|
228 |
-
: ($expr->isCaseSensitive() ? '-path' : '-ipath')
|
229 |
-
)
|
230 |
-
->arg($expr->renderPattern());
|
231 |
-
}
|
232 |
-
|
233 |
-
$command->cmd(')');
|
234 |
-
}
|
235 |
-
|
236 |
-
/**
|
237 |
-
* @param Command $command
|
238 |
-
* @param NumberComparator[] $sizes
|
239 |
-
*/
|
240 |
-
private function buildSizesFiltering(Command $command, array $sizes)
|
241 |
-
{
|
242 |
-
foreach ($sizes as $i => $size) {
|
243 |
-
$command->add($i > 0 ? '-and' : null);
|
244 |
-
|
245 |
-
switch ($size->getOperator()) {
|
246 |
-
case '<=':
|
247 |
-
$command->add('-size -'.($size->getTarget() + 1).'c');
|
248 |
-
break;
|
249 |
-
case '>=':
|
250 |
-
$command->add('-size +'.($size->getTarget() - 1).'c');
|
251 |
-
break;
|
252 |
-
case '>':
|
253 |
-
$command->add('-size +'.$size->getTarget().'c');
|
254 |
-
break;
|
255 |
-
case '!=':
|
256 |
-
$command->add('-size -'.$size->getTarget().'c');
|
257 |
-
$command->add('-size +'.$size->getTarget().'c');
|
258 |
-
break;
|
259 |
-
case '<':
|
260 |
-
default:
|
261 |
-
$command->add('-size -'.$size->getTarget().'c');
|
262 |
-
}
|
263 |
-
}
|
264 |
-
}
|
265 |
-
|
266 |
-
/**
|
267 |
-
* @param Command $command
|
268 |
-
* @param DateComparator[] $dates
|
269 |
-
*/
|
270 |
-
private function buildDatesFiltering(Command $command, array $dates)
|
271 |
-
{
|
272 |
-
foreach ($dates as $i => $date) {
|
273 |
-
$command->add($i > 0 ? '-and' : null);
|
274 |
-
|
275 |
-
$mins = (int) round((time()-$date->getTarget()) / 60);
|
276 |
-
|
277 |
-
if (0 > $mins) {
|
278 |
-
// mtime is in the future
|
279 |
-
$command->add(' -mmin -0');
|
280 |
-
// we will have no result so we don't need to continue
|
281 |
-
return;
|
282 |
-
}
|
283 |
-
|
284 |
-
switch ($date->getOperator()) {
|
285 |
-
case '<=':
|
286 |
-
$command->add('-mmin +'.($mins - 1));
|
287 |
-
break;
|
288 |
-
case '>=':
|
289 |
-
$command->add('-mmin -'.($mins + 1));
|
290 |
-
break;
|
291 |
-
case '>':
|
292 |
-
$command->add('-mmin -'.$mins);
|
293 |
-
break;
|
294 |
-
case '!=':
|
295 |
-
$command->add('-mmin +'.$mins.' -or -mmin -'.$mins);
|
296 |
-
break;
|
297 |
-
case '<':
|
298 |
-
default:
|
299 |
-
$command->add('-mmin +'.$mins);
|
300 |
-
}
|
301 |
-
}
|
302 |
-
}
|
303 |
-
|
304 |
-
/**
|
305 |
-
* @param Command $command
|
306 |
-
* @param string $sort
|
307 |
-
*
|
308 |
-
* @throws \InvalidArgumentException
|
309 |
-
*/
|
310 |
-
private function buildSorting(Command $command, $sort)
|
311 |
-
{
|
312 |
-
$this->buildFormatSorting($command, $sort);
|
313 |
-
}
|
314 |
-
|
315 |
-
/**
|
316 |
-
* @param Command $command
|
317 |
-
* @param string $sort
|
318 |
-
*/
|
319 |
-
abstract protected function buildFormatSorting(Command $command, $sort);
|
320 |
-
|
321 |
-
/**
|
322 |
-
* @param Command $command
|
323 |
-
* @param array $contains
|
324 |
-
* @param bool $not
|
325 |
-
*/
|
326 |
-
abstract protected function buildContentFiltering(Command $command, array $contains, $not = false);
|
327 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Adapter/AdapterInterface.php
DELETED
@@ -1,144 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Adapter;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
16 |
-
*/
|
17 |
-
interface AdapterInterface
|
18 |
-
{
|
19 |
-
/**
|
20 |
-
* @param bool $followLinks
|
21 |
-
*
|
22 |
-
* @return AdapterInterface Current instance
|
23 |
-
*/
|
24 |
-
public function setFollowLinks($followLinks);
|
25 |
-
|
26 |
-
/**
|
27 |
-
* @param int $mode
|
28 |
-
*
|
29 |
-
* @return AdapterInterface Current instance
|
30 |
-
*/
|
31 |
-
public function setMode($mode);
|
32 |
-
|
33 |
-
/**
|
34 |
-
* @param array $exclude
|
35 |
-
*
|
36 |
-
* @return AdapterInterface Current instance
|
37 |
-
*/
|
38 |
-
public function setExclude(array $exclude);
|
39 |
-
|
40 |
-
/**
|
41 |
-
* @param array $depths
|
42 |
-
*
|
43 |
-
* @return AdapterInterface Current instance
|
44 |
-
*/
|
45 |
-
public function setDepths(array $depths);
|
46 |
-
|
47 |
-
/**
|
48 |
-
* @param array $names
|
49 |
-
*
|
50 |
-
* @return AdapterInterface Current instance
|
51 |
-
*/
|
52 |
-
public function setNames(array $names);
|
53 |
-
|
54 |
-
/**
|
55 |
-
* @param array $notNames
|
56 |
-
*
|
57 |
-
* @return AdapterInterface Current instance
|
58 |
-
*/
|
59 |
-
public function setNotNames(array $notNames);
|
60 |
-
|
61 |
-
/**
|
62 |
-
* @param array $contains
|
63 |
-
*
|
64 |
-
* @return AdapterInterface Current instance
|
65 |
-
*/
|
66 |
-
public function setContains(array $contains);
|
67 |
-
|
68 |
-
/**
|
69 |
-
* @param array $notContains
|
70 |
-
*
|
71 |
-
* @return AdapterInterface Current instance
|
72 |
-
*/
|
73 |
-
public function setNotContains(array $notContains);
|
74 |
-
|
75 |
-
/**
|
76 |
-
* @param array $sizes
|
77 |
-
*
|
78 |
-
* @return AdapterInterface Current instance
|
79 |
-
*/
|
80 |
-
public function setSizes(array $sizes);
|
81 |
-
|
82 |
-
/**
|
83 |
-
* @param array $dates
|
84 |
-
*
|
85 |
-
* @return AdapterInterface Current instance
|
86 |
-
*/
|
87 |
-
public function setDates(array $dates);
|
88 |
-
|
89 |
-
/**
|
90 |
-
* @param array $filters
|
91 |
-
*
|
92 |
-
* @return AdapterInterface Current instance
|
93 |
-
*/
|
94 |
-
public function setFilters(array $filters);
|
95 |
-
|
96 |
-
/**
|
97 |
-
* @param \Closure|int $sort
|
98 |
-
*
|
99 |
-
* @return AdapterInterface Current instance
|
100 |
-
*/
|
101 |
-
public function setSort($sort);
|
102 |
-
|
103 |
-
/**
|
104 |
-
* @param array $paths
|
105 |
-
*
|
106 |
-
* @return AdapterInterface Current instance
|
107 |
-
*/
|
108 |
-
public function setPath(array $paths);
|
109 |
-
|
110 |
-
/**
|
111 |
-
* @param array $notPaths
|
112 |
-
*
|
113 |
-
* @return AdapterInterface Current instance
|
114 |
-
*/
|
115 |
-
public function setNotPath(array $notPaths);
|
116 |
-
|
117 |
-
/**
|
118 |
-
* @param bool $ignore
|
119 |
-
*
|
120 |
-
* @return AdapterInterface Current instance
|
121 |
-
*/
|
122 |
-
public function ignoreUnreadableDirs($ignore = true);
|
123 |
-
|
124 |
-
/**
|
125 |
-
* @param string $dir
|
126 |
-
*
|
127 |
-
* @return \Iterator Result iterator
|
128 |
-
*/
|
129 |
-
public function searchInDirectory($dir);
|
130 |
-
|
131 |
-
/**
|
132 |
-
* Tests adapter support for current platform.
|
133 |
-
*
|
134 |
-
* @return bool
|
135 |
-
*/
|
136 |
-
public function isSupported();
|
137 |
-
|
138 |
-
/**
|
139 |
-
* Returns adapter name.
|
140 |
-
*
|
141 |
-
* @return string
|
142 |
-
*/
|
143 |
-
public function getName();
|
144 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Adapter/BsdFindAdapter.php
DELETED
@@ -1,103 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Adapter;
|
13 |
-
|
14 |
-
use Symfony\Component\Finder\Shell\Shell;
|
15 |
-
use Symfony\Component\Finder\Shell\Command;
|
16 |
-
use Symfony\Component\Finder\Iterator\SortableIterator;
|
17 |
-
use Symfony\Component\Finder\Expression\Expression;
|
18 |
-
|
19 |
-
/**
|
20 |
-
* Shell engine implementation using BSD find command.
|
21 |
-
*
|
22 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
23 |
-
*/
|
24 |
-
class BsdFindAdapter extends AbstractFindAdapter
|
25 |
-
{
|
26 |
-
/**
|
27 |
-
* {@inheritdoc}
|
28 |
-
*/
|
29 |
-
public function getName()
|
30 |
-
{
|
31 |
-
return 'bsd_find';
|
32 |
-
}
|
33 |
-
|
34 |
-
/**
|
35 |
-
* {@inheritdoc}
|
36 |
-
*/
|
37 |
-
protected function canBeUsed()
|
38 |
-
{
|
39 |
-
return in_array($this->shell->getType(), array(Shell::TYPE_BSD, Shell::TYPE_DARWIN)) && parent::canBeUsed();
|
40 |
-
}
|
41 |
-
|
42 |
-
/**
|
43 |
-
* {@inheritdoc}
|
44 |
-
*/
|
45 |
-
protected function buildFormatSorting(Command $command, $sort)
|
46 |
-
{
|
47 |
-
switch ($sort) {
|
48 |
-
case SortableIterator::SORT_BY_NAME:
|
49 |
-
$command->ins('sort')->add('| sort');
|
50 |
-
|
51 |
-
return;
|
52 |
-
case SortableIterator::SORT_BY_TYPE:
|
53 |
-
$format = '%HT';
|
54 |
-
break;
|
55 |
-
case SortableIterator::SORT_BY_ACCESSED_TIME:
|
56 |
-
$format = '%a';
|
57 |
-
break;
|
58 |
-
case SortableIterator::SORT_BY_CHANGED_TIME:
|
59 |
-
$format = '%c';
|
60 |
-
break;
|
61 |
-
case SortableIterator::SORT_BY_MODIFIED_TIME:
|
62 |
-
$format = '%m';
|
63 |
-
break;
|
64 |
-
default:
|
65 |
-
throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
|
66 |
-
}
|
67 |
-
|
68 |
-
$command
|
69 |
-
->add('-print0 | xargs -0 stat -f')
|
70 |
-
->arg($format.'%t%N')
|
71 |
-
->add('| sort | cut -f 2');
|
72 |
-
}
|
73 |
-
|
74 |
-
/**
|
75 |
-
* {@inheritdoc}
|
76 |
-
*/
|
77 |
-
protected function buildFindCommand(Command $command, $dir)
|
78 |
-
{
|
79 |
-
parent::buildFindCommand($command, $dir)->addAtIndex('-E', 1);
|
80 |
-
|
81 |
-
return $command;
|
82 |
-
}
|
83 |
-
|
84 |
-
/**
|
85 |
-
* {@inheritdoc}
|
86 |
-
*/
|
87 |
-
protected function buildContentFiltering(Command $command, array $contains, $not = false)
|
88 |
-
{
|
89 |
-
foreach ($contains as $contain) {
|
90 |
-
$expr = Expression::create($contain);
|
91 |
-
|
92 |
-
// todo: avoid forking process for each $pattern by using multiple -e options
|
93 |
-
$command
|
94 |
-
->add('| grep -v \'^$\'')
|
95 |
-
->add('| xargs -I{} grep -I')
|
96 |
-
->add($expr->isCaseSensitive() ? null : '-i')
|
97 |
-
->add($not ? '-L' : '-l')
|
98 |
-
->add('-Ee')->arg($expr->renderPattern())
|
99 |
-
->add('{}')
|
100 |
-
;
|
101 |
-
}
|
102 |
-
}
|
103 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Adapter/GnuFindAdapter.php
DELETED
@@ -1,104 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Adapter;
|
13 |
-
|
14 |
-
use Symfony\Component\Finder\Shell\Shell;
|
15 |
-
use Symfony\Component\Finder\Shell\Command;
|
16 |
-
use Symfony\Component\Finder\Iterator\SortableIterator;
|
17 |
-
use Symfony\Component\Finder\Expression\Expression;
|
18 |
-
|
19 |
-
/**
|
20 |
-
* Shell engine implementation using GNU find command.
|
21 |
-
*
|
22 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
23 |
-
*/
|
24 |
-
class GnuFindAdapter extends AbstractFindAdapter
|
25 |
-
{
|
26 |
-
/**
|
27 |
-
* {@inheritdoc}
|
28 |
-
*/
|
29 |
-
public function getName()
|
30 |
-
{
|
31 |
-
return 'gnu_find';
|
32 |
-
}
|
33 |
-
|
34 |
-
/**
|
35 |
-
* {@inheritdoc}
|
36 |
-
*/
|
37 |
-
protected function buildFormatSorting(Command $command, $sort)
|
38 |
-
{
|
39 |
-
switch ($sort) {
|
40 |
-
case SortableIterator::SORT_BY_NAME:
|
41 |
-
$command->ins('sort')->add('| sort');
|
42 |
-
|
43 |
-
return;
|
44 |
-
case SortableIterator::SORT_BY_TYPE:
|
45 |
-
$format = '%y';
|
46 |
-
break;
|
47 |
-
case SortableIterator::SORT_BY_ACCESSED_TIME:
|
48 |
-
$format = '%A@';
|
49 |
-
break;
|
50 |
-
case SortableIterator::SORT_BY_CHANGED_TIME:
|
51 |
-
$format = '%C@';
|
52 |
-
break;
|
53 |
-
case SortableIterator::SORT_BY_MODIFIED_TIME:
|
54 |
-
$format = '%T@';
|
55 |
-
break;
|
56 |
-
default:
|
57 |
-
throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
|
58 |
-
}
|
59 |
-
|
60 |
-
$command
|
61 |
-
->get('find')
|
62 |
-
->add('-printf')
|
63 |
-
->arg($format.' %h/%f\\n')
|
64 |
-
->add('| sort | cut')
|
65 |
-
->arg('-d ')
|
66 |
-
->arg('-f2-')
|
67 |
-
;
|
68 |
-
}
|
69 |
-
|
70 |
-
/**
|
71 |
-
* {@inheritdoc}
|
72 |
-
*/
|
73 |
-
protected function canBeUsed()
|
74 |
-
{
|
75 |
-
return $this->shell->getType() === Shell::TYPE_UNIX && parent::canBeUsed();
|
76 |
-
}
|
77 |
-
|
78 |
-
/**
|
79 |
-
* {@inheritdoc}
|
80 |
-
*/
|
81 |
-
protected function buildFindCommand(Command $command, $dir)
|
82 |
-
{
|
83 |
-
return parent::buildFindCommand($command, $dir)->add('-regextype posix-extended');
|
84 |
-
}
|
85 |
-
|
86 |
-
/**
|
87 |
-
* {@inheritdoc}
|
88 |
-
*/
|
89 |
-
protected function buildContentFiltering(Command $command, array $contains, $not = false)
|
90 |
-
{
|
91 |
-
foreach ($contains as $contain) {
|
92 |
-
$expr = Expression::create($contain);
|
93 |
-
|
94 |
-
// todo: avoid forking process for each $pattern by using multiple -e options
|
95 |
-
$command
|
96 |
-
->add('| xargs -I{} -r grep -I')
|
97 |
-
->add($expr->isCaseSensitive() ? null : '-i')
|
98 |
-
->add($not ? '-L' : '-l')
|
99 |
-
->add('-Ee')->arg($expr->renderPattern())
|
100 |
-
->add('{}')
|
101 |
-
;
|
102 |
-
}
|
103 |
-
}
|
104 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Adapter/PhpAdapter.php
DELETED
@@ -1,98 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Adapter;
|
13 |
-
|
14 |
-
use Symfony\Component\Finder\Iterator;
|
15 |
-
|
16 |
-
/**
|
17 |
-
* PHP finder engine implementation.
|
18 |
-
*
|
19 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
20 |
-
*/
|
21 |
-
class PhpAdapter extends AbstractAdapter
|
22 |
-
{
|
23 |
-
/**
|
24 |
-
* {@inheritdoc}
|
25 |
-
*/
|
26 |
-
public function searchInDirectory($dir)
|
27 |
-
{
|
28 |
-
$flags = \RecursiveDirectoryIterator::SKIP_DOTS;
|
29 |
-
|
30 |
-
if ($this->followLinks) {
|
31 |
-
$flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
|
32 |
-
}
|
33 |
-
|
34 |
-
$iterator = new \RecursiveIteratorIterator(
|
35 |
-
new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs),
|
36 |
-
\RecursiveIteratorIterator::SELF_FIRST
|
37 |
-
);
|
38 |
-
|
39 |
-
if ($this->minDepth > 0 || $this->maxDepth < PHP_INT_MAX) {
|
40 |
-
$iterator = new Iterator\DepthRangeFilterIterator($iterator, $this->minDepth, $this->maxDepth);
|
41 |
-
}
|
42 |
-
|
43 |
-
if ($this->mode) {
|
44 |
-
$iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
|
45 |
-
}
|
46 |
-
|
47 |
-
if ($this->exclude) {
|
48 |
-
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
|
49 |
-
}
|
50 |
-
|
51 |
-
if ($this->names || $this->notNames) {
|
52 |
-
$iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
|
53 |
-
}
|
54 |
-
|
55 |
-
if ($this->contains || $this->notContains) {
|
56 |
-
$iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
|
57 |
-
}
|
58 |
-
|
59 |
-
if ($this->sizes) {
|
60 |
-
$iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
|
61 |
-
}
|
62 |
-
|
63 |
-
if ($this->dates) {
|
64 |
-
$iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
|
65 |
-
}
|
66 |
-
|
67 |
-
if ($this->filters) {
|
68 |
-
$iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
|
69 |
-
}
|
70 |
-
|
71 |
-
if ($this->sort) {
|
72 |
-
$iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
|
73 |
-
$iterator = $iteratorAggregate->getIterator();
|
74 |
-
}
|
75 |
-
|
76 |
-
if ($this->paths || $this->notPaths) {
|
77 |
-
$iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
|
78 |
-
}
|
79 |
-
|
80 |
-
return $iterator;
|
81 |
-
}
|
82 |
-
|
83 |
-
/**
|
84 |
-
* {@inheritdoc}
|
85 |
-
*/
|
86 |
-
public function getName()
|
87 |
-
{
|
88 |
-
return 'php';
|
89 |
-
}
|
90 |
-
|
91 |
-
/**
|
92 |
-
* {@inheritdoc}
|
93 |
-
*/
|
94 |
-
protected function canBeUsed()
|
95 |
-
{
|
96 |
-
return true;
|
97 |
-
}
|
98 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/CHANGELOG.md
DELETED
@@ -1,34 +0,0 @@
|
|
1 |
-
CHANGELOG
|
2 |
-
=========
|
3 |
-
|
4 |
-
2.5.0
|
5 |
-
-----
|
6 |
-
* added support for GLOB_BRACE in the paths passed to Finder::in()
|
7 |
-
|
8 |
-
2.3.0
|
9 |
-
-----
|
10 |
-
|
11 |
-
* added a way to ignore unreadable directories (via Finder::ignoreUnreadableDirs())
|
12 |
-
* unified the way subfolders that are not executable are handled by always throwing an AccessDeniedException exception
|
13 |
-
|
14 |
-
2.2.0
|
15 |
-
-----
|
16 |
-
|
17 |
-
* added Finder::path() and Finder::notPath() methods
|
18 |
-
* added finder adapters to improve performance on specific platforms
|
19 |
-
* added support for wildcard characters (glob patterns) in the paths passed
|
20 |
-
to Finder::in()
|
21 |
-
|
22 |
-
2.1.0
|
23 |
-
-----
|
24 |
-
|
25 |
-
* added Finder::sortByAccessedTime(), Finder::sortByChangedTime(), and
|
26 |
-
Finder::sortByModifiedTime()
|
27 |
-
* added Countable to Finder
|
28 |
-
* added support for an array of directories as an argument to
|
29 |
-
Finder::exclude()
|
30 |
-
* added searching based on the file content via Finder::contains() and
|
31 |
-
Finder::notContains()
|
32 |
-
* added support for the != operator in the Comparator
|
33 |
-
* [BC BREAK] filter expressions (used for file name and content) are no more
|
34 |
-
considered as regexps but glob patterns when they are enclosed in '*' or '?'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Comparator/Comparator.php
DELETED
@@ -1,98 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Comparator;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Comparator.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
*/
|
19 |
-
class Comparator
|
20 |
-
{
|
21 |
-
private $target;
|
22 |
-
private $operator = '==';
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Gets the target value.
|
26 |
-
*
|
27 |
-
* @return string The target value
|
28 |
-
*/
|
29 |
-
public function getTarget()
|
30 |
-
{
|
31 |
-
return $this->target;
|
32 |
-
}
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Sets the target value.
|
36 |
-
*
|
37 |
-
* @param string $target The target value
|
38 |
-
*/
|
39 |
-
public function setTarget($target)
|
40 |
-
{
|
41 |
-
$this->target = $target;
|
42 |
-
}
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Gets the comparison operator.
|
46 |
-
*
|
47 |
-
* @return string The operator
|
48 |
-
*/
|
49 |
-
public function getOperator()
|
50 |
-
{
|
51 |
-
return $this->operator;
|
52 |
-
}
|
53 |
-
|
54 |
-
/**
|
55 |
-
* Sets the comparison operator.
|
56 |
-
*
|
57 |
-
* @param string $operator A valid operator
|
58 |
-
*
|
59 |
-
* @throws \InvalidArgumentException
|
60 |
-
*/
|
61 |
-
public function setOperator($operator)
|
62 |
-
{
|
63 |
-
if (!$operator) {
|
64 |
-
$operator = '==';
|
65 |
-
}
|
66 |
-
|
67 |
-
if (!in_array($operator, array('>', '<', '>=', '<=', '==', '!='))) {
|
68 |
-
throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
|
69 |
-
}
|
70 |
-
|
71 |
-
$this->operator = $operator;
|
72 |
-
}
|
73 |
-
|
74 |
-
/**
|
75 |
-
* Tests against the target.
|
76 |
-
*
|
77 |
-
* @param mixed $test A test value
|
78 |
-
*
|
79 |
-
* @return bool
|
80 |
-
*/
|
81 |
-
public function test($test)
|
82 |
-
{
|
83 |
-
switch ($this->operator) {
|
84 |
-
case '>':
|
85 |
-
return $test > $this->target;
|
86 |
-
case '>=':
|
87 |
-
return $test >= $this->target;
|
88 |
-
case '<':
|
89 |
-
return $test < $this->target;
|
90 |
-
case '<=':
|
91 |
-
return $test <= $this->target;
|
92 |
-
case '!=':
|
93 |
-
return $test != $this->target;
|
94 |
-
}
|
95 |
-
|
96 |
-
return $test == $this->target;
|
97 |
-
}
|
98 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Comparator/DateComparator.php
DELETED
@@ -1,53 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Comparator;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* DateCompare compiles date comparisons.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
*/
|
19 |
-
class DateComparator extends Comparator
|
20 |
-
{
|
21 |
-
/**
|
22 |
-
* Constructor.
|
23 |
-
*
|
24 |
-
* @param string $test A comparison string
|
25 |
-
*
|
26 |
-
* @throws \InvalidArgumentException If the test is not understood
|
27 |
-
*/
|
28 |
-
public function __construct($test)
|
29 |
-
{
|
30 |
-
if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) {
|
31 |
-
throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test));
|
32 |
-
}
|
33 |
-
|
34 |
-
try {
|
35 |
-
$date = new \DateTime($matches[2]);
|
36 |
-
$target = $date->format('U');
|
37 |
-
} catch (\Exception $e) {
|
38 |
-
throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2]));
|
39 |
-
}
|
40 |
-
|
41 |
-
$operator = isset($matches[1]) ? $matches[1] : '==';
|
42 |
-
if ('since' === $operator || 'after' === $operator) {
|
43 |
-
$operator = '>';
|
44 |
-
}
|
45 |
-
|
46 |
-
if ('until' === $operator || 'before' === $operator) {
|
47 |
-
$operator = '<';
|
48 |
-
}
|
49 |
-
|
50 |
-
$this->setOperator($operator);
|
51 |
-
$this->setTarget($target);
|
52 |
-
}
|
53 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Comparator/NumberComparator.php
DELETED
@@ -1,81 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Comparator;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* NumberComparator compiles a simple comparison to an anonymous
|
16 |
-
* subroutine, which you can call with a value to be tested again.
|
17 |
-
*
|
18 |
-
* Now this would be very pointless, if NumberCompare didn't understand
|
19 |
-
* magnitudes.
|
20 |
-
*
|
21 |
-
* The target value may use magnitudes of kilobytes (k, ki),
|
22 |
-
* megabytes (m, mi), or gigabytes (g, gi). Those suffixed
|
23 |
-
* with an i use the appropriate 2**n version in accordance with the
|
24 |
-
* IEC standard: http://physics.nist.gov/cuu/Units/binary.html
|
25 |
-
*
|
26 |
-
* Based on the Perl Number::Compare module.
|
27 |
-
*
|
28 |
-
* @author Fabien Potencier <fabien@symfony.com> PHP port
|
29 |
-
* @author Richard Clamp <richardc@unixbeard.net> Perl version
|
30 |
-
* @copyright 2004-2005 Fabien Potencier <fabien@symfony.com>
|
31 |
-
* @copyright 2002 Richard Clamp <richardc@unixbeard.net>
|
32 |
-
*
|
33 |
-
* @see http://physics.nist.gov/cuu/Units/binary.html
|
34 |
-
*/
|
35 |
-
class NumberComparator extends Comparator
|
36 |
-
{
|
37 |
-
/**
|
38 |
-
* Constructor.
|
39 |
-
*
|
40 |
-
* @param string $test A comparison string
|
41 |
-
*
|
42 |
-
* @throws \InvalidArgumentException If the test is not understood
|
43 |
-
*/
|
44 |
-
public function __construct($test)
|
45 |
-
{
|
46 |
-
if (!preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) {
|
47 |
-
throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test));
|
48 |
-
}
|
49 |
-
|
50 |
-
$target = $matches[2];
|
51 |
-
if (!is_numeric($target)) {
|
52 |
-
throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target));
|
53 |
-
}
|
54 |
-
if (isset($matches[3])) {
|
55 |
-
// magnitude
|
56 |
-
switch (strtolower($matches[3])) {
|
57 |
-
case 'k':
|
58 |
-
$target *= 1000;
|
59 |
-
break;
|
60 |
-
case 'ki':
|
61 |
-
$target *= 1024;
|
62 |
-
break;
|
63 |
-
case 'm':
|
64 |
-
$target *= 1000000;
|
65 |
-
break;
|
66 |
-
case 'mi':
|
67 |
-
$target *= 1024*1024;
|
68 |
-
break;
|
69 |
-
case 'g':
|
70 |
-
$target *= 1000000000;
|
71 |
-
break;
|
72 |
-
case 'gi':
|
73 |
-
$target *= 1024*1024*1024;
|
74 |
-
break;
|
75 |
-
}
|
76 |
-
}
|
77 |
-
|
78 |
-
$this->setTarget($target);
|
79 |
-
$this->setOperator(isset($matches[1]) ? $matches[1] : '==');
|
80 |
-
}
|
81 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Exception/AccessDeniedException.php
DELETED
@@ -1,19 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Exception;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
|
16 |
-
*/
|
17 |
-
class AccessDeniedException extends \UnexpectedValueException
|
18 |
-
{
|
19 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Exception/AdapterFailureException.php
DELETED
@@ -1,46 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Exception;
|
13 |
-
|
14 |
-
use Symfony\Component\Finder\Adapter\AdapterInterface;
|
15 |
-
|
16 |
-
/**
|
17 |
-
* Base exception for all adapter failures.
|
18 |
-
*
|
19 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
20 |
-
*/
|
21 |
-
class AdapterFailureException extends \RuntimeException implements ExceptionInterface
|
22 |
-
{
|
23 |
-
/**
|
24 |
-
* @var \Symfony\Component\Finder\Adapter\AdapterInterface
|
25 |
-
*/
|
26 |
-
private $adapter;
|
27 |
-
|
28 |
-
/**
|
29 |
-
* @param AdapterInterface $adapter
|
30 |
-
* @param string|null $message
|
31 |
-
* @param \Exception|null $previous
|
32 |
-
*/
|
33 |
-
public function __construct(AdapterInterface $adapter, $message = null, \Exception $previous = null)
|
34 |
-
{
|
35 |
-
$this->adapter = $adapter;
|
36 |
-
parent::__construct($message ?: 'Search failed with "'.$adapter->getName().'" adapter.', $previous);
|
37 |
-
}
|
38 |
-
|
39 |
-
/**
|
40 |
-
* {@inheritdoc}
|
41 |
-
*/
|
42 |
-
public function getAdapter()
|
43 |
-
{
|
44 |
-
return $this->adapter;
|
45 |
-
}
|
46 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Exception/ExceptionInterface.php
DELETED
@@ -1,23 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Exception;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
16 |
-
*/
|
17 |
-
interface ExceptionInterface
|
18 |
-
{
|
19 |
-
/**
|
20 |
-
* @return \Symfony\Component\Finder\Adapter\AdapterInterface
|
21 |
-
*/
|
22 |
-
public function getAdapter();
|
23 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Exception/OperationNotPermitedException.php
DELETED
@@ -1,19 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Exception;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
16 |
-
*/
|
17 |
-
class OperationNotPermitedException extends AdapterFailureException
|
18 |
-
{
|
19 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Exception/ShellCommandFailureException.php
DELETED
@@ -1,45 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Exception;
|
13 |
-
|
14 |
-
use Symfony\Component\Finder\Adapter\AdapterInterface;
|
15 |
-
use Symfony\Component\Finder\Shell\Command;
|
16 |
-
|
17 |
-
/**
|
18 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
19 |
-
*/
|
20 |
-
class ShellCommandFailureException extends AdapterFailureException
|
21 |
-
{
|
22 |
-
/**
|
23 |
-
* @var Command
|
24 |
-
*/
|
25 |
-
private $command;
|
26 |
-
|
27 |
-
/**
|
28 |
-
* @param AdapterInterface $adapter
|
29 |
-
* @param Command $command
|
30 |
-
* @param \Exception|null $previous
|
31 |
-
*/
|
32 |
-
public function __construct(AdapterInterface $adapter, Command $command, \Exception $previous = null)
|
33 |
-
{
|
34 |
-
$this->command = $command;
|
35 |
-
parent::__construct($adapter, 'Shell command failed: "'.$command->join().'".', $previous);
|
36 |
-
}
|
37 |
-
|
38 |
-
/**
|
39 |
-
* @return Command
|
40 |
-
*/
|
41 |
-
public function getCommand()
|
42 |
-
{
|
43 |
-
return $this->command;
|
44 |
-
}
|
45 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Expression/Expression.php
DELETED
@@ -1,146 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Expression;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
16 |
-
*/
|
17 |
-
class Expression implements ValueInterface
|
18 |
-
{
|
19 |
-
const TYPE_REGEX = 1;
|
20 |
-
const TYPE_GLOB = 2;
|
21 |
-
|
22 |
-
/**
|
23 |
-
* @var ValueInterface
|
24 |
-
*/
|
25 |
-
private $value;
|
26 |
-
|
27 |
-
/**
|
28 |
-
* @param string $expr
|
29 |
-
*
|
30 |
-
* @return Expression
|
31 |
-
*/
|
32 |
-
public static function create($expr)
|
33 |
-
{
|
34 |
-
return new self($expr);
|
35 |
-
}
|
36 |
-
|
37 |
-
/**
|
38 |
-
* @param string $expr
|
39 |
-
*/
|
40 |
-
public function __construct($expr)
|
41 |
-
{
|
42 |
-
try {
|
43 |
-
$this->value = Regex::create($expr);
|
44 |
-
} catch (\InvalidArgumentException $e) {
|
45 |
-
$this->value = new Glob($expr);
|
46 |
-
}
|
47 |
-
}
|
48 |
-
|
49 |
-
/**
|
50 |
-
* @return string
|
51 |
-
*/
|
52 |
-
public function __toString()
|
53 |
-
{
|
54 |
-
return $this->render();
|
55 |
-
}
|
56 |
-
|
57 |
-
/**
|
58 |
-
* {@inheritdoc}
|
59 |
-
*/
|
60 |
-
public function render()
|
61 |
-
{
|
62 |
-
return $this->value->render();
|
63 |
-
}
|
64 |
-
|
65 |
-
/**
|
66 |
-
* {@inheritdoc}
|
67 |
-
*/
|
68 |
-
public function renderPattern()
|
69 |
-
{
|
70 |
-
return $this->value->renderPattern();
|
71 |
-
}
|
72 |
-
|
73 |
-
/**
|
74 |
-
* @return bool
|
75 |
-
*/
|
76 |
-
public function isCaseSensitive()
|
77 |
-
{
|
78 |
-
return $this->value->isCaseSensitive();
|
79 |
-
}
|
80 |
-
|
81 |
-
/**
|
82 |
-
* @return int
|
83 |
-
*/
|
84 |
-
public function getType()
|
85 |
-
{
|
86 |
-
return $this->value->getType();
|
87 |
-
}
|
88 |
-
|
89 |
-
/**
|
90 |
-
* {@inheritdoc}
|
91 |
-
*/
|
92 |
-
public function prepend($expr)
|
93 |
-
{
|
94 |
-
$this->value->prepend($expr);
|
95 |
-
|
96 |
-
return $this;
|
97 |
-
}
|
98 |
-
|
99 |
-
/**
|
100 |
-
* {@inheritdoc}
|
101 |
-
*/
|
102 |
-
public function append($expr)
|
103 |
-
{
|
104 |
-
$this->value->append($expr);
|
105 |
-
|
106 |
-
return $this;
|
107 |
-
}
|
108 |
-
|
109 |
-
/**
|
110 |
-
* @return bool
|
111 |
-
*/
|
112 |
-
public function isRegex()
|
113 |
-
{
|
114 |
-
return self::TYPE_REGEX === $this->value->getType();
|
115 |
-
}
|
116 |
-
|
117 |
-
/**
|
118 |
-
* @return bool
|
119 |
-
*/
|
120 |
-
public function isGlob()
|
121 |
-
{
|
122 |
-
return self::TYPE_GLOB === $this->value->getType();
|
123 |
-
}
|
124 |
-
|
125 |
-
/**
|
126 |
-
* @throws \LogicException
|
127 |
-
*
|
128 |
-
* @return Glob
|
129 |
-
*/
|
130 |
-
public function getGlob()
|
131 |
-
{
|
132 |
-
if (self::TYPE_GLOB !== $this->value->getType()) {
|
133 |
-
throw new \LogicException('Regex can\'t be transformed to glob.');
|
134 |
-
}
|
135 |
-
|
136 |
-
return $this->value;
|
137 |
-
}
|
138 |
-
|
139 |
-
/**
|
140 |
-
* @return Regex
|
141 |
-
*/
|
142 |
-
public function getRegex()
|
143 |
-
{
|
144 |
-
return self::TYPE_REGEX === $this->value->getType() ? $this->value : $this->value->toRegex();
|
145 |
-
}
|
146 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Expression/Glob.php
DELETED
@@ -1,157 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Expression;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
16 |
-
*/
|
17 |
-
class Glob implements ValueInterface
|
18 |
-
{
|
19 |
-
/**
|
20 |
-
* @var string
|
21 |
-
*/
|
22 |
-
private $pattern;
|
23 |
-
|
24 |
-
/**
|
25 |
-
* @param string $pattern
|
26 |
-
*/
|
27 |
-
public function __construct($pattern)
|
28 |
-
{
|
29 |
-
$this->pattern = $pattern;
|
30 |
-
}
|
31 |
-
|
32 |
-
/**
|
33 |
-
* {@inheritdoc}
|
34 |
-
*/
|
35 |
-
public function render()
|
36 |
-
{
|
37 |
-
return $this->pattern;
|
38 |
-
}
|
39 |
-
|
40 |
-
/**
|
41 |
-
* {@inheritdoc}
|
42 |
-
*/
|
43 |
-
public function renderPattern()
|
44 |
-
{
|
45 |
-
return $this->pattern;
|
46 |
-
}
|
47 |
-
|
48 |
-
/**
|
49 |
-
* {@inheritdoc}
|
50 |
-
*/
|
51 |
-
public function getType()
|
52 |
-
{
|
53 |
-
return Expression::TYPE_GLOB;
|
54 |
-
}
|
55 |
-
|
56 |
-
/**
|
57 |
-
* {@inheritdoc}
|
58 |
-
*/
|
59 |
-
public function isCaseSensitive()
|
60 |
-
{
|
61 |
-
return true;
|
62 |
-
}
|
63 |
-
|
64 |
-
/**
|
65 |
-
* {@inheritdoc}
|
66 |
-
*/
|
67 |
-
public function prepend($expr)
|
68 |
-
{
|
69 |
-
$this->pattern = $expr.$this->pattern;
|
70 |
-
|
71 |
-
return $this;
|
72 |
-
}
|
73 |
-
|
74 |
-
/**
|
75 |
-
* {@inheritdoc}
|
76 |
-
*/
|
77 |
-
public function append($expr)
|
78 |
-
{
|
79 |
-
$this->pattern .= $expr;
|
80 |
-
|
81 |
-
return $this;
|
82 |
-
}
|
83 |
-
|
84 |
-
/**
|
85 |
-
* Tests if glob is expandable ("*.{a,b}" syntax).
|
86 |
-
*
|
87 |
-
* @return bool
|
88 |
-
*/
|
89 |
-
public function isExpandable()
|
90 |
-
{
|
91 |
-
return false !== strpos($this->pattern, '{')
|
92 |
-
&& false !== strpos($this->pattern, '}');
|
93 |
-
}
|
94 |
-
|
95 |
-
/**
|
96 |
-
* @param bool $strictLeadingDot
|
97 |
-
* @param bool $strictWildcardSlash
|
98 |
-
*
|
99 |
-
* @return Regex
|
100 |
-
*/
|
101 |
-
public function toRegex($strictLeadingDot = true, $strictWildcardSlash = true)
|
102 |
-
{
|
103 |
-
$firstByte = true;
|
104 |
-
$escaping = false;
|
105 |
-
$inCurlies = 0;
|
106 |
-
$regex = '';
|
107 |
-
$sizeGlob = strlen($this->pattern);
|
108 |
-
for ($i = 0; $i < $sizeGlob; $i++) {
|
109 |
-
$car = $this->pattern[$i];
|
110 |
-
if ($firstByte) {
|
111 |
-
if ($strictLeadingDot && '.' !== $car) {
|
112 |
-
$regex .= '(?=[^\.])';
|
113 |
-
}
|
114 |
-
|
115 |
-
$firstByte = false;
|
116 |
-
}
|
117 |
-
|
118 |
-
if ('/' === $car) {
|
119 |
-
$firstByte = true;
|
120 |
-
}
|
121 |
-
|
122 |
-
if ('.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
|
123 |
-
$regex .= "\\$car";
|
124 |
-
} elseif ('*' === $car) {
|
125 |
-
$regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
|
126 |
-
} elseif ('?' === $car) {
|
127 |
-
$regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
|
128 |
-
} elseif ('{' === $car) {
|
129 |
-
$regex .= $escaping ? '\\{' : '(';
|
130 |
-
if (!$escaping) {
|
131 |
-
++$inCurlies;
|
132 |
-
}
|
133 |
-
} elseif ('}' === $car && $inCurlies) {
|
134 |
-
$regex .= $escaping ? '}' : ')';
|
135 |
-
if (!$escaping) {
|
136 |
-
--$inCurlies;
|
137 |
-
}
|
138 |
-
} elseif (',' === $car && $inCurlies) {
|
139 |
-
$regex .= $escaping ? ',' : '|';
|
140 |
-
} elseif ('\\' === $car) {
|
141 |
-
if ($escaping) {
|
142 |
-
$regex .= '\\\\';
|
143 |
-
$escaping = false;
|
144 |
-
} else {
|
145 |
-
$escaping = true;
|
146 |
-
}
|
147 |
-
|
148 |
-
continue;
|
149 |
-
} else {
|
150 |
-
$regex .= $car;
|
151 |
-
}
|
152 |
-
$escaping = false;
|
153 |
-
}
|
154 |
-
|
155 |
-
return new Regex('^'.$regex.'$');
|
156 |
-
}
|
157 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Expression/Regex.php
DELETED
@@ -1,321 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Expression;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
16 |
-
*/
|
17 |
-
class Regex implements ValueInterface
|
18 |
-
{
|
19 |
-
const START_FLAG = '^';
|
20 |
-
const END_FLAG = '$';
|
21 |
-
const BOUNDARY = '~';
|
22 |
-
const JOKER = '.*';
|
23 |
-
const ESCAPING = '\\';
|
24 |
-
|
25 |
-
/**
|
26 |
-
* @var string
|
27 |
-
*/
|
28 |
-
private $pattern;
|
29 |
-
|
30 |
-
/**
|
31 |
-
* @var array
|
32 |
-
*/
|
33 |
-
private $options;
|
34 |
-
|
35 |
-
/**
|
36 |
-
* @var bool
|
37 |
-
*/
|
38 |
-
private $startFlag;
|
39 |
-
|
40 |
-
/**
|
41 |
-
* @var bool
|
42 |
-
*/
|
43 |
-
private $endFlag;
|
44 |
-
|
45 |
-
/**
|
46 |
-
* @var bool
|
47 |
-
*/
|
48 |
-
private $startJoker;
|
49 |
-
|
50 |
-
/**
|
51 |
-
* @var bool
|
52 |
-
*/
|
53 |
-
private $endJoker;
|
54 |
-
|
55 |
-
/**
|
56 |
-
* @param string $expr
|
57 |
-
*
|
58 |
-
* @return Regex
|
59 |
-
*
|
60 |
-
* @throws \InvalidArgumentException
|
61 |
-
*/
|
62 |
-
public static function create($expr)
|
63 |
-
{
|
64 |
-
if (preg_match('/^(.{3,}?)([imsxuADU]*)$/', $expr, $m)) {
|
65 |
-
$start = substr($m[1], 0, 1);
|
66 |
-
$end = substr($m[1], -1);
|
67 |
-
|
68 |
-
if (
|
69 |
-
($start === $end && !preg_match('/[*?[:alnum:] \\\\]/', $start))
|
70 |
-
|| ($start === '{' && $end === '}')
|
71 |
-
|| ($start === '(' && $end === ')')
|
72 |
-
) {
|
73 |
-
return new self(substr($m[1], 1, -1), $m[2], $end);
|
74 |
-
}
|
75 |
-
}
|
76 |
-
|
77 |
-
throw new \InvalidArgumentException('Given expression is not a regex.');
|
78 |
-
}
|
79 |
-
|
80 |
-
/**
|
81 |
-
* @param string $pattern
|
82 |
-
* @param string $options
|
83 |
-
* @param string $delimiter
|
84 |
-
*/
|
85 |
-
public function __construct($pattern, $options = '', $delimiter = null)
|
86 |
-
{
|
87 |
-
if (null !== $delimiter) {
|
88 |
-
// removes delimiter escaping
|
89 |
-
$pattern = str_replace('\\'.$delimiter, $delimiter, $pattern);
|
90 |
-
}
|
91 |
-
|
92 |
-
$this->parsePattern($pattern);
|
93 |
-
$this->options = $options;
|
94 |
-
}
|
95 |
-
|
96 |
-
/**
|
97 |
-
* @return string
|
98 |
-
*/
|
99 |
-
public function __toString()
|
100 |
-
{
|
101 |
-
return $this->render();
|
102 |
-
}
|
103 |
-
|
104 |
-
/**
|
105 |
-
* {@inheritdoc}
|
106 |
-
*/
|
107 |
-
public function render()
|
108 |
-
{
|
109 |
-
return self::BOUNDARY
|
110 |
-
.$this->renderPattern()
|
111 |
-
.self::BOUNDARY
|
112 |
-
.$this->options;
|
113 |
-
}
|
114 |
-
|
115 |
-
/**
|
116 |
-
* {@inheritdoc}
|
117 |
-
*/
|
118 |
-
public function renderPattern()
|
119 |
-
{
|
120 |
-
return ($this->startFlag ? self::START_FLAG : '')
|
121 |
-
.($this->startJoker ? self::JOKER : '')
|
122 |
-
.str_replace(self::BOUNDARY, '\\'.self::BOUNDARY, $this->pattern)
|
123 |
-
.($this->endJoker ? self::JOKER : '')
|
124 |
-
.($this->endFlag ? self::END_FLAG : '');
|
125 |
-
}
|
126 |
-
|
127 |
-
/**
|
128 |
-
* {@inheritdoc}
|
129 |
-
*/
|
130 |
-
public function isCaseSensitive()
|
131 |
-
{
|
132 |
-
return !$this->hasOption('i');
|
133 |
-
}
|
134 |
-
|
135 |
-
/**
|
136 |
-
* {@inheritdoc}
|
137 |
-
*/
|
138 |
-
public function getType()
|
139 |
-
{
|
140 |
-
return Expression::TYPE_REGEX;
|
141 |
-
}
|
142 |
-
|
143 |
-
/**
|
144 |
-
* {@inheritdoc}
|
145 |
-
*/
|
146 |
-
public function prepend($expr)
|
147 |
-
{
|
148 |
-
$this->pattern = $expr.$this->pattern;
|
149 |
-
|
150 |
-
return $this;
|
151 |
-
}
|
152 |
-
|
153 |
-
/**
|
154 |
-
* {@inheritdoc}
|
155 |
-
*/
|
156 |
-
public function append($expr)
|
157 |
-
{
|
158 |
-
$this->pattern .= $expr;
|
159 |
-
|
160 |
-
return $this;
|
161 |
-
}
|
162 |
-
|
163 |
-
/**
|
164 |
-
* @param string $option
|
165 |
-
*
|
166 |
-
* @return bool
|
167 |
-
*/
|
168 |
-
public function hasOption($option)
|
169 |
-
{
|
170 |
-
return false !== strpos($this->options, $option);
|
171 |
-
}
|
172 |
-
|
173 |
-
/**
|
174 |
-
* @param string $option
|
175 |
-
*
|
176 |
-
* @return Regex
|
177 |
-
*/
|
178 |
-
public function addOption($option)
|
179 |
-
{
|
180 |
-
if (!$this->hasOption($option)) {
|
181 |
-
$this->options .= $option;
|
182 |
-
}
|
183 |
-
|
184 |
-
return $this;
|
185 |
-
}
|
186 |
-
|
187 |
-
/**
|
188 |
-
* @param string $option
|
189 |
-
*
|
190 |
-
* @return Regex
|
191 |
-
*/
|
192 |
-
public function removeOption($option)
|
193 |
-
{
|
194 |
-
$this->options = str_replace($option, '', $this->options);
|
195 |
-
|
196 |
-
return $this;
|
197 |
-
}
|
198 |
-
|
199 |
-
/**
|
200 |
-
* @param bool $startFlag
|
201 |
-
*
|
202 |
-
* @return Regex
|
203 |
-
*/
|
204 |
-
public function setStartFlag($startFlag)
|
205 |
-
{
|
206 |
-
$this->startFlag = $startFlag;
|
207 |
-
|
208 |
-
return $this;
|
209 |
-
}
|
210 |
-
|
211 |
-
/**
|
212 |
-
* @return bool
|
213 |
-
*/
|
214 |
-
public function hasStartFlag()
|
215 |
-
{
|
216 |
-
return $this->startFlag;
|
217 |
-
}
|
218 |
-
|
219 |
-
/**
|
220 |
-
* @param bool $endFlag
|
221 |
-
*
|
222 |
-
* @return Regex
|
223 |
-
*/
|
224 |
-
public function setEndFlag($endFlag)
|
225 |
-
{
|
226 |
-
$this->endFlag = (bool) $endFlag;
|
227 |
-
|
228 |
-
return $this;
|
229 |
-
}
|
230 |
-
|
231 |
-
/**
|
232 |
-
* @return bool
|
233 |
-
*/
|
234 |
-
public function hasEndFlag()
|
235 |
-
{
|
236 |
-
return $this->endFlag;
|
237 |
-
}
|
238 |
-
|
239 |
-
/**
|
240 |
-
* @param bool $startJoker
|
241 |
-
*
|
242 |
-
* @return Regex
|
243 |
-
*/
|
244 |
-
public function setStartJoker($startJoker)
|
245 |
-
{
|
246 |
-
$this->startJoker = $startJoker;
|
247 |
-
|
248 |
-
return $this;
|
249 |
-
}
|
250 |
-
|
251 |
-
/**
|
252 |
-
* @return bool
|
253 |
-
*/
|
254 |
-
public function hasStartJoker()
|
255 |
-
{
|
256 |
-
return $this->startJoker;
|
257 |
-
}
|
258 |
-
|
259 |
-
/**
|
260 |
-
* @param bool $endJoker
|
261 |
-
*
|
262 |
-
* @return Regex
|
263 |
-
*/
|
264 |
-
public function setEndJoker($endJoker)
|
265 |
-
{
|
266 |
-
$this->endJoker = (bool) $endJoker;
|
267 |
-
|
268 |
-
return $this;
|
269 |
-
}
|
270 |
-
|
271 |
-
/**
|
272 |
-
* @return bool
|
273 |
-
*/
|
274 |
-
public function hasEndJoker()
|
275 |
-
{
|
276 |
-
return $this->endJoker;
|
277 |
-
}
|
278 |
-
|
279 |
-
/**
|
280 |
-
* @param array $replacement
|
281 |
-
*
|
282 |
-
* @return Regex
|
283 |
-
*/
|
284 |
-
public function replaceJokers($replacement)
|
285 |
-
{
|
286 |
-
$replace = function ($subject) use ($replacement) {
|
287 |
-
$subject = $subject[0];
|
288 |
-
$replace = 0 === substr_count($subject, '\\') % 2;
|
289 |
-
|
290 |
-
return $replace ? str_replace('.', $replacement, $subject) : $subject;
|
291 |
-
};
|
292 |
-
|
293 |
-
$this->pattern = preg_replace_callback('~[\\\\]*\\.~', $replace, $this->pattern);
|
294 |
-
|
295 |
-
return $this;
|
296 |
-
}
|
297 |
-
|
298 |
-
/**
|
299 |
-
* @param string $pattern
|
300 |
-
*/
|
301 |
-
private function parsePattern($pattern)
|
302 |
-
{
|
303 |
-
if ($this->startFlag = self::START_FLAG === substr($pattern, 0, 1)) {
|
304 |
-
$pattern = substr($pattern, 1);
|
305 |
-
}
|
306 |
-
|
307 |
-
if ($this->startJoker = self::JOKER === substr($pattern, 0, 2)) {
|
308 |
-
$pattern = substr($pattern, 2);
|
309 |
-
}
|
310 |
-
|
311 |
-
if ($this->endFlag = (self::END_FLAG === substr($pattern, -1) && self::ESCAPING !== substr($pattern, -2, -1))) {
|
312 |
-
$pattern = substr($pattern, 0, -1);
|
313 |
-
}
|
314 |
-
|
315 |
-
if ($this->endJoker = (self::JOKER === substr($pattern, -2) && self::ESCAPING !== substr($pattern, -3, -2))) {
|
316 |
-
$pattern = substr($pattern, 0, -2);
|
317 |
-
}
|
318 |
-
|
319 |
-
$this->pattern = $pattern;
|
320 |
-
}
|
321 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Expression/ValueInterface.php
DELETED
@@ -1,60 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Expression;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
16 |
-
*/
|
17 |
-
interface ValueInterface
|
18 |
-
{
|
19 |
-
/**
|
20 |
-
* Renders string representation of expression.
|
21 |
-
*
|
22 |
-
* @return string
|
23 |
-
*/
|
24 |
-
public function render();
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Renders string representation of pattern.
|
28 |
-
*
|
29 |
-
* @return string
|
30 |
-
*/
|
31 |
-
public function renderPattern();
|
32 |
-
|
33 |
-
/**
|
34 |
-
* Returns value case sensitivity.
|
35 |
-
*
|
36 |
-
* @return bool
|
37 |
-
*/
|
38 |
-
public function isCaseSensitive();
|
39 |
-
|
40 |
-
/**
|
41 |
-
* Returns expression type.
|
42 |
-
*
|
43 |
-
* @return int
|
44 |
-
*/
|
45 |
-
public function getType();
|
46 |
-
|
47 |
-
/**
|
48 |
-
* @param string $expr
|
49 |
-
*
|
50 |
-
* @return ValueInterface
|
51 |
-
*/
|
52 |
-
public function prepend($expr);
|
53 |
-
|
54 |
-
/**
|
55 |
-
* @param string $expr
|
56 |
-
*
|
57 |
-
* @return ValueInterface
|
58 |
-
*/
|
59 |
-
public function append($expr);
|
60 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Finder.php
DELETED
@@ -1,840 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder;
|
13 |
-
|
14 |
-
use Symfony\Component\Finder\Adapter\AdapterInterface;
|
15 |
-
use Symfony\Component\Finder\Adapter\GnuFindAdapter;
|
16 |
-
use Symfony\Component\Finder\Adapter\BsdFindAdapter;
|
17 |
-
use Symfony\Component\Finder\Adapter\PhpAdapter;
|
18 |
-
use Symfony\Component\Finder\Comparator\DateComparator;
|
19 |
-
use Symfony\Component\Finder\Comparator\NumberComparator;
|
20 |
-
use Symfony\Component\Finder\Exception\ExceptionInterface;
|
21 |
-
use Symfony\Component\Finder\Iterator\CustomFilterIterator;
|
22 |
-
use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
|
23 |
-
use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
|
24 |
-
use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
|
25 |
-
use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
|
26 |
-
use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
|
27 |
-
use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
|
28 |
-
use Symfony\Component\Finder\Iterator\SortableIterator;
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Finder allows to build rules to find files and directories.
|
32 |
-
*
|
33 |
-
* It is a thin wrapper around several specialized iterator classes.
|
34 |
-
*
|
35 |
-
* All rules may be invoked several times.
|
36 |
-
*
|
37 |
-
* All methods return the current Finder object to allow easy chaining:
|
38 |
-
*
|
39 |
-
* $finder = Finder::create()->files()->name('*.php')->in(__DIR__);
|
40 |
-
*
|
41 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
42 |
-
*
|
43 |
-
* @api
|
44 |
-
*/
|
45 |
-
class Finder implements \IteratorAggregate, \Countable
|
46 |
-
{
|
47 |
-
const IGNORE_VCS_FILES = 1;
|
48 |
-
const IGNORE_DOT_FILES = 2;
|
49 |
-
|
50 |
-
private $mode = 0;
|
51 |
-
private $names = array();
|
52 |
-
private $notNames = array();
|
53 |
-
private $exclude = array();
|
54 |
-
private $filters = array();
|
55 |
-
private $depths = array();
|
56 |
-
private $sizes = array();
|
57 |
-
private $followLinks = false;
|
58 |
-
private $sort = false;
|
59 |
-
private $ignore = 0;
|
60 |
-
private $dirs = array();
|
61 |
-
private $dates = array();
|
62 |
-
private $iterators = array();
|
63 |
-
private $contains = array();
|
64 |
-
private $notContains = array();
|
65 |
-
private $adapters = array();
|
66 |
-
private $paths = array();
|
67 |
-
private $notPaths = array();
|
68 |
-
private $ignoreUnreadableDirs = false;
|
69 |
-
|
70 |
-
private static $vcsPatterns = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg');
|
71 |
-
|
72 |
-
/**
|
73 |
-
* Constructor.
|
74 |
-
*/
|
75 |
-
public function __construct()
|
76 |
-
{
|
77 |
-
$this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
|
78 |
-
|
79 |
-
$this
|
80 |
-
->addAdapter(new GnuFindAdapter())
|
81 |
-
->addAdapter(new BsdFindAdapter())
|
82 |
-
->addAdapter(new PhpAdapter(), -50)
|
83 |
-
->setAdapter('php')
|
84 |
-
;
|
85 |
-
}
|
86 |
-
|
87 |
-
/**
|
88 |
-
* Creates a new Finder.
|
89 |
-
*
|
90 |
-
* @return Finder A new Finder instance
|
91 |
-
*
|
92 |
-
* @api
|
93 |
-
*/
|
94 |
-
public static function create()
|
95 |
-
{
|
96 |
-
return new static();
|
97 |
-
}
|
98 |
-
|
99 |
-
/**
|
100 |
-
* Registers a finder engine implementation.
|
101 |
-
*
|
102 |
-
* @param AdapterInterface $adapter An adapter instance
|
103 |
-
* @param int $priority Highest is selected first
|
104 |
-
*
|
105 |
-
* @return Finder The current Finder instance
|
106 |
-
*/
|
107 |
-
public function addAdapter(AdapterInterface $adapter, $priority = 0)
|
108 |
-
{
|
109 |
-
$this->adapters[$adapter->getName()] = array(
|
110 |
-
'adapter' => $adapter,
|
111 |
-
'priority' => $priority,
|
112 |
-
'selected' => false,
|
113 |
-
);
|
114 |
-
|
115 |
-
return $this->sortAdapters();
|
116 |
-
}
|
117 |
-
|
118 |
-
/**
|
119 |
-
* Sets the selected adapter to the best one according to the current platform the code is run on.
|
120 |
-
*
|
121 |
-
* @return Finder The current Finder instance
|
122 |
-
*/
|
123 |
-
public function useBestAdapter()
|
124 |
-
{
|
125 |
-
$this->resetAdapterSelection();
|
126 |
-
|
127 |
-
return $this->sortAdapters();
|
128 |
-
}
|
129 |
-
|
130 |
-
/**
|
131 |
-
* Selects the adapter to use.
|
132 |
-
*
|
133 |
-
* @param string $name
|
134 |
-
*
|
135 |
-
* @throws \InvalidArgumentException
|
136 |
-
*
|
137 |
-
* @return Finder The current Finder instance
|
138 |
-
*/
|
139 |
-
public function setAdapter($name)
|
140 |
-
{
|
141 |
-
if (!isset($this->adapters[$name])) {
|
142 |
-
throw new \InvalidArgumentException(sprintf('Adapter "%s" does not exist.', $name));
|
143 |
-
}
|
144 |
-
|
145 |
-
$this->resetAdapterSelection();
|
146 |
-
$this->adapters[$name]['selected'] = true;
|
147 |
-
|
148 |
-
return $this->sortAdapters();
|
149 |
-
}
|
150 |
-
|
151 |
-
/**
|
152 |
-
* Removes all adapters registered in the finder.
|
153 |
-
*
|
154 |
-
* @return Finder The current Finder instance
|
155 |
-
*/
|
156 |
-
public function removeAdapters()
|
157 |
-
{
|
158 |
-
$this->adapters = array();
|
159 |
-
|
160 |
-
return $this;
|
161 |
-
}
|
162 |
-
|
163 |
-
/**
|
164 |
-
* Returns registered adapters ordered by priority without extra information.
|
165 |
-
*
|
166 |
-
* @return AdapterInterface[]
|
167 |
-
*/
|
168 |
-
public function getAdapters()
|
169 |
-
{
|
170 |
-
return array_values(array_map(function (array $adapter) {
|
171 |
-
return $adapter['adapter'];
|
172 |
-
}, $this->adapters));
|
173 |
-
}
|
174 |
-
|
175 |
-
/**
|
176 |
-
* Restricts the matching to directories only.
|
177 |
-
*
|
178 |
-
* @return Finder The current Finder instance
|
179 |
-
*
|
180 |
-
* @api
|
181 |
-
*/
|
182 |
-
public function directories()
|
183 |
-
{
|
184 |
-
$this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;
|
185 |
-
|
186 |
-
return $this;
|
187 |
-
}
|
188 |
-
|
189 |
-
/**
|
190 |
-
* Restricts the matching to files only.
|
191 |
-
*
|
192 |
-
* @return Finder The current Finder instance
|
193 |
-
*
|
194 |
-
* @api
|
195 |
-
*/
|
196 |
-
public function files()
|
197 |
-
{
|
198 |
-
$this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
|
199 |
-
|
200 |
-
return $this;
|
201 |
-
}
|
202 |
-
|
203 |
-
/**
|
204 |
-
* Adds tests for the directory depth.
|
205 |
-
*
|
206 |
-
* Usage:
|
207 |
-
*
|
208 |
-
* $finder->depth('> 1') // the Finder will start matching at level 1.
|
209 |
-
* $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point.
|
210 |
-
*
|
211 |
-
* @param int $level The depth level expression
|
212 |
-
*
|
213 |
-
* @return Finder The current Finder instance
|
214 |
-
*
|
215 |
-
* @see DepthRangeFilterIterator
|
216 |
-
* @see NumberComparator
|
217 |
-
*
|
218 |
-
* @api
|
219 |
-
*/
|
220 |
-
public function depth($level)
|
221 |
-
{
|
222 |
-
$this->depths[] = new Comparator\NumberComparator($level);
|
223 |
-
|
224 |
-
return $this;
|
225 |
-
}
|
226 |
-
|
227 |
-
/**
|
228 |
-
* Adds tests for file dates (last modified).
|
229 |
-
*
|
230 |
-
* The date must be something that strtotime() is able to parse:
|
231 |
-
*
|
232 |
-
* $finder->date('since yesterday');
|
233 |
-
* $finder->date('until 2 days ago');
|
234 |
-
* $finder->date('> now - 2 hours');
|
235 |
-
* $finder->date('>= 2005-10-15');
|
236 |
-
*
|
237 |
-
* @param string $date A date rage string
|
238 |
-
*
|
239 |
-
* @return Finder The current Finder instance
|
240 |
-
*
|
241 |
-
* @see strtotime
|
242 |
-
* @see DateRangeFilterIterator
|
243 |
-
* @see DateComparator
|
244 |
-
*
|
245 |
-
* @api
|
246 |
-
*/
|
247 |
-
public function date($date)
|
248 |
-
{
|
249 |
-
$this->dates[] = new Comparator\DateComparator($date);
|
250 |
-
|
251 |
-
return $this;
|
252 |
-
}
|
253 |
-
|
254 |
-
/**
|
255 |
-
* Adds rules that files must match.
|
256 |
-
*
|
257 |
-
* You can use patterns (delimited with / sign), globs or simple strings.
|
258 |
-
*
|
259 |
-
* $finder->name('*.php')
|
260 |
-
* $finder->name('/\.php$/') // same as above
|
261 |
-
* $finder->name('test.php')
|
262 |
-
*
|
263 |
-
* @param string $pattern A pattern (a regexp, a glob, or a string)
|
264 |
-
*
|
265 |
-
* @return Finder The current Finder instance
|
266 |
-
*
|
267 |
-
* @see FilenameFilterIterator
|
268 |
-
*
|
269 |
-
* @api
|
270 |
-
*/
|
271 |
-
public function name($pattern)
|
272 |
-
{
|
273 |
-
$this->names[] = $pattern;
|
274 |
-
|
275 |
-
return $this;
|
276 |
-
}
|
277 |
-
|
278 |
-
/**
|
279 |
-
* Adds rules that files must not match.
|
280 |
-
*
|
281 |
-
* @param string $pattern A pattern (a regexp, a glob, or a string)
|
282 |
-
*
|
283 |
-
* @return Finder The current Finder instance
|
284 |
-
*
|
285 |
-
* @see FilenameFilterIterator
|
286 |
-
*
|
287 |
-
* @api
|
288 |
-
*/
|
289 |
-
public function notName($pattern)
|
290 |
-
{
|
291 |
-
$this->notNames[] = $pattern;
|
292 |
-
|
293 |
-
return $this;
|
294 |
-
}
|
295 |
-
|
296 |
-
/**
|
297 |
-
* Adds tests that file contents must match.
|
298 |
-
*
|
299 |
-
* Strings or PCRE patterns can be used:
|
300 |
-
*
|
301 |
-
* $finder->contains('Lorem ipsum')
|
302 |
-
* $finder->contains('/Lorem ipsum/i')
|
303 |
-
*
|
304 |
-
* @param string $pattern A pattern (string or regexp)
|
305 |
-
*
|
306 |
-
* @return Finder The current Finder instance
|
307 |
-
*
|
308 |
-
* @see FilecontentFilterIterator
|
309 |
-
*/
|
310 |
-
public function contains($pattern)
|
311 |
-
{
|
312 |
-
$this->contains[] = $pattern;
|
313 |
-
|
314 |
-
return $this;
|
315 |
-
}
|
316 |
-
|
317 |
-
/**
|
318 |
-
* Adds tests that file contents must not match.
|
319 |
-
*
|
320 |
-
* Strings or PCRE patterns can be used:
|
321 |
-
*
|
322 |
-
* $finder->notContains('Lorem ipsum')
|
323 |
-
* $finder->notContains('/Lorem ipsum/i')
|
324 |
-
*
|
325 |
-
* @param string $pattern A pattern (string or regexp)
|
326 |
-
*
|
327 |
-
* @return Finder The current Finder instance
|
328 |
-
*
|
329 |
-
* @see FilecontentFilterIterator
|
330 |
-
*/
|
331 |
-
public function notContains($pattern)
|
332 |
-
{
|
333 |
-
$this->notContains[] = $pattern;
|
334 |
-
|
335 |
-
return $this;
|
336 |
-
}
|
337 |
-
|
338 |
-
/**
|
339 |
-
* Adds rules that filenames must match.
|
340 |
-
*
|
341 |
-
* You can use patterns (delimited with / sign) or simple strings.
|
342 |
-
*
|
343 |
-
* $finder->path('some/special/dir')
|
344 |
-
* $finder->path('/some\/special\/dir/') // same as above
|
345 |
-
*
|
346 |
-
* Use only / as dirname separator.
|
347 |
-
*
|
348 |
-
* @param string $pattern A pattern (a regexp or a string)
|
349 |
-
*
|
350 |
-
* @return Finder The current Finder instance
|
351 |
-
*
|
352 |
-
* @see FilenameFilterIterator
|
353 |
-
*/
|
354 |
-
public function path($pattern)
|
355 |
-
{
|
356 |
-
$this->paths[] = $pattern;
|
357 |
-
|
358 |
-
return $this;
|
359 |
-
}
|
360 |
-
|
361 |
-
/**
|
362 |
-
* Adds rules that filenames must not match.
|
363 |
-
*
|
364 |
-
* You can use patterns (delimited with / sign) or simple strings.
|
365 |
-
*
|
366 |
-
* $finder->notPath('some/special/dir')
|
367 |
-
* $finder->notPath('/some\/special\/dir/') // same as above
|
368 |
-
*
|
369 |
-
* Use only / as dirname separator.
|
370 |
-
*
|
371 |
-
* @param string $pattern A pattern (a regexp or a string)
|
372 |
-
*
|
373 |
-
* @return Finder The current Finder instance
|
374 |
-
*
|
375 |
-
* @see FilenameFilterIterator
|
376 |
-
*/
|
377 |
-
public function notPath($pattern)
|
378 |
-
{
|
379 |
-
$this->notPaths[] = $pattern;
|
380 |
-
|
381 |
-
return $this;
|
382 |
-
}
|
383 |
-
|
384 |
-
/**
|
385 |
-
* Adds tests for file sizes.
|
386 |
-
*
|
387 |
-
* $finder->size('> 10K');
|
388 |
-
* $finder->size('<= 1Ki');
|
389 |
-
* $finder->size(4);
|
390 |
-
*
|
391 |
-
* @param string $size A size range string
|
392 |
-
*
|
393 |
-
* @return Finder The current Finder instance
|
394 |
-
*
|
395 |
-
* @see SizeRangeFilterIterator
|
396 |
-
* @see NumberComparator
|
397 |
-
*
|
398 |
-
* @api
|
399 |
-
*/
|
400 |
-
public function size($size)
|
401 |
-
{
|
402 |
-
$this->sizes[] = new Comparator\NumberComparator($size);
|
403 |
-
|
404 |
-
return $this;
|
405 |
-
}
|
406 |
-
|
407 |
-
/**
|
408 |
-
* Excludes directories.
|
409 |
-
*
|
410 |
-
* @param string|array $dirs A directory path or an array of directories
|
411 |
-
*
|
412 |
-
* @return Finder The current Finder instance
|
413 |
-
*
|
414 |
-
* @see ExcludeDirectoryFilterIterator
|
415 |
-
*
|
416 |
-
* @api
|
417 |
-
*/
|
418 |
-
public function exclude($dirs)
|
419 |
-
{
|
420 |
-
$this->exclude = array_merge($this->exclude, (array) $dirs);
|
421 |
-
|
422 |
-
return $this;
|
423 |
-
}
|
424 |
-
|
425 |
-
/**
|
426 |
-
* Excludes "hidden" directories and files (starting with a dot).
|
427 |
-
*
|
428 |
-
* @param bool $ignoreDotFiles Whether to exclude "hidden" files or not
|
429 |
-
*
|
430 |
-
* @return Finder The current Finder instance
|
431 |
-
*
|
432 |
-
* @see ExcludeDirectoryFilterIterator
|
433 |
-
*
|
434 |
-
* @api
|
435 |
-
*/
|
436 |
-
public function ignoreDotFiles($ignoreDotFiles)
|
437 |
-
{
|
438 |
-
if ($ignoreDotFiles) {
|
439 |
-
$this->ignore = $this->ignore | static::IGNORE_DOT_FILES;
|
440 |
-
} else {
|
441 |
-
$this->ignore = $this->ignore & ~static::IGNORE_DOT_FILES;
|
442 |
-
}
|
443 |
-
|
444 |
-
return $this;
|
445 |
-
}
|
446 |
-
|
447 |
-
/**
|
448 |
-
* Forces the finder to ignore version control directories.
|
449 |
-
*
|
450 |
-
* @param bool $ignoreVCS Whether to exclude VCS files or not
|
451 |
-
*
|
452 |
-
* @return Finder The current Finder instance
|
453 |
-
*
|
454 |
-
* @see ExcludeDirectoryFilterIterator
|
455 |
-
*
|
456 |
-
* @api
|
457 |
-
*/
|
458 |
-
public function ignoreVCS($ignoreVCS)
|
459 |
-
{
|
460 |
-
if ($ignoreVCS) {
|
461 |
-
$this->ignore = $this->ignore | static::IGNORE_VCS_FILES;
|
462 |
-
} else {
|
463 |
-
$this->ignore = $this->ignore & ~static::IGNORE_VCS_FILES;
|
464 |
-
}
|
465 |
-
|
466 |
-
return $this;
|
467 |
-
}
|
468 |
-
|
469 |
-
/**
|
470 |
-
* Adds VCS patterns.
|
471 |
-
*
|
472 |
-
* @see ignoreVCS()
|
473 |
-
*
|
474 |
-
* @param string|string[] $pattern VCS patterns to ignore
|
475 |
-
*/
|
476 |
-
public static function addVCSPattern($pattern)
|
477 |
-
{
|
478 |
-
foreach ((array) $pattern as $p) {
|
479 |
-
self::$vcsPatterns[] = $p;
|
480 |
-
}
|
481 |
-
|
482 |
-
self::$vcsPatterns = array_unique(self::$vcsPatterns);
|
483 |
-
}
|
484 |
-
|
485 |
-
/**
|
486 |
-
* Sorts files and directories by an anonymous function.
|
487 |
-
*
|
488 |
-
* The anonymous function receives two \SplFileInfo instances to compare.
|
489 |
-
*
|
490 |
-
* This can be slow as all the matching files and directories must be retrieved for comparison.
|
491 |
-
*
|
492 |
-
* @param \Closure $closure An anonymous function
|
493 |
-
*
|
494 |
-
* @return Finder The current Finder instance
|
495 |
-
*
|
496 |
-
* @see SortableIterator
|
497 |
-
*
|
498 |
-
* @api
|
499 |
-
*/
|
500 |
-
public function sort(\Closure $closure)
|
501 |
-
{
|
502 |
-
$this->sort = $closure;
|
503 |
-
|
504 |
-
return $this;
|
505 |
-
}
|
506 |
-
|
507 |
-
/**
|
508 |
-
* Sorts files and directories by name.
|
509 |
-
*
|
510 |
-
* This can be slow as all the matching files and directories must be retrieved for comparison.
|
511 |
-
*
|
512 |
-
* @return Finder The current Finder instance
|
513 |
-
*
|
514 |
-
* @see SortableIterator
|
515 |
-
*
|
516 |
-
* @api
|
517 |
-
*/
|
518 |
-
public function sortByName()
|
519 |
-
{
|
520 |
-
$this->sort = Iterator\SortableIterator::SORT_BY_NAME;
|
521 |
-
|
522 |
-
return $this;
|
523 |
-
}
|
524 |
-
|
525 |
-
/**
|
526 |
-
* Sorts files and directories by type (directories before files), then by name.
|
527 |
-
*
|
528 |
-
* This can be slow as all the matching files and directories must be retrieved for comparison.
|
529 |
-
*
|
530 |
-
* @return Finder The current Finder instance
|
531 |
-
*
|
532 |
-
* @see SortableIterator
|
533 |
-
*
|
534 |
-
* @api
|
535 |
-
*/
|
536 |
-
public function sortByType()
|
537 |
-
{
|
538 |
-
$this->sort = Iterator\SortableIterator::SORT_BY_TYPE;
|
539 |
-
|
540 |
-
return $this;
|
541 |
-
}
|
542 |
-
|
543 |
-
/**
|
544 |
-
* Sorts files and directories by the last accessed time.
|
545 |
-
*
|
546 |
-
* This is the time that the file was last accessed, read or written to.
|
547 |
-
*
|
548 |
-
* This can be slow as all the matching files and directories must be retrieved for comparison.
|
549 |
-
*
|
550 |
-
* @return Finder The current Finder instance
|
551 |
-
*
|
552 |
-
* @see SortableIterator
|
553 |
-
*
|
554 |
-
* @api
|
555 |
-
*/
|
556 |
-
public function sortByAccessedTime()
|
557 |
-
{
|
558 |
-
$this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;
|
559 |
-
|
560 |
-
return $this;
|
561 |
-
}
|
562 |
-
|
563 |
-
/**
|
564 |
-
* Sorts files and directories by the last inode changed time.
|
565 |
-
*
|
566 |
-
* This is the time that the inode information was last modified (permissions, owner, group or other metadata).
|
567 |
-
*
|
568 |
-
* On Windows, since inode is not available, changed time is actually the file creation time.
|
569 |
-
*
|
570 |
-
* This can be slow as all the matching files and directories must be retrieved for comparison.
|
571 |
-
*
|
572 |
-
* @return Finder The current Finder instance
|
573 |
-
*
|
574 |
-
* @see SortableIterator
|
575 |
-
*
|
576 |
-
* @api
|
577 |
-
*/
|
578 |
-
public function sortByChangedTime()
|
579 |
-
{
|
580 |
-
$this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;
|
581 |
-
|
582 |
-
return $this;
|
583 |
-
}
|
584 |
-
|
585 |
-
/**
|
586 |
-
* Sorts files and directories by the last modified time.
|
587 |
-
*
|
588 |
-
* This is the last time the actual contents of the file were last modified.
|
589 |
-
*
|
590 |
-
* This can be slow as all the matching files and directories must be retrieved for comparison.
|
591 |
-
*
|
592 |
-
* @return Finder The current Finder instance
|
593 |
-
*
|
594 |
-
* @see SortableIterator
|
595 |
-
*
|
596 |
-
* @api
|
597 |
-
*/
|
598 |
-
public function sortByModifiedTime()
|
599 |
-
{
|
600 |
-
$this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;
|
601 |
-
|
602 |
-
return $this;
|
603 |
-
}
|
604 |
-
|
605 |
-
/**
|
606 |
-
* Filters the iterator with an anonymous function.
|
607 |
-
*
|
608 |
-
* The anonymous function receives a \SplFileInfo and must return false
|
609 |
-
* to remove files.
|
610 |
-
*
|
611 |
-
* @param \Closure $closure An anonymous function
|
612 |
-
*
|
613 |
-
* @return Finder The current Finder instance
|
614 |
-
*
|
615 |
-
* @see CustomFilterIterator
|
616 |
-
*
|
617 |
-
* @api
|
618 |
-
*/
|
619 |
-
public function filter(\Closure $closure)
|
620 |
-
{
|
621 |
-
$this->filters[] = $closure;
|
622 |
-
|
623 |
-
return $this;
|
624 |
-
}
|
625 |
-
|
626 |
-
/**
|
627 |
-
* Forces the following of symlinks.
|
628 |
-
*
|
629 |
-
* @return Finder The current Finder instance
|
630 |
-
*
|
631 |
-
* @api
|
632 |
-
*/
|
633 |
-
public function followLinks()
|
634 |
-
{
|
635 |
-
$this->followLinks = true;
|
636 |
-
|
637 |
-
return $this;
|
638 |
-
}
|
639 |
-
|
640 |
-
/**
|
641 |
-
* Tells finder to ignore unreadable directories.
|
642 |
-
*
|
643 |
-
* By default, scanning unreadable directories content throws an AccessDeniedException.
|
644 |
-
*
|
645 |
-
* @param bool $ignore
|
646 |
-
*
|
647 |
-
* @return Finder The current Finder instance
|
648 |
-
*/
|
649 |
-
public function ignoreUnreadableDirs($ignore = true)
|
650 |
-
{
|
651 |
-
$this->ignoreUnreadableDirs = (bool) $ignore;
|
652 |
-
|
653 |
-
return $this;
|
654 |
-
}
|
655 |
-
|
656 |
-
/**
|
657 |
-
* Searches files and directories which match defined rules.
|
658 |
-
*
|
659 |
-
* @param string|array $dirs A directory path or an array of directories
|
660 |
-
*
|
661 |
-
* @return Finder The current Finder instance
|
662 |
-
*
|
663 |
-
* @throws \InvalidArgumentException if one of the directories does not exist
|
664 |
-
*
|
665 |
-
* @api
|
666 |
-
*/
|
667 |
-
public function in($dirs)
|
668 |
-
{
|
669 |
-
$resolvedDirs = array();
|
670 |
-
|
671 |
-
foreach ((array) $dirs as $dir) {
|
672 |
-
if (is_dir($dir)) {
|
673 |
-
$resolvedDirs[] = $dir;
|
674 |
-
} elseif ($glob = glob($dir, GLOB_BRACE | GLOB_ONLYDIR)) {
|
675 |
-
$resolvedDirs = array_merge($resolvedDirs, $glob);
|
676 |
-
} else {
|
677 |
-
throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir));
|
678 |
-
}
|
679 |
-
}
|
680 |
-
|
681 |
-
$this->dirs = array_merge($this->dirs, $resolvedDirs);
|
682 |
-
|
683 |
-
return $this;
|
684 |
-
}
|
685 |
-
|
686 |
-
/**
|
687 |
-
* Returns an Iterator for the current Finder configuration.
|
688 |
-
*
|
689 |
-
* This method implements the IteratorAggregate interface.
|
690 |
-
*
|
691 |
-
* @return \Iterator An iterator
|
692 |
-
*
|
693 |
-
* @throws \LogicException if the in() method has not been called
|
694 |
-
*/
|
695 |
-
public function getIterator()
|
696 |
-
{
|
697 |
-
if (0 === count($this->dirs) && 0 === count($this->iterators)) {
|
698 |
-
throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.');
|
699 |
-
}
|
700 |
-
|
701 |
-
if (1 === count($this->dirs) && 0 === count($this->iterators)) {
|
702 |
-
return $this->searchInDirectory($this->dirs[0]);
|
703 |
-
}
|
704 |
-
|
705 |
-
$iterator = new \AppendIterator();
|
706 |
-
foreach ($this->dirs as $dir) {
|
707 |
-
$iterator->append($this->searchInDirectory($dir));
|
708 |
-
}
|
709 |
-
|
710 |
-
foreach ($this->iterators as $it) {
|
711 |
-
$iterator->append($it);
|
712 |
-
}
|
713 |
-
|
714 |
-
return $iterator;
|
715 |
-
}
|
716 |
-
|
717 |
-
/**
|
718 |
-
* Appends an existing set of files/directories to the finder.
|
719 |
-
*
|
720 |
-
* The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array.
|
721 |
-
*
|
722 |
-
* @param mixed $iterator
|
723 |
-
*
|
724 |
-
* @return Finder The finder
|
725 |
-
*
|
726 |
-
* @throws \InvalidArgumentException When the given argument is not iterable.
|
727 |
-
*/
|
728 |
-
public function append($iterator)
|
729 |
-
{
|
730 |
-
if ($iterator instanceof \IteratorAggregate) {
|
731 |
-
$this->iterators[] = $iterator->getIterator();
|
732 |
-
} elseif ($iterator instanceof \Iterator) {
|
733 |
-
$this->iterators[] = $iterator;
|
734 |
-
} elseif ($iterator instanceof \Traversable || is_array($iterator)) {
|
735 |
-
$it = new \ArrayIterator();
|
736 |
-
foreach ($iterator as $file) {
|
737 |
-
$it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file));
|
738 |
-
}
|
739 |
-
$this->iterators[] = $it;
|
740 |
-
} else {
|
741 |
-
throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
|
742 |
-
}
|
743 |
-
|
744 |
-
return $this;
|
745 |
-
}
|
746 |
-
|
747 |
-
/**
|
748 |
-
* Counts all the results collected by the iterators.
|
749 |
-
*
|
750 |
-
* @return int
|
751 |
-
*/
|
752 |
-
public function count()
|
753 |
-
{
|
754 |
-
return iterator_count($this->getIterator());
|
755 |
-
}
|
756 |
-
|
757 |
-
/**
|
758 |
-
* @return Finder The current Finder instance
|
759 |
-
*/
|
760 |
-
private function sortAdapters()
|
761 |
-
{
|
762 |
-
uasort($this->adapters, function (array $a, array $b) {
|
763 |
-
if ($a['selected'] || $b['selected']) {
|
764 |
-
return $a['selected'] ? -1 : 1;
|
765 |
-
}
|
766 |
-
|
767 |
-
return $a['priority'] > $b['priority'] ? -1 : 1;
|
768 |
-
});
|
769 |
-
|
770 |
-
return $this;
|
771 |
-
}
|
772 |
-
|
773 |
-
/**
|
774 |
-
* @param $dir
|
775 |
-
*
|
776 |
-
* @return \Iterator
|
777 |
-
*
|
778 |
-
* @throws \RuntimeException When none of the adapters are supported
|
779 |
-
*/
|
780 |
-
private function searchInDirectory($dir)
|
781 |
-
{
|
782 |
-
if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
|
783 |
-
$this->exclude = array_merge($this->exclude, self::$vcsPatterns);
|
784 |
-
}
|
785 |
-
|
786 |
-
if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
|
787 |
-
$this->notPaths[] = '#(^|/)\..+(/|$)#';
|
788 |
-
}
|
789 |
-
|
790 |
-
foreach ($this->adapters as $adapter) {
|
791 |
-
if ($adapter['adapter']->isSupported()) {
|
792 |
-
try {
|
793 |
-
return $this
|
794 |
-
->buildAdapter($adapter['adapter'])
|
795 |
-
->searchInDirectory($dir);
|
796 |
-
} catch (ExceptionInterface $e) {
|
797 |
-
}
|
798 |
-
}
|
799 |
-
}
|
800 |
-
|
801 |
-
throw new \RuntimeException('No supported adapter found.');
|
802 |
-
}
|
803 |
-
|
804 |
-
/**
|
805 |
-
* @param AdapterInterface $adapter
|
806 |
-
*
|
807 |
-
* @return AdapterInterface
|
808 |
-
*/
|
809 |
-
private function buildAdapter(AdapterInterface $adapter)
|
810 |
-
{
|
811 |
-
return $adapter
|
812 |
-
->setFollowLinks($this->followLinks)
|
813 |
-
->setDepths($this->depths)
|
814 |
-
->setMode($this->mode)
|
815 |
-
->setExclude($this->exclude)
|
816 |
-
->setNames($this->names)
|
817 |
-
->setNotNames($this->notNames)
|
818 |
-
->setContains($this->contains)
|
819 |
-
->setNotContains($this->notContains)
|
820 |
-
->setSizes($this->sizes)
|
821 |
-
->setDates($this->dates)
|
822 |
-
->setFilters($this->filters)
|
823 |
-
->setSort($this->sort)
|
824 |
-
->setPath($this->paths)
|
825 |
-
->setNotPath($this->notPaths)
|
826 |
-
->ignoreUnreadableDirs($this->ignoreUnreadableDirs);
|
827 |
-
}
|
828 |
-
|
829 |
-
/**
|
830 |
-
* Unselects all adapters.
|
831 |
-
*/
|
832 |
-
private function resetAdapterSelection()
|
833 |
-
{
|
834 |
-
$this->adapters = array_map(function (array $properties) {
|
835 |
-
$properties['selected'] = false;
|
836 |
-
|
837 |
-
return $properties;
|
838 |
-
}, $this->adapters);
|
839 |
-
}
|
840 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Glob.php
DELETED
@@ -1,103 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Glob matches globbing patterns against text.
|
16 |
-
*
|
17 |
-
* if match_glob("foo.*", "foo.bar") echo "matched\n";
|
18 |
-
*
|
19 |
-
* // prints foo.bar and foo.baz
|
20 |
-
* $regex = glob_to_regex("foo.*");
|
21 |
-
* for (array('foo.bar', 'foo.baz', 'foo', 'bar') as $t)
|
22 |
-
* {
|
23 |
-
* if (/$regex/) echo "matched: $car\n";
|
24 |
-
* }
|
25 |
-
*
|
26 |
-
* Glob implements glob(3) style matching that can be used to match
|
27 |
-
* against text, rather than fetching names from a filesystem.
|
28 |
-
*
|
29 |
-
* Based on the Perl Text::Glob module.
|
30 |
-
*
|
31 |
-
* @author Fabien Potencier <fabien@symfony.com> PHP port
|
32 |
-
* @author Richard Clamp <richardc@unixbeard.net> Perl version
|
33 |
-
* @copyright 2004-2005 Fabien Potencier <fabien@symfony.com>
|
34 |
-
* @copyright 2002 Richard Clamp <richardc@unixbeard.net>
|
35 |
-
*/
|
36 |
-
class Glob
|
37 |
-
{
|
38 |
-
/**
|
39 |
-
* Returns a regexp which is the equivalent of the glob pattern.
|
40 |
-
*
|
41 |
-
* @param string $glob The glob pattern
|
42 |
-
* @param bool $strictLeadingDot
|
43 |
-
* @param bool $strictWildcardSlash
|
44 |
-
*
|
45 |
-
* @return string regex The regexp
|
46 |
-
*/
|
47 |
-
public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true)
|
48 |
-
{
|
49 |
-
$firstByte = true;
|
50 |
-
$escaping = false;
|
51 |
-
$inCurlies = 0;
|
52 |
-
$regex = '';
|
53 |
-
$sizeGlob = strlen($glob);
|
54 |
-
for ($i = 0; $i < $sizeGlob; $i++) {
|
55 |
-
$car = $glob[$i];
|
56 |
-
if ($firstByte) {
|
57 |
-
if ($strictLeadingDot && '.' !== $car) {
|
58 |
-
$regex .= '(?=[^\.])';
|
59 |
-
}
|
60 |
-
|
61 |
-
$firstByte = false;
|
62 |
-
}
|
63 |
-
|
64 |
-
if ('/' === $car) {
|
65 |
-
$firstByte = true;
|
66 |
-
}
|
67 |
-
|
68 |
-
if ('.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
|
69 |
-
$regex .= "\\$car";
|
70 |
-
} elseif ('*' === $car) {
|
71 |
-
$regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
|
72 |
-
} elseif ('?' === $car) {
|
73 |
-
$regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
|
74 |
-
} elseif ('{' === $car) {
|
75 |
-
$regex .= $escaping ? '\\{' : '(';
|
76 |
-
if (!$escaping) {
|
77 |
-
++$inCurlies;
|
78 |
-
}
|
79 |
-
} elseif ('}' === $car && $inCurlies) {
|
80 |
-
$regex .= $escaping ? '}' : ')';
|
81 |
-
if (!$escaping) {
|
82 |
-
--$inCurlies;
|
83 |
-
}
|
84 |
-
} elseif (',' === $car && $inCurlies) {
|
85 |
-
$regex .= $escaping ? ',' : '|';
|
86 |
-
} elseif ('\\' === $car) {
|
87 |
-
if ($escaping) {
|
88 |
-
$regex .= '\\\\';
|
89 |
-
$escaping = false;
|
90 |
-
} else {
|
91 |
-
$escaping = true;
|
92 |
-
}
|
93 |
-
|
94 |
-
continue;
|
95 |
-
} else {
|
96 |
-
$regex .= $car;
|
97 |
-
}
|
98 |
-
$escaping = false;
|
99 |
-
}
|
100 |
-
|
101 |
-
return '#^'.$regex.'$#';
|
102 |
-
}
|
103 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Iterator/CustomFilterIterator.php
DELETED
@@ -1,63 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Iterator;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* CustomFilterIterator filters files by applying anonymous functions.
|
16 |
-
*
|
17 |
-
* The anonymous function receives a \SplFileInfo and must return false
|
18 |
-
* to remove files.
|
19 |
-
*
|
20 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
21 |
-
*/
|
22 |
-
class CustomFilterIterator extends FilterIterator
|
23 |
-
{
|
24 |
-
private $filters = array();
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Constructor.
|
28 |
-
*
|
29 |
-
* @param \Iterator $iterator The Iterator to filter
|
30 |
-
* @param array $filters An array of PHP callbacks
|
31 |
-
*
|
32 |
-
* @throws \InvalidArgumentException
|
33 |
-
*/
|
34 |
-
public function __construct(\Iterator $iterator, array $filters)
|
35 |
-
{
|
36 |
-
foreach ($filters as $filter) {
|
37 |
-
if (!is_callable($filter)) {
|
38 |
-
throw new \InvalidArgumentException('Invalid PHP callback.');
|
39 |
-
}
|
40 |
-
}
|
41 |
-
$this->filters = $filters;
|
42 |
-
|
43 |
-
parent::__construct($iterator);
|
44 |
-
}
|
45 |
-
|
46 |
-
/**
|
47 |
-
* Filters the iterator values.
|
48 |
-
*
|
49 |
-
* @return bool true if the value should be kept, false otherwise
|
50 |
-
*/
|
51 |
-
public function accept()
|
52 |
-
{
|
53 |
-
$fileinfo = $this->current();
|
54 |
-
|
55 |
-
foreach ($this->filters as $filter) {
|
56 |
-
if (false === call_user_func($filter, $fileinfo)) {
|
57 |
-
return false;
|
58 |
-
}
|
59 |
-
}
|
60 |
-
|
61 |
-
return true;
|
62 |
-
}
|
63 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.php
DELETED
@@ -1,60 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Iterator;
|
13 |
-
|
14 |
-
use Symfony\Component\Finder\Comparator\DateComparator;
|
15 |
-
|
16 |
-
/**
|
17 |
-
* DateRangeFilterIterator filters out files that are not in the given date range (last modified dates).
|
18 |
-
*
|
19 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
20 |
-
*/
|
21 |
-
class DateRangeFilterIterator extends FilterIterator
|
22 |
-
{
|
23 |
-
private $comparators = array();
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Constructor.
|
27 |
-
*
|
28 |
-
* @param \Iterator $iterator The Iterator to filter
|
29 |
-
* @param DateComparator[] $comparators An array of DateComparator instances
|
30 |
-
*/
|
31 |
-
public function __construct(\Iterator $iterator, array $comparators)
|
32 |
-
{
|
33 |
-
$this->comparators = $comparators;
|
34 |
-
|
35 |
-
parent::__construct($iterator);
|
36 |
-
}
|
37 |
-
|
38 |
-
/**
|
39 |
-
* Filters the iterator values.
|
40 |
-
*
|
41 |
-
* @return bool true if the value should be kept, false otherwise
|
42 |
-
*/
|
43 |
-
public function accept()
|
44 |
-
{
|
45 |
-
$fileinfo = $this->current();
|
46 |
-
|
47 |
-
if (!file_exists($fileinfo->getRealPath())) {
|
48 |
-
return false;
|
49 |
-
}
|
50 |
-
|
51 |
-
$filedate = $fileinfo->getMTime();
|
52 |
-
foreach ($this->comparators as $compare) {
|
53 |
-
if (!$compare->test($filedate)) {
|
54 |
-
return false;
|
55 |
-
}
|
56 |
-
}
|
57 |
-
|
58 |
-
return true;
|
59 |
-
}
|
60 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Iterator/DepthRangeFilterIterator.php
DELETED
@@ -1,47 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Iterator;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* DepthRangeFilterIterator limits the directory depth.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
*/
|
19 |
-
class DepthRangeFilterIterator extends FilterIterator
|
20 |
-
{
|
21 |
-
private $minDepth = 0;
|
22 |
-
|
23 |
-
/**
|
24 |
-
* Constructor.
|
25 |
-
*
|
26 |
-
* @param \RecursiveIteratorIterator $iterator The Iterator to filter
|
27 |
-
* @param int $minDepth The min depth
|
28 |
-
* @param int $maxDepth The max depth
|
29 |
-
*/
|
30 |
-
public function __construct(\RecursiveIteratorIterator $iterator, $minDepth = 0, $maxDepth = PHP_INT_MAX)
|
31 |
-
{
|
32 |
-
$this->minDepth = $minDepth;
|
33 |
-
$iterator->setMaxDepth(PHP_INT_MAX === $maxDepth ? -1 : $maxDepth);
|
34 |
-
|
35 |
-
parent::__construct($iterator);
|
36 |
-
}
|
37 |
-
|
38 |
-
/**
|
39 |
-
* Filters the iterator values.
|
40 |
-
*
|
41 |
-
* @return bool true if the value should be kept, false otherwise
|
42 |
-
*/
|
43 |
-
public function accept()
|
44 |
-
{
|
45 |
-
return $this->getInnerIterator()->getDepth() >= $this->minDepth;
|
46 |
-
}
|
47 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php
DELETED
@@ -1,55 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Iterator;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* ExcludeDirectoryFilterIterator filters out directories.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
*/
|
19 |
-
class ExcludeDirectoryFilterIterator extends FilterIterator
|
20 |
-
{
|
21 |
-
private $patterns = array();
|
22 |
-
|
23 |
-
/**
|
24 |
-
* Constructor.
|
25 |
-
*
|
26 |
-
* @param \Iterator $iterator The Iterator to filter
|
27 |
-
* @param array $directories An array of directories to exclude
|
28 |
-
*/
|
29 |
-
public function __construct(\Iterator $iterator, array $directories)
|
30 |
-
{
|
31 |
-
foreach ($directories as $directory) {
|
32 |
-
$this->patterns[] = '#(^|/)'.preg_quote($directory, '#').'(/|$)#';
|
33 |
-
}
|
34 |
-
|
35 |
-
parent::__construct($iterator);
|
36 |
-
}
|
37 |
-
|
38 |
-
/**
|
39 |
-
* Filters the iterator values.
|
40 |
-
*
|
41 |
-
* @return bool true if the value should be kept, false otherwise
|
42 |
-
*/
|
43 |
-
public function accept()
|
44 |
-
{
|
45 |
-
$path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
|
46 |
-
$path = strtr($path, '\\', '/');
|
47 |
-
foreach ($this->patterns as $pattern) {
|
48 |
-
if (preg_match($pattern, $path)) {
|
49 |
-
return false;
|
50 |
-
}
|
51 |
-
}
|
52 |
-
|
53 |
-
return true;
|
54 |
-
}
|
55 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilePathsIterator.php
DELETED
@@ -1,131 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Iterator;
|
13 |
-
|
14 |
-
use Symfony\Component\Finder\SplFileInfo;
|
15 |
-
|
16 |
-
/**
|
17 |
-
* Iterate over shell command result.
|
18 |
-
*
|
19 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
20 |
-
*/
|
21 |
-
class FilePathsIterator extends \ArrayIterator
|
22 |
-
{
|
23 |
-
/**
|
24 |
-
* @var string
|
25 |
-
*/
|
26 |
-
private $baseDir;
|
27 |
-
|
28 |
-
/**
|
29 |
-
* @var int
|
30 |
-
*/
|
31 |
-
private $baseDirLength;
|
32 |
-
|
33 |
-
/**
|
34 |
-
* @var string
|
35 |
-
*/
|
36 |
-
private $subPath;
|
37 |
-
|
38 |
-
/**
|
39 |
-
* @var string
|
40 |
-
*/
|
41 |
-
private $subPathname;
|
42 |
-
|
43 |
-
/**
|
44 |
-
* @var SplFileInfo
|
45 |
-
*/
|
46 |
-
private $current;
|
47 |
-
|
48 |
-
/**
|
49 |
-
* @param array $paths List of paths returned by shell command
|
50 |
-
* @param string $baseDir Base dir for relative path building
|
51 |
-
*/
|
52 |
-
public function __construct(array $paths, $baseDir)
|
53 |
-
{
|
54 |
-
$this->baseDir = $baseDir;
|
55 |
-
$this->baseDirLength = strlen($baseDir);
|
56 |
-
|
57 |
-
parent::__construct($paths);
|
58 |
-
}
|
59 |
-
|
60 |
-
/**
|
61 |
-
* @param string $name
|
62 |
-
* @param array $arguments
|
63 |
-
*
|
64 |
-
* @return mixed
|
65 |
-
*/
|
66 |
-
public function __call($name, array $arguments)
|
67 |
-
{
|
68 |
-
return call_user_func_array(array($this->current(), $name), $arguments);
|
69 |
-
}
|
70 |
-
|
71 |
-
/**
|
72 |
-
* Return an instance of SplFileInfo with support for relative paths.
|
73 |
-
*
|
74 |
-
* @return SplFileInfo File information
|
75 |
-
*/
|
76 |
-
public function current()
|
77 |
-
{
|
78 |
-
return $this->current;
|
79 |
-
}
|
80 |
-
|
81 |
-
/**
|
82 |
-
* @return string
|
83 |
-
*/
|
84 |
-
public function key()
|
85 |
-
{
|
86 |
-
return $this->current->getPathname();
|
87 |
-
}
|
88 |
-
|
89 |
-
public function next()
|
90 |
-
{
|
91 |
-
parent::next();
|
92 |
-
$this->buildProperties();
|
93 |
-
}
|
94 |
-
|
95 |
-
public function rewind()
|
96 |
-
{
|
97 |
-
parent::rewind();
|
98 |
-
$this->buildProperties();
|
99 |
-
}
|
100 |
-
|
101 |
-
/**
|
102 |
-
* @return string
|
103 |
-
*/
|
104 |
-
public function getSubPath()
|
105 |
-
{
|
106 |
-
return $this->subPath;
|
107 |
-
}
|
108 |
-
|
109 |
-
/**
|
110 |
-
* @return string
|
111 |
-
*/
|
112 |
-
public function getSubPathname()
|
113 |
-
{
|
114 |
-
return $this->subPathname;
|
115 |
-
}
|
116 |
-
|
117 |
-
private function buildProperties()
|
118 |
-
{
|
119 |
-
$absolutePath = parent::current();
|
120 |
-
|
121 |
-
if ($this->baseDir === substr($absolutePath, 0, $this->baseDirLength)) {
|
122 |
-
$this->subPathname = ltrim(substr($absolutePath, $this->baseDirLength), '/\\');
|
123 |
-
$dir = dirname($this->subPathname);
|
124 |
-
$this->subPath = '.' === $dir ? '' : $dir;
|
125 |
-
} else {
|
126 |
-
$this->subPath = $this->subPathname = '';
|
127 |
-
}
|
128 |
-
|
129 |
-
$this->current = new SplFileInfo(parent::current(), $this->subPath, $this->subPathname);
|
130 |
-
}
|
131 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Iterator/FileTypeFilterIterator.php
DELETED
@@ -1,55 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Iterator;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* FileTypeFilterIterator only keeps files, directories, or both.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
*/
|
19 |
-
class FileTypeFilterIterator extends FilterIterator
|
20 |
-
{
|
21 |
-
const ONLY_FILES = 1;
|
22 |
-
const ONLY_DIRECTORIES = 2;
|
23 |
-
|
24 |
-
private $mode;
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Constructor.
|
28 |
-
*
|
29 |
-
* @param \Iterator $iterator The Iterator to filter
|
30 |
-
* @param int $mode The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES)
|
31 |
-
*/
|
32 |
-
public function __construct(\Iterator $iterator, $mode)
|
33 |
-
{
|
34 |
-
$this->mode = $mode;
|
35 |
-
|
36 |
-
parent::__construct($iterator);
|
37 |
-
}
|
38 |
-
|
39 |
-
/**
|
40 |
-
* Filters the iterator values.
|
41 |
-
*
|
42 |
-
* @return bool true if the value should be kept, false otherwise
|
43 |
-
*/
|
44 |
-
public function accept()
|
45 |
-
{
|
46 |
-
$fileinfo = $this->current();
|
47 |
-
if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {
|
48 |
-
return false;
|
49 |
-
} elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) {
|
50 |
-
return false;
|
51 |
-
}
|
52 |
-
|
53 |
-
return true;
|
54 |
-
}
|
55 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilecontentFilterIterator.php
DELETED
@@ -1,76 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Iterator;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* FilecontentFilterIterator filters files by their contents using patterns (regexps or strings).
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
* @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
|
19 |
-
*/
|
20 |
-
class FilecontentFilterIterator extends MultiplePcreFilterIterator
|
21 |
-
{
|
22 |
-
/**
|
23 |
-
* Filters the iterator values.
|
24 |
-
*
|
25 |
-
* @return bool true if the value should be kept, false otherwise
|
26 |
-
*/
|
27 |
-
public function accept()
|
28 |
-
{
|
29 |
-
if (!$this->matchRegexps && !$this->noMatchRegexps) {
|
30 |
-
return true;
|
31 |
-
}
|
32 |
-
|
33 |
-
$fileinfo = $this->current();
|
34 |
-
|
35 |
-
if ($fileinfo->isDir() || !$fileinfo->isReadable()) {
|
36 |
-
return false;
|
37 |
-
}
|
38 |
-
|
39 |
-
$content = $fileinfo->getContents();
|
40 |
-
if (!$content) {
|
41 |
-
return false;
|
42 |
-
}
|
43 |
-
|
44 |
-
// should at least not match one rule to exclude
|
45 |
-
foreach ($this->noMatchRegexps as $regex) {
|
46 |
-
if (preg_match($regex, $content)) {
|
47 |
-
return false;
|
48 |
-
}
|
49 |
-
}
|
50 |
-
|
51 |
-
// should at least match one rule
|
52 |
-
$match = true;
|
53 |
-
if ($this->matchRegexps) {
|
54 |
-
$match = false;
|
55 |
-
foreach ($this->matchRegexps as $regex) {
|
56 |
-
if (preg_match($regex, $content)) {
|
57 |
-
return true;
|
58 |
-
}
|
59 |
-
}
|
60 |
-
}
|
61 |
-
|
62 |
-
return $match;
|
63 |
-
}
|
64 |
-
|
65 |
-
/**
|
66 |
-
* Converts string to regexp if necessary.
|
67 |
-
*
|
68 |
-
* @param string $str Pattern: string or regexp
|
69 |
-
*
|
70 |
-
* @return string regexp corresponding to a given string or regexp
|
71 |
-
*/
|
72 |
-
protected function toRegex($str)
|
73 |
-
{
|
74 |
-
return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
|
75 |
-
}
|
76 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilenameFilterIterator.php
DELETED
@@ -1,67 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Iterator;
|
13 |
-
|
14 |
-
use Symfony\Component\Finder\Expression\Expression;
|
15 |
-
|
16 |
-
/**
|
17 |
-
* FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string).
|
18 |
-
*
|
19 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
20 |
-
*/
|
21 |
-
class FilenameFilterIterator extends MultiplePcreFilterIterator
|
22 |
-
{
|
23 |
-
/**
|
24 |
-
* Filters the iterator values.
|
25 |
-
*
|
26 |
-
* @return bool true if the value should be kept, false otherwise
|
27 |
-
*/
|
28 |
-
public function accept()
|
29 |
-
{
|
30 |
-
$filename = $this->current()->getFilename();
|
31 |
-
|
32 |
-
// should at least not match one rule to exclude
|
33 |
-
foreach ($this->noMatchRegexps as $regex) {
|
34 |
-
if (preg_match($regex, $filename)) {
|
35 |
-
return false;
|
36 |
-
}
|
37 |
-
}
|
38 |
-
|
39 |
-
// should at least match one rule
|
40 |
-
$match = true;
|
41 |
-
if ($this->matchRegexps) {
|
42 |
-
$match = false;
|
43 |
-
foreach ($this->matchRegexps as $regex) {
|
44 |
-
if (preg_match($regex, $filename)) {
|
45 |
-
return true;
|
46 |
-
}
|
47 |
-
}
|
48 |
-
}
|
49 |
-
|
50 |
-
return $match;
|
51 |
-
}
|
52 |
-
|
53 |
-
/**
|
54 |
-
* Converts glob to regexp.
|
55 |
-
*
|
56 |
-
* PCRE patterns are left unchanged.
|
57 |
-
* Glob strings are transformed with Glob::toRegex().
|
58 |
-
*
|
59 |
-
* @param string $str Pattern: glob or regexp
|
60 |
-
*
|
61 |
-
* @return string regexp corresponding to a given glob or regexp
|
62 |
-
*/
|
63 |
-
protected function toRegex($str)
|
64 |
-
{
|
65 |
-
return Expression::create($str)->getRegex()->render();
|
66 |
-
}
|
67 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilterIterator.php
DELETED
@@ -1,49 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Iterator;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* This iterator just overrides the rewind method in order to correct a PHP bug.
|
16 |
-
*
|
17 |
-
* @see https://bugs.php.net/bug.php?id=49104
|
18 |
-
*
|
19 |
-
* @author Alex Bogomazov
|
20 |
-
*/
|
21 |
-
abstract class FilterIterator extends \FilterIterator
|
22 |
-
{
|
23 |
-
/**
|
24 |
-
* This is a workaround for the problem with \FilterIterator leaving inner \FilesystemIterator in wrong state after
|
25 |
-
* rewind in some cases.
|
26 |
-
*
|
27 |
-
* @see FilterIterator::rewind()
|
28 |
-
*/
|
29 |
-
public function rewind()
|
30 |
-
{
|
31 |
-
$iterator = $this;
|
32 |
-
while ($iterator instanceof \OuterIterator) {
|
33 |
-
$innerIterator = $iterator->getInnerIterator();
|
34 |
-
|
35 |
-
if ($innerIterator instanceof RecursiveDirectoryIterator) {
|
36 |
-
if ($innerIterator->isRewindable()) {
|
37 |
-
$innerIterator->next();
|
38 |
-
$innerIterator->rewind();
|
39 |
-
}
|
40 |
-
} elseif ($iterator->getInnerIterator() instanceof \FilesystemIterator) {
|
41 |
-
$iterator->getInnerIterator()->next();
|
42 |
-
$iterator->getInnerIterator()->rewind();
|
43 |
-
}
|
44 |
-
$iterator = $iterator->getInnerIterator();
|
45 |
-
}
|
46 |
-
|
47 |
-
parent::rewind();
|
48 |
-
}
|
49 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Iterator/MultiplePcreFilterIterator.php
DELETED
@@ -1,66 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Iterator;
|
13 |
-
|
14 |
-
use Symfony\Component\Finder\Expression\Expression;
|
15 |
-
|
16 |
-
/**
|
17 |
-
* MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings).
|
18 |
-
*
|
19 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
20 |
-
*/
|
21 |
-
abstract class MultiplePcreFilterIterator extends FilterIterator
|
22 |
-
{
|
23 |
-
protected $matchRegexps = array();
|
24 |
-
protected $noMatchRegexps = array();
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Constructor.
|
28 |
-
*
|
29 |
-
* @param \Iterator $iterator The Iterator to filter
|
30 |
-
* @param array $matchPatterns An array of patterns that need to match
|
31 |
-
* @param array $noMatchPatterns An array of patterns that need to not match
|
32 |
-
*/
|
33 |
-
public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
|
34 |
-
{
|
35 |
-
foreach ($matchPatterns as $pattern) {
|
36 |
-
$this->matchRegexps[] = $this->toRegex($pattern);
|
37 |
-
}
|
38 |
-
|
39 |
-
foreach ($noMatchPatterns as $pattern) {
|
40 |
-
$this->noMatchRegexps[] = $this->toRegex($pattern);
|
41 |
-
}
|
42 |
-
|
43 |
-
parent::__construct($iterator);
|
44 |
-
}
|
45 |
-
|
46 |
-
/**
|
47 |
-
* Checks whether the string is a regex.
|
48 |
-
*
|
49 |
-
* @param string $str
|
50 |
-
*
|
51 |
-
* @return bool Whether the given string is a regex
|
52 |
-
*/
|
53 |
-
protected function isRegex($str)
|
54 |
-
{
|
55 |
-
return Expression::create($str)->isRegex();
|
56 |
-
}
|
57 |
-
|
58 |
-
/**
|
59 |
-
* Converts string into regexp.
|
60 |
-
*
|
61 |
-
* @param string $str Pattern
|
62 |
-
*
|
63 |
-
* @return string regexp corresponding to a given string
|
64 |
-
*/
|
65 |
-
abstract protected function toRegex($str);
|
66 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Iterator/PathFilterIterator.php
DELETED
@@ -1,74 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Iterator;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* PathFilterIterator filters files by path patterns (e.g. some/special/dir).
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
* @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
|
19 |
-
*/
|
20 |
-
class PathFilterIterator extends MultiplePcreFilterIterator
|
21 |
-
{
|
22 |
-
/**
|
23 |
-
* Filters the iterator values.
|
24 |
-
*
|
25 |
-
* @return bool true if the value should be kept, false otherwise
|
26 |
-
*/
|
27 |
-
public function accept()
|
28 |
-
{
|
29 |
-
$filename = $this->current()->getRelativePathname();
|
30 |
-
|
31 |
-
if ('\\' === DIRECTORY_SEPARATOR) {
|
32 |
-
$filename = strtr($filename, '\\', '/');
|
33 |
-
}
|
34 |
-
|
35 |
-
// should at least not match one rule to exclude
|
36 |
-
foreach ($this->noMatchRegexps as $regex) {
|
37 |
-
if (preg_match($regex, $filename)) {
|
38 |
-
return false;
|
39 |
-
}
|
40 |
-
}
|
41 |
-
|
42 |
-
// should at least match one rule
|
43 |
-
$match = true;
|
44 |
-
if ($this->matchRegexps) {
|
45 |
-
$match = false;
|
46 |
-
foreach ($this->matchRegexps as $regex) {
|
47 |
-
if (preg_match($regex, $filename)) {
|
48 |
-
return true;
|
49 |
-
}
|
50 |
-
}
|
51 |
-
}
|
52 |
-
|
53 |
-
return $match;
|
54 |
-
}
|
55 |
-
|
56 |
-
/**
|
57 |
-
* Converts strings to regexp.
|
58 |
-
*
|
59 |
-
* PCRE patterns are left unchanged.
|
60 |
-
*
|
61 |
-
* Default conversion:
|
62 |
-
* 'lorem/ipsum/dolor' ==> 'lorem\/ipsum\/dolor/'
|
63 |
-
*
|
64 |
-
* Use only / as directory separator (on Windows also).
|
65 |
-
*
|
66 |
-
* @param string $str Pattern: regexp or dirname.
|
67 |
-
*
|
68 |
-
* @return string regexp corresponding to a given string or regexp
|
69 |
-
*/
|
70 |
-
protected function toRegex($str)
|
71 |
-
{
|
72 |
-
return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
|
73 |
-
}
|
74 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php
DELETED
@@ -1,126 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Iterator;
|
13 |
-
|
14 |
-
use Symfony\Component\Finder\Exception\AccessDeniedException;
|
15 |
-
use Symfony\Component\Finder\SplFileInfo;
|
16 |
-
|
17 |
-
/**
|
18 |
-
* Extends the \RecursiveDirectoryIterator to support relative paths.
|
19 |
-
*
|
20 |
-
* @author Victor Berchet <victor@suumit.com>
|
21 |
-
*/
|
22 |
-
class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
|
23 |
-
{
|
24 |
-
/**
|
25 |
-
* @var bool
|
26 |
-
*/
|
27 |
-
private $ignoreUnreadableDirs;
|
28 |
-
|
29 |
-
/**
|
30 |
-
* @var bool
|
31 |
-
*/
|
32 |
-
private $rewindable;
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Constructor.
|
36 |
-
*
|
37 |
-
* @param string $path
|
38 |
-
* @param int $flags
|
39 |
-
* @param bool $ignoreUnreadableDirs
|
40 |
-
*
|
41 |
-
* @throws \RuntimeException
|
42 |
-
*/
|
43 |
-
public function __construct($path, $flags, $ignoreUnreadableDirs = false)
|
44 |
-
{
|
45 |
-
if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
|
46 |
-
throw new \RuntimeException('This iterator only support returning current as fileinfo.');
|
47 |
-
}
|
48 |
-
|
49 |
-
parent::__construct($path, $flags);
|
50 |
-
$this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
|
51 |
-
}
|
52 |
-
|
53 |
-
/**
|
54 |
-
* Return an instance of SplFileInfo with support for relative paths.
|
55 |
-
*
|
56 |
-
* @return SplFileInfo File information
|
57 |
-
*/
|
58 |
-
public function current()
|
59 |
-
{
|
60 |
-
return new SplFileInfo(parent::current()->getPathname(), $this->getSubPath(), $this->getSubPathname());
|
61 |
-
}
|
62 |
-
|
63 |
-
/**
|
64 |
-
* @return \RecursiveIterator
|
65 |
-
*
|
66 |
-
* @throws AccessDeniedException
|
67 |
-
*/
|
68 |
-
public function getChildren()
|
69 |
-
{
|
70 |
-
try {
|
71 |
-
$children = parent::getChildren();
|
72 |
-
|
73 |
-
if ($children instanceof self) {
|
74 |
-
// parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore
|
75 |
-
$children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
|
76 |
-
}
|
77 |
-
|
78 |
-
return $children;
|
79 |
-
} catch (\UnexpectedValueException $e) {
|
80 |
-
if ($this->ignoreUnreadableDirs) {
|
81 |
-
// If directory is unreadable and finder is set to ignore it, a fake empty content is returned.
|
82 |
-
return new \RecursiveArrayIterator(array());
|
83 |
-
} else {
|
84 |
-
throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
|
85 |
-
}
|
86 |
-
}
|
87 |
-
}
|
88 |
-
|
89 |
-
/**
|
90 |
-
* Do nothing for non rewindable stream.
|
91 |
-
*/
|
92 |
-
public function rewind()
|
93 |
-
{
|
94 |
-
if (false === $this->isRewindable()) {
|
95 |
-
return;
|
96 |
-
}
|
97 |
-
|
98 |
-
// @see https://bugs.php.net/bug.php?id=49104
|
99 |
-
parent::next();
|
100 |
-
|
101 |
-
parent::rewind();
|
102 |
-
}
|
103 |
-
|
104 |
-
/**
|
105 |
-
* Checks if the stream is rewindable.
|
106 |
-
*
|
107 |
-
* @return bool true when the stream is rewindable, false otherwise
|
108 |
-
*/
|
109 |
-
public function isRewindable()
|
110 |
-
{
|
111 |
-
if (null !== $this->rewindable) {
|
112 |
-
return $this->rewindable;
|
113 |
-
}
|
114 |
-
|
115 |
-
if (false !== $stream = @opendir($this->getPath())) {
|
116 |
-
$infos = stream_get_meta_data($stream);
|
117 |
-
closedir($stream);
|
118 |
-
|
119 |
-
if ($infos['seekable']) {
|
120 |
-
return $this->rewindable = true;
|
121 |
-
}
|
122 |
-
}
|
123 |
-
|
124 |
-
return $this->rewindable = false;
|
125 |
-
}
|
126 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Iterator/SizeRangeFilterIterator.php
DELETED
@@ -1,59 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Iterator;
|
13 |
-
|
14 |
-
use Symfony\Component\Finder\Comparator\NumberComparator;
|
15 |
-
|
16 |
-
/**
|
17 |
-
* SizeRangeFilterIterator filters out files that are not in the given size range.
|
18 |
-
*
|
19 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
20 |
-
*/
|
21 |
-
class SizeRangeFilterIterator extends FilterIterator
|
22 |
-
{
|
23 |
-
private $comparators = array();
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Constructor.
|
27 |
-
*
|
28 |
-
* @param \Iterator $iterator The Iterator to filter
|
29 |
-
* @param NumberComparator[] $comparators An array of NumberComparator instances
|
30 |
-
*/
|
31 |
-
public function __construct(\Iterator $iterator, array $comparators)
|
32 |
-
{
|
33 |
-
$this->comparators = $comparators;
|
34 |
-
|
35 |
-
parent::__construct($iterator);
|
36 |
-
}
|
37 |
-
|
38 |
-
/**
|
39 |
-
* Filters the iterator values.
|
40 |
-
*
|
41 |
-
* @return bool true if the value should be kept, false otherwise
|
42 |
-
*/
|
43 |
-
public function accept()
|
44 |
-
{
|
45 |
-
$fileinfo = $this->current();
|
46 |
-
if (!$fileinfo->isFile()) {
|
47 |
-
return true;
|
48 |
-
}
|
49 |
-
|
50 |
-
$filesize = $fileinfo->getSize();
|
51 |
-
foreach ($this->comparators as $compare) {
|
52 |
-
if (!$compare->test($filesize)) {
|
53 |
-
return false;
|
54 |
-
}
|
55 |
-
}
|
56 |
-
|
57 |
-
return true;
|
58 |
-
}
|
59 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Iterator/SortableIterator.php
DELETED
@@ -1,82 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Iterator;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* SortableIterator applies a sort on a given Iterator.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
*/
|
19 |
-
class SortableIterator implements \IteratorAggregate
|
20 |
-
{
|
21 |
-
const SORT_BY_NAME = 1;
|
22 |
-
const SORT_BY_TYPE = 2;
|
23 |
-
const SORT_BY_ACCESSED_TIME = 3;
|
24 |
-
const SORT_BY_CHANGED_TIME = 4;
|
25 |
-
const SORT_BY_MODIFIED_TIME = 5;
|
26 |
-
|
27 |
-
private $iterator;
|
28 |
-
private $sort;
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Constructor.
|
32 |
-
*
|
33 |
-
* @param \Traversable $iterator The Iterator to filter
|
34 |
-
* @param int|callable $sort The sort type (SORT_BY_NAME, SORT_BY_TYPE, or a PHP callback)
|
35 |
-
*
|
36 |
-
* @throws \InvalidArgumentException
|
37 |
-
*/
|
38 |
-
public function __construct(\Traversable $iterator, $sort)
|
39 |
-
{
|
40 |
-
$this->iterator = $iterator;
|
41 |
-
|
42 |
-
if (self::SORT_BY_NAME === $sort) {
|
43 |
-
$this->sort = function ($a, $b) {
|
44 |
-
return strcmp($a->getRealpath(), $b->getRealpath());
|
45 |
-
};
|
46 |
-
} elseif (self::SORT_BY_TYPE === $sort) {
|
47 |
-
$this->sort = function ($a, $b) {
|
48 |
-
if ($a->isDir() && $b->isFile()) {
|
49 |
-
return -1;
|
50 |
-
} elseif ($a->isFile() && $b->isDir()) {
|
51 |
-
return 1;
|
52 |
-
}
|
53 |
-
|
54 |
-
return strcmp($a->getRealpath(), $b->getRealpath());
|
55 |
-
};
|
56 |
-
} elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
|
57 |
-
$this->sort = function ($a, $b) {
|
58 |
-
return ($a->getATime() - $b->getATime());
|
59 |
-
};
|
60 |
-
} elseif (self::SORT_BY_CHANGED_TIME === $sort) {
|
61 |
-
$this->sort = function ($a, $b) {
|
62 |
-
return ($a->getCTime() - $b->getCTime());
|
63 |
-
};
|
64 |
-
} elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
|
65 |
-
$this->sort = function ($a, $b) {
|
66 |
-
return ($a->getMTime() - $b->getMTime());
|
67 |
-
};
|
68 |
-
} elseif (is_callable($sort)) {
|
69 |
-
$this->sort = $sort;
|
70 |
-
} else {
|
71 |
-
throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
|
72 |
-
}
|
73 |
-
}
|
74 |
-
|
75 |
-
public function getIterator()
|
76 |
-
{
|
77 |
-
$array = iterator_to_array($this->iterator, true);
|
78 |
-
uasort($array, $this->sort);
|
79 |
-
|
80 |
-
return new \ArrayIterator($array);
|
81 |
-
}
|
82 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/LICENSE
DELETED
@@ -1,19 +0,0 @@
|
|
1 |
-
Copyright (c) 2004-2015 Fabien Potencier
|
2 |
-
|
3 |
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4 |
-
of this software and associated documentation files (the "Software"), to deal
|
5 |
-
in the Software without restriction, including without limitation the rights
|
6 |
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7 |
-
copies of the Software, and to permit persons to whom the Software is furnished
|
8 |
-
to do so, subject to the following conditions:
|
9 |
-
|
10 |
-
The above copyright notice and this permission notice shall be included in all
|
11 |
-
copies or substantial portions of the Software.
|
12 |
-
|
13 |
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14 |
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15 |
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16 |
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17 |
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18 |
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19 |
-
THE SOFTWARE.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/README.md
DELETED
@@ -1,53 +0,0 @@
|
|
1 |
-
Finder Component
|
2 |
-
================
|
3 |
-
|
4 |
-
Finder finds files and directories via an intuitive fluent interface.
|
5 |
-
|
6 |
-
```php
|
7 |
-
use Symfony\Component\Finder\Finder;
|
8 |
-
|
9 |
-
$finder = new Finder();
|
10 |
-
|
11 |
-
$iterator = $finder
|
12 |
-
->files()
|
13 |
-
->name('*.php')
|
14 |
-
->depth(0)
|
15 |
-
->size('>= 1K')
|
16 |
-
->in(__DIR__);
|
17 |
-
|
18 |
-
foreach ($iterator as $file) {
|
19 |
-
print $file->getRealpath()."\n";
|
20 |
-
}
|
21 |
-
```
|
22 |
-
|
23 |
-
The iterator returns instances of [Symfony\Component\Finder\SplFileInfo\SplFileInfo][1].
|
24 |
-
Besides the build-in methods inherited from [\SplFileInfo][2] (`getPerms()`, `getSize()`, ...),
|
25 |
-
you can also use `getRelativePath()` and `getRelativePathname()`. Read the
|
26 |
-
[official documentation][3] for more information.
|
27 |
-
|
28 |
-
But you can also use it to find files stored remotely like in this example where
|
29 |
-
we are looking for files on Amazon S3:
|
30 |
-
|
31 |
-
```php
|
32 |
-
$s3 = new \Zend_Service_Amazon_S3($key, $secret);
|
33 |
-
$s3->registerStreamWrapper("s3");
|
34 |
-
|
35 |
-
$finder = new Finder();
|
36 |
-
$finder->name('photos*')->size('< 100K')->date('since 1 hour ago');
|
37 |
-
foreach ($finder->in('s3://bucket-name') as $file) {
|
38 |
-
print $file->getFilename()."\n";
|
39 |
-
}
|
40 |
-
```
|
41 |
-
|
42 |
-
Resources
|
43 |
-
---------
|
44 |
-
|
45 |
-
You can run the unit tests with the following command:
|
46 |
-
|
47 |
-
$ cd path/to/Symfony/Component/Finder/
|
48 |
-
$ composer.phar install
|
49 |
-
$ phpunit
|
50 |
-
|
51 |
-
[1]: http://api.symfony.com/2.5/Symfony/Component/Finder/SplFileInfo.html
|
52 |
-
[2]: http://php.net/splfileinfo
|
53 |
-
[3]: http://symfony.com/doc/current/components/finder.html#usage
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Shell/Command.php
DELETED
@@ -1,294 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Shell;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
16 |
-
*/
|
17 |
-
class Command
|
18 |
-
{
|
19 |
-
/**
|
20 |
-
* @var Command|null
|
21 |
-
*/
|
22 |
-
private $parent;
|
23 |
-
|
24 |
-
/**
|
25 |
-
* @var array
|
26 |
-
*/
|
27 |
-
private $bits = array();
|
28 |
-
|
29 |
-
/**
|
30 |
-
* @var array
|
31 |
-
*/
|
32 |
-
private $labels = array();
|
33 |
-
|
34 |
-
/**
|
35 |
-
* @var \Closure|null
|
36 |
-
*/
|
37 |
-
private $errorHandler;
|
38 |
-
|
39 |
-
/**
|
40 |
-
* Constructor.
|
41 |
-
*
|
42 |
-
* @param Command|null $parent Parent command
|
43 |
-
*/
|
44 |
-
public function __construct(Command $parent = null)
|
45 |
-
{
|
46 |
-
$this->parent = $parent;
|
47 |
-
}
|
48 |
-
|
49 |
-
/**
|
50 |
-
* Returns command as string.
|
51 |
-
*
|
52 |
-
* @return string
|
53 |
-
*/
|
54 |
-
public function __toString()
|
55 |
-
{
|
56 |
-
return $this->join();
|
57 |
-
}
|
58 |
-
|
59 |
-
/**
|
60 |
-
* Creates a new Command instance.
|
61 |
-
*
|
62 |
-
* @param Command|null $parent Parent command
|
63 |
-
*
|
64 |
-
* @return Command New Command instance
|
65 |
-
*/
|
66 |
-
public static function create(Command $parent = null)
|
67 |
-
{
|
68 |
-
return new self($parent);
|
69 |
-
}
|
70 |
-
|
71 |
-
/**
|
72 |
-
* Escapes special chars from input.
|
73 |
-
*
|
74 |
-
* @param string $input A string to escape
|
75 |
-
*
|
76 |
-
* @return string The escaped string
|
77 |
-
*/
|
78 |
-
public static function escape($input)
|
79 |
-
{
|
80 |
-
return escapeshellcmd($input);
|
81 |
-
}
|
82 |
-
|
83 |
-
/**
|
84 |
-
* Quotes input.
|
85 |
-
*
|
86 |
-
* @param string $input An argument string
|
87 |
-
*
|
88 |
-
* @return string The quoted string
|
89 |
-
*/
|
90 |
-
public static function quote($input)
|
91 |
-
{
|
92 |
-
return escapeshellarg($input);
|
93 |
-
}
|
94 |
-
|
95 |
-
/**
|
96 |
-
* Appends a string or a Command instance.
|
97 |
-
*
|
98 |
-
* @param string|Command $bit
|
99 |
-
*
|
100 |
-
* @return Command The current Command instance
|
101 |
-
*/
|
102 |
-
public function add($bit)
|
103 |
-
{
|
104 |
-
$this->bits[] = $bit;
|
105 |
-
|
106 |
-
return $this;
|
107 |
-
}
|
108 |
-
|
109 |
-
/**
|
110 |
-
* Prepends a string or a command instance.
|
111 |
-
*
|
112 |
-
* @param string|Command $bit
|
113 |
-
*
|
114 |
-
* @return Command The current Command instance
|
115 |
-
*/
|
116 |
-
public function top($bit)
|
117 |
-
{
|
118 |
-
array_unshift($this->bits, $bit);
|
119 |
-
|
120 |
-
foreach ($this->labels as $label => $index) {
|
121 |
-
$this->labels[$label] += 1;
|
122 |
-
}
|
123 |
-
|
124 |
-
return $this;
|
125 |
-
}
|
126 |
-
|
127 |
-
/**
|
128 |
-
* Appends an argument, will be quoted.
|
129 |
-
*
|
130 |
-
* @param string $arg
|
131 |
-
*
|
132 |
-
* @return Command The current Command instance
|
133 |
-
*/
|
134 |
-
public function arg($arg)
|
135 |
-
{
|
136 |
-
$this->bits[] = self::quote($arg);
|
137 |
-
|
138 |
-
return $this;
|
139 |
-
}
|
140 |
-
|
141 |
-
/**
|
142 |
-
* Appends escaped special command chars.
|
143 |
-
*
|
144 |
-
* @param string $esc
|
145 |
-
*
|
146 |
-
* @return Command The current Command instance
|
147 |
-
*/
|
148 |
-
public function cmd($esc)
|
149 |
-
{
|
150 |
-
$this->bits[] = self::escape($esc);
|
151 |
-
|
152 |
-
return $this;
|
153 |
-
}
|
154 |
-
|
155 |
-
/**
|
156 |
-
* Inserts a labeled command to feed later.
|
157 |
-
*
|
158 |
-
* @param string $label The unique label
|
159 |
-
*
|
160 |
-
* @return Command The current Command instance
|
161 |
-
*
|
162 |
-
* @throws \RuntimeException If label already exists
|
163 |
-
*/
|
164 |
-
public function ins($label)
|
165 |
-
{
|
166 |
-
if (isset($this->labels[$label])) {
|
167 |
-
throw new \RuntimeException(sprintf('Label "%s" already exists.', $label));
|
168 |
-
}
|
169 |
-
|
170 |
-
$this->bits[] = self::create($this);
|
171 |
-
$this->labels[$label] = count($this->bits)-1;
|
172 |
-
|
173 |
-
return $this->bits[$this->labels[$label]];
|
174 |
-
}
|
175 |
-
|
176 |
-
/**
|
177 |
-
* Retrieves a previously labeled command.
|
178 |
-
*
|
179 |
-
* @param string $label
|
180 |
-
*
|
181 |
-
* @return Command The labeled command
|
182 |
-
*
|
183 |
-
* @throws \RuntimeException
|
184 |
-
*/
|
185 |
-
public function get($label)
|
186 |
-
{
|
187 |
-
if (!isset($this->labels[$label])) {
|
188 |
-
throw new \RuntimeException(sprintf('Label "%s" does not exist.', $label));
|
189 |
-
}
|
190 |
-
|
191 |
-
return $this->bits[$this->labels[$label]];
|
192 |
-
}
|
193 |
-
|
194 |
-
/**
|
195 |
-
* Returns parent command (if any).
|
196 |
-
*
|
197 |
-
* @return Command Parent command
|
198 |
-
*
|
199 |
-
* @throws \RuntimeException If command has no parent
|
200 |
-
*/
|
201 |
-
public function end()
|
202 |
-
{
|
203 |
-
if (null === $this->parent) {
|
204 |
-
throw new \RuntimeException('Calling end on root command doesn\'t make sense.');
|
205 |
-
}
|
206 |
-
|
207 |
-
return $this->parent;
|
208 |
-
}
|
209 |
-
|
210 |
-
/**
|
211 |
-
* Counts bits stored in command.
|
212 |
-
*
|
213 |
-
* @return int The bits count
|
214 |
-
*/
|
215 |
-
public function length()
|
216 |
-
{
|
217 |
-
return count($this->bits);
|
218 |
-
}
|
219 |
-
|
220 |
-
/**
|
221 |
-
* @param \Closure $errorHandler
|
222 |
-
*
|
223 |
-
* @return Command
|
224 |
-
*/
|
225 |
-
public function setErrorHandler(\Closure $errorHandler)
|
226 |
-
{
|
227 |
-
$this->errorHandler = $errorHandler;
|
228 |
-
|
229 |
-
return $this;
|
230 |
-
}
|
231 |
-
|
232 |
-
/**
|
233 |
-
* @return \Closure|null
|
234 |
-
*/
|
235 |
-
public function getErrorHandler()
|
236 |
-
{
|
237 |
-
return $this->errorHandler;
|
238 |
-
}
|
239 |
-
|
240 |
-
/**
|
241 |
-
* Executes current command.
|
242 |
-
*
|
243 |
-
* @return array The command result
|
244 |
-
*
|
245 |
-
* @throws \RuntimeException
|
246 |
-
*/
|
247 |
-
public function execute()
|
248 |
-
{
|
249 |
-
if (null === $errorHandler = $this->errorHandler) {
|
250 |
-
exec($this->join(), $output);
|
251 |
-
} else {
|
252 |
-
$process = proc_open($this->join(), array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $pipes);
|
253 |
-
$output = preg_split('~(\r\n|\r|\n)~', stream_get_contents($pipes[1]), -1, PREG_SPLIT_NO_EMPTY);
|
254 |
-
|
255 |
-
if ($error = stream_get_contents($pipes[2])) {
|
256 |
-
$errorHandler($error);
|
257 |
-
}
|
258 |
-
|
259 |
-
proc_close($process);
|
260 |
-
}
|
261 |
-
|
262 |
-
return $output ?: array();
|
263 |
-
}
|
264 |
-
|
265 |
-
/**
|
266 |
-
* Joins bits.
|
267 |
-
*
|
268 |
-
* @return string
|
269 |
-
*/
|
270 |
-
public function join()
|
271 |
-
{
|
272 |
-
return implode(' ', array_filter(
|
273 |
-
array_map(function ($bit) {
|
274 |
-
return $bit instanceof Command ? $bit->join() : ($bit ?: null);
|
275 |
-
}, $this->bits),
|
276 |
-
function ($bit) { return null !== $bit; }
|
277 |
-
));
|
278 |
-
}
|
279 |
-
|
280 |
-
/**
|
281 |
-
* Insert a string or a Command instance before the bit at given position $index (index starts from 0).
|
282 |
-
*
|
283 |
-
* @param string|Command $bit
|
284 |
-
* @param int $index
|
285 |
-
*
|
286 |
-
* @return Command The current Command instance
|
287 |
-
*/
|
288 |
-
public function addAtIndex($bit, $index)
|
289 |
-
{
|
290 |
-
array_splice($this->bits, $index, 0, $bit);
|
291 |
-
|
292 |
-
return $this;
|
293 |
-
}
|
294 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/Shell/Shell.php
DELETED
@@ -1,97 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder\Shell;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @author Jean-François Simon <contact@jfsimon.fr>
|
16 |
-
*/
|
17 |
-
class Shell
|
18 |
-
{
|
19 |
-
const TYPE_UNIX = 1;
|
20 |
-
const TYPE_DARWIN = 2;
|
21 |
-
const TYPE_CYGWIN = 3;
|
22 |
-
const TYPE_WINDOWS = 4;
|
23 |
-
const TYPE_BSD = 5;
|
24 |
-
|
25 |
-
/**
|
26 |
-
* @var string|null
|
27 |
-
*/
|
28 |
-
private $type;
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Returns guessed OS type.
|
32 |
-
*
|
33 |
-
* @return int
|
34 |
-
*/
|
35 |
-
public function getType()
|
36 |
-
{
|
37 |
-
if (null === $this->type) {
|
38 |
-
$this->type = $this->guessType();
|
39 |
-
}
|
40 |
-
|
41 |
-
return $this->type;
|
42 |
-
}
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Tests if a command is available.
|
46 |
-
*
|
47 |
-
* @param string $command
|
48 |
-
*
|
49 |
-
* @return bool
|
50 |
-
*/
|
51 |
-
public function testCommand($command)
|
52 |
-
{
|
53 |
-
if (!function_exists('exec')) {
|
54 |
-
return false;
|
55 |
-
}
|
56 |
-
|
57 |
-
// todo: find a better way (command could not be available)
|
58 |
-
$testCommand = 'which ';
|
59 |
-
if (self::TYPE_WINDOWS === $this->type) {
|
60 |
-
$testCommand = 'where ';
|
61 |
-
}
|
62 |
-
|
63 |
-
$command = escapeshellcmd($command);
|
64 |
-
|
65 |
-
exec($testCommand.$command, $output, $code);
|
66 |
-
|
67 |
-
return 0 === $code && count($output) > 0;
|
68 |
-
}
|
69 |
-
|
70 |
-
/**
|
71 |
-
* Guesses OS type.
|
72 |
-
*
|
73 |
-
* @return int
|
74 |
-
*/
|
75 |
-
private function guessType()
|
76 |
-
{
|
77 |
-
$os = strtolower(PHP_OS);
|
78 |
-
|
79 |
-
if (false !== strpos($os, 'cygwin')) {
|
80 |
-
return self::TYPE_CYGWIN;
|
81 |
-
}
|
82 |
-
|
83 |
-
if (false !== strpos($os, 'darwin')) {
|
84 |
-
return self::TYPE_DARWIN;
|
85 |
-
}
|
86 |
-
|
87 |
-
if (false !== strpos($os, 'bsd')) {
|
88 |
-
return self::TYPE_BSD;
|
89 |
-
}
|
90 |
-
|
91 |
-
if (0 === strpos($os, 'win')) {
|
92 |
-
return self::TYPE_WINDOWS;
|
93 |
-
}
|
94 |
-
|
95 |
-
return self::TYPE_UNIX;
|
96 |
-
}
|
97 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/SplFileInfo.php
DELETED
@@ -1,77 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of the Symfony package.
|
5 |
-
*
|
6 |
-
* (c) Fabien Potencier <fabien@symfony.com>
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
namespace Symfony\Component\Finder;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Extends \SplFileInfo to support relative paths.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
*/
|
19 |
-
class SplFileInfo extends \SplFileInfo
|
20 |
-
{
|
21 |
-
private $relativePath;
|
22 |
-
private $relativePathname;
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Constructor.
|
26 |
-
*
|
27 |
-
* @param string $file The file name
|
28 |
-
* @param string $relativePath The relative path
|
29 |
-
* @param string $relativePathname The relative path name
|
30 |
-
*/
|
31 |
-
public function __construct($file, $relativePath, $relativePathname)
|
32 |
-
{
|
33 |
-
parent::__construct($file);
|
34 |
-
$this->relativePath = $relativePath;
|
35 |
-
$this->relativePathname = $relativePathname;
|
36 |
-
}
|
37 |
-
|
38 |
-
/**
|
39 |
-
* Returns the relative path.
|
40 |
-
*
|
41 |
-
* @return string the relative path
|
42 |
-
*/
|
43 |
-
public function getRelativePath()
|
44 |
-
{
|
45 |
-
return $this->relativePath;
|
46 |
-
}
|
47 |
-
|
48 |
-
/**
|
49 |
-
* Returns the relative path name.
|
50 |
-
*
|
51 |
-
* @return string the relative path name
|
52 |
-
*/
|
53 |
-
public function getRelativePathname()
|
54 |
-
{
|
55 |
-
return $this->relativePathname;
|
56 |
-
}
|
57 |
-
|
58 |
-
/**
|
59 |
-
* Returns the contents of the file.
|
60 |
-
*
|
61 |
-
* @return string the contents of the file
|
62 |
-
*
|
63 |
-
* @throws \RuntimeException
|
64 |
-
*/
|
65 |
-
public function getContents()
|
66 |
-
{
|
67 |
-
$level = error_reporting(0);
|
68 |
-
$content = file_get_contents($this->getPathname());
|
69 |
-
error_reporting($level);
|
70 |
-
if (false === $content) {
|
71 |
-
$error = error_get_last();
|
72 |
-
throw new \RuntimeException($error['message']);
|
73 |
-
}
|
74 |
-
|
75 |
-
return $content;
|
76 |
-
}
|
77 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/composer.json
DELETED
@@ -1,31 +0,0 @@
|
|
1 |
-
{
|
2 |
-
"name": "symfony/finder",
|
3 |
-
"type": "library",
|
4 |
-
"description": "Symfony Finder Component",
|
5 |
-
"keywords": [],
|
6 |
-
"homepage": "http://symfony.com",
|
7 |
-
"license": "MIT",
|
8 |
-
"authors": [
|
9 |
-
{
|
10 |
-
"name": "Fabien Potencier",
|
11 |
-
"email": "fabien@symfony.com"
|
12 |
-
},
|
13 |
-
{
|
14 |
-
"name": "Symfony Community",
|
15 |
-
"homepage": "http://symfony.com/contributors"
|
16 |
-
}
|
17 |
-
],
|
18 |
-
"require": {
|
19 |
-
"php": ">=5.3.3"
|
20 |
-
},
|
21 |
-
"autoload": {
|
22 |
-
"psr-0": { "Symfony\\Component\\Finder\\": "" }
|
23 |
-
},
|
24 |
-
"target-dir": "Symfony/Component/Finder",
|
25 |
-
"minimum-stability": "dev",
|
26 |
-
"extra": {
|
27 |
-
"branch-alias": {
|
28 |
-
"dev-master": "2.6-dev"
|
29 |
-
}
|
30 |
-
}
|
31 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/Symfony/Component/Finder/phpunit.xml.dist
DELETED
@@ -1,28 +0,0 @@
|
|
1 |
-
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
-
|
3 |
-
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
4 |
-
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
|
5 |
-
backupGlobals="false"
|
6 |
-
colors="true"
|
7 |
-
bootstrap="vendor/autoload.php"
|
8 |
-
>
|
9 |
-
<php>
|
10 |
-
<!-- Silence E_USER_DEPRECATED (-16385 == -1 & ~E_USER_DEPRECATED) -->
|
11 |
-
<ini name="error_reporting" value="-16385"/>
|
12 |
-
</php>
|
13 |
-
<testsuites>
|
14 |
-
<testsuite name="Symfony Finder Component Test Suite">
|
15 |
-
<directory>./Tests/</directory>
|
16 |
-
</testsuite>
|
17 |
-
</testsuites>
|
18 |
-
|
19 |
-
<filter>
|
20 |
-
<whitelist>
|
21 |
-
<directory>./</directory>
|
22 |
-
<exclude>
|
23 |
-
<directory>./Tests</directory>
|
24 |
-
<directory>./vendor</directory>
|
25 |
-
</exclude>
|
26 |
-
</whitelist>
|
27 |
-
</filter>
|
28 |
-
</phpunit>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vendor/symfony/finder/composer.json
CHANGED
@@ -19,12 +19,15 @@
|
|
19 |
"php": ">=5.3.9"
|
20 |
},
|
21 |
"autoload": {
|
22 |
-
"psr-4": { "Symfony\\Component\\Finder\\": "" }
|
|
|
|
|
|
|
23 |
},
|
24 |
"minimum-stability": "dev",
|
25 |
"extra": {
|
26 |
"branch-alias": {
|
27 |
-
"dev-master": "2.
|
28 |
}
|
29 |
}
|
30 |
}
|
19 |
"php": ">=5.3.9"
|
20 |
},
|
21 |
"autoload": {
|
22 |
+
"psr-4": { "Symfony\\Component\\Finder\\": "" },
|
23 |
+
"exclude-from-classmap": [
|
24 |
+
"/Tests/"
|
25 |
+
]
|
26 |
},
|
27 |
"minimum-stability": "dev",
|
28 |
"extra": {
|
29 |
"branch-alias": {
|
30 |
+
"dev-master": "2.8-dev"
|
31 |
}
|
32 |
}
|
33 |
}
|