'logs',
'singular' => 'log',
'ajax' => true,
]
);
$this->log_folder = get_site_option( 'backwpup_cfg_logfolder' );
$this->log_folder = BackWPup_File::get_absolute_path( $this->log_folder );
$this->log_folder = untrailingslashit( $this->log_folder );
}
/**
* Retrieves the table classes for the job page.
*
* This method constructs an array of CSS classes to be applied to the table
* on the job page. The 'fixed' class is intentionally omitted from the default
* classes.
*
* @return array An array of CSS classes for the table.
*/
protected function get_table_classes() {
// Remove 'fixed' from the default classes.
$classes = [ 'widefat', 'striped', $this->_args['plural'] ];
return $classes;
}
/**
* User can.
*
* @return bool True if user has the right capabilities, false otherwise
*/
public function ajax_user_can() {
return current_user_can( 'backwpup_logs' );
}
/**
* Prepare Items.
*/
public function prepare_items() {
$this->job_types = BackWPup::get_job_types();
$per_page = $this->get_items_per_page( 'backwpuplogs_per_page' );
if ( empty( $per_page ) || $per_page < 1 ) {
$per_page = 20;
}
// Load logs.
$logfiles = [];
if ( is_readable( $this->log_folder ) ) {
$dir = new BackWPup_Directory( $this->log_folder );
foreach ( $dir as $file ) {
if ( $file->isFile() && $file->isReadable() && strpos( $file->getFilename(), 'backwpup_log_' ) !== false && strpos( $file->getFilename(), '.html' ) !== false ) {
$logfiles[ $file->getMTime() ] = $file->getFilename();
}
}
}
// Ordering.
$order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
$order = $order ? sanitize_key( $order ) : 'desc';
$order = in_array( $order, [ 'asc', 'desc' ], true ) ? $order : 'desc';
$orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
$orderby = $orderby ? sanitize_key( $orderby ) : 'time';
$orderby = in_array( $orderby, [ 'time' ], true ) ? $orderby : 'time';
if ( 'time' === $orderby ) {
if ( 'asc' === $order ) {
ksort( $logfiles );
} else {
krsort( $logfiles );
}
}
// By page.
$start = intval( ( $this->get_pagenum() - 1 ) * $per_page );
$end = $start + $per_page;
if ( $end > count( $logfiles ) ) {
$end = count( $logfiles );
}
$this->items = [];
$i = -1;
foreach ( $logfiles as $mtime => $logfile ) {
++$i;
if ( $i < $start ) {
continue;
}
if ( $i >= $end ) {
break;
}
$this->items[ $mtime ] = BackWPup_Job::read_logheader( $this->log_folder . '/' . $logfile );
$this->items[ $mtime ]['file'] = $logfile;
}
$this->set_pagination_args(
[
'total_items' => count( $logfiles ),
'per_page' => $per_page,
'orderby' => $orderby,
'order' => $order,
]
);
}
/**
* {@inheritdoc}
*/
public function get_sortable_columns() {
return [
'time' => [ 'time', false ],
];
}
/**
* {@inheritdoc}
*/
public function no_items() {
esc_html_e( 'No Logs.', 'backwpup' );
}
/**
* {@inheritdoc}
*/
public function get_bulk_actions() {
if ( ! $this->has_items() ) {
return [];
}
$actions = [];
$actions['delete'] = __( 'Delete', 'backwpup' );
return $actions;
}
/**
* {@inheritdoc}
*/
public function get_columns() {
$posts_columns = [];
$posts_columns['cb'] = '';
$posts_columns['time'] = __( 'Time', 'backwpup' );
$posts_columns['job'] = __( 'Job', 'backwpup' );
$posts_columns['status'] = __( 'Status', 'backwpup' );
$posts_columns['type'] = __( 'Type', 'backwpup' );
$posts_columns['size'] = __( 'Size', 'backwpup' );
$posts_columns['runtime'] = __( 'Runtime', 'backwpup' );
return $posts_columns;
}
/**
* Render the bulk actions checkbox.
*
* @param array $item Item data.
*
* @return string
*/
public function column_cb( $item ) {
return '';
}
/**
* The time column.
*
* @param array $item Item data.
*
* @return string
*/
public function column_time( $item ) {
return sprintf(
// translators: %1$s: date, %2$s: time.
esc_html__( '%1$s at %2$s', 'backwpup' ),
esc_html( self::format_log_date( (int) $item['logtime'] ) ),
esc_html( self::format_log_time( (int) $item['logtime'] ) )
);
}
/**
* The type column.
*
* @param array $item Item data.
*
* @return string
*/
public function column_type( $item ) {
$r = '';
$types = explode( '+', (string) $item['type'] );
if ( ! empty( $types ) ) {
foreach ( $types as $type ) {
if ( isset( $this->job_types[ $type ] ) ) {
$r .= esc_html( $this->job_types[ $type ]->info['name'] ) . '
';
} else {
$r .= esc_html( $type ) . '
';
}
}
}
return $r;
}
/**
* The job column.
*
* @param array $item Item data.
*
* @return string
*/
public function column_job( $item ) {
$log_name = str_replace( [ '.html', '.gz' ], '', basename( (string) $item['file'] ) );
$view_url = admin_url( 'admin-ajax.php' ) . '?&action=backwpup_view_log&log=' . $log_name . '&_ajax_nonce=' . wp_create_nonce( 'view-log_' . $log_name ) . '&TB_iframe=true&width=640&height=440';
// translators: %d: job ID.
$job_id_label = sprintf( __( 'Job ID: %d', 'backwpup' ), absint( $item['jobid'] ) );
$title = esc_attr( $item['file'] . "\n" . $job_id_label );
$r = '' . esc_html( ! empty( $item['name'] ) ? $item['name'] : $item['file'] ) . '';
$actions = [];
$actions['view'] = '' . esc_html__( 'View', 'backwpup' ) . '';
if ( current_user_can( 'backwpup_logs_delete' ) ) {
$actions['delete'] = '' . esc_html__( 'Delete', 'backwpup' ) . '';
}
$actions['download'] = '' . esc_html__( 'Download', 'backwpup' ) . '';
$r .= $this->row_actions( $actions );
return $r;
}
/**
* The status column.
*
* @param array $item Item data.
*
* @return string
*/
public function column_status( $item ) {
$r = '';
$backup_status = $this->get_backup_status_for_item( $item );
if ( 'failed' === $backup_status ) {
$r .= '' . esc_html__( 'Failed', 'backwpup' ) . '';
if ( ! empty( $item['errors'] ) || ! empty( $item['warnings'] ) ) {
$r .= '
';
}
}
if ( $item['errors'] ) {
$errors_text = sprintf(
// translators: %d: number of errors.
_n( '%d ERROR', '%d ERRORS', $item['errors'], 'backwpup' ),
absint( $item['errors'] )
);
$r .= sprintf(
'%s
',
esc_html( $errors_text )
);
}
if ( $item['warnings'] ) {
$warnings_text = sprintf(
// translators: %d: number of warnings.
_n( '%d WARNING', '%d WARNINGS', $item['warnings'], 'backwpup' ),
absint( $item['warnings'] )
);
$r .= sprintf(
'%s
',
esc_html( $warnings_text )
);
}
if ( ! $item['errors'] && ! $item['warnings'] && 'failed' !== $backup_status ) {
$r .= '' . esc_html__( 'O.K.', 'backwpup' ) . '';
}
return $r;
}
/**
* Resolve the persisted backup status for a log item.
*
* @param array $item Item data.
*
* @return string
*/
private function get_backup_status_for_item( array $item ): string {
$logfile = isset( $item['file'] ) ? basename( (string) $item['file'] ) : '';
if ( '' === $logfile || '' === $this->log_folder ) {
return '';
}
$container = wpm_apply_filters_typed( '?object', 'backwpup_container', null );
if ( ! $container || ! method_exists( $container, 'get' ) ) {
return '';
}
$database = $container->get( 'backwpup_database' );
if ( ! $database || ! method_exists( $database, 'get_status_by_logfile' ) ) {
return '';
}
return (string) $database->get_status_by_logfile( $this->log_folder . '/' . $logfile );
}
/**
* The size column.
*
* @param array $item Item data.
*
* @return string
*/
public function column_size( $item ) {
if ( ! empty( $item['backupfilesize'] ) ) {
return esc_html( size_format( $item['backupfilesize'], 2 ) );
}
return esc_html__( 'Log only', 'backwpup' );
}
/**
* The runtime column.
*
* @param array $item Item data.
*
* @return string
*/
public function column_runtime( $item ) {
return absint( $item['runtime'] ) . ' ' . esc_html__( 'seconds', 'backwpup' );
}
/**
* Load.
*/
public static function load() {
global $current_user;
// Create table.
self::$listtable = new BackWPup_Page_Logs();
switch ( self::$listtable->current_action() ) {
// Delete log.
case 'delete':
if ( ! current_user_can( 'backwpup_logs_delete' ) ) {
break;
}
if ( isset( $_GET['logfiles'] ) && is_array( $_GET['logfiles'] ) ) {
check_admin_referer( 'bulk-logs' );
// Unslash and sanitize input.
$logfiles = array_map( 'sanitize_text_field', wp_unslash( $_GET['logfiles'] ) );
foreach ( $logfiles as $logfile ) {
$logfile = basename( (string) $logfile );
$file_path = self::$listtable->log_folder . '/' . $logfile;
$is_writable = wp_is_writable( $file_path );
if ( $is_writable && ! is_dir( $file_path ) && ! is_link( $file_path ) ) {
wp_delete_file( $file_path );
}
}
}
break;
// Download log.
case 'download':
check_admin_referer( 'download_backwpup_logs', 'download_backwpup_logs' );
$file = filter_input( INPUT_GET, 'file', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
if ( empty( $file ) ) {
break;
}
$log_file = trailingslashit( self::$listtable->log_folder ) . basename( trim( (string) $file ) );
$log_file = realpath( BackWPup_Sanitize_Path::sanitize_path( $log_file ) );
if ( ! $log_file
|| ! is_readable( $log_file )
|| is_dir( $log_file )
|| is_link( $log_file )
) {
header( 'HTTP/1.0 404 Not Found' );
exit();
}
$capability = 'backwpup_logs';
$download_handler = new BackWpup_Download_Handler(
new BackWPup_Download_File(
$log_file,
function ( BackWPup_Download_File_Interface $obj ) {
$obj->clean_ob()
->headers();
// phpcs:ignore
echo backwpup_wpfilesystem()->get_contents($obj->filepath());
exit();
},
$capability
),
'download_backwpup_logs',
$capability,
'download'
);
$download_handler->handle();
break;
}
// Save per page.
$screen_options_apply = filter_input( INPUT_POST, 'screen-options-apply', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
$screen_options = filter_input( INPUT_POST, 'wp_screen_options', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
if ( ! empty( $screen_options_apply ) && is_array( $screen_options ) ) {
$screen_options = wp_unslash( $screen_options );
$option = isset( $screen_options['option'] ) ? sanitize_text_field( $screen_options['option'] ) : '';
$value = isset( $screen_options['value'] ) ? absint( $screen_options['value'] ) : 0;
if ( 'backwpuplogs_per_page' === $option ) {
check_admin_referer( 'screen-options-nonce', 'screenoptionnonce' );
if ( $value > 0 && $value < 1000 ) {
update_user_option( $current_user->ID, 'backwpuplogs_per_page', $value );
wp_safe_redirect( remove_query_arg( [ 'pagenum', 'apage', 'paged' ], wp_get_referer() ) );
exit;
}
}
}
add_screen_option(
'per_page',
[
'label' => __( 'Logs', 'backwpup' ),
'default' => 20,
'option' => 'backwpuplogs_per_page',
]
);
self::$listtable->prepare_items();
}
/**
* Output css.
*/
public static function admin_print_styles() {
?>