BackUpWordPress - Version 3.10

Version Description

= 3.4 =

  • This version introduces a major refactoring of the code responsible for the core backup engine. 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 improvements to reliability.

= 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 xibodevelopment
Plugin Icon 128x128 BackUpWordPress
Version 3.10
Comparing to
See all releases

Code changes from version 3.9 to 3.10

admin/faq.php CHANGED
@@ -1,58 +1,58 @@
1
- <?php
2
- echo '<p><strong>' . __( 'Where does BackUpWordPress store the backup files?', 'backupwordpress' ) . '</strong></p>' .
3
-
4
- '<p>' . __( 'Backups are stored on your server in <code>/wp-content/backups</code>, you can change the directory.', 'backupwordpress' ). '</p>' .
5
-
6
- '<p>' . __( 'Important: By default BackUpWordPress backs up everything in your site root as well as your database, this includes any non WordPress folders that happen to be in your site root. This does mean that your backup directory can get quite large.', 'backupwordpress' ) . '</p>' .
7
-
8
- '<p><strong>' . __( 'What if I want to back up my site to another destination?', 'backupwordpress' ) . '</strong></p>' .
9
-
10
- '<p>' . __( 'We no longer sell or support the paid add-ons (e.g. for backups to Dropbox and Google Drive). It\'s certainly a good idea to backup to cloud storage to protect against server-wide risks. For this we recommend <a href="https://updraftplus.com/?afref=744" title="UpdraftPlus WordPress Backups" target="_blank">UpdraftPlus WordPress Backups</a> which can do things for free BackupWordPress Premium could do on a paid basis. Click here for <a href="https://updraftplus.com/backupwordpress/?afref=744" title="plugin comparison" target="_blank">full comparison</a>.', 'backupwordpress' ) . '</p>' .
11
-
12
- '<p><strong>' . __( 'How do I restore my site from a backup?', 'backupwordpress' ) . '</strong></p>' .
13
-
14
- '<p>' . __( 'You need to download the latest backup file either by clicking download on the backups page or via <code>FTP</code>. <code>Unzip</code> the files and upload all the files to your server overwriting your site. You can then import the database using your hosts database management tool (likely <code>phpMyAdmin</code>).', 'backupwordpress' ) . '</p>' .
15
-
16
- '<p>' . __( 'See this guide for more details - <a href="https://bwp.hmn.md/support-center/restore-backup/" title="Go to support center" target="_blank">How to restore from backup</a>.', 'backupwordpress' ) . '</p>' .
17
-
18
- '<p><strong>' . __( 'Does BackUpWordPress back up the backups directory?', 'backupwordpress' ) . '</strong></p>' .
19
-
20
- '<p>' . __( 'No.', 'backupwordpress' ) . '</p>' .
21
-
22
- '<p><strong>' . __( 'I\'m not receiving my backups by email', 'backupwordpress' ) . '</strong></p>' .
23
-
24
- '<p>' . __( 'Most servers have a filesize limit on email attachments, it\'s generally about 10mb. If your backup file is over that limit, it won\'t be sent attached to the email. Instead, you should receive an email with a link to download the backup. If you aren\'t even receiving that, then you likely have a mail issue on your server that you\'ll need to contact your host about.', 'backupwordpress' ) . '</p>' .
25
-
26
- '<p><strong>' . __( 'How many backups are stored by default?', 'backupwordpress' ) . '</strong></p>' .
27
-
28
- '<p>' . __( 'BackUpWordPress stores the last 10 backups by default.', 'backupwordpress' ) . '</p>' .
29
-
30
- '<p><strong>' . __( 'How long should a backup take?', 'backupwordpress' ) . '</strong></p>' .
31
-
32
- '<p>' . __( 'Unless your site is very large (many gigabytes) it should only take a few minutes to perform a backup. If your back up has been running for longer than an hour, it\'s safe to assume that something has gone wrong. Try de-activating and re-activating the plugin. If it keeps happening, contact support.', 'backupwordpress' ) . '</p>' .
33
-
34
- '<p><strong>' . __( 'What do I do if I get the wp-cron error message?', 'backupwordpress' ) . '</strong></p>' .
35
-
36
- '<p>' . __( 'The issue is that your <code>wp-cron.php</code> is not returning a <code>200</code> response when hit with a HTTP request originating from your own server, it could be several things. In most cases, it\'s an issue with the server / site.', 'backupwordpress' ) . '</p>' .
37
-
38
- '<p>' . __( 'There are some things you can test to confirm this is the issue.', 'backupwordpress' ) . '</p>' .
39
-
40
- '<ul><li>' . __( 'Are scheduled posts working? (They use wp-cron as well.)', 'backupwordpress' ) . '</li>' .
41
-
42
- '<li>' . __( 'Are you hosted on Heart Internet? (wp-cron may not be supported by Heart Internet, see below for work-around.)', 'backupwordpress' ) . '</li>' .
43
-
44
- '<li>' . __( 'If you click manual backup, does it work?', 'backupwordpress' ) . '</li>' .
45
-
46
- '<li>' . __( 'Try adding <code>define( \'ALTERNATE_WP_CRON\', true );</code> to your <code>wp-config.php</code>. Do automatic backups work?', 'backupwordpress' ) . '</li>' .
47
-
48
- '<li>' . __( 'Is your site private (i.e. is it behind some kind of authentication, maintenance plugin, .htaccess)? If so, wp-cron won\'t work until you remove it. If you are and you temporarily remove the authentication, do backups start working?', 'backupwordpress' ) . '</li></ul>' .
49
-
50
- '<p>' . __( 'For further help, please post on our <a href="http://wordpress.org/support/plugin/backupwordpress" title="support forums" target="_blank">support forums</a>', 'backupwordpress' ) . '</p>' .
51
-
52
- '<p><strong>' . __( 'How to get BackUpWordPress working in Heart Internet', 'backupwordpress' ) . '</strong></p>' .
53
-
54
- '<p>' . __( 'The script to be entered into the Heart Internet cPanel is: <code>/usr/bin/php5 /home/sites/yourdomain.com/public_html/wp-cron.php</code> (note the space between php5 and the location of the file). The file <code>wp-cron.php</code> <code>chmod</code> must be set to <code>711</code>.', 'backupwordpress' ) . '</p>' .
55
-
56
- '<p><strong>' . __( 'My backups seem to be failing?', 'backupwordpress' ) . '</strong></p>' .
57
-
58
- '<p>' . __( 'If your backups are failing, it\'s commonly caused by a lack of available resources on your server. To establish this is the case, exclude the complete (or parts of the) uploads folder and run a backup. If that succeeds, you know it\'s probably a server issue. If it does not succeed, you can seek further help on our <a href="http://wordpress.org/support/plugin/backupwordpress" title="support forums" target="_blank">support forums</a>', 'backupwordpress' ) . '</p>';
1
+ <?php
2
+ echo '<p><strong>' . __( 'Where does BackUpWordPress store the backup files?', 'backupwordpress' ) . '</strong></p>' .
3
+
4
+ '<p>' . __( 'Backups are stored on your server in <code>/wp-content/backups</code>, you can change the directory.', 'backupwordpress' ). '</p>' .
5
+
6
+ '<p>' . __( 'Important: By default BackUpWordPress backs up everything in your site root as well as your database, this includes any non WordPress folders that happen to be in your site root. This does mean that your backup directory can get quite large.', 'backupwordpress' ) . '</p>' .
7
+
8
+ '<p><strong>' . __( 'What if I want to back up my site to another destination?', 'backupwordpress' ) . '</strong></p>' .
9
+
10
+ '<p>' . __( 'We no longer sell or support the paid add-ons (e.g. for backups to Dropbox and Google Drive). It\'s certainly a good idea to backup to cloud storage to protect against server-wide risks. For this we recommend <a href="https://updraftplus.com/?afref=744" title="UpdraftPlus WordPress Backups" target="_blank">UpdraftPlus WordPress Backups</a> which can do things for free BackupWordPress Premium could do on a paid basis. Click here for <a href="https://updraftplus.com/backupwordpress/?afref=744" title="plugin comparison" target="_blank">full comparison</a>.', 'backupwordpress' ) . '</p>' .
11
+
12
+ '<p><strong>' . __( 'How do I restore my site from a backup?', 'backupwordpress' ) . '</strong></p>' .
13
+
14
+ '<p>' . __( 'You need to download the latest backup file either by clicking download on the backups page or via <code>FTP</code>. <code>Unzip</code> the files and upload all the files to your server overwriting your site. You can then import the database using your hosts database management tool (likely <code>phpMyAdmin</code>).', 'backupwordpress' ) . '</p>' .
15
+
16
+ '<p>' . __( 'See this guide for more details - <a href="https://bwp.hmn.md/support-center/restore-backup/" title="Go to support center" target="_blank">How to restore from backup</a>.', 'backupwordpress' ) . '</p>' .
17
+
18
+ '<p><strong>' . __( 'Does BackUpWordPress back up the backups directory?', 'backupwordpress' ) . '</strong></p>' .
19
+
20
+ '<p>' . __( 'No.', 'backupwordpress' ) . '</p>' .
21
+
22
+ '<p><strong>' . __( 'I\'m not receiving my backups by email', 'backupwordpress' ) . '</strong></p>' .
23
+
24
+ '<p>' . __( 'Most servers have a filesize limit on email attachments, it\'s generally about 10mb. If your backup file is over that limit, it won\'t be sent attached to the email. Instead, you should receive an email with a link to download the backup. If you aren\'t even receiving that, then you likely have a mail issue on your server that you\'ll need to contact your host about.', 'backupwordpress' ) . '</p>' .
25
+
26
+ '<p><strong>' . __( 'How many backups are stored by default?', 'backupwordpress' ) . '</strong></p>' .
27
+
28
+ '<p>' . __( 'BackUpWordPress stores the last 10 backups by default.', 'backupwordpress' ) . '</p>' .
29
+
30
+ '<p><strong>' . __( 'How long should a backup take?', 'backupwordpress' ) . '</strong></p>' .
31
+
32
+ '<p>' . __( 'Unless your site is very large (many gigabytes) it should only take a few minutes to perform a backup. If your back up has been running for longer than an hour, it\'s safe to assume that something has gone wrong. Try de-activating and re-activating the plugin. If it keeps happening, contact support.', 'backupwordpress' ) . '</p>' .
33
+
34
+ '<p><strong>' . __( 'What do I do if I get the wp-cron error message?', 'backupwordpress' ) . '</strong></p>' .
35
+
36
+ '<p>' . __( 'The issue is that your <code>wp-cron.php</code> is not returning a <code>200</code> response when hit with a HTTP request originating from your own server, it could be several things. In most cases, it\'s an issue with the server / site.', 'backupwordpress' ) . '</p>' .
37
+
38
+ '<p>' . __( 'There are some things you can test to confirm this is the issue.', 'backupwordpress' ) . '</p>' .
39
+
40
+ '<ul><li>' . __( 'Are scheduled posts working? (They use wp-cron as well.)', 'backupwordpress' ) . '</li>' .
41
+
42
+ '<li>' . __( 'Are you hosted on Heart Internet? (wp-cron may not be supported by Heart Internet, see below for work-around.)', 'backupwordpress' ) . '</li>' .
43
+
44
+ '<li>' . __( 'If you click manual backup, does it work?', 'backupwordpress' ) . '</li>' .
45
+
46
+ '<li>' . __( 'Try adding <code>define( \'ALTERNATE_WP_CRON\', true );</code> to your <code>wp-config.php</code>. Do automatic backups work?', 'backupwordpress' ) . '</li>' .
47
+
48
+ '<li>' . __( 'Is your site private (i.e. is it behind some kind of authentication, maintenance plugin, .htaccess)? If so, wp-cron won\'t work until you remove it. If you are and you temporarily remove the authentication, do backups start working?', 'backupwordpress' ) . '</li></ul>' .
49
+
50
+ '<p>' . __( 'For further help, please post on our <a href="http://wordpress.org/support/plugin/backupwordpress" title="support forums" target="_blank">support forums</a>', 'backupwordpress' ) . '</p>' .
51
+
52
+ '<p><strong>' . __( 'How to get BackUpWordPress working in Heart Internet', 'backupwordpress' ) . '</strong></p>' .
53
+
54
+ '<p>' . __( 'The script to be entered into the Heart Internet cPanel is: <code>/usr/bin/php5 /home/sites/yourdomain.com/public_html/wp-cron.php</code> (note the space between php5 and the location of the file). The file <code>wp-cron.php</code> <code>chmod</code> must be set to <code>711</code>.', 'backupwordpress' ) . '</p>' .
55
+
56
+ '<p><strong>' . __( 'My backups seem to be failing?', 'backupwordpress' ) . '</strong></p>' .
57
+
58
+ '<p>' . __( 'If your backups are failing, it\'s commonly caused by a lack of available resources on your server. To establish this is the case, exclude the complete (or parts of the) uploads folder and run a backup. If that succeeds, you know it\'s probably a server issue. If it does not succeed, you can seek further help on our <a href="http://wordpress.org/support/plugin/backupwordpress" title="support forums" target="_blank">support forums</a>', 'backupwordpress' ) . '</p>';
backdrop/README.md ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Backdrop
2
+ Backdrop is a simple library that does one thing: allows you to run one-off
3
+ tasks in the background.
4
+
5
+ ## How to Use
6
+ ```php
7
+ function my_awesome_function( $id ) {
8
+ // Download initial data to my site. Might take a long time!
9
+ $data = wp_remote_get( 'http://example.com/' . $id );
10
+
11
+ if ( is_wp_error( $data ) ) {
12
+ return $data;
13
+ }
14
+
15
+ update_option( 'initial_data', $data );
16
+ }
17
+
18
+ add_action( 'init', function () {
19
+ if ( ! get_option( 'initial_data' ) ) {
20
+ $task = new \HM\Backdrop\Task( 'my_awesome_function', get_current_user_id() );
21
+ $task->schedule();
22
+ }
23
+ } );
24
+ ```
25
+
26
+ ## API
27
+ ### `Task::__construct( $callback [, $...] )`
28
+ Creating a new task sets up all of the internal data for your task. Pass in your
29
+ callback followed by your arguments to the function, and Backdrop will call it
30
+ in a background process.
31
+
32
+ #### Arguments
33
+ * `$callback`: Callback method you want to use. Can be any callable type
34
+ (including object methods and static methods) **except for anonymous
35
+ functions**. Closures cannot be serialized, so they cannot be used for
36
+ Backdrop callbacks. This is an internal PHP limitation.
37
+ * `$...`: Any other arguments you'd like to pass to your callback, as variable
38
+ arguments. e.g. `new Task( 'a', 'b', 'c', 'd' )` maps to `a( 'b', 'c', 'd' )`
39
+
40
+ #### Return Value
41
+ None (constructor).
42
+
43
+ ### `Task::schedule()`
44
+ Schedules your task to run. Typically runs after your page has been rendered, in
45
+ a separate process.
46
+
47
+ Backdrop de-duplicates tasks based on the arguments passed in. For example, you
48
+ can do `new Task( 'myfunc', 1 )` on every request, and only one will be run.
49
+ After this has been run, the next call will schedule again.
50
+
51
+ To avoid this, you should pass in unique identifiers as needed. Everything that
52
+ makes your task unique should be passed in and used by your function, as global
53
+ state may change.
54
+
55
+ #### Arguments
56
+ None.
57
+
58
+ #### Return Value
59
+ Either `true`, or a `WP_Error` on failure. The error object will indicate the
60
+ type of error; typically this is a `hm_backdrop_scheduled` if the task is
61
+ already scheduled to run or is currently running.
62
+
63
+ ### `Task::is_scheduled()`
64
+ Checks whether your task is scheduled to run.
65
+
66
+ #### Arguments
67
+ None.
68
+
69
+ #### Return Value
70
+ Boolean indicating whether your task is scheduled to run, or is already running.
71
+
72
+ #### `Task::cancel()`
73
+ Cancels a previously scheduled task.
74
+
75
+ Note that if the task is already running, this will not cancel execution; it
76
+ simply removes it from the tasks scheduled to run.
77
+
78
+ #### Arguments
79
+ None.
80
+
81
+ #### Return Value
82
+ Either `true`, or a `WP_Error` on failure. The error object will indicate the
83
+ type of error; typically this is a `hm_backdrop_not_scheduled` if the task
84
+ hasn't been scheduled.
85
+
86
+ ## Compatibility
87
+ Backdrop is compatible with PHP 5.2 and upwards.
88
+
89
+ ### PHP 5.2
90
+ Use the `HM_Backdrop_Task` class (and `HM_Backdrop_Server`).
91
+
92
+ **Important note:** If subclassing `HM_Backdrop_Server` with 5.2 compatibility,
93
+ you *must* reimplement the `spawn` method, as PHP 5.2 does not include late
94
+ static bindings. This is automatically handled for 5.3+.
95
+
96
+ Here's a minimal implementation that you can use:
97
+
98
+ ```
99
+ class MyBackdrop_Server extends HM_Backdrop_Server {
100
+ public static function spawn() {
101
+ return self::spawn_run( __CLASS__ );
102
+ }
103
+ }
104
+ ```
105
+
106
+ ### PHP 5.3+
107
+ Use the `HM\Backdrop\Task` class (and `HM\Backdrop\Server`). You can also import
108
+ the classes with the `use` keyword; for example, `use HM\Backdrop\Task` will
109
+ allow you to create tasks with `new Task`.
110
+
111
+ ## License
112
+ Backdrop is licensed under the GPL version 2.
113
+
114
+ Copyright 2014 Human Made Limited
backdrop/hm-backdrop.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require dirname( __FILE__ ) . '/server.php';
4
+ require dirname( __FILE__ ) . '/task.php';
5
+
6
+ if ( version_compare( PHP_VERSION, '5.3', '>=' ) ) {
7
+ require dirname( __FILE__ ) . '/namespace.php';
8
+ add_action( 'wp_ajax_nopriv_hm_backdrop_run', 'HM\Backdrop\Server::spawn' );
9
+ }
10
+ else {
11
+ add_action( 'wp_ajax_nopriv_hm_backdrop_run', 'HM_Backdrop_Server::spawn' );
12
+ }
backdrop/license.txt ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ GNU GENERAL PUBLIC LICENSE
3
+ Version 2, June 1991
4
+
5
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
6
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
7
+ Everyone is permitted to copy and distribute verbatim copies
8
+ of this license document, but changing it is not allowed.
9
+
10
+ Preamble
11
+
12
+ The licenses for most software are designed to take away your
13
+ freedom to share and change it. By contrast, the GNU General Public
14
+ License is intended to guarantee your freedom to share and change free
15
+ software--to make sure the software is free for all its users. This
16
+ General Public License applies to most of the Free Software
17
+ Foundation's software and to any other program whose authors commit to
18
+ using it. (Some other Free Software Foundation software is covered by
19
+ the GNU Lesser General Public License instead.) You can apply it to
20
+ your programs, too.
21
+
22
+ When we speak of free software, we are referring to freedom, not
23
+ price. Our General Public Licenses are designed to make sure that you
24
+ have the freedom to distribute copies of free software (and charge for
25
+ this service if you wish), that you receive source code or can get it
26
+ if you want it, that you can change the software or use pieces of it
27
+ in new free programs; and that you know you can do these things.
28
+
29
+ To protect your rights, we need to make restrictions that forbid
30
+ anyone to deny you these rights or to ask you to surrender the rights.
31
+ These restrictions translate to certain responsibilities for you if you
32
+ distribute copies of the software, or if you modify it.
33
+
34
+ For example, if you distribute copies of such a program, whether
35
+ gratis or for a fee, you must give the recipients all the rights that
36
+ you have. You must make sure that they, too, receive or can get the
37
+ source code. And you must show them these terms so they know their
38
+ rights.
39
+
40
+ We protect your rights with two steps: (1) copyright the software, and
41
+ (2) offer you this license which gives you legal permission to copy,
42
+ distribute and/or modify the software.
43
+
44
+ Also, for each author's protection and ours, we want to make certain
45
+ that everyone understands that there is no warranty for this free
46
+ software. If the software is modified by someone else and passed on, we
47
+ want its recipients to know that what they have is not the original, so
48
+ that any problems introduced by others will not reflect on the original
49
+ authors' reputations.
50
+
51
+ Finally, any free program is threatened constantly by software
52
+ patents. We wish to avoid the danger that redistributors of a free
53
+ program will individually obtain patent licenses, in effect making the
54
+ program proprietary. To prevent this, we have made it clear that any
55
+ patent must be licensed for everyone's free use or not licensed at all.
56
+
57
+ The precise terms and conditions for copying, distribution and
58
+ modification follow.
59
+
60
+ GNU GENERAL PUBLIC LICENSE
61
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
62
+
63
+ 0. This License applies to any program or other work which contains
64
+ a notice placed by the copyright holder saying it may be distributed
65
+ under the terms of this General Public License. The "Program", below,
66
+ refers to any such program or work, and a "work based on the Program"
67
+ means either the Program or any derivative work under copyright law:
68
+ that is to say, a work containing the Program or a portion of it,
69
+ either verbatim or with modifications and/or translated into another
70
+ language. (Hereinafter, translation is included without limitation in
71
+ the term "modification".) Each licensee is addressed as "you".
72
+
73
+ Activities other than copying, distribution and modification are not
74
+ covered by this License; they are outside its scope. The act of
75
+ running the Program is not restricted, and the output from the Program
76
+ is covered only if its contents constitute a work based on the
77
+ Program (independent of having been made by running the Program).
78
+ Whether that is true depends on what the Program does.
79
+
80
+ 1. You may copy and distribute verbatim copies of the Program's
81
+ source code as you receive it, in any medium, provided that you
82
+ conspicuously and appropriately publish on each copy an appropriate
83
+ copyright notice and disclaimer of warranty; keep intact all the
84
+ notices that refer to this License and to the absence of any warranty;
85
+ and give any other recipients of the Program a copy of this License
86
+ along with the Program.
87
+
88
+ You may charge a fee for the physical act of transferring a copy, and
89
+ you may at your option offer warranty protection in exchange for a fee.
90
+
91
+ 2. You may modify your copy or copies of the Program or any portion
92
+ of it, thus forming a work based on the Program, and copy and
93
+ distribute such modifications or work under the terms of Section 1
94
+ above, provided that you also meet all of these conditions:
95
+
96
+ a) You must cause the modified files to carry prominent notices
97
+ stating that you changed the files and the date of any change.
98
+
99
+ b) You must cause any work that you distribute or publish, that in
100
+ whole or in part contains or is derived from the Program or any
101
+ part thereof, to be licensed as a whole at no charge to all third
102
+ parties under the terms of this License.
103
+
104
+ c) If the modified program normally reads commands interactively
105
+ when run, you must cause it, when started running for such
106
+ interactive use in the most ordinary way, to print or display an
107
+ announcement including an appropriate copyright notice and a
108
+ notice that there is no warranty (or else, saying that you provide
109
+ a warranty) and that users may redistribute the program under
110
+ these conditions, and telling the user how to view a copy of this
111
+ License. (Exception: if the Program itself is interactive but
112
+ does not normally print such an announcement, your work based on
113
+ the Program is not required to print an announcement.)
114
+
115
+ These requirements apply to the modified work as a whole. If
116
+ identifiable sections of that work are not derived from the Program,
117
+ and can be reasonably considered independent and separate works in
118
+ themselves, then this License, and its terms, do not apply to those
119
+ sections when you distribute them as separate works. But when you
120
+ distribute the same sections as part of a whole which is a work based
121
+ on the Program, the distribution of the whole must be on the terms of
122
+ this License, whose permissions for other licensees extend to the
123
+ entire whole, and thus to each and every part regardless of who wrote it.
124
+
125
+ Thus, it is not the intent of this section to claim rights or contest
126
+ your rights to work written entirely by you; rather, the intent is to
127
+ exercise the right to control the distribution of derivative or
128
+ collective works based on the Program.
129
+
130
+ In addition, mere aggregation of another work not based on the Program
131
+ with the Program (or with a work based on the Program) on a volume of
132
+ a storage or distribution medium does not bring the other work under
133
+ the scope of this License.
134
+
135
+ 3. You may copy and distribute the Program (or a work based on it,
136
+ under Section 2) in object code or executable form under the terms of
137
+ Sections 1 and 2 above provided that you also do one of the following:
138
+
139
+ a) Accompany it with the complete corresponding machine-readable
140
+ source code, which must be distributed under the terms of Sections
141
+ 1 and 2 above on a medium customarily used for software interchange; or,
142
+
143
+ b) Accompany it with a written offer, valid for at least three
144
+ years, to give any third party, for a charge no more than your
145
+ cost of physically performing source distribution, a complete
146
+ machine-readable copy of the corresponding source code, to be
147
+ distributed under the terms of Sections 1 and 2 above on a medium
148
+ customarily used for software interchange; or,
149
+
150
+ c) Accompany it with the information you received as to the offer
151
+ to distribute corresponding source code. (This alternative is
152
+ allowed only for noncommercial distribution and only if you
153
+ received the program in object code or executable form with such
154
+ an offer, in accord with Subsection b above.)
155
+
156
+ The source code for a work means the preferred form of the work for
157
+ making modifications to it. For an executable work, complete source
158
+ code means all the source code for all modules it contains, plus any
159
+ associated interface definition files, plus the scripts used to
160
+ control compilation and installation of the executable. However, as a
161
+ special exception, the source code distributed need not include
162
+ anything that is normally distributed (in either source or binary
163
+ form) with the major components (compiler, kernel, and so on) of the
164
+ operating system on which the executable runs, unless that component
165
+ itself accompanies the executable.
166
+
167
+ If distribution of executable or object code is made by offering
168
+ access to copy from a designated place, then offering equivalent
169
+ access to copy the source code from the same place counts as
170
+ distribution of the source code, even though third parties are not
171
+ compelled to copy the source along with the object code.
172
+
173
+ 4. You may not copy, modify, sublicense, or distribute the Program
174
+ except as expressly provided under this License. Any attempt
175
+ otherwise to copy, modify, sublicense or distribute the Program is
176
+ void, and will automatically terminate your rights under this License.
177
+ However, parties who have received copies, or rights, from you under
178
+ this License will not have their licenses terminated so long as such
179
+ parties remain in full compliance.
180
+
181
+ 5. You are not required to accept this License, since you have not
182
+ signed it. However, nothing else grants you permission to modify or
183
+ distribute the Program or its derivative works. These actions are
184
+ prohibited by law if you do not accept this License. Therefore, by
185
+ modifying or distributing the Program (or any work based on the
186
+ Program), you indicate your acceptance of this License to do so, and
187
+ all its terms and conditions for copying, distributing or modifying
188
+ the Program or works based on it.
189
+
190
+ 6. Each time you redistribute the Program (or any work based on the
191
+ Program), the recipient automatically receives a license from the
192
+ original licensor to copy, distribute or modify the Program subject to
193
+ these terms and conditions. You may not impose any further
194
+ restrictions on the recipients' exercise of the rights granted herein.
195
+ You are not responsible for enforcing compliance by third parties to
196
+ this License.
197
+
198
+ 7. If, as a consequence of a court judgment or allegation of patent
199
+ infringement or for any other reason (not limited to patent issues),
200
+ conditions are imposed on you (whether by court order, agreement or
201
+ otherwise) that contradict the conditions of this License, they do not
202
+ excuse you from the conditions of this License. If you cannot
203
+ distribute so as to satisfy simultaneously your obligations under this
204
+ License and any other pertinent obligations, then as a consequence you
205
+ may not distribute the Program at all. For example, if a patent
206
+ license would not permit royalty-free redistribution of the Program by
207
+ all those who receive copies directly or indirectly through you, then
208
+ the only way you could satisfy both it and this License would be to
209
+ refrain entirely from distribution of the Program.
210
+
211
+ If any portion of this section is held invalid or unenforceable under
212
+ any particular circumstance, the balance of the section is intended to
213
+ apply and the section as a whole is intended to apply in other
214
+ circumstances.
215
+
216
+ It is not the purpose of this section to induce you to infringe any
217
+ patents or other property right claims or to contest validity of any
218
+ such claims; this section has the sole purpose of protecting the
219
+ integrity of the free software distribution system, which is
220
+ implemented by public license practices. Many people have made
221
+ generous contributions to the wide range of software distributed
222
+ through that system in reliance on consistent application of that
223
+ system; it is up to the author/donor to decide if he or she is willing
224
+ to distribute software through any other system and a licensee cannot
225
+ impose that choice.
226
+
227
+ This section is intended to make thoroughly clear what is believed to
228
+ be a consequence of the rest of this License.
229
+
230
+ 8. If the distribution and/or use of the Program is restricted in
231
+ certain countries either by patents or by copyrighted interfaces, the
232
+ original copyright holder who places the Program under this License
233
+ may add an explicit geographical distribution limitation excluding
234
+ those countries, so that distribution is permitted only in or among
235
+ countries not thus excluded. In such case, this License incorporates
236
+ the limitation as if written in the body of this License.
237
+
238
+ 9. The Free Software Foundation may publish revised and/or new versions
239
+ of the General Public License from time to time. Such new versions will
240
+ be similar in spirit to the present version, but may differ in detail to
241
+ address new problems or concerns.
242
+
243
+ Each version is given a distinguishing version number. If the Program
244
+ specifies a version number of this License which applies to it and "any
245
+ later version", you have the option of following the terms and conditions
246
+ either of that version or of any later version published by the Free
247
+ Software Foundation. If the Program does not specify a version number of
248
+ this License, you may choose any version ever published by the Free Software
249
+ Foundation.
250
+
251
+ 10. If you wish to incorporate parts of the Program into other free
252
+ programs whose distribution conditions are different, write to the author
253
+ to ask for permission. For software which is copyrighted by the Free
254
+ Software Foundation, write to the Free Software Foundation; we sometimes
255
+ make exceptions for this. Our decision will be guided by the two goals
256
+ of preserving the free status of all derivatives of our free software and
257
+ of promoting the sharing and reuse of software generally.
258
+
259
+ NO WARRANTY
260
+
261
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
262
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
263
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
264
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
265
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
266
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
267
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
268
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
269
+ REPAIR OR CORRECTION.
270
+
271
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
272
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
273
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
274
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
275
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
276
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
277
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
278
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
279
+ POSSIBILITY OF SUCH DAMAGES.
280
+
281
+ END OF TERMS AND CONDITIONS
282
+
283
+ How to Apply These Terms to Your New Programs
284
+
285
+ If you develop a new program, and you want it to be of the greatest
286
+ possible use to the public, the best way to achieve this is to make it
287
+ free software which everyone can redistribute and change under these terms.
288
+
289
+ To do so, attach the following notices to the program. It is safest
290
+ to attach them to the start of each source file to most effectively
291
+ convey the exclusion of warranty; and each file should have at least
292
+ the "copyright" line and a pointer to where the full notice is found.
293
+
294
+ <one line to give the program's name and a brief idea of what it does.>
295
+ Copyright (C) <year> <name of author>
296
+
297
+ This program is free software; you can redistribute it and/or modify
298
+ it under the terms of the GNU General Public License as published by
299
+ the Free Software Foundation; either version 2 of the License, or
300
+ (at your option) any later version.
301
+
302
+ This program is distributed in the hope that it will be useful,
303
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
304
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
305
+ GNU General Public License for more details.
306
+
307
+ You should have received a copy of the GNU General Public License along
308
+ with this program; if not, write to the Free Software Foundation, Inc.,
309
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
310
+
311
+ Also add information on how to contact you by electronic and paper mail.
312
+
313
+ If the program is interactive, make it output a short notice like this
314
+ when it starts in an interactive mode:
315
+
316
+ Gnomovision version 69, Copyright (C) year name of author
317
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
318
+ This is free software, and you are welcome to redistribute it
319
+ under certain conditions; type `show c' for details.
320
+
321
+ The hypothetical commands `show w' and `show c' should show the appropriate
322
+ parts of the General Public License. Of course, the commands you use may
323
+ be called something other than `show w' and `show c'; they could even be
324
+ mouse-clicks or menu items--whatever suits your program.
325
+
326
+ You should also get your employer (if you work as a programmer) or your
327
+ school, if any, to sign a "copyright disclaimer" for the program, if
328
+ necessary. Here is a sample; alter the names:
329
+
330
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
331
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
332
+
333
+ <signature of Ty Coon>, 1 April 1989
334
+ Ty Coon, President of Vice
335
+
336
+ This General Public License does not permit incorporating your program into
337
+ proprietary programs. If your program is a subroutine library, you may
338
+ consider it more useful to permit linking proprietary applications with the
339
+ library. If this is what you want to do, use the GNU Lesser General
340
+ Public License instead of this License.
backdrop/namespace.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace HM\Backdrop;
4
+
5
+ class Server extends \HM_Backdrop_Server {}
6
+ class Task extends \HM_Backdrop_Task {}
backdrop/server.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class HM_Backdrop_Server {
4
+ public function run() {
5
+ if ( empty( $_POST['key'] ) ) {
6
+ return new WP_Error( 'hm_backdrop_no_key', __( 'No key supplied', 'hm_backdrop' ) );
7
+ }
8
+
9
+ $data = get_transient( 'hm_backdrop-' . $_POST['key'] );
10
+ if ( empty( $data ) ) {
11
+ return new WP_Error( 'hm_backdrop_invalid_key', __( 'Supplied key was not valid', 'hm_backdrop' ) );
12
+ }
13
+
14
+ $result = call_user_func_array( $data['callback'], $data['params'] );
15
+ delete_transient( 'hm_backdrop-' . $_POST['key'] );
16
+
17
+ if ( is_wp_error( $result ) ) {
18
+ return $result;
19
+ }
20
+
21
+ return true;
22
+ }
23
+
24
+ public static function spawn() {
25
+ $class = get_class();
26
+ if ( function_exists( 'get_called_class' ) ) {
27
+ $class = get_called_class();
28
+ }
29
+
30
+ return call_user_func( array( $class, 'spawn_run' ), $class );
31
+ }
32
+
33
+ protected static function spawn_run( $class ) {
34
+ $server = new $class();
35
+ $server->run();
36
+ exit;
37
+ }
38
+ }
backdrop/task.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class HM_Backdrop_Task {
4
+ protected $key;
5
+ protected $callback;
6
+ protected $params = array();
7
+
8
+ public function __construct( $callback /* , $... */ ) {
9
+ $this->callback = $callback;
10
+
11
+ if ( func_num_args() > 1 ) {
12
+ $args = func_get_args();
13
+ $this->params = array_slice( $args, 1 );
14
+ }
15
+
16
+ $this->key = $this->get_unique_id();
17
+ }
18
+
19
+ public function schedule() {
20
+
21
+ if ( $this->is_scheduled() ) {
22
+ return new WP_Error( 'hm_backdrop_scheduled', __( 'Task is already scheduled to run', 'hm_backdrop' ) );
23
+ }
24
+
25
+ $data = array(
26
+ 'callback' => $this->callback,
27
+ 'params' => $this->params
28
+ );
29
+ set_transient( 'hm_backdrop-' . $this->key, $data, 300 );
30
+ add_action( 'shutdown', array( $this, 'spawn_server' ) );
31
+
32
+ return true;
33
+ }
34
+
35
+ public function is_scheduled() {
36
+ return (bool) $this->get_data();
37
+ }
38
+
39
+ public function cancel() {
40
+ if ( ! $this->is_scheduled() ) {
41
+ return new WP_Error( 'hm_backdrop_not_scheduled', __( 'Task is not scheduled to run', 'hm_backdrop' ) );
42
+ }
43
+
44
+ delete_transient( 'hm_backdrop-' . $this->key );
45
+ return true;
46
+ }
47
+
48
+ public function spawn_server() {
49
+ $server_url = admin_url( 'admin-ajax.php' );
50
+ $data = array(
51
+ 'action' => 'hm_backdrop_run',
52
+ 'key' => $this->key,
53
+ );
54
+ $args = array(
55
+ 'body' => $data,
56
+ 'timeout' => 0.01,
57
+ 'blocking' => false,
58
+ 'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
59
+ );
60
+ wp_remote_post( $server_url, $args );
61
+ return true;
62
+ }
63
+
64
+ protected function get_data() {
65
+ return get_transient( 'hm_backdrop-' . $this->key );
66
+ }
67
+
68
+ protected function get_unique_id() {
69
+ return substr( sha1( serialize( $this->callback ) . serialize( $this->params ) ), -28 );
70
+ }
71
+ }
backupwordpress.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: BackUpWordPress
4
  Plugin URI: https://updraftplus.com/backupwordpress/?afref=744
5
  Description: Simple automated backups of your WordPress powered website. Once activated you'll find me under <strong>Tools &rarr; Backups</strong>. On multisite, you'll find me under the Network Settings menu.
6
- Version: 3.9
7
  Author: XIBO Ltd
8
  Author URI: https://profiles.wordpress.org/xibodevelopment
9
  License: GPL-2+
3
  Plugin Name: BackUpWordPress
4
  Plugin URI: https://updraftplus.com/backupwordpress/?afref=744
5
  Description: Simple automated backups of your WordPress powered website. Once activated you'll find me under <strong>Tools &rarr; Backups</strong>. On multisite, you'll find me under the Network Settings menu.
6
+ Version: 3.10
7
  Author: XIBO Ltd
8
  Author URI: https://profiles.wordpress.org/xibodevelopment
9
  License: GPL-2+
classes/class-email-service.php CHANGED
@@ -1,216 +1,216 @@
1
- <?php
2
-
3
- namespace HM\BackUpWordPress;
4
-
5
- /**
6
- * Email notifications for backups
7
- *
8
- * @extends Service
9
- */
10
- class Email_Service extends Service {
11
-
12
- /**
13
- * Human readable name for this service
14
- * @var string
15
- */
16
- public $name = 'Email';
17
-
18
- /**
19
- * Output the email form field
20
- *
21
- * @access public
22
- */
23
- public function field() {
24
-
25
- ?>
26
-
27
- <tr>
28
-
29
- <th scope="row">
30
- <label for="<?php echo esc_attr( $this->get_field_name( 'email' ) ); ?>"><?php _e( 'Email notification', 'backupwordpress' ); ?></label>
31
- </th>
32
-
33
- <td>
34
- <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" />
35
-
36
- <p class="description"><?php printf( __( 'Receive a notification email when a backup completes. If the backup is small enough (&lt; %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>
37
- </td>
38
-
39
- </tr>
40
-
41
- <?php }
42
-
43
- /**
44
- * Not used as we only need a field
45
- *
46
- * @see field
47
- * @return string Empty string
48
- */
49
- public function form() {
50
- return '';
51
- }
52
-
53
- public static function constant() {
54
-
55
- ?>
56
-
57
- <tr<?php if ( defined( 'HMBKP_ATTACHMENT_MAX_FILESIZE' ) ) { ?> class="hmbkp_active"<?php } ?>>
58
-
59
- <td><code>HMBKP_ATTACHMENT_MAX_FILESIZE</code></td>
60
-
61
- <td>
62
-
63
- <?php if ( defined( 'HMBKP_ATTACHMENT_MAX_FILESIZE' ) ) { ?>
64
- <p><?php printf( __( 'You\'ve set it to: %s', 'backupwordpress' ), '<code>' . HMBKP_ATTACHMENT_MAX_FILESIZE . '</code>' ); ?></p>
65
- <?php } ?>
66
-
67
- <p><?php printf( __( 'The maximum filesize of your backup that will be attached to your notification emails . Defaults to %s.', 'backupwordpress' ), '<code>10MB</code>' ); ?> <?php _e( 'e.g.', 'backupwordpress' ); ?> <code>define( 'HMBKP_ATTACHMENT_MAX_FILESIZE', '25MB' );</code></p>
68
-
69
- </td>
70
-
71
- </tr>
72
-
73
- <?php }
74
-
75
- /**
76
- * The sentence fragment that is output as part of the schedule sentence
77
- *
78
- * @return string
79
- */
80
- public function display() {
81
-
82
- if ( $emails = $this->get_email_address_array() ) {
83
-
84
- $email = '<code>' . implode( '</code>, <code>', array_map( 'esc_html', $emails ) ) . '</code>';
85
-
86
- return sprintf( __( 'Send an email notification to %s', 'backupwordpress' ), $email );
87
-
88
- }
89
-
90
- return '';
91
-
92
- }
93
-
94
- /**
95
- * Used to determine if the service is in use or not
96
- */
97
- public function is_service_active() {
98
- return (bool) $this->get_email_address_array();
99
- }
100
-
101
- /**
102
- * Validate the email and return an error if validation fails
103
- *
104
- * @param array &$new_data Array of new data, passed by reference.
105
- * @param array $old_data The data we are replacing.
106
- *
107
- * @return array|null Null on success, array of errors if validation failed.
108
- */
109
- public function update( &$new_data, $old_data ) {
110
-
111
- $errors = array();
112
-
113
- if ( isset( $new_data['email'] ) ) {
114
-
115
- if ( ! empty( $new_data['email'] ) ) {
116
-
117
- foreach ( explode( ',', $new_data['email'] ) as $email ) {
118
-
119
- $email = trim( $email );
120
-
121
- if ( ! is_email( $email ) ) {
122
- $errors['email'] = sprintf( __( '%s isn\'t a valid email', 'backupwordpress' ), $email );
123
- }
124
- }
125
- }
126
-
127
- if ( ! empty( $errors['email'] ) ) {
128
- $new_data['email'] = '';
129
- }
130
-
131
- return $errors;
132
-
133
- }
134
- }
135
-
136
- /**
137
- * Get an array or validated email address's
138
- * @return array An array of validated email address's
139
- */
140
- private function get_email_address_array() {
141
- $emails = array_map( 'trim', explode( ',', $this->get_field_value( 'email' ) ) );
142
- return array_filter( array_unique( $emails ), 'is_email' );
143
- }
144
-
145
- /**
146
- * Fire the email notification on the hmbkp_backup_complete
147
- *
148
- * @see Backup::do_action
149
- * @param string $action The action received from the backup
150
- */
151
- public function action( $action, Backup $backup ) {
152
-
153
- if ( 'hmbkp_backup_complete' === $action && $this->get_email_address_array() ) {
154
-
155
- $file = $backup->get_backup_filepath();
156
-
157
- $sent = false;
158
-
159
- $download = add_query_arg( 'hmbkp_download', base64_encode( $file ), HMBKP_ADMIN_URL );
160
- $domain = parse_url( home_url(), PHP_URL_HOST ) . parse_url( home_url(), PHP_URL_PATH );
161
-
162
- $headers = 'From: BackUpWordPress <' . apply_filters( 'hmbkp_from_email', get_bloginfo( 'admin_email' ) ) . '>' . "\r\n";
163
-
164
- // The backup failed, send a message saying as much
165
- if ( ! file_exists( $file ) && ( $errors = array_merge( $backup->get_errors(), $backup->get_warnings() ) ) ) {
166
-
167
- $error_message = '';
168
-
169
- foreach ( $errors as $error_set ) {
170
- $error_message .= implode( "\n - ", $error_set );
171
- }
172
-
173
- if ( $error_message ) {
174
- $error_message = ' - ' . $error_message;
175
- }
176
-
177
- $subject = sprintf( __( 'Backup of %s Failed', 'backupwordpress' ), $domain );
178
-
179
- $message = sprintf( __( 'BackUpWordPress was unable to backup your site %1$s.', 'backupwordpress' ) . "\n\n" . __( 'Here are the errors that we\'ve encountered:', 'backupwordpress' ) . "\n\n" . '%2$s' . "\n\n" . __( 'If the errors above look like Martian, you can find further assistance on our %3$ssupport forums%4$s ', 'backupwordpress' ) . "\n\n" . __( "Kind Regards,\nThe Apologetic BackUpWordPress Backup Emailing Robot", 'backupwordpress' ), home_url(), $error_message, '<a href="http://wordpress.org/support/plugin/backupwordpress" title="support forums" target="_blank">', '</a>' );
180
-
181
- wp_mail( $this->get_email_address_array(), $subject, $message, $headers );
182
-
183
- return;
184
-
185
- }
186
-
187
- $subject = sprintf( __( 'Backup of %s', 'backupwordpress' ), $domain );
188
-
189
- // If it's larger than the max attachment size limit assume it's not going to be able to send the backup
190
- if ( @filesize( $file ) < get_max_attachment_size() ) {
191
-
192
- $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 );
193
-
194
- $sent = wp_mail( $this->get_email_address_array(), $subject, $message, $headers, $file );
195
-
196
- }
197
-
198
- // If we didn't send the email above then send just the notification
199
- if ( ! $sent ) {
200
-
201
- $message = sprintf( __( 'BackUpWordPress has completed a backup of your site %1$s.', 'backupwordpress' ) . "\n\n" . __( 'Unfortunately, the backup file was too large to attach 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 );
202
- wp_mail( $this->get_email_address_array(), $subject, $message, $headers );
203
-
204
- }
205
- }
206
- }
207
-
208
- public static function intercom_data() {
209
- return array();
210
- }
211
-
212
- public static function intercom_data_html() {}
213
- }
214
-
215
- // Register the service
216
- Services::register( __FILE__, 'HM\BackUpWordPress\Email_Service' );
1
+ <?php
2
+
3
+ namespace HM\BackUpWordPress;
4
+
5
+ /**
6
+ * Email notifications for backups
7
+ *
8
+ * @extends Service
9
+ */
10
+ class Email_Service extends Service {
11
+
12
+ /**
13
+ * Human readable name for this service
14
+ * @var string
15
+ */
16
+ public $name = 'Email';
17
+
18
+ /**
19
+ * Output the email form field
20
+ *
21
+ * @access public
22
+ */
23
+ public function field() {
24
+
25
+ ?>
26
+
27
+ <tr>
28
+
29
+ <th scope="row">
30
+ <label for="<?php echo esc_attr( $this->get_field_name( 'email' ) ); ?>"><?php _e( 'Email notification', 'backupwordpress' ); ?></label>
31
+ </th>
32
+
33
+ <td>
34
+ <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" />
35
+
36
+ <p class="description"><?php printf( __( 'Receive a notification email when a backup completes. If the backup is small enough (&lt; %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>
37
+ </td>
38
+
39
+ </tr>
40
+
41
+ <?php }
42
+
43
+ /**
44
+ * Not used as we only need a field
45
+ *
46
+ * @see field
47
+ * @return string Empty string
48
+ */
49
+ public function form() {
50
+ return '';
51
+ }
52
+
53
+ public static function constant() {
54
+
55
+ ?>
56
+
57
+ <tr<?php if ( defined( 'HMBKP_ATTACHMENT_MAX_FILESIZE' ) ) { ?> class="hmbkp_active"<?php } ?>>
58
+
59
+ <td><code>HMBKP_ATTACHMENT_MAX_FILESIZE</code></td>
60
+
61
+ <td>
62
+
63
+ <?php if ( defined( 'HMBKP_ATTACHMENT_MAX_FILESIZE' ) ) { ?>
64
+ <p><?php printf( __( 'You\'ve set it to: %s', 'backupwordpress' ), '<code>' . HMBKP_ATTACHMENT_MAX_FILESIZE . '</code>' ); ?></p>
65
+ <?php } ?>
66
+
67
+ <p><?php printf( __( 'The maximum filesize of your backup that will be attached to your notification emails . Defaults to %s.', 'backupwordpress' ), '<code>10MB</code>' ); ?> <?php _e( 'e.g.', 'backupwordpress' ); ?> <code>define( 'HMBKP_ATTACHMENT_MAX_FILESIZE', '25MB' );</code></p>
68
+
69
+ </td>
70
+
71
+ </tr>
72
+
73
+ <?php }
74
+
75
+ /**
76
+ * The sentence fragment that is output as part of the schedule sentence
77
+ *
78
+ * @return string
79
+ */
80
+ public function display() {
81
+
82
+ if ( $emails = $this->get_email_address_array() ) {
83
+
84
+ $email = '<code>' . implode( '</code>, <code>', array_map( 'esc_html', $emails ) ) . '</code>';
85
+
86
+ return sprintf( __( 'Send an email notification to %s', 'backupwordpress' ), $email );
87
+
88
+ }
89
+
90
+ return '';
91
+
92
+ }
93
+
94
+ /**
95
+ * Used to determine if the service is in use or not
96
+ */
97
+ public function is_service_active() {
98
+ return (bool) $this->get_email_address_array();
99
+ }
100
+
101
+ /**
102
+ * Validate the email and return an error if validation fails
103
+ *
104
+ * @param array &$new_data Array of new data, passed by reference.
105
+ * @param array $old_data The data we are replacing.
106
+ *
107
+ * @return array|null Null on success, array of errors if validation failed.
108
+ */
109
+ public function update( &$new_data, $old_data ) {
110
+
111
+ $errors = array();
112
+
113
+ if ( isset( $new_data['email'] ) ) {
114
+
115
+ if ( ! empty( $new_data['email'] ) ) {
116
+
117
+ foreach ( explode( ',', $new_data['email'] ) as $email ) {
118
+
119
+ $email = trim( $email );
120
+
121
+ if ( ! is_email( $email ) ) {
122
+ $errors['email'] = sprintf( __( '%s isn\'t a valid email', 'backupwordpress' ), $email );
123
+ }
124
+ }
125
+ }
126
+
127
+ if ( ! empty( $errors['email'] ) ) {
128
+ $new_data['email'] = '';
129
+ }
130
+
131
+ return $errors;
132
+
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Get an array or validated email address's
138
+ * @return array An array of validated email address's
139
+ */
140
+ private function get_email_address_array() {
141
+ $emails = array_map( 'trim', explode( ',', $this->get_field_value( 'email' ) ) );
142
+ return array_filter( array_unique( $emails ), 'is_email' );
143
+ }
144
+
145
+ /**
146
+ * Fire the email notification on the hmbkp_backup_complete
147
+ *
148
+ * @see Backup::do_action
149
+ * @param string $action The action received from the backup
150
+ */
151
+ public function action( $action, Backup $backup ) {
152
+
153
+ if ( 'hmbkp_backup_complete' === $action && $this->get_email_address_array() ) {
154
+
155
+ $file = $backup->get_backup_filepath();
156
+
157
+ $sent = false;
158
+
159
+ $download = add_query_arg( 'hmbkp_download', base64_encode( $file ), HMBKP_ADMIN_URL );
160
+ $domain = parse_url( home_url(), PHP_URL_HOST ) . parse_url( home_url(), PHP_URL_PATH );
161
+
162
+ $headers = 'From: BackUpWordPress <' . apply_filters( 'hmbkp_from_email', get_bloginfo( 'admin_email' ) ) . '>' . "\r\n";
163
+
164
+ // The backup failed, send a message saying as much
165
+ if ( ! file_exists( $file ) && ( $errors = array_merge( $backup->get_errors(), $backup->get_warnings() ) ) ) {
166
+
167
+ $error_message = '';
168
+
169
+ foreach ( $errors as $error_set ) {
170
+ $error_message .= implode( "\n - ", $error_set );
171
+ }
172
+
173
+ if ( $error_message ) {
174
+ $error_message = ' - ' . $error_message;
175
+ }
176
+
177
+ $subject = sprintf( __( 'Backup of %s Failed', 'backupwordpress' ), $domain );
178
+
179
+ $message = sprintf( __( 'BackUpWordPress was unable to backup your site %1$s.', 'backupwordpress' ) . "\n\n" . __( 'Here are the errors that we\'ve encountered:', 'backupwordpress' ) . "\n\n" . '%2$s' . "\n\n" . __( 'If the errors above look like Martian, you can find further assistance on our %3$ssupport forums%4$s ', 'backupwordpress' ) . "\n\n" . __( "Kind Regards,\nThe Apologetic BackUpWordPress Backup Emailing Robot", 'backupwordpress' ), home_url(), $error_message, '<a href="http://wordpress.org/support/plugin/backupwordpress" title="support forums" target="_blank">', '</a>' );
180
+
181
+ wp_mail( $this->get_email_address_array(), $subject, $message, $headers );
182
+
183
+ return;
184
+
185
+ }
186
+
187
+ $subject = sprintf( __( 'Backup of %s', 'backupwordpress' ), $domain );
188
+
189
+ // If it's larger than the max attachment size limit assume it's not going to be able to send the backup
190
+ if ( @filesize( $file ) < get_max_attachment_size() ) {
191
+
192
+ $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 );
193
+
194
+ $sent = wp_mail( $this->get_email_address_array(), $subject, $message, $headers, $file );
195
+
196
+ }
197
+
198
+ // If we didn't send the email above then send just the notification
199
+ if ( ! $sent ) {
200
+
201
+ $message = sprintf( __( 'BackUpWordPress has completed a backup of your site %1$s.', 'backupwordpress' ) . "\n\n" . __( 'Unfortunately, the backup file was too large to attach 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 );
202
+ wp_mail( $this->get_email_address_array(), $subject, $message, $headers );
203
+
204
+ }
205
+ }
206
+ }
207
+
208
+ public static function intercom_data() {
209
+ return array();
210
+ }
211
+
212
+ public static function intercom_data_html() {}
213
+ }
214
+
215
+ // Register the service
216
+ Services::register( __FILE__, 'HM\BackUpWordPress\Email_Service' );
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.9';
10
 
11
  /**
12
  * @var Plugin The singleton instance.
6
  * Class Plugin
7
  */
8
  final class Plugin {
9
+ const PLUGIN_VERSION = '3.10';
10
 
11
  /**
12
  * @var Plugin The singleton instance.
languages/backupwordpress.pot CHANGED
@@ -2,7 +2,7 @@
2
  # This file is distributed under the GPL-2+.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: BackUpWordPress 3.9\n"
6
  "Report-Msgid-Bugs-To: support@xibomarketing.com\n"
7
  "POT-Creation-Date: 2018-10-29 10:39:44+00:00\n"
8
  "MIME-Version: 1.0\n"
2
  # This file is distributed under the GPL-2+.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: BackUpWordPress 3.10\n"
6
  "Report-Msgid-Bugs-To: support@xibomarketing.com\n"
7
  "POT-Creation-Date: 2018-10-29 10:39:44+00:00\n"
8
  "MIME-Version: 1.0\n"
package-lock.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ {
2
+ "name": "BackUpWordPress",
3
+ "version": "3.9",
4
+ "lockfileVersion": 1
5
+ }
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: xibodevelopment, willmot, dashaluna, pauldewouters, joehoyle, mattheu, tcrsavage, cuvelier, katmoody, sambulance
3
  Tags: back up, backup, backups, database, zip, db, files, archive, wp-cli, xibodevelopment
4
  Requires at least: 3.9
5
- Tested up to: 4.9.8
6
- Stable tag: 3.9
7
 
8
  Simple automated backups of your WordPress-powered website.
9
 
@@ -157,6 +157,10 @@ users should see major improvements to reliability.
157
 
158
  == Changelog ==
159
 
 
 
 
 
160
  ### 3.9 / 2019-06-10
161
 
162
  * Readme update
@@ -1305,7 +1309,7 @@ Fix some silly 1.0 bugs
1305
 
1306
  #### 1.0
1307
 
1308
- 1.0 represents a total rewrite & rethink of the BackUpWordPress plugin with a focus on making it "Just Work". The management and development of the plugin has been taken over by [XIBO Ltd](http://hmn.md) the chaps behind [WP Remote](https://wpremote.com)
1309
 
1310
  #### Previous
1311
 
2
  Contributors: xibodevelopment, willmot, dashaluna, pauldewouters, joehoyle, mattheu, tcrsavage, cuvelier, katmoody, sambulance
3
  Tags: back up, backup, backups, database, zip, db, files, archive, wp-cli, xibodevelopment
4
  Requires at least: 3.9
5
+ Tested up to: 5.1
6
+ Stable tag: 3.10
7
 
8
  Simple automated backups of your WordPress-powered website.
9
 
157
 
158
  == Changelog ==
159
 
160
+ ### 3.10 / 2019-06-12
161
+
162
+ * Fixed whitelist-html
163
+
164
  ### 3.9 / 2019-06-10
165
 
166
  * Readme update
1309
 
1310
  #### 1.0
1311
 
1312
+ 1.0 represents a total rewrite & rethink of the BackUpWordPress plugin with a focus on making it "Just Work". The management and development of the plugin has been taken over by [XIBO Development](http://hmn.md) the chaps behind [WP Remote](https://wpremote.com)
1313
 
1314
  #### Previous
1315
 
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInitec295a6d5e5af85df96f8020de01e26f::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit1a75378a5bdc0fa45cf53a852d91c4ca::getLoader();
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInitec295a6d5e5af85df96f8020de01e26f
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInitec295a6d5e5af85df96f8020de01e26f
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInitec295a6d5e5af85df96f8020de01e26f', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInitec295a6d5e5af85df96f8020de01e26f', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInitec295a6d5e5af85df96f8020de01e26f::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit1a75378a5bdc0fa45cf53a852d91c4ca
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit1a75378a5bdc0fa45cf53a852d91c4ca', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit1a75378a5bdc0fa45cf53a852d91c4ca', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInit1a75378a5bdc0fa45cf53a852d91c4ca::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInitec295a6d5e5af85df96f8020de01e26f
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'S' =>
@@ -36,8 +36,8 @@ class ComposerStaticInitec295a6d5e5af85df96f8020de01e26f
36
  public static function getInitializer(ClassLoader $loader)
37
  {
38
  return \Closure::bind(function () use ($loader) {
39
- $loader->prefixLengthsPsr4 = ComposerStaticInitec295a6d5e5af85df96f8020de01e26f::$prefixLengthsPsr4;
40
- $loader->prefixDirsPsr4 = ComposerStaticInitec295a6d5e5af85df96f8020de01e26f::$prefixDirsPsr4;
41
 
42
  }, null, ClassLoader::class);
43
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit1a75378a5bdc0fa45cf53a852d91c4ca
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'S' =>
36
  public static function getInitializer(ClassLoader $loader)
37
  {
38
  return \Closure::bind(function () use ($loader) {
39
+ $loader->prefixLengthsPsr4 = ComposerStaticInit1a75378a5bdc0fa45cf53a852d91c4ca::$prefixLengthsPsr4;
40
+ $loader->prefixDirsPsr4 = ComposerStaticInit1a75378a5bdc0fa45cf53a852d91c4ca::$prefixDirsPsr4;
41
 
42
  }, null, ClassLoader::class);
43
  }
whitelist-html/README.md ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Whitelist HTML
2
+
3
+ Introduces an `esc_*()`-like function for when you need to allow *some* HTML.
4
+
5
+ ## Rationale
6
+ ### Background
7
+
8
+ Best practices when working with any sort of data is to escape your output, and
9
+ do it as late as possible. Values can't usually know about where they're going
10
+ to be used, so you need to escape based on whatever context you're
11
+ outputting into. These are things like `esc_attr()` for HTML attribute values,
12
+ `esc_html()` for text in HTML, and so on.
13
+
14
+ Even if values could know about their output context, it's still possible for
15
+ users to craft malicious output if you're not escaping properly. For this
16
+ reason, you need to do sanitization on input (to ensure your value is correct),
17
+ as well as escaping on output (to ensure the value is output into the context
18
+ correctly).
19
+
20
+ Right now across every WordPress site, there's a glaring hole in escaping, and
21
+ hence in security.
22
+
23
+ When translating strings in WordPress, the most common functions to use are
24
+ `__()` (translate and return) or `_e()` (translate and output). Where possible,
25
+ these need to be escaped too, to ensure that translations don't accidentally
26
+ break your output. For this reason, `esc_html_e()`, `esc_attr_e()`, etc are
27
+ offered as convenience functions.
28
+
29
+ However, this falls down when you need to have HTML in the translation.
30
+ Translation best practices say to include as much information as possible for
31
+ translators when you translate a string. This means including HTML tags in the
32
+ string so translators can understand how the sentence is formed.
33
+
34
+ It's possible to do "clever" hacks to get around this with placeholders,
35
+ for example:
36
+
37
+ ```php
38
+ $text = sprintf(
39
+ esc_html__( 'This is some text %1$swith a link%2$s'),
40
+ '<a href="http://example.com/">',
41
+ '</a>'
42
+ );
43
+ ```
44
+
45
+ Note though that this is much harder for translators to understand, since they
46
+ can't intuitively tell what's going on without checking the code. Even with
47
+ translator comments, it's still harder to understand. There's also no guarantee
48
+ that this is secure. You could swap the placeholders, or leave out pieces. Best
49
+ practice states that we should instead have the following:
50
+
51
+ ```php
52
+ $text = sprintf(
53
+ esc_html__( 'This is some text <a href="%1$s">with a link</a>'),
54
+ 'http://example.com/'
55
+ );
56
+ ```
57
+
58
+ Right now, the policy is essentially to treat translated strings with HTML as
59
+ trusted. Not only does this push the burden off to translation validators in
60
+ GlotPress, but it means you're no longer in control of your output. This is an
61
+ attack vector waiting to be exploited.
62
+
63
+
64
+ ### How do we solve this?
65
+
66
+ WordPress contains functions specifically designed to help with this problem.
67
+ After all, people can submit comments or posts with HTML in them, but WP can
68
+ handle this fine. WordPress handles this through a library called kses, which
69
+ sanitizes HTML down to a small, whitelisted subset of HTML. Posts can have more
70
+ HTML tags than comments can, since they're usually semi-trusted users.
71
+
72
+ kses is great, but is not typically used outside of large HTML blocks like post
73
+ or comment content. The reason for this is often stated as performance. It's
74
+ well-known that kses is pretty slow, since it has to essentially disassemble the
75
+ HTML, then reconstruct it with the allowed tags.
76
+
77
+ However, Zack Tollman wrote a [fantastic post][tollmanz-kses] that calls into
78
+ question this accepted knowledge of kses performance. Zack's findings show that
79
+ while kses is worse with performance on longer pieces of content (like post
80
+ content), it's actually closer to being on-par with other escaping for short
81
+ strings. This is even more evident when reducing the whitelist of elements down
82
+ from the default to just the elements you need.
83
+
84
+ [tollmanz-kses]: https://www.tollmanz.com/wp-kses-performance/
85
+
86
+ ### `whitelist_html`
87
+
88
+ This library provides a nice, easy, performant way to perform sanitization on
89
+ translated strings. Rather than requiring you to work with the internals of
90
+ kses, it's much closer to functions like `esc_html`.
91
+
92
+ Security is only useful if it's also usable. For the most part, `whitelist_html`
93
+ can be used in exactly the same way developers are used to using other escaping
94
+ functions.
95
+
96
+ A quick example to demonstrate how easy it is:
97
+ ```html
98
+ <!-- Previously -->
99
+ <p><?php _e( 'This is a terrific use of <code>WP_Error</code>.' ) ?></p>
100
+
101
+ <!-- Secure version -->
102
+ <p><?php print_whitelist_html( __( 'This is a terrific use of <code>WP_Error</code>.' ), 'code' ) ?></p>
103
+ ```
104
+
105
+ Even if a malicious translator changed this to include a link to a spam site (or
106
+ worse), this would be caught and stripped by `whitelist_html`.
107
+
108
+ Taking our original example from above, we can modify it to only allow `a` tags:
109
+
110
+ ```php
111
+ $text = whitelist_html(
112
+ sprintf(
113
+ __( 'This is some text <a href="%1$s">with a link</a>'),
114
+ 'http://example.com/'
115
+ ),
116
+ 'a'
117
+ );
118
+ ```
119
+
120
+ It's that easy. You can do this with multiple elements as well, using a
121
+ comma-separated string or list of elements:
122
+
123
+ ```php
124
+ $text = whitelist_html(
125
+ sprintf(
126
+ __( 'This is <code>some</code> text <a href="%1$s">with a link</a>'),
127
+ 'http://example.com/'
128
+ ),
129
+ 'a, code' // or array( 'a', 'code' )
130
+ );
131
+ ```
132
+
133
+ If you need custom attributes, you can use kses-style attribute specifiers.
134
+ These can be mixed too:
135
+
136
+ ```php
137
+ $text = whitelist_html(
138
+ sprintf(
139
+ __( 'This is <span class="x">some</span> text <a href="%1$s">with a link</a>'),
140
+ 'http://example.com/'
141
+ ),
142
+ array(
143
+ 'a',
144
+ 'span' => array(
145
+ 'class' => true,
146
+ ),
147
+ )
148
+ );
149
+ ```
150
+
151
+
152
+ ### Performance Test
153
+
154
+ In a quick test, the string
155
+ `'hello with a <a href="wak://example.com">malicious extra link!<///q><o>b'` was
156
+ run through both `whitelist_html` (with only `a`) and `esc_html` with 10,000
157
+ iterations. While the two functions don't perform the same task, they're both
158
+ escaping functions, so it's useful to compare performance to understand whether
159
+ this approach can be used in production code.
160
+
161
+ In an unscientific trial, this gave figures of 0.96s for `whitelist_html` and
162
+ 1.07s for `esc_html` for 10,000 trials each. This indicates that
163
+ `whitelist_html` is at least on the order of other escaping functions.
164
+
165
+
166
+ ## Using this Library
167
+
168
+ Two steps to using this library:
169
+
170
+ 1. Add this library in as a git submodule.
171
+ 2. Load `whitelist-html.php` before you need to use it. We recommend in
172
+ `mu-plugins`, but you can also load it in via `wp-config.php` if you want it
173
+ earlier.
174
+
175
+ Done. Start using the function.
whitelist-html/whitelist-html.php ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Escapes text for HTML output, allowing certain tags
5
+ *
6
+ * Takes an arbitrary string and ensures it's safe for output into HTML. Unlike
7
+ * `esc_html`, this allows a certain subset of tags, allowing it to be used for
8
+ * strings which need to have some HTML in them (such as translated text).
9
+ *
10
+ * Allowed tags can be passed in one of two formats. The verbose form is the
11
+ * traditional kses form of
12
+ * `[ 'element' => array( 'attr' => true, 'otherattr' => true ) ]` which
13
+ * specifies tags and their attributes.
14
+ *
15
+ * The concise form, useful for inline usage on output, is in the form of
16
+ * `[ 'element', 'otherelement' ]` - This concise form takes the attribute list
17
+ * from WP core's attribute whitelist for a good-enough list for most usages.
18
+ * This can also be passed as a comma separated string.
19
+ *
20
+ * (You can also mix these forms, so something like
21
+ * `[ 'a', 'code', 'x-panel' => array( 'src' => true ) ] )` is perfectly valid.)
22
+ *
23
+ * For example:
24
+ *
25
+ * whitelist_html( __( 'Hello <a href="http://example.com">World!</a>' ), 'a' );
26
+ *
27
+ * This example would strip any tag except `a`, but would allow the default
28
+ * attributes on it (`href` and `title`).
29
+ *
30
+ * The default attributes and tags are based on {@see wp_kses_allowed_html} with
31
+ * the blank (default) "context". These are the tags in {@see $allowedtags}. To
32
+ * get all allowed post tags, pass `'post'` as the `$context` parameter, or pass
33
+ * the tags you need in the `$allowedtags` array. If a specified tag is not in
34
+ * the list, no attributes will be allowed.
35
+ *
36
+ * @link https://www.tollmanz.com/wp-kses-performance/
37
+ *
38
+ * @param string $text Content to escape
39
+ * @param array $allowedtags Allowed tags, see description.
40
+ * @param string $context kses context to use, {@see wp_kses_allowed_html}.
41
+ * @return string Escaped string for output into HTML context.
42
+ */
43
+ function whitelist_html( $text, $allowedtags = array(), $context = '' ) {
44
+ $actually_allowed = array();
45
+ $default_list = wp_kses_allowed_html( $context );
46
+
47
+ // Split comma-separated string
48
+ if ( is_string( $allowedtags ) ) {
49
+ $allowedtags = array_map( 'trim', explode( ',', $allowedtags ) );
50
+ }
51
+
52
+ foreach ( $allowedtags as $key => $tag ) {
53
+ if ( is_array( $tag ) && is_string( $key ) ) {
54
+ // kses-formatted of `'element' => [ 'attr' => true ]
55
+ // `$tag` is actually the attrs, and `$key` is the tag name
56
+ $actually_allowed[ $key ] = $tag;
57
+ continue;
58
+ }
59
+
60
+ if ( ! is_string( $tag ) ) {
61
+ // Not concise form, what even is this?
62
+ _doing_it_wrong( 'whitelist_html', '$allowedtags must consist of strings or kses-style arrays' );
63
+ continue;
64
+ }
65
+
66
+ // Grab default attributes for the tag
67
+ $attrs = array();
68
+ if ( isset( $default_list[ $tag ] ) ) {
69
+ $attrs = $default_list[ $tag ];
70
+ }
71
+
72
+ // Add to allowed list
73
+ $actually_allowed[ $tag ] = $attrs;
74
+ }
75
+
76
+ // Do the sanitization dance
77
+ $sanitized = wp_kses( $text, $actually_allowed );
78
+
79
+ /**
80
+ * Filter a string to be output into HTML, allowing some tags
81
+ *
82
+ * @param string $sanitized The text after it has been escaped.
83
+ * @param string $text The text before it has been escaped.
84
+ * @param string $allowedtags Tags requested to whitelist.
85
+ * @param string
86
+ */
87
+ return apply_filters( 'whitelist_html', $sanitized, $text, $allowedtags, $context );
88
+ }
89
+
90
+ /**
91
+ * Escapes text for HTML output, allowing certain tags, then outputs.
92
+ *
93
+ * @see whitelist_html
94
+ *
95
+ * @param string $text Content to escape
96
+ * @param array $allowedtags Allowed tags, {@see whitelist_html}.
97
+ * @param string $context kses context to use, {@see wp_kses_allowed_html}.
98
+ * @return string Escaped string for output into HTML context.
99
+ */
100
+ function print_whitelist_html( $text, $allowedtags = array(), $context = '' ) {
101
+ echo whitelist_html( $text, $allowedtags, $context );
102
+ }