File "WPDA_Data_Export.php"
Full Path: /home/vantageo/public_html/cache/cache/cache/cache/cache/cache/.wp-cli/wp-content/plugins/wp-data-access/WPDataAccess/Backup/WPDA_Data_Export.php
File size: 44.93 KB
MIME-type: text/x-php
Charset: utf-8
<?php // phpcs:ignore Standard.Category.SniffName.ErrorCode
/**
* Suppress "error - 0 - No summary was found for this file" on phpdoc generation
*
* @package WPDataAccess\Backup
*/
namespace WPDataAccess\Backup {
use Dropbox\Dropbox;
use Dropbox\Dropbox\Auth;
use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Lists;
use WPDataAccess\Settings\WPDA_Settings_DataBackup;
use WPDataAccess\Utilities\WPDA_Export_Sql;
use WPDataAccess\Utilities\WPDA_Remote_Call;
use WPDataAccess\WPDA;
use WPDataAccess\Utilities\WPDA_Message_Box;
use WPDataAccess\Utilities\WPDA_Repository;
/**
* Class WPDA_Data_Export
*
* This class offers support to manage unattended data exports. Data exports can be run once only or scheduled.
* Every data backup has a unique name to identify it. The data backup name is used in combination with the date
* and time to create a unique file name.
*
* @author Peter Schulz
* @since 1.0.0
*/
class WPDA_Data_Export {
const PREFIX_RUNONCE = 'wpda-run-once-';
const SHOW_JOBS_OPTION_NAME = 'wpda_data_backup_show_jobs';
/**
* Holds the scheduled cron jobs
*
* @var array
*/
protected $schedules;
/**
* WPDA_Data_Export constructor
*
* Gets and stores the scheduled cron jobs.
*/
public function __construct() {
$this->schedules = wp_get_schedules();
}
/**
* Data entry form to add or update a data backup
*
* @param string $action Add for new export; Update to edit existing export.
*/
public function create_export( $action ) {
$wpda_db_options_activated = get_option( 'wpda_db_options_activated' );
if ( ! is_array( $wpda_db_options_activated ) || 0 === count( $wpda_db_options_activated ) ) {//phpcs:ignore - 8.1 proof
echo '<br/>';
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
echo '<br/>';
echo '<a href="?page=wpdataaccess&tab=databackup">» ';
echo __( 'Define and/or activate a storage device', 'wp-data-access' ); // phpcs:ignore WordPress.Security.EscapeOutput
echo '</a>';
wp_die();
}
if ( isset( $_REQUEST['wpdaschema_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpdaschema_name'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
} else {
$schema_name = '';
}
$device_arg = '';
if ( 'update' === $action ) {
if ( isset( $_REQUEST['schedule'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$schedule = sanitize_text_field( wp_unslash( $_REQUEST['schedule'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
if ( 'wpda_data_backup' !== $schedule ) {
wp_die( __( 'ERROR: Wrong arguments', 'wp-data-access' ) ); // phpcs:ignore WordPress.Security.EscapeOutput
}
} else {
wp_die( __( 'ERROR: Wrong arguments', 'wp-data-access' ) ); // phpcs:ignore WordPress.Security.EscapeOutput
}
if ( isset( $_REQUEST['schedule_args'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$backupid = sanitize_text_field( wp_unslash( $_REQUEST['schedule_args'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
} else {
wp_die( __( 'ERROR: Wrong arguments', 'wp-data-access' ) ); // phpcs:ignore WordPress.Security.EscapeOutput
}
$data_backups = get_option( 'wpda_data_backup_option' );
$data_backup_found = false;
foreach ( $data_backups as $data_backup ) {
if ( $data_backup['id'] === $backupid ) {
$data_backup_tables = $data_backup['tables'];
$keep = $data_backup['keep'];
$schema_name = isset( $data_backup['schema_name'] ) ? $data_backup['schema_name'] : '';
$data_backup_found = true;
}
}
if ( ! $data_backup_found ) {
wp_die( __( 'ERROR: Wrong arguments', 'wp-data-access' ) ); // phpcs:ignore WordPress.Security.EscapeOutput
}
if ( isset( $_REQUEST['interval'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$interval = sanitize_text_field( wp_unslash( $_REQUEST['interval'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
}
if ( isset( $_REQUEST['device'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$device_arg = sanitize_text_field( wp_unslash( $_REQUEST['device'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
}
} else {
$backupid = '';
}
$table_list = WPDA_Dictionary_Lists::get_tables( false, $schema_name );
?>
<div class="wrap">
<h1 class="wp-heading-inline">
<?php echo __( 'Data Backup' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
</h1>
<div id="wpda_export_import">
<div class="wpda_export_import">
<form id="wpda_export_import_form"
action="?page=wpda&page_action=wpda_backup"
method="post"
onsubmit="return pre_submit()">
<table>
<tr>
<td style="font-weight:bold;padding-left:10px;"><?php echo __( 'Database Tables' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
<td></td>
<td style="font-weight:bold;padding-left:10px"><?php echo __( 'Tables To Be Exported' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
</tr>
<tr>
<td>
<select id="wpda_table_name_db" name="wpda_table_name_db" multiple size="20"
style="width:300px;">
<?php
foreach ( $table_list as $key => $value ) {
echo '<option value="' . esc_attr( $value['table_name'] ) . '">' . esc_attr( $value['table_name'] ) . '</option>';
}
?>
</select>
</td>
<td>
<a href="javascript:void(0)" class="button" onclick="move_all_to_export()">
>>> </a>
<br/>
<a href="javascript:void(0)" class="button" onclick="move_all_to_db()"> <<< </a>
</td>
<td>
<select id="wpda_table_name_export" name="wpda_table_name_export[]" multiple
size="20" style="width:300px;">
</select>
</td>
</tr>
<tr>
<td colspan="3" style="text-align:center;">
<table align="center">
<tr>
<td style="text-align:right;"><?php echo __( 'Backup Id' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
<td style="text-align:left;">
<input
type="text"
id="backupid"
name="backupid"
value="<?php echo esc_attr( $backupid ); ?>"
maxlength="50"
<?php
if ( 'update' === $action ) {
echo 'readonly';
}
?>
/>
</td>
</tr>
<tr>
<td style="text-align:right;"><?php echo __( 'Backup Interval' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
<td style="text-align:left;">
<select id="interval" name="interval">
<?php if ( 'add' === $action ) { ?>
<option value="runonce"><?php echo __( 'Run once (no interval)' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></option>
<?php } ?>
<?php
foreach ( $this->schedules as $key => $schedule ) {
echo '<option value="' . esc_attr( $key ) . '">' .
esc_attr( $schedule['display'] ) . ' (' . esc_attr( $schedule['interval'] ) . ' sec)' .
'</option>';
}
?>
</select>
</td>
</tr>
<tr>
<td style="text-align:right;"><?php echo __( 'Backup Location' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
<td style="text-align:left;">
<select id="device" name="device">
<?php
foreach ( $wpda_db_options_activated as $key => $value ) {
$device = $key;
if ( 'local_path' === $key ) {
$device = 'local > ' . WPDA::get_option( WPDA::OPTION_DB_LOCAL_PATH );
} elseif ( 'dropbox' === $key ) {
$dropbox_path = WPDA::get_option( WPDA::OPTION_DB_DROPBOX_PATH );
if ( '' === $dropbox_path ) {
$dropbox_path = '/wp-data-access-backups/'; // Use last version.
}
$device = 'dropbox > ' . $dropbox_path;
}
echo '<option value="' . esc_attr( $key ) . '"' . ( $key === $device_arg ? 'selected' : '' ) . '>' .
esc_attr( $device ) .
'</option>';
}
?>
</select>
</td>
</tr>
<tr>
<td style="text-align:right;"><?php echo __( 'Backup Files Kept' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></td>
<td style="text-align:left;">
<select id="keep" name="keep">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="ALL">ALL</option>
</select>
</td>
</tr>
<tr>
<td></td>
<td style="text-align:left;">
<button type="submit" class="button button-primary">
<i class="fas fa-check wpda_icon_on_button"></i>
<?php echo __( 'Start' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
</button>
<button type="button" class="button button-secondary"
onclick="window.location.href=window.location.href">
<i class="fas fa-times-circle wpda_icon_on_button"></i>
<?php echo __( 'Cancel' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
</button>
</td>
</tr>
</table>
</td>
</tr>
</table>
<input type="hidden" name="wpdaschema_name" value="<?php echo esc_attr( $schema_name ); ?>"/>
<input type="hidden" name="action" value="<?php echo esc_attr( $action ); ?>"/>
<input type="hidden" name="wp_nonce" value="<?php echo esc_attr( $this->get_wp_nonce() ); ?>"/>
</form>
</div>
</div>
</div>
<script type='text/javascript'>
var tables_selected = [];
<?php
if ( 'update' === $action ) {
foreach ( $data_backup_tables as $data_backup_table ) {
?>
tables_selected.push('<?php echo esc_attr( $data_backup_table ); ?>');
<?php
}
?>
jQuery(function () {
jQuery("#keep option[value='<?php echo esc_attr( $keep ); ?>']").prop('selected', true);
jQuery("#interval option[value='<?php echo esc_attr( $interval ); ?>']").prop('selected', true);
for (var i = 0; i < tables_selected.length; i++) {
jQuery("#wpda_table_name_db option[value='" + tables_selected[i] + "']").remove();
jQuery('#wpda_table_name_export').append(jQuery('<option>', {
value: tables_selected[i],
text: tables_selected[i]
}));
}
});
<?php
} else {
?>
jQuery(function () {
jQuery("#keep option[value='3']").prop('selected', true);
jQuery( '.wpda_tooltip' ).tooltip();
});
<?php
}
?>
function pre_submit() {
if (0 === jQuery("#wpda_table_name_export > option").length) {
alert('<?php echo __( 'No tables to be exported' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>');
return false;
}
if ('' === jQuery("#backupid").val().trim()) {
alert('<?php echo __( 'You must specify a backupid' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>');
return false;
}
jQuery("#wpda_table_name_export > option").each(function () {
jQuery(this).attr("selected", "true");
});
return true;
}
function move_all_to_export() {
jQuery("#wpda_table_name_db > option").each(function () {
jQuery('#wpda_table_name_export').append(jQuery('<option>', {
value: this.text,
text: this.text
}));
});
jQuery('#wpda_table_name_db > option').remove();
}
function move_all_to_db() {
jQuery("#wpda_table_name_export > option").each(function () {
jQuery('#wpda_table_name_db').append(jQuery('<option>', {
value: this.text,
text: this.text
}));
});
jQuery('#wpda_table_name_export > option').remove();
}
jQuery(function () {
jQuery('#wpda_table_name_db').on('click', function (event) {
if ('' !== event.target.text && undefined != event.target.text) {
jQuery('#wpda_table_name_export').append(jQuery('<option>', {
value: event.target.text,
text: event.target.text
}));
jQuery("#wpda_table_name_db option[value='" + event.target.text + "']").remove();
}
});
jQuery('#wpda_table_name_export').on('click', function (event) {
if ('' !== event.target.text && undefined != event.target.text) {
jQuery('#wpda_table_name_db').append(jQuery('<option>', {
value: event.target.text,
text: event.target.text
}));
jQuery("#wpda_table_name_export option[value='" + event.target.text + "']").remove();
}
});
});
</script>
<?php
}
/**
* Show available cron jobs
*
* Shows data backups only be default. Other cron jobs can be displayed as well.
*/
public function show_wp_cron() {
$wpda_repository = new WPDA_Repository();
$wpda_repository->inform_user();
$no_data_backup_events = 0;
$data_backups = get_option( 'wpda_data_backup_option' );
$data_backups_keep = array();
$data_backups_device = array();
if ( null !== $data_backups && false !== $data_backups ) {
foreach ( $data_backups as $data_backup ) {
$data_backups_keep[ $data_backup['id'] ] = $data_backup['keep'];
$data_backups_device[ $data_backup['id'] ] = $data_backup['device'];
}
}
$crons = _get_cron_array();
$data_backups_found = false;
foreach ( $crons as $key => $cron ) {
foreach ( $cron as $key => $value ) {
if ( 'wpda_data_backup' === $key ) {
$data_backups_found = true;
continue;
}
}
if ( $data_backups_found ) {
continue;
}
}
if ( isset( $_REQUEST['show_jobs'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$show_jobs = sanitize_text_field( wp_unslash( $_REQUEST['show_jobs'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
update_option( self::SHOW_JOBS_OPTION_NAME, $show_jobs );
} else {
$show_jobs = get_option( self::SHOW_JOBS_OPTION_NAME, 'wpda' );
}
if ( isset( $_REQUEST['wpdaschema_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpdaschema_name'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
} else {
$schema_name = '';
}
global $wpdb;
echo '<div class="wrap">';
echo '<h1 class="wp-heading-inline">';
echo __( 'Data Backup' ); // phpcs:ignore WordPress.Security.EscapeOutput
echo '</h1>';
if ( $data_backups_found || 'all' === $show_jobs ) {
echo '<table cellpadding="3" cellspacing="3" border="0" style="border-collapse:collapse;">';
echo '<tr>';
echo '<th></th>';
echo '<th></th>';
echo '<th style="text-align:left;">' . __( 'Hook Name' ) . '</th>'; // phpcs:ignore WordPress.Security.EscapeOutput
echo '<th style="text-align:left;">' . __( 'Arguments' ) . '</th>'; // phpcs:ignore WordPress.Security.EscapeOutput
echo '<th style="text-align:left;">' . __( 'Interval' ) . '</th>'; // phpcs:ignore WordPress.Security.EscapeOutput
echo '<th style="text-align:left;">' . __( 'Next Execution' ) . '</th>'; // phpcs:ignore WordPress.Security.EscapeOutput
echo '<th style="text-align:left;">' . __( 'Backup Location' ) . '</th>'; // phpcs:ignore WordPress.Security.EscapeOutput
echo '<th style="text-align:left;">' . __( 'Files Kept' ) . '</th>'; // phpcs:ignore WordPress.Security.EscapeOutput
echo '<th colspan="2" style="text-align:left;">' . __( 'Status' ) . '</th>'; // phpcs:ignore WordPress.Security.EscapeOutput
echo '</tr>';
foreach ( $crons as $key => $cron ) {
foreach ( $cron as $key => $value ) {
if ( 'wpda_data_backup' === $key ) {
// Filter run once jobs.
$is_runonce = false;
foreach ( $value as $value_key => $value_value ) {
if ( isset( $value_value['args'][0] ) && substr( $value_value['args'][0], 0, 14 ) === 'wpda-run-once-' ) {
$is_runonce = true;
continue;
}
}
if ( $is_runonce ) {
continue;
}
$style = 'style="background-color:#ffffff;"';
$no_data_backup_events ++;
} else {
$style = '';
if ( 'all' !== $show_jobs ) {
// Hide other cron jobs.
continue;
}
}
echo '<tr ' . esc_attr( $style ) . '>';
if ( 'wpda_data_backup' === $key ) {
echo '<td>';
echo '<form method="post" action="?page=wpda&page_action=wpda_backup">';
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>';
echo '<input type="hidden" name="action" value="remove" />';
echo '<input type="hidden" name="schedule" value="' . esc_attr( $key ) . '" />';
foreach ( $value as $value_key => $value_value ) {
$schedule_args = isset( $value_value['args'][0] ) ? $value_value['args'][0] : '';
echo '<input type="hidden" name="schedule_args" value="' . esc_attr( $schedule_args ) . '" />';
}
echo '<input type="hidden" name="wp_nonce" value="' . $this->get_wp_nonce() . '" />';
echo '</form>';
echo '</td>';
echo '<td>';
echo '<form method="post" action="?page=wpda&page_action=wpda_backup">';
echo '<a href="javascript:void(0)" onclick="jQuery(this).closest(\'form\').submit()" class="dashicons dashicons-edit"></a>';
echo '<input type="hidden" name="action" value="edit" />';
echo '<input type="hidden" name="schedule" value="' . esc_attr( $key ) . '" />';
foreach ( $this->schedules as $schedule_key => $schedule ) {
if ( $schedule['display'] === $this->schedules[ $value_value['schedule'] ]['display'] ) {
$interval = $schedule_key;
}
}
foreach ( $value as $value_key => $value_value ) {
echo '<input type="hidden" name="schedule_args" value="' . esc_attr( $value_value['args'][0] ) . '" />';
echo '<input type="hidden" name="interval" value="' . esc_attr( $interval ) . '" />';
}
if ( isset( $data_backups_keep[ $value_value['args'][0] ] ) ) {
echo '<input type="hidden" name="device" value="' . esc_attr( $data_backups_device[ $value_value['args'][0] ] ) . '" />';
}
echo '<input type="hidden" name="wp_nonce" value="' . $this->get_wp_nonce() . '" />';
echo '</form>';
echo '</td>';
} else {
echo '<td>';
echo '</td>';
echo '<td>';
echo '</td>';
}
echo '<td>';
echo esc_attr( $key );
echo '</td>';
foreach ( $value as $value_key => $value_value ) {
echo '<td>';
if ( is_array ($value_value['args']) &&
0 < count( $value_value['args'] ) ) {//phpcs:ignore - 8.1 proof
foreach ( $value_value['args'] as $arg ) {
if ( reset( $value_value['args'] ) !== $arg ) {//phpcs:ignore - 8.1 proof
echo ',';
}
echo esc_attr( $arg );
}
} else {
echo '-';
}
echo '</td>';
echo '<td>';
if ( isset( $this->schedules[ $value_value['schedule'] ]['display'] ) ) {
echo esc_attr( $this->schedules[ $value_value['schedule'] ]['display'] );
if ( isset( $value_value['interval'] ) ) {
echo ' (' . esc_attr( $value_value['interval'] ) . ' sec)';
}
}
echo '</td>';
echo '<td>';
$next = wp_next_scheduled( $key, $value_value['args'] );
echo esc_attr( get_date_from_gmt( gmdate( 'Y-m-d H:i:s', $next ) ) );
echo '</td>';
echo '<td>';
if ( 'wpda_data_backup' === $key ) {
if ( isset( $data_backups_device[ $value_value['args'][0] ] ) ) {
echo esc_attr( $data_backups_device[ $value_value['args'][0] ] );
}
}
echo '</td>';
echo '<td>';
if ( 'wpda_data_backup' === $key ) {
if ( isset( $data_backups_keep[ $value_value['args'][0] ] ) ) {
echo esc_attr( $data_backups_keep[ $value_value['args'][0] ] );
}
}
echo '</td>';
echo '<td>';
if ( 'wpda_data_backup' === $key ) {
echo '<form method="post" action="?page=wpda">';
echo '<input type="hidden" name="table_name" value="' . esc_attr( $wpdb->prefix ) . 'wpda_logging" />';
echo '<input type="hidden" name="wpda_s" value="' . esc_attr( $value_value['args'][0] ) . '" />';
echo '<a href="javascript:void(0)" onclick="jQuery(this).closest(\'form\').submit()" class="dashicons dashicons-info"></a>';
echo '</form>';
}
echo '</td>';
echo '<td>';
if ( 'wpda_data_backup' === $key ) {
$resultset = $wpdb->get_results(
$wpdb->prepare(
"
SELECT `log_time`, `log_type`, `log_msg`
FROM `{$wpdb->prefix}wpda_logging`
WHERE `log_id` = %s
ORDER BY `log_time` desc limit 1",
array(
$value_value['args'][0],
)
),
'ARRAY_A'
); // db call ok; no-cache ok.
if ( 1 === $wpdb->num_rows ) {
echo esc_attr( $resultset[0]['log_type'] ) . ': ' .
esc_attr( $resultset[0]['log_msg'] ) .
' (' . esc_attr( $resultset[0]['log_time'] ) . ')';
} else {
echo __( 'No logging information found' ); // phpcs:ignore WordPress.Security.EscapeOutput
}
}
echo '</td>';
}
echo '</tr>';
}
}
echo '</table>';
echo '<table style="margin-top:10px">';
echo '<tr>';
echo '<td><strong>' . esc_attr( $no_data_backup_events ) . ' data backup job' .
( 1 < $no_data_backup_events ? 's' : '' ) . ' scheduled</strong></td>';
} else {
echo '<table>';
echo '<tr>';
echo '<td><strong>' . __( 'No data backup jobs found' ) . '</strong></td>'; // phpcs:ignore WordPress.Security.EscapeOutput
}
echo '<td>';
echo '<form method="post" action="?page=wpda&page_action=wpda_backup" style="display: inline-block; vertical-align: unset;">';
echo '<select name="show_jobs" onchange="jQuery(this).closest(\'form\').submit()" >';
echo '<option value="wpda"' . ( 'all' !== $show_jobs ? 'selected' : '' ) . '>' . __( 'Show plugin jobs only' ) . '</option>'; // phpcs:ignore WordPress.Security.EscapeOutput
echo '<option value="all"' . ( 'all' === $show_jobs ? 'selected' : '' ) . '>' . __( 'Show all WordPress jobs' ) . '</option>'; // phpcs:ignore WordPress.Security.EscapeOutput
echo '</select>';
echo '<input type="hidden" name="wp_nonce" value="' . $this->get_wp_nonce() . '" />';
echo '</form>';
echo '</td>';
echo '</tr>';
echo '</table>';
echo '</div>';
?>
<script type="text/javascript">
jQuery(function () {
jQuery( '.wpda_tooltip' ).tooltip();
});
// Add toolbar events
jQuery("#wpda_toolbar_icon_add_backup").on("click", function() {
jQuery("#wpda_new_backup_wpdaschema_name").val("<?php echo esc_attr( $schema_name ); ?>");
jQuery("#wpda_new_backup").submit();
});
</script>
<?php
}
/**
* Prepares an unattended data backup (export)
*
* @param string $backupid Unique ID that identifies a data backup.
*/
public function wpda_data_backup( $backupid ) {
$is_runonce_data_backup = substr( $backupid, 0, strlen( self::PREFIX_RUNONCE ) ) === self::PREFIX_RUNONCE;
if ( $is_runonce_data_backup ) {
// Run once data backup.
$data_backups = get_option( 'wpda_data_backup_option_runonce' );
// Directly remove data backup to prevent multiple backups.
$data_backups_new = array();
foreach ( $data_backups as $data_backup ) {
if ( $data_backup['id'] !== $backupid ) {
array_push( $data_backups_new, $data_backup );//phpcs:ignore - 8.1 proof
}
}
update_option( 'wpda_data_backup_option_runonce', $data_backups_new );
} else {
// Data backup job.
$data_backups = get_option( 'wpda_data_backup_option' );
}
foreach ( $data_backups as $data_backup ) {
if ( $data_backup['id'] === $backupid ) {
if ( $is_runonce_data_backup ) {
$user_backupid = substr( $backupid, strlen( self::PREFIX_RUNONCE ) );
} else {
$user_backupid = $backupid;
}
$keep = $data_backup['keep'];
$device = $data_backup['device'];
$schema = $data_backup['schema_name'];
$tables = $data_backup['tables'];
$this->wpda_data_backup_run( $user_backupid, $keep, $device, $tables, $schema );
}
}
}
/**
* Performs an unattended data backup (export)
*
* @param string $backupid Unique ID that identifies a data backup.
* @param integer $keep Number of backup files to be kept.
* @param string $device Location where export file is stored.
* @param array $tables Tables to be exported.
* @param array $schema Database schema name or remote database connection string.
*/
protected function wpda_data_backup_run( $backupid, $keep, $device, $tables, $schema ) {
try {
$prefix = "wpda-data-backup-$backupid-";
$filename = $prefix . gmdate( 'YmdHis' ) . '.sql';
if ( 'local_path' === $device ) {
$local_path = WPDA::get_option( WPDA::OPTION_DB_LOCAL_PATH );
$client_file_name = $local_path . $filename;
$file = fopen( $client_file_name, 'w' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
$wpda_export = new WPDA_Export_Sql();
$wpda_export->set_output_stream( $file );
$wpda_export->export_with_arguments(
'on',
'on',
'on',
$schema,
$tables,
'table'
);
fclose( $file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
$keep_counting = 0;
$files_sorted = array();
foreach ( glob( $local_path . "wpda-data-backup-$backupid-*.sql" ) as $filename ) {
array_push( $files_sorted, $filename );//phpcs:ignore - 8.1 proof
}
rsort( $files_sorted );//phpcs:ignore - 8.1 proof
foreach ( $files_sorted as $file ) {
$keep_counting ++;
if ( $keep_counting > (int) $keep ) {
unlink( $file );
}
}
} elseif ( 'dropbox' === $device ) {
// To use a stream for Dropbox we first need to write the export to a temporary file.
$temporary_file = tmpfile();
$wpda_export = new WPDA_Export_Sql();
$wpda_export->set_output_stream( $temporary_file );
$wpda_export->export_with_arguments(
'on',
'on',
'on',
$schema,
$tables,
'table'
);
$client_access_token = WPDA_Settings_DataBackup::dropbox_get_token();
if ( false === $client_access_token ) {
// Use old token strategy (for older activations).
$client_access_token = get_option( 'wpda_db_dropbox_access_token' );
if ( false === $client_access_token ) {
// No token = no dropbox backup.
WPDA::log( $backupid, 'ERROR', "Data backup '$backupid'' failed (missing access token)" );
return;
}
}
$client_access_path = WPDA::get_option( WPDA::OPTION_DB_DROPBOX_PATH );
if ( '' === $client_access_path ) {
$client_access_path = '/';
}
$client_file_name = $client_access_path . $filename;
$post_max_size = WPDA_Remote_Call::max_size();
if (
$post_max_size < filesize( stream_get_meta_data( $temporary_file )['uri'] ) &&
! extension_loaded('zip')
) {
// File is too big to send in one chunk and zip archive is not installed.
WPDA::log( $backupid, 'ERROR', "Data backup '$backupid'' failed (ZipArchive not installed)" );
return;
}
if ( extension_loaded('zip') ) {
$zip = new \ZipArchive();
$zipfile = sys_get_temp_dir() . '/' . $filename . '.zip';
if ( ! $zip->open( $zipfile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE ) ) {
WPDA::log( $backupid, 'ERROR', "Data backup '$backupid'' failed (could not create ZIP file)" );
return;
}
$zip->addFile( stream_get_meta_data( $temporary_file )['uri'], $filename );
$zip->close();
$zpf = fopen( $zipfile, 'r' );
WPDA_Remote_Call::post(
'https://content.dropboxapi.com/2/files/upload',
fread( $zpf, filesize( $zipfile ) ),
false,
array(
'Authorization' => "Bearer $client_access_token",
'Content-Type' => 'application/octet-stream',
'Dropbox-API-Arg' => '{"path":"' . $client_file_name . '.zip","mode":"add","autorename":false,"mute":false,"strict_conflict":false}',
)
);
} else {
fseek( $temporary_file, 0 );
WPDA_Remote_Call::post(
'https://content.dropboxapi.com/2/files/upload',
fread( $temporary_file, filesize( stream_get_meta_data( $temporary_file )['uri'] ) ),
false,
array(
'Authorization' => "Bearer $client_access_token",
'Content-Type' => 'application/octet-stream',
'Dropbox-API-Arg' => '{"path":"' . $client_file_name . '","mode":"add","autorename":false,"mute":false,"strict_conflict":false}',
)
);
}
// Search for outdated files.
$ext = extension_loaded('zip') ? '.zip' : '';
$response = WPDA_Remote_Call::post(
'https://api.dropboxapi.com/2/files/search_v2',
json_encode(
array(
'options' => array(
'file_status' => 'active',
'filename_only' => false,
'max_results' => 999,
'path' => substr( $client_access_path, 0, strlen( $client_access_path ) - 1 )
),
'query' => $prefix . '*' . $ext,
)
),
false,
array(
'Authorization' => "Bearer $client_access_token",
'Content-Type' => 'application/json',
)
);
if ( 'ALL' !== $keep && isset( $response['body'] ) ) {
$body_content = json_decode( $response['body'], true );
if ( isset( $body_content['matches'] ) ) {
$keep_counting = 0;
$files_sorted = array();
foreach ( $body_content['matches'] as $match ) {
array_push( $files_sorted, $match['metadata']['metadata']['name'] );//phpcs:ignore - 8.1 proof
}
rsort( $files_sorted );//phpcs:ignore - 8.1 proof
foreach ( $files_sorted as $file ) {
$keep_counting++;
if ( $keep_counting > (int) $keep ) {
// Remove outdated files.
WPDA_Remote_Call::post(
'https://api.dropboxapi.com/2/files/delete_v2',
json_encode(
array(
'path' => $client_access_path . $file,
)
),
false,
array(
'Authorization' => "Bearer $client_access_token",
'Content-Type' => 'application/json',
)
);
}
}
}
}
}
} catch ( Exception $e ) {
WPDA::log( $backupid, 'ERROR', "Data backup '$backupid' failed: " . $e->getMessage() );
}
WPDA::log( $backupid, 'INFO', "Data backup '$backupid' finished" );
}
/**
* Create a cron job for data export
*
* Backup ID = $_REQUEST['backupid']
*/
public function wpda_add_cron_job() {
if ( ! isset( $_REQUEST['backupid'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$this->show_wp_cron();
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Mandatory item "backupid" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
return;
}
$backupid = sanitize_text_field( wp_unslash( $_REQUEST['backupid'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
if ( ! isset( $_REQUEST['interval'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$this->show_wp_cron();
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Mandatory item "interval" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
return;
}
$interval = sanitize_text_field( wp_unslash( $_REQUEST['interval'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
if ( ! isset( $_REQUEST['keep'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$this->show_wp_cron();
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Mandatory item "keep" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
return;
}
$keep = sanitize_text_field( wp_unslash( $_REQUEST['keep'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
if ( ! isset( $_REQUEST['device'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$this->show_wp_cron();
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Mandatory item "device" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
return;
}
$device = sanitize_text_field( wp_unslash( $_REQUEST['device'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
if ( ! isset( $_REQUEST['wpda_table_name_export'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$this->show_wp_cron();
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'No tables defined to backup', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
return;
} else {
$request_tables = WPDA::sanitize_text_field_array( $_REQUEST['wpda_table_name_export'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput, WordPress.Security.NonceVerification
}
if ( isset( $_REQUEST['wpdaschema_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpdaschema_name'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
} else {
$schema_name = '';
}
if ( 'runonce' === $interval ) {
// Run data backup once. Do not create job.
$data_backups = get_option( 'wpda_data_backup_option_runonce' );
if ( ! $data_backups ) {
$data_backups = array();
}
$data_backup = array(
'id' => self::PREFIX_RUNONCE . $backupid,
'device' => $device,
'keep' => $keep,
'schema_name' => $schema_name,
'tables' => $request_tables,
);
array_push( $data_backups, $data_backup );//phpcs:ignore - 8.1 proof
if ( ! update_option( 'wpda_data_backup_option_runonce', $data_backups ) ) {
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Could not create data backup', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
} else {
if ( ! wp_schedule_single_event(
current_time( 'timestamp' ), // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
'wpda_data_backup',
array( self::PREFIX_RUNONCE . $backupid )
)
) {
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Backup failed', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
}
}
?>
<div class="wrap">
<h1 class="wp-heading-inline">
<?php echo __( 'Data Backup' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
</h1>
<p><?php echo __( 'Data backup started. Please check backup location.' ); // phpcs:ignore WordPress.Security.EscapeOutput ?></p>
<p>
<a href="?page=wpda&page_action=wpda_backup" class="button">
<i class="fas fa-angle-left wpda_icon_on_button"></i>
<?php echo __( 'List' ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
</a>
</p>
</div>
<?php
} else {
// Create job for data backup.
$data_backups = get_option( 'wpda_data_backup_option' );
if ( ! $data_backups ) {
$data_backups = array();
} else {
foreach ( $data_backups as $data_backup ) {
if ( $data_backup['id'] === $backupid ) {
$this->show_wp_cron();
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Backup id already exists', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
return;
}
}
}
$data_backup = array(
'id' => $backupid,
'device' => $device,
'keep' => $keep,
'schema_name' => $schema_name,
'tables' => $request_tables,
);
array_push( $data_backups, $data_backup );//phpcs:ignore - 8.1 proof
if ( ! update_option( 'wpda_data_backup_option', $data_backups ) ) {
$this->show_wp_cron();
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Could not save data backup options', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
} else {
global $wpdb;
$wpdb->flush();
wp_cache_flush();
if ( ! wp_next_scheduled( 'wpda_data_backup', array( $backupid ) ) ) {
wp_schedule_event( current_time( 'timestamp' ), $interval, 'wpda_data_backup', array( $backupid ) ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
}
}
$this->show_wp_cron();
}
}
/**
* Remove a data backup from cron
*
* Backup ID = $_REQUEST['schedule_args']
*/
public function wpda_remove_cron_job() {
if ( isset( $_REQUEST['schedule_args'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$backupid = sanitize_text_field( wp_unslash( $_REQUEST['schedule_args'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
if ( isset( $_REQUEST['schedule'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$schedule = sanitize_text_field( wp_unslash( $_REQUEST['schedule'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
if ( '' !== $backupid ) {
$timestamp = wp_next_scheduled( $schedule, array( $backupid ) );
$unschedule = wp_unschedule_event( $timestamp, $schedule, array( $backupid ) );
} else {
$timestamp = wp_next_scheduled( $schedule );
$unschedule = wp_unschedule_event( $timestamp, $schedule );
}
if ( false === $unschedule ) {
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Could not delete data backup schedule', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
} else {
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Deleted data backup schedule', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
)
);
$msg->box();
// Remove job from queue.
$data_backups = get_option( 'wpda_data_backup_option' );
$data_backups_new = array();
foreach ( $data_backups as $data_backup ) {
if ( $data_backup['id'] !== $backupid ) {
array_push( $data_backups_new, $data_backup );//phpcs:ignore - 8.1 proof
}
}
update_option( 'wpda_data_backup_option', $data_backups_new );
}
}
}
$this->show_wp_cron();
}
/**
* Update a data backup
*
* Backup ID = $_REQUEST['backupid']
*/
public function wpda_update_cron_job() {
if ( isset( $_REQUEST['backupid'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$backupid = sanitize_text_field( wp_unslash( $_REQUEST['backupid'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
} else {
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Mandatory item "backupid" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
}
if ( isset( $_REQUEST['wpda_table_name_export'] ) && is_array( $_REQUEST['wpda_table_name_export'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$wpda_table_name_export = WPDA::sanitize_text_field_array( $_REQUEST['wpda_table_name_export'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput ,WordPress.Security.NonceVerification
} else {
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'No tables defined to backup', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
}
if ( isset( $_REQUEST['interval'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$interval = sanitize_text_field( wp_unslash( $_REQUEST['interval'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
} else {
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Mandatory item "interval" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
}
if ( isset( $_REQUEST['keep'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$keep = sanitize_text_field( wp_unslash( $_REQUEST['keep'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
} else {
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Mandatory item "keep" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
}
if ( isset( $_REQUEST['device'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$device = sanitize_text_field( wp_unslash( $_REQUEST['device'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
} else {
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Mandatory item "device" not found', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
}
if ( isset( $_REQUEST['wpdaschema_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpdaschema_name'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
} else {
$schema_name = '';
}
// Reschedule current job.
$timestamp = wp_next_scheduled( 'wpda_data_backup', array( $backupid ) );
if ( false === wp_unschedule_event( $timestamp, 'wpda_data_backup', array( $backupid ) ) ) {
$msg = new WPDA_Message_Box(
array(
'message_text' => __( 'Could not delete data backup schedule', 'wp-data-access' ), // phpcs:ignore WordPress.Security.EscapeOutput
'message_type' => 'error',
'message_is_dismissible' => false,
)
);
$msg->box();
} else {
// Update job settings.
$data_backups = get_option( 'wpda_data_backup_option' );
$data_backups_new = array();
foreach ( $data_backups as $data_backup ) {
if ( $data_backup['id'] !== $backupid ) {
array_push( $data_backups_new, $data_backup );//phpcs:ignore - 8.1 proof
} else {
$data_backup_updated = array(
'id' => $backupid,
'keep' => $keep,
'device' => $device,
'schema_name' => $schema_name,
'tables' => $wpda_table_name_export,
);
array_push( $data_backups_new, $data_backup_updated );//phpcs:ignore - 8.1 proof
}
}
update_option( 'wpda_data_backup_option', $data_backups_new );
// Reschedule job with new arguments.
wp_schedule_event( current_time( 'timestamp' ), $interval, 'wpda_data_backup', array( $backupid ) ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
}
$this->show_wp_cron();
}
private function get_wp_nonce() {
return wp_create_nonce( 'wpda-backup-' . WPDA::get_current_user_login() );
}
}
}