PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.3
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.3
5.5.84 5.5.83 5.5.82 5.5.81 5.5.80 5.5.79 5.5.77 5.5.76 5.5.75 5.5.73 5.5.72 5.5.22 5.5.23 5.5.29 5.5.3 5.5.31 5.5.32 5.5.34 5.5.35 5.5.36 5.5.37 5.5.4 5.5.40 5.5.41 5.5.42 All 160 releases
wp-data-access / WPDataAccess / Backup / WPDA_Data_Export.php

WPDA_Data_Export.php in WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards 5.5.3, at WPDataAccess/Backup/WPDA_Data_Export.php

1,155 lines 44.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php // phpcs:ignore Standard.Category.SniffName.ErrorCode
2 /**
3 * Suppress "error - 0 - No summary was found for this file" on phpdoc generation
4 *
5 * @package WPDataAccess\Backup
6 */
7
8 namespace WPDataAccess\Backup {
9
10 use Dropbox\Dropbox;
11 use Dropbox\Dropbox\Auth;
12 use WPDataAccess\Dashboard\WPDA_Dashboard;
13 use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Lists;
14 use WPDataAccess\Settings\WPDA_Settings_DataBackup;
15 use WPDataAccess\Utilities\WPDA_Export_Sql;
16 use WPDataAccess\Utilities\WPDA_Remote_Call;
17 use WPDataAccess\WPDA;
18 use WPDataAccess\Utilities\WPDA_Message_Box;
19 use WPDataAccess\Utilities\WPDA_Repository;
20
21 /**
22 * Class WPDA_Data_Export
23 *
24 * This class offers support to manage unattended data exports. Data exports can be run once only or scheduled.
25 * Every data backup has a unique name to identify it. The data backup name is used in combination with the date
26 * and time to create a unique file name.
27 *
28 * @author Peter Schulz
29 * @since 1.0.0
30 */
31 class WPDA_Data_Export {
32
33 const PREFIX_RUNONCE = 'wpda-run-once-';
34 const SHOW_JOBS_OPTION_NAME = 'wpda_data_backup_show_jobs';
35
36 /**
37 * Holds the scheduled cron jobs
38 *
39 * @var array
40 */
41 protected $schedules;
42
43 /**
44 * WPDA_Data_Export constructor
45 *
46 * Gets and stores the scheduled cron jobs.
47 */
48 public function __construct() {
49 $this->schedules = wp_get_schedules();
50 }
51
52 /**
53 * Data entry form to add or update a data backup
54 *
55 * @param string $action Add for new export; Update to edit existing export.
56 */
57 public function create_export( $action ) {
58 $wpda_db_options_activated = get_option( 'wpda_db_options_activated' );
59 if ( ! is_array( $wpda_db_options_activated ) || 0 === count( $wpda_db_options_activated ) ) {//phpcs:ignore - 8.1 proof
60 echo '<br/>';
61 echo __( 'You need to define and activate at least one storage device in Data Backup Settings to use this feature.', 'wp-data-access' ); // phpcs:ignore WordPress.Security.EscapeOutput
62 echo '<br/>';
63 echo '<a href="?page=wpdataaccess&tab=databackup">&raquo; ';
64 echo __( 'Define and/or activate a storage device', 'wp-data-access' ); // phpcs:ignore WordPress.Security.EscapeOutput
65 echo '</a>';
66 wp_die();
67 }
68
69 if ( isset( $_REQUEST['wpdaschema_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
70 $schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpdaschema_name'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
71 } else {
72 $schema_name = '';
73 }
74
75 $device_arg = '';
76 if ( 'update' === $action ) {
77 if ( isset( $_REQUEST['schedule'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
78 $schedule = sanitize_text_field( wp_unslash( $_REQUEST['schedule'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
79 if ( 'wpda_data_backup' !== $schedule ) {
80 wp_die( __( 'ERROR: Wrong arguments', 'wp-data-access' ) ); // phpcs:ignore WordPress.Security.EscapeOutput
81 }
82 } else {
83 wp_die( __( 'ERROR: Wrong arguments', 'wp-data-access' ) ); // phpcs:ignore WordPress.Security.EscapeOutput
84 }
85 if ( isset( $_REQUEST['schedule_args'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
86 $backupid = sanitize_text_field( wp_unslash( $_REQUEST['schedule_args'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
87 } else {
88 wp_die( __( 'ERROR: Wrong arguments', 'wp-data-access' ) ); // phpcs:ignore WordPress.Security.EscapeOutput
89 }
90 $data_backups = get_option( 'wpda_data_backup_option' );
91 $data_backup_found = false;
92 foreach ( $data_backups as $data_backup ) {
93 if ( $data_backup['id'] === $backupid ) {
94 $data_backup_tables = $data_backup['tables'];
95 $keep = $data_backup['keep'];
96 $schema_name = isset( $data_backup['schema_name'] ) ? $data_backup['schema_name'] : '';
97 $data_backup_found = true;
98 }
99 }
100 if ( ! $data_backup_found ) {
101 wp_die( __( 'ERROR: Wrong arguments', 'wp-data-access' ) ); // phpcs:ignore WordPress.Security.EscapeOutput
102 }
103 if ( isset( $_REQUEST['interval'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
104 $interval = sanitize_text_field( wp_unslash( $_REQUEST['interval'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
105 }
106 if ( isset( $_REQUEST['device'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
107 $device_arg = sanitize_text_field( wp_unslash( $_REQUEST['device'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
108 }
109 } else {
110 $backupid = '';
111 }
112
113 $table_list = WPDA_Dictionary_Lists::get_tables( false, $schema_name );
114 ?>
115 <div class="wrap">
116 <h1 class="wp-heading-inline">
117 <?php echo __( 'Data Backup' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
118 </h1>
119 <div id="wpda_export_import">
120 <div class="wpda_export_import">
121 <form id="wpda_export_import_form"
122 action="?page=wpda&page_action=wpda_backup"
123 method="post"
124 onsubmit="return pre_submit()">
125 <table>
126 <tr>
127 <td style="font-weight:bold;padding-left:10px;"><?php echo __( 'Database Tables' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
128 <td></td>
129 <td style="font-weight:bold;padding-left:10px"><?php echo __( 'Tables To Be Exported' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
130 </tr>
131 <tr>
132 <td>
133 <select id="wpda_table_name_db" name="wpda_table_name_db" multiple size="20"
134 style="width:300px;">
135 <?php
136 foreach ( $table_list as $key => $value ) {
137 echo '<option value="' . esc_attr( $value['table_name'] ) . '">' . esc_attr( $value['table_name'] ) . '</option>';
138 }
139 ?>
140 </select>
141 </td>
142 <td>
143 <a href="javascript:void(0)" class="button" onclick="move_all_to_export()">
144 >>> </a>
145 <br/>
146 <a href="javascript:void(0)" class="button" onclick="move_all_to_db()"> <<< </a>
147 </td>
148 <td>
149 <select id="wpda_table_name_export" name="wpda_table_name_export[]" multiple
150 size="20" style="width:300px;">
151 </select>
152 </td>
153 </tr>
154 <tr>
155 <td colspan="3" style="text-align:center;">
156 <table align="center">
157 <tr>
158 <td style="text-align:right;"><?php echo __( 'Backup Id' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
159 <td style="text-align:left;">
160 <input
161 type="text"
162 id="backupid"
163 name="backupid"
164 value="<?php echo esc_attr( $backupid ); ?>"
165 maxlength="50"
166 <?php
167 if ( 'update' === $action ) {
168 echo 'readonly';
169 }
170 ?>
171 />
172 </td>
173 </tr>
174 <tr>
175 <td style="text-align:right;"><?php echo __( 'Backup Interval' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
176 <td style="text-align:left;">
177 <select id="interval" name="interval">
178 <?php if ( 'add' === $action ) { ?>
179 <option value="runonce"><?php echo __( 'Run once (no interval)' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></option>
180 <?php } ?>
181 <?php
182 foreach ( $this->schedules as $key => $schedule ) {
183 echo '<option value="' . esc_attr( $key ) . '">' .
184 esc_attr( $schedule['display'] ) . ' (' . esc_attr( $schedule['interval'] ) . ' sec)' .
185 '</option>';
186 }
187 ?>
188 </select>
189 </td>
190 </tr>
191 <tr>
192 <td style="text-align:right;"><?php echo __( 'Backup Location' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
193 <td style="text-align:left;">
194 <select id="device" name="device">
195 <?php
196 foreach ( $wpda_db_options_activated as $key => $value ) {
197 $device = $key;
198 if ( 'local_path' === $key ) {
199 $device = 'local > ' . WPDA::get_option( WPDA::OPTION_DB_LOCAL_PATH );
200 } elseif ( 'dropbox' === $key ) {
201 $dropbox_path = WPDA::get_option( WPDA::OPTION_DB_DROPBOX_PATH );
202 if ( '' === $dropbox_path ) {
203 $dropbox_path = '/wp-data-access-backups/'; // Use last version.
204 }
205 $device = 'dropbox > ' . $dropbox_path;
206 }
207 echo '<option value="' . esc_attr( $key ) . '"' . ( $key === $device_arg ? 'selected' : '' ) . '>' .
208 esc_attr( $device ) .
209 '</option>';
210 }
211 ?>
212 </select>
213 </td>
214 </tr>
215 <tr>
216 <td style="text-align:right;"><?php echo __( 'Backup Files Kept' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
217 <td style="text-align:left;">
218 <select id="keep" name="keep">
219 <option value="1">1</option>
220 <option value="2">2</option>
221 <option value="3">3</option>
222 <option value="4">4</option>
223 <option value="5">5</option>
224 <option value="6">6</option>
225 <option value="7">7</option>
226 <option value="8">8</option>
227 <option value="9">9</option>
228 <option value="10">10</option>
229 <option value="ALL">ALL</option>
230 </select>
231 </td>
232 </tr>
233 <tr>
234 <td></td>
235 <td style="text-align:left;">
236 <button type="submit" class="button button-primary">
237 <i class="fas fa-check wpda_icon_on_button"></i>
238 <?php echo __( 'Start' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
239 </button>
240 <button type="button" class="button button-secondary"
241 onclick="window.location.href=window.location.href">
242 <i class="fas fa-times-circle wpda_icon_on_button"></i>
243 <?php echo __( 'Cancel' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
244 </button>
245 </td>
246 </tr>
247 </table>
248 </td>
249 </tr>
250 </table>
251 <input type="hidden" name="wpdaschema_name" value="<?php echo esc_attr( $schema_name ); ?>"/>
252 <input type="hidden" name="action" value="<?php echo esc_attr( $action ); ?>"/>
253 </form>
254 </div>
255 </div>
256 </div>
257 <script type='text/javascript'>
258 var tables_selected = [];
259 <?php
260 if ( 'update' === $action ) {
261 foreach ( $data_backup_tables as $data_backup_table ) {
262 ?>
263 tables_selected.push('<?php echo esc_attr( $data_backup_table ); ?>');
264 <?php
265 }
266 ?>
267 jQuery(function () {
268 jQuery("#keep option[value='<?php echo esc_attr( $keep ); ?>']").prop('selected', true);
269 jQuery("#interval option[value='<?php echo esc_attr( $interval ); ?>']").prop('selected', true);
270 for (var i = 0; i < tables_selected.length; i++) {
271 jQuery("#wpda_table_name_db option[value='" + tables_selected[i] + "']").remove();
272 jQuery('#wpda_table_name_export').append(jQuery('<option>', {
273 value: tables_selected[i],
274 text: tables_selected[i]
275 }));
276 }
277 });
278 <?php
279 } else {
280 ?>
281 jQuery(function () {
282 jQuery("#keep option[value='3']").prop('selected', true);
283 jQuery( '.wpda_tooltip' ).tooltip();
284 });
285 <?php
286 }
287 ?>
288 function pre_submit() {
289 if (0 === jQuery("#wpda_table_name_export > option").length) {
290 alert('<?php echo __( 'No tables to be exported' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>');
291 return false;
292 }
293 if ('' === jQuery("#backupid").val().trim()) {
294 alert('<?php echo __( 'You must specify a backupid' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>');
295 return false;
296 }
297 jQuery("#wpda_table_name_export > option").each(function () {
298 jQuery(this).attr("selected", "true");
299 });
300 return true;
301 }
302
303 function move_all_to_export() {
304 jQuery("#wpda_table_name_db > option").each(function () {
305 jQuery('#wpda_table_name_export').append(jQuery('<option>', {
306 value: this.text,
307 text: this.text
308 }));
309 });
310 jQuery('#wpda_table_name_db > option').remove();
311 }
312
313 function move_all_to_db() {
314 jQuery("#wpda_table_name_export > option").each(function () {
315 jQuery('#wpda_table_name_db').append(jQuery('<option>', {
316 value: this.text,
317 text: this.text
318 }));
319 });
320 jQuery('#wpda_table_name_export > option').remove();
321 }
322
323 jQuery(function () {
324 jQuery('#wpda_table_name_db').on('click', function (event) {
325 if ('' !== event.target.text && undefined != event.target.text) {
326 jQuery('#wpda_table_name_export').append(jQuery('<option>', {
327 value: event.target.text,
328 text: event.target.text
329 }));
330 jQuery("#wpda_table_name_db option[value='" + event.target.text + "']").remove();
331 }
332 });
333 jQuery('#wpda_table_name_export').on('click', function (event) {
334 if ('' !== event.target.text && undefined != event.target.text) {
335 jQuery('#wpda_table_name_db').append(jQuery('<option>', {
336 value: event.target.text,
337 text: event.target.text
338 }));
339 jQuery("#wpda_table_name_export option[value='" + event.target.text + "']").remove();
340 }
341 });
342 });
343 </script>
344 <?php
345 }
346
347 /**
348 * Show available cron jobs
349 *
350 * Shows data backups only be default. Other cron jobs can be displayed as well.
351 */
352 public function show_wp_cron() {
353 $wpda_repository = new WPDA_Repository();
354 $wpda_repository->inform_user();
355
356 $no_data_backup_events = 0;
357 $data_backups = get_option( 'wpda_data_backup_option' );
358 $data_backups_keep = array();
359 $data_backups_device = array();
360 if ( null !== $data_backups && false !== $data_backups ) {
361 foreach ( $data_backups as $data_backup ) {
362 $data_backups_keep[ $data_backup['id'] ] = $data_backup['keep'];
363 $data_backups_device[ $data_backup['id'] ] = $data_backup['device'];
364 }
365 }
366
367 $crons = _get_cron_array();
368 $data_backups_found = false;
369 foreach ( $crons as $key => $cron ) {
370 foreach ( $cron as $key => $value ) {
371 if ( 'wpda_data_backup' === $key ) {
372 $data_backups_found = true;
373 continue;
374 }
375 }
376 if ( $data_backups_found ) {
377 continue;
378 }
379 }
380
381 if ( isset( $_REQUEST['show_jobs'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
382 $show_jobs = sanitize_text_field( wp_unslash( $_REQUEST['show_jobs'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
383 update_option( self::SHOW_JOBS_OPTION_NAME, $show_jobs );
384 } else {
385 $show_jobs = get_option( self::SHOW_JOBS_OPTION_NAME, 'wpda' );
386 }
387
388 if ( isset( $_REQUEST['wpdaschema_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
389 $schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpdaschema_name'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
390 } else {
391 $schema_name = '';
392 }
393
394 global $wpdb;
395
396 echo '<div class="wrap">';
397 echo '<h1 class="wp-heading-inline">';
398 echo __( 'Data Backup' ); // phpcs:ignore WordPress.Security.EscapeOutput
399 echo '</h1>';
400
401 if ( $data_backups_found || 'all' === $show_jobs ) {
402 echo '<table cellpadding="3" cellspacing="3" border="0" style="border-collapse:collapse;">';
403 echo '<tr>';
404 echo '<th></th>';
405 echo '<th></th>';
406 echo '<th style="text-align:left;">' . __( 'Hook Name' ) . '</th>'; // phpcs:ignore WordPress.Security.EscapeOutput
407 echo '<th style="text-align:left;">' . __( 'Arguments' ) . '</th>'; // phpcs:ignore WordPress.Security.EscapeOutput
408 echo '<th style="text-align:left;">' . __( 'Interval' ) . '</th>'; // phpcs:ignore WordPress.Security.EscapeOutput
409 echo '<th style="text-align:left;">' . __( 'Next Execution' ) . '</th>'; // phpcs:ignore WordPress.Security.EscapeOutput
410 echo '<th style="text-align:left;">' . __( 'Backup Location' ) . '</th>'; // phpcs:ignore WordPress.Security.EscapeOutput
411 echo '<th style="text-align:left;">' . __( 'Files Kept' ) . '</th>'; // phpcs:ignore WordPress.Security.EscapeOutput
412 echo '<th colspan="2" style="text-align:left;">' . __( 'Status' ) . '</th>'; // phpcs:ignore WordPress.Security.EscapeOutput
413 echo '</tr>';
414 foreach ( $crons as $key => $cron ) {
415 foreach ( $cron as $key => $value ) {
416 if ( 'wpda_data_backup' === $key ) {
417 // Filter run once jobs.
418 $is_runonce = false;
419 foreach ( $value as $value_key => $value_value ) {
420 if ( isset( $value_value['args'][0] ) && substr( $value_value['args'][0], 0, 14 ) === 'wpda-run-once-' ) {
421 $is_runonce = true;
422 continue;
423 }
424 }
425 if ( $is_runonce ) {
426 continue;
427 }
428 $style = 'style="background-color:#ffffff;"';
429 $no_data_backup_events ++;
430 } else {
431 $style = '';
432 if ( 'all' !== $show_jobs ) {
433 // Hide other cron jobs.
434 continue;
435 }
436 }
437 echo '<tr ' . esc_attr( $style ) . '>';
438 if ( 'wpda_data_backup' === $key ) {
439 echo '<td>';
440 echo '<form method="post" action="?page=wpda&page_action=wpda_backup">';
441 echo '<a href="javascript:void(0)" onclick="if (confirm(\'Are you sure you want to delete this data backup job?\')) { jQuery(this).closest(\'form\').submit(); }" class="dashicons dashicons-trash"></a>';
442 echo '<input type="hidden" name="action" value="remove" />';
443 echo '<input type="hidden" name="schedule" value="' . esc_attr( $key ) . '" />';
444 foreach ( $value as $value_key => $value_value ) {
445 $schedule_args = isset( $value_value['args'][0] ) ? $value_value['args'][0] : '';
446 echo '<input type="hidden" name="schedule_args" value="' . esc_attr( $schedule_args ) . '" />';
447 }
448 echo '</form>';
449 echo '</td>';
450 echo '<td>';
451 echo '<form method="post" action="?page=wpda&page_action=wpda_backup">';
452 echo '<a href="javascript:void(0)" onclick="jQuery(this).closest(\'form\').submit()" class="dashicons dashicons-edit"></a>';
453 echo '<input type="hidden" name="action" value="edit" />';
454 echo '<input type="hidden" name="schedule" value="' . esc_attr( $key ) . '" />';
455 foreach ( $this->schedules as $schedule_key => $schedule ) {
456 if ( $schedule['display'] === $this->schedules[ $value_value['schedule'] ]['display'] ) {
457 $interval = $schedule_key;
458 }
459 }
460 foreach ( $value as $value_key => $value_value ) {
461 echo '<input type="hidden" name="schedule_args" value="' . esc_attr( $value_value['args'][0] ) . '" />';
462 echo '<input type="hidden" name="interval" value="' . esc_attr( $interval ) . '" />';
463 }
464 if ( isset( $data_backups_keep[ $value_value['args'][0] ] ) ) {
465 echo '<input type="hidden" name="device" value="' . esc_attr( $data_backups_device[ $value_value['args'][0] ] ) . '" />';
466 }
467 echo '</form>';
468 echo '</td>';
469 } else {
470 echo '<td>';
471 echo '</td>';
472 echo '<td>';
473 echo '</td>';
474 }
475 echo '<td>';
476 echo esc_attr( $key );
477 echo '</td>';
478 foreach ( $value as $value_key => $value_value ) {
479 echo '<td>';
480 if ( is_array ($value_value['args']) &&
481 0 < count( $value_value['args'] ) ) {//phpcs:ignore - 8.1 proof
482 foreach ( $value_value['args'] as $arg ) {
483 if ( reset( $value_value['args'] ) !== $arg ) {//phpcs:ignore - 8.1 proof
484 echo ',';
485 }
486 echo esc_attr( $arg );
487 }
488 } else {
489 echo '-';
490 }
491 echo '</td>';
492 echo '<td>';
493 if ( isset( $this->schedules[ $value_value['schedule'] ]['display'] ) ) {
494 echo esc_attr( $this->schedules[ $value_value['schedule'] ]['display'] );
495 if ( isset( $value_value['interval'] ) ) {
496 echo ' (' . esc_attr( $value_value['interval'] ) . ' sec)';
497 }
498 }
499 echo '</td>';
500 echo '<td>';
501 $next = wp_next_scheduled( $key, $value_value['args'] );
502 echo esc_attr( get_date_from_gmt( gmdate( 'Y-m-d H:i:s', $next ) ) );
503 echo '</td>';
504 echo '<td>';
505 if ( 'wpda_data_backup' === $key ) {
506 if ( isset( $data_backups_device[ $value_value['args'][0] ] ) ) {
507 echo esc_attr( $data_backups_device[ $value_value['args'][0] ] );
508 }
509 }
510 echo '</td>';
511 echo '<td>';
512 if ( 'wpda_data_backup' === $key ) {
513 if ( isset( $data_backups_keep[ $value_value['args'][0] ] ) ) {
514 echo esc_attr( $data_backups_keep[ $value_value['args'][0] ] );
515 }
516 }
517 echo '</td>';
518 echo '<td>';
519 if ( 'wpda_data_backup' === $key ) {
520 echo '<form method="post" action="?page=wpda">';
521 echo '<input type="hidden" name="table_name" value="' . esc_attr( $wpdb->prefix ) . 'wpda_logging" />';
522 echo '<input type="hidden" name="wpda_s" value="' . esc_attr( $value_value['args'][0] ) . '" />';
523 echo '<a href="javascript:void(0)" onclick="jQuery(this).closest(\'form\').submit()" class="dashicons dashicons-info"></a>';
524 echo '</form>';
525 }
526 echo '</td>';
527 echo '<td>';
528 if ( 'wpda_data_backup' === $key ) {
529 $resultset = $wpdb->get_results(
530 $wpdb->prepare(
531 "
532 SELECT `log_time`, `log_type`, `log_msg`
533 FROM `{$wpdb->prefix}wpda_logging`
534 WHERE `log_id` = %s
535 ORDER BY `log_time` desc limit 1",
536 array(
537 $value_value['args'][0],
538 )
539 ),
540 'ARRAY_A'
541 ); // db call ok; no-cache ok.
542 if ( 1 === $wpdb->num_rows ) {
543 echo esc_attr( $resultset[0]['log_type'] ) . ': ' .
544 esc_attr( $resultset[0]['log_msg'] ) .
545 ' (' . esc_attr( $resultset[0]['log_time'] ) . ')';
546 } else {
547 echo __( 'No logging information found' ); // phpcs:ignore WordPress.Security.EscapeOutput
548 }
549 }
550 echo '</td>';
551 }
552 echo '</tr>';
553 }
554 }
555 echo '</table>';
556 echo '<table style="margin-top:10px">';
557 echo '<tr>';
558 echo '<td><strong>' . esc_attr( $no_data_backup_events ) . ' data backup job' .
559 ( 1 < $no_data_backup_events ? 's' : '' ) . ' scheduled</strong></td>';
560 } else {
561 echo '<table>';
562 echo '<tr>';
563 echo '<td><strong>' . __( 'No data backup jobs found' ) . '</strong></td>'; // phpcs:ignore WordPress.Security.EscapeOutput
564 }
565 echo '<td>';
566 echo '<form method="post" action="?page=wpda&page_action=wpda_backup" style="display: inline-block; vertical-align: unset;">';
567 echo '<select name="show_jobs" onchange="jQuery(this).closest(\'form\').submit()" >';
568 echo '<option value="wpda"' . ( 'all' !== $show_jobs ? 'selected' : '' ) . '>' . __( 'Show plugin jobs only' ) . '</option>'; // phpcs:ignore WordPress.Security.EscapeOutput
569 echo '<option value="all"' . ( 'all' === $show_jobs ? 'selected' : '' ) . '>' . __( 'Show all WordPress jobs' ) . '</option>'; // phpcs:ignore WordPress.Security.EscapeOutput
570 echo '</select>';
571 echo '</form>';
572 echo '</td>';
573 echo '</tr>';
574 echo '</table>';
575 echo '</div>';
576 ?>
577 <script type="text/javascript">
578 jQuery(function () {
579 jQuery( '.wpda_tooltip' ).tooltip();
580 });
581 // Add toolbar events
582 jQuery("#wpda_toolbar_icon_add_backup").on("click", function() {
583 jQuery("#wpda_new_backup_wpdaschema_name").val("<?php echo esc_attr( $schema_name ); ?>");
584 jQuery("#wpda_new_backup").submit();
585 });
586 </script>
587 <?php
588 }
589
590 /**
591 * Prepares an unattended data backup (export)
592 *
593 * @param string $backupid Unique ID that identifies a data backup.
594 */
595 public function wpda_data_backup( $backupid ) {
596 $is_runonce_data_backup = substr( $backupid, 0, strlen( self::PREFIX_RUNONCE ) ) === self::PREFIX_RUNONCE;
597 if ( $is_runonce_data_backup ) {
598 // Run once data backup.
599 $data_backups = get_option( 'wpda_data_backup_option_runonce' );
600 // Directly remove data backup to prevent multiple backups.
601 $data_backups_new = array();
602 foreach ( $data_backups as $data_backup ) {
603 if ( $data_backup['id'] !== $backupid ) {
604 array_push( $data_backups_new, $data_backup );//phpcs:ignore - 8.1 proof
605 }
606 }
607 update_option( 'wpda_data_backup_option_runonce', $data_backups_new );
608 } else {
609 // Data backup job.
610 $data_backups = get_option( 'wpda_data_backup_option' );
611 }
612
613 foreach ( $data_backups as $data_backup ) {
614 if ( $data_backup['id'] === $backupid ) {
615 if ( $is_runonce_data_backup ) {
616 $user_backupid = substr( $backupid, strlen( self::PREFIX_RUNONCE ) );
617 } else {
618 $user_backupid = $backupid;
619 }
620
621 $keep = $data_backup['keep'];
622 $device = $data_backup['device'];
623 $schema = $data_backup['schema_name'];
624 $tables = $data_backup['tables'];
625
626 $this->wpda_data_backup_run( $user_backupid, $keep, $device, $tables, $schema );
627 }
628 }
629 }
630
631 /**
632 * Performs an unattended data backup (export)
633 *
634 * @param string $backupid Unique ID that identifies a data backup.
635 * @param integer $keep Number of backup files to be kept.
636 * @param string $device Location where export file is stored.
637 * @param array $tables Tables to be exported.
638 * @param array $schema Database schema name or remote database connection string.
639 */
640 protected function wpda_data_backup_run( $backupid, $keep, $device, $tables, $schema ) {
641 try {
642 $prefix = "wpda-data-backup-$backupid-";
643 $filename = $prefix . gmdate( 'YmdHis' ) . '.sql';
644
645 if ( 'local_path' === $device ) {
646 $local_path = WPDA::get_option( WPDA::OPTION_DB_LOCAL_PATH );
647 $client_file_name = $local_path . $filename;
648 $file = fopen( $client_file_name, 'w' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
649 $wpda_export = new WPDA_Export_Sql();
650 $wpda_export->set_output_stream( $file );
651 $wpda_export->export_with_arguments(
652 'on',
653 'on',
654 'on',
655 $schema,
656 $tables,
657 'table'
658 );
659 fclose( $file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
660 $keep_counting = 0;
661 $files_sorted = array();
662 foreach ( glob( $local_path . "wpda-data-backup-$backupid-*.sql" ) as $filename ) {
663 array_push( $files_sorted, $filename );//phpcs:ignore - 8.1 proof
664 }
665 rsort( $files_sorted );//phpcs:ignore - 8.1 proof
666 foreach ( $files_sorted as $file ) {
667 $keep_counting ++;
668 if ( $keep_counting > (int) $keep ) {
669 unlink( $file );
670 }
671 }
672 } elseif ( 'dropbox' === $device ) {
673 // To use a stream for Dropbox we first need to write the export to a temporary file.
674 $temporary_file = tmpfile();
675 $wpda_export = new WPDA_Export_Sql();
676 $wpda_export->set_output_stream( $temporary_file );
677 $wpda_export->export_with_arguments(
678 'on',
679 'on',
680 'on',
681 $schema,
682 $tables,
683 'table'
684 );
685
686 $client_access_token = WPDA_Settings_DataBackup::dropbox_get_token();
687 if ( false === $client_access_token ) {
688 // Use old token strategy (for older activations).
689 $client_access_token = get_option( 'wpda_db_dropbox_access_token' );
690 if ( false === $client_access_token ) {
691 // No token = no dropbox backup.
692 WPDA::log( $backupid, 'ERROR', "Data backup '$backupid'' failed (missing access token)" );
693 return;
694 }
695 }
696
697 $client_access_path = WPDA::get_option( WPDA::OPTION_DB_DROPBOX_PATH );
698 if ( '' === $client_access_path ) {
699 $client_access_path = '/';
700 }
701 $client_file_name = $client_access_path . $filename;
702 $post_max_size = WPDA_Remote_Call::max_size();
703
704 if (
705 $post_max_size < filesize( stream_get_meta_data( $temporary_file )['uri'] ) &&
706 ! extension_loaded('zip')
707 ) {
708 // File is too big to send in one chunk and zip archive is not installed.
709 WPDA::log( $backupid, 'ERROR', "Data backup '$backupid'' failed (ZipArchive not installed)" );
710 return;
711 }
712
713 if ( extension_loaded('zip') ) {
714 $zip = new \ZipArchive();
715 $zipfile = sys_get_temp_dir() . '/' . $filename . '.zip';
716 if ( ! $zip->open( $zipfile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE ) ) {
717 WPDA::log( $backupid, 'ERROR', "Data backup '$backupid'' failed (could not create ZIP file)" );
718 return;
719 }
720 $zip->addFile( stream_get_meta_data( $temporary_file )['uri'], $filename );
721 $zip->close();
722
723 $zpf = fopen( $zipfile, 'r' );
724 WPDA_Remote_Call::post(
725 'https://content.dropboxapi.com/2/files/upload',
726 fread( $zpf, filesize( $zipfile ) ),
727 false,
728 array(
729 'Authorization' => "Bearer $client_access_token",
730 'Content-Type' => 'application/octet-stream',
731 'Dropbox-API-Arg' => '{"path":"' . $client_file_name . '.zip","mode":"add","autorename":false,"mute":false,"strict_conflict":false}',
732 )
733 );
734 } else {
735 fseek( $temporary_file, 0 );
736 WPDA_Remote_Call::post(
737 'https://content.dropboxapi.com/2/files/upload',
738 fread( $temporary_file, filesize( stream_get_meta_data( $temporary_file )['uri'] ) ),
739 false,
740 array(
741 'Authorization' => "Bearer $client_access_token",
742 'Content-Type' => 'application/octet-stream',
743 'Dropbox-API-Arg' => '{"path":"' . $client_file_name . '","mode":"add","autorename":false,"mute":false,"strict_conflict":false}',
744 )
745 );
746 }
747
748 // Search for outdated files.
749 $ext = extension_loaded('zip') ? '.zip' : '';
750 $response = WPDA_Remote_Call::post(
751 'https://api.dropboxapi.com/2/files/search_v2',
752 json_encode(
753 array(
754 'options' => array(
755 'file_status' => 'active',
756 'filename_only' => false,
757 'max_results' => 999,
758 'path' => substr( $client_access_path, 0, strlen( $client_access_path ) - 1 )
759 ),
760 'query' => $prefix . '*' . $ext,
761 )
762 ),
763 false,
764 array(
765 'Authorization' => "Bearer $client_access_token",
766 'Content-Type' => 'application/json',
767 )
768 );
769
770 if ( 'ALL' !== $keep && isset( $response['body'] ) ) {
771 $body_content = json_decode( $response['body'], true );
772 if ( isset( $body_content['matches'] ) ) {
773 $keep_counting = 0;
774 $files_sorted = array();
775 foreach ( $body_content['matches'] as $match ) {
776 array_push( $files_sorted, $match['metadata']['metadata']['name'] );//phpcs:ignore - 8.1 proof
777 }
778 rsort( $files_sorted );//phpcs:ignore - 8.1 proof
779 foreach ( $files_sorted as $file ) {
780 $keep_counting++;
781 if ( $keep_counting > (int) $keep ) {
782 // Remove outdated files.
783 WPDA_Remote_Call::post(
784 'https://api.dropboxapi.com/2/files/delete_v2',
785 json_encode(
786 array(
787 'path' => $client_access_path . $file,
788 )
789 ),
790 false,
791 array(
792 'Authorization' => "Bearer $client_access_token",
793 'Content-Type' => 'application/json',
794 )
795 );
796 }
797 }
798 }
799 }
800 }
801 } catch ( Exception $e ) {
802 WPDA::log( $backupid, 'ERROR', "Data backup '$backupid' failed: " . $e->getMessage() );
803 }
804
805 WPDA::log( $backupid, 'INFO', "Data backup '$backupid' finished" );
806 }
807
808 /**
809 * Create a cron job for data export
810 *
811 * Backup ID = $_REQUEST['backupid']
812 */
813 public function wpda_add_cron_job() {
814 if ( ! isset( $_REQUEST['backupid'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
815 $this->show_wp_cron();
816 $msg = new WPDA_Message_Box(
817 array(
818 'message_text' => __( 'Mandatory item "backupid" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
819 'message_type' => 'error',
820 'message_is_dismissible' => false,
821 )
822 );
823 $msg->box();
824
825 return;
826 }
827 $backupid = sanitize_text_field( wp_unslash( $_REQUEST['backupid'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
828 if ( ! isset( $_REQUEST['interval'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
829 $this->show_wp_cron();
830 $msg = new WPDA_Message_Box(
831 array(
832 'message_text' => __( 'Mandatory item "interval" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
833 'message_type' => 'error',
834 'message_is_dismissible' => false,
835 )
836 );
837 $msg->box();
838
839 return;
840 }
841 $interval = sanitize_text_field( wp_unslash( $_REQUEST['interval'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
842 if ( ! isset( $_REQUEST['keep'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
843 $this->show_wp_cron();
844 $msg = new WPDA_Message_Box(
845 array(
846 'message_text' => __( 'Mandatory item "keep" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
847 'message_type' => 'error',
848 'message_is_dismissible' => false,
849 )
850 );
851 $msg->box();
852
853 return;
854 }
855 $keep = sanitize_text_field( wp_unslash( $_REQUEST['keep'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
856 if ( ! isset( $_REQUEST['device'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
857 $this->show_wp_cron();
858 $msg = new WPDA_Message_Box(
859 array(
860 'message_text' => __( 'Mandatory item "device" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
861 'message_type' => 'error',
862 'message_is_dismissible' => false,
863 )
864 );
865 $msg->box();
866
867 return;
868 }
869 $device = sanitize_text_field( wp_unslash( $_REQUEST['device'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
870 if ( ! isset( $_REQUEST['wpda_table_name_export'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
871 $this->show_wp_cron();
872 $msg = new WPDA_Message_Box(
873 array(
874 'message_text' => __( 'No tables defined to backup', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
875 'message_type' => 'error',
876 'message_is_dismissible' => false,
877 )
878 );
879 $msg->box();
880
881 return;
882 } else {
883 $request_tables = WPDA::sanitize_text_field_array( $_REQUEST['wpda_table_name_export'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput, WordPress.Security.NonceVerification
884 }
885 if ( isset( $_REQUEST['wpdaschema_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
886 $schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpdaschema_name'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
887 } else {
888 $schema_name = '';
889 }
890 if ( 'runonce' === $interval ) {
891 // Run data backup once. Do not create job.
892 $data_backups = get_option( 'wpda_data_backup_option_runonce' );
893 if ( ! $data_backups ) {
894 $data_backups = array();
895 }
896 $data_backup = array(
897 'id' => self::PREFIX_RUNONCE . $backupid,
898 'device' => $device,
899 'keep' => $keep,
900 'schema_name' => $schema_name,
901 'tables' => $request_tables,
902 );
903 array_push( $data_backups, $data_backup );//phpcs:ignore - 8.1 proof
904 if ( ! update_option( 'wpda_data_backup_option_runonce', $data_backups ) ) {
905 $msg = new WPDA_Message_Box(
906 array(
907 'message_text' => __( 'Could not create data backup', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
908 'message_type' => 'error',
909 'message_is_dismissible' => false,
910 )
911 );
912 $msg->box();
913 } else {
914 if ( ! wp_schedule_single_event(
915 current_time( 'timestamp' ), // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
916 'wpda_data_backup',
917 array( self::PREFIX_RUNONCE . $backupid )
918 )
919 ) {
920 $msg = new WPDA_Message_Box(
921 array(
922 'message_text' => __( 'Backup failed', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
923 'message_type' => 'error',
924 'message_is_dismissible' => false,
925 )
926 );
927 $msg->box();
928 }
929 }
930 ?>
931 <div class="wrap">
932 <h1 class="wp-heading-inline">
933 <?php echo __( 'Data Backup' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
934 </h1>
935 <p><?php echo __( 'Data backup started. Please check backup location.' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></p>
936 <p>
937 <a href="?page=wpda&page_action=wpda_backup" class="button">
938 <i class="fas fa-angle-left wpda_icon_on_button"></i>
939 <?php echo __( 'List' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
940 </a>
941 </p>
942 </div>
943 <?php
944 } else {
945 // Create job for data backup.
946 $data_backups = get_option( 'wpda_data_backup_option' );
947 if ( ! $data_backups ) {
948 $data_backups = array();
949 } else {
950 foreach ( $data_backups as $data_backup ) {
951 if ( $data_backup['id'] === $backupid ) {
952 $this->show_wp_cron();
953 $msg = new WPDA_Message_Box(
954 array(
955 'message_text' => __( 'Backup id already exists', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
956 'message_type' => 'error',
957 'message_is_dismissible' => false,
958 )
959 );
960 $msg->box();
961
962 return;
963 }
964 }
965 }
966 $data_backup = array(
967 'id' => $backupid,
968 'device' => $device,
969 'keep' => $keep,
970 'schema_name' => $schema_name,
971 'tables' => $request_tables,
972 );
973 array_push( $data_backups, $data_backup );//phpcs:ignore - 8.1 proof
974 if ( ! update_option( 'wpda_data_backup_option', $data_backups ) ) {
975 $this->show_wp_cron();
976 $msg = new WPDA_Message_Box(
977 array(
978 'message_text' => __( 'Could not save data backup options', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
979 'message_type' => 'error',
980 'message_is_dismissible' => false,
981 )
982 );
983 $msg->box();
984 } else {
985 global $wpdb;
986 $wpdb->flush();
987 wp_cache_flush();
988 if ( ! wp_next_scheduled( 'wpda_data_backup', array( $backupid ) ) ) {
989 wp_schedule_event( current_time( 'timestamp' ), $interval, 'wpda_data_backup', array( $backupid ) ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
990 }
991 }
992 $this->show_wp_cron();
993 }
994 }
995
996 /**
997 * Remove a data backup from cron
998 *
999 * Backup ID = $_REQUEST['schedule_args']
1000 */
1001 public function wpda_remove_cron_job() {
1002 if ( isset( $_REQUEST['schedule_args'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
1003 $backupid = sanitize_text_field( wp_unslash( $_REQUEST['schedule_args'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
1004 if ( isset( $_REQUEST['schedule'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
1005 $schedule = sanitize_text_field( wp_unslash( $_REQUEST['schedule'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
1006 if ( '' !== $backupid ) {
1007 $timestamp = wp_next_scheduled( $schedule, array( $backupid ) );
1008 $unschedule = wp_unschedule_event( $timestamp, $schedule, array( $backupid ) );
1009 } else {
1010 $timestamp = wp_next_scheduled( $schedule );
1011 $unschedule = wp_unschedule_event( $timestamp, $schedule );
1012 }
1013
1014 if ( false === $unschedule ) {
1015 $msg = new WPDA_Message_Box(
1016 array(
1017 'message_text' => __( 'Could not delete data backup schedule', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
1018 'message_type' => 'error',
1019 'message_is_dismissible' => false,
1020 )
1021 );
1022 $msg->box();
1023 } else {
1024 $msg = new WPDA_Message_Box(
1025 array(
1026 'message_text' => __( 'Deleted data backup schedule', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
1027 )
1028 );
1029 $msg->box();
1030 // Remove job from queue.
1031 $data_backups = get_option( 'wpda_data_backup_option' );
1032 $data_backups_new = array();
1033 foreach ( $data_backups as $data_backup ) {
1034 if ( $data_backup['id'] !== $backupid ) {
1035 array_push( $data_backups_new, $data_backup );//phpcs:ignore - 8.1 proof
1036 }
1037 }
1038 update_option( 'wpda_data_backup_option', $data_backups_new );
1039 }
1040 }
1041 }
1042 $this->show_wp_cron();
1043 }
1044
1045 /**
1046 * Update a data backup
1047 *
1048 * Backup ID = $_REQUEST['backupid']
1049 */
1050 public function wpda_update_cron_job() {
1051 if ( isset( $_REQUEST['backupid'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
1052 $backupid = sanitize_text_field( wp_unslash( $_REQUEST['backupid'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
1053 } else {
1054 $msg = new WPDA_Message_Box(
1055 array(
1056 'message_text' => __( 'Mandatory item "backupid" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
1057 'message_type' => 'error',
1058 'message_is_dismissible' => false,
1059 )
1060 );
1061 $msg->box();
1062 }
1063 if ( isset( $_REQUEST['wpda_table_name_export'] ) && is_array( $_REQUEST['wpda_table_name_export'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
1064 $wpda_table_name_export = WPDA::sanitize_text_field_array( $_REQUEST['wpda_table_name_export'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput ,WordPress.Security.NonceVerification
1065 } else {
1066 $msg = new WPDA_Message_Box(
1067 array(
1068 'message_text' => __( 'No tables defined to backup', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
1069 'message_type' => 'error',
1070 'message_is_dismissible' => false,
1071 )
1072 );
1073 $msg->box();
1074 }
1075 if ( isset( $_REQUEST['interval'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
1076 $interval = sanitize_text_field( wp_unslash( $_REQUEST['interval'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
1077 } else {
1078 $msg = new WPDA_Message_Box(
1079 array(
1080 'message_text' => __( 'Mandatory item "interval" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
1081 'message_type' => 'error',
1082 'message_is_dismissible' => false,
1083 )
1084 );
1085 $msg->box();
1086 }
1087 if ( isset( $_REQUEST['keep'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
1088 $keep = sanitize_text_field( wp_unslash( $_REQUEST['keep'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
1089 } else {
1090 $msg = new WPDA_Message_Box(
1091 array(
1092 'message_text' => __( 'Mandatory item "keep" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
1093 'message_type' => 'error',
1094 'message_is_dismissible' => false,
1095 )
1096 );
1097 $msg->box();
1098 }
1099 if ( isset( $_REQUEST['device'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
1100 $device = sanitize_text_field( wp_unslash( $_REQUEST['device'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
1101 } else {
1102 $msg = new WPDA_Message_Box(
1103 array(
1104 'message_text' => __( 'Mandatory item "device" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
1105 'message_type' => 'error',
1106 'message_is_dismissible' => false,
1107 )
1108 );
1109 $msg->box();
1110 }
1111 if ( isset( $_REQUEST['wpdaschema_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
1112 $schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpdaschema_name'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
1113 } else {
1114 $schema_name = '';
1115 }
1116 // Reschedule current job.
1117 $timestamp = wp_next_scheduled( 'wpda_data_backup', array( $backupid ) );
1118 if ( false === wp_unschedule_event( $timestamp, 'wpda_data_backup', array( $backupid ) ) ) {
1119 $msg = new WPDA_Message_Box(
1120 array(
1121 'message_text' => __( 'Could not delete data backup schedule', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
1122 'message_type' => 'error',
1123 'message_is_dismissible' => false,
1124 )
1125 );
1126 $msg->box();
1127 } else {
1128 // Update job settings.
1129 $data_backups = get_option( 'wpda_data_backup_option' );
1130 $data_backups_new = array();
1131 foreach ( $data_backups as $data_backup ) {
1132 if ( $data_backup['id'] !== $backupid ) {
1133 array_push( $data_backups_new, $data_backup );//phpcs:ignore - 8.1 proof
1134 } else {
1135 $data_backup_updated = array(
1136 'id' => $backupid,
1137 'keep' => $keep,
1138 'device' => $device,
1139 'schema_name' => $schema_name,
1140 'tables' => $wpda_table_name_export,
1141 );
1142 array_push( $data_backups_new, $data_backup_updated );//phpcs:ignore - 8.1 proof
1143 }
1144 }
1145 update_option( 'wpda_data_backup_option', $data_backups_new );
1146 // Reschedule job with new arguments.
1147 wp_schedule_event( current_time( 'timestamp' ), $interval, 'wpda_data_backup', array( $backupid ) ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
1148 }
1149 $this->show_wp_cron();
1150 }
1151
1152 }
1153
1154 }
1155