process_download(get_query_var('actlogpro_download_type'));
}
}
/**
* Process the download request
*/
public function process_download($type) {
// Verify user has permission
if (!current_user_can('manage_options')) {
wp_die(esc_html__('You do not have permission to download this file.', 'activity-log-pro'));
}
// Clear any output buffers
while (ob_get_level()) {
ob_end_clean();
}
if ($type === 'test') {
// Set headers for CSV download
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=test-export-' . gmdate('Y-m-d-H-i-s') . '.csv');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
// Output CSV content
echo "ID,Name,Email\r\n";
echo "1,Test User,test@example.com\r\n";
echo "2,Another User,another@example.com\r\n";
} else {
wp_die(esc_html__('Invalid download type.', 'activity-log-pro'));
}
exit;
}
/**
* Test export functionality.
*
* @since 1.0.0
*/
public function test_export() {
// Instead of trying to output directly, redirect to our download endpoint
$download_url = home_url('alp-download/test');
wp_safe_redirect($download_url);
exit;
}
/**
* Handle direct export via admin-post.php
*
* Security: Requires 'manage_options' capability and valid nonce verification.
* This function handles admin_post_actlogpro_export_logs_direct action.
*
* @since 1.0.0
*/
public function handle_direct_export() {
// Verify user is in admin context
if (!is_admin()) {
wp_die(esc_html__('Access denied.', 'activity-log-pro'));
}
// Check user capabilities first
if (!current_user_can('manage_options')) {
wp_die(esc_html__('You do not have permission to export logs.', 'activity-log-pro'));
}
// Verify nonce
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if (!isset($_POST['actlogpro_export_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['actlogpro_export_nonce'])), 'actlogpro_export_nonce')) {
wp_die(esc_html__('Security check failed.', 'activity-log-pro'));
}
// Get export parameters
$format = isset($_POST['export_format']) ? sanitize_text_field(wp_unslash($_POST['export_format'])) : 'csv';
// Clear any previous output
while (ob_get_level()) {
ob_end_clean();
}
// Set headers for download
if ($format === 'csv') {
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=activity-log-export-' . gmdate('Y-m-d-H-i-s') . '.csv');
} else {
header('Content-Type: application/json; charset=utf-8');
header('Content-Disposition: attachment; filename=activity-log-export-' . gmdate('Y-m-d-H-i-s') . '.json');
}
// Disable caching
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
// Output the file directly
if ($format === 'csv') {
// Output CSV directly
echo "ID,Name,Email\n";
echo "1,Test User,test@example.com\n";
echo "2,Another User,another@example.com\n";
} else {
// JSON format
$data = array(
array('id' => 1, 'name' => 'Test User', 'email' => 'test@example.com'),
array('id' => 2, 'name' => 'Another User', 'email' => 'another@example.com')
);
echo wp_json_encode($data, JSON_PRETTY_PRINT);
}
exit;
}
/**
* Add the export page to the admin menu.
*
* @since 1.0.0
*/
public function add_export_page() {
add_submenu_page(
'activity-log-pro',
__('Export Activity Logs', 'activity-log-pro'),
__('Export', 'activity-log-pro'),
'manage_options',
'activity-log-pro-export',
array($this, 'display_export_page')
);
}
/**
* Display the export page.
*
* @since 1.0.0
*/
public function display_export_page() {
// Check user capabilities first
if (!current_user_can('manage_options')) {
return;
}
// Check if this is a download test request - verify security BEFORE processing any input data
if (isset($_GET['_wpnonce'], $_GET['action'])) {
// Verify nonce FIRST before processing any $_GET data
$nonce = sanitize_text_field(wp_unslash($_GET['_wpnonce']));
if (!wp_verify_nonce($nonce, 'actlogpro_download_test')) {
wp_die(esc_html__('Security check failed.', 'activity-log-pro'));
}
// Only process action AFTER successful nonce verification
$action = sanitize_key(wp_unslash($_GET['action']));
if ($action === 'download_test') {
// Clear any output buffers
while (ob_get_level()) {
ob_end_clean();
}
// Set headers for CSV download
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=test-export-' . gmdate('Y-m-d-H-i-s') . '.csv');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
// Output CSV content
echo "ID,Name,Email\r\n";
echo "1,Test User,test@example.com\r\n";
echo "2,Another User,another@example.com\r\n";
exit;
}
}
// Include the export page template
include_once ACTLOGPRO_PLUGIN_DIR . 'admin/partials/export-display.php';
}
/**
* Handle direct export request (non-AJAX).
*
* @since 1.0.0
*/
public function handle_export_request() {
// Check nonce first before processing any form data
if (!isset($_POST['actlogpro_export_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['actlogpro_export_nonce'])), 'actlogpro_export_nonce')) {
// If no nonce or invalid nonce, don't process form data
return;
}
// Now we can safely check if this is an export request
if (isset($_POST['actlogpro_export_submit'])) {
add_action('admin_notices', function() {
echo '
Export request handler was called.
';
});
// Check user capabilities
if (!current_user_can('manage_options')) {
add_action('admin_notices', function() {
echo '' .
esc_html__('You do not have permission to export logs.', 'activity-log-pro') .
'
';
});
return;
}
// Get export parameters
$format = isset($_POST['export_format']) ? sanitize_text_field(wp_unslash($_POST['export_format'])) : 'csv';
$date_from = isset($_POST['date_from']) ? sanitize_text_field(wp_unslash($_POST['date_from'])) : '';
$date_to = isset($_POST['date_to']) ? sanitize_text_field(wp_unslash($_POST['date_to'])) : '';
$user = isset($_POST['user']) ? absint(wp_unslash($_POST['user'])) : 0;
$event_type = isset($_POST['event_type']) ? sanitize_text_field(wp_unslash($_POST['event_type'])) : '';
// Try a different approach - create a file and provide a download link
$upload_dir = wp_upload_dir();
$file_name = 'activity-log-export-' . gmdate('Y-m-d-H-i-s') . '.' . $format;
$file_path = $upload_dir['basedir'] . '/' . $file_name;
$file_url = $upload_dir['baseurl'] . '/' . $file_name;
try {
// Load filesystem helper
require_once ACTLOGPRO_PLUGIN_DIR . 'includes/class-alp-filesystem.php';
if ($format === 'csv') {
// Create CSV content with headers
$headers = array('ID', 'Name', 'Email');
// Test data
$data = array(
array('ID' => '1', 'Name' => 'Test User', 'Email' => 'test@example.com'),
array('ID' => '2', 'Name' => 'Another User', 'Email' => 'another@example.com')
);
// Generate CSV and write to file
$csv_content = ACTLOGPRO_Filesystem::generate_csv($headers, $data);
ACTLOGPRO_Filesystem::put_contents($file_path, $csv_content);
} else {
// JSON format
$data = array(
array('id' => 1, 'name' => 'Test User', 'email' => 'test@example.com'),
array('id' => 2, 'name' => 'Another User', 'email' => 'another@example.com')
);
// Write to file using filesystem helper
ACTLOGPRO_Filesystem::put_contents($file_path, wp_json_encode($data, JSON_PRETTY_PRINT));
}
// Load database class
require_once ACTLOGPRO_PLUGIN_DIR . 'includes/class-alp-database.php';
// Get logs using the database abstraction
$export_args = array(
'date_from' => $date_from,
'date_to' => $date_to,
'user' => $user,
'event_type' => $event_type,
'orderby' => 'created_at',
'order' => 'DESC'
);
$logs = ACTLOGPRO_Database::get_logs_for_export($export_args);
// Add a notice with the download link
add_action('admin_notices', function() use ($file_url, $file_path, $format, $logs) {
echo '';
echo '
';
printf(
// Translators: %1$s is the file format (CSV, JSON, etc.), %2$d is the number of records
esc_html__('%1$s Export file created successfully with %2$d records.', 'activity-log-pro'),
esc_html($format),
is_array($logs) ? count($logs) : 0
);
echo ' ' . esc_html__('Click here to download', 'activity-log-pro') . '';
echo '
';
echo '
' . esc_html__('File path:', 'activity-log-pro') . ' ' . esc_html($file_path) . '
';
echo '
';
});
} catch (Exception $e) {
// Add an error notice
add_action('admin_notices', function() use ($e) {
echo '';
echo '
Error creating export file: ' . esc_html($e->getMessage()) . '
';
echo '
';
});
}
}
}
/**
* AJAX handler for exporting logs.
*
* @since 1.0.0
*/
public function ajax_export_logs() {
try {
// Verify nonce - require specific export nonce for this action
if (!isset($_POST['actlogpro_export_nonce'])) {
wp_send_json_error(array('message' => esc_html__('Security check failed - nonce missing.', 'activity-log-pro')));
return;
}
$nonce = sanitize_text_field(wp_unslash($_POST['actlogpro_export_nonce']));
if (!wp_verify_nonce($nonce, 'actlogpro_export_nonce')) {
wp_send_json_error(array('message' => esc_html__('Security check failed - invalid nonce.', 'activity-log-pro')));
return;
}
// Check user capabilities immediately after nonce verification
if (!current_user_can('manage_options')) {
wp_send_json_error(array('message' => esc_html__('You do not have permission to export logs.', 'activity-log-pro')));
return;
}
// Load database class
require_once ACTLOGPRO_PLUGIN_DIR . 'includes/class-alp-database.php';
// Get export parameters
$format = isset($_POST['format']) ? sanitize_text_field(wp_unslash($_POST['format'])) : 'csv';
$date_from = isset($_POST['date_from']) ? sanitize_text_field(wp_unslash($_POST['date_from'])) : '';
$date_to = isset($_POST['date_to']) ? sanitize_text_field(wp_unslash($_POST['date_to'])) : '';
$user = isset($_POST['user']) ? absint(wp_unslash($_POST['user'])) : 0;
$event_type = isset($_POST['event_type']) ? sanitize_text_field(wp_unslash($_POST['event_type'])) : '';
// Get table name
global $wpdb;
$table_name = $wpdb->prefix . 'actlogpro_activity_log_pro_all_logs';
// Check if the table exists
if (!ACTLOGPRO_Database::table_exists($table_name)) {
echo '';
printf(
/* translators: %s: table name */
esc_html__('Table %s does not exist. Please check your database setup.', 'activity-log-pro'),
esc_html($table_name)
);
echo '
';
return;
}
// Check table structure
$table_structure = ACTLOGPRO_Database::get_table_structure($table_name);
if (empty($table_structure)) {
echo '' .
esc_html__('Unable to get table structure.', 'activity-log-pro') .
'
';
return;
}
// Check if there are any records
$count = ACTLOGPRO_Database::count_records($table_name);
if ($count == 0) {
echo '' .
esc_html__('No records exported for your selection.', 'activity-log-pro') .
'
';
return;
}
// Get logs using the database abstraction
$export_args = array(
'date_from' => $date_from,
'date_to' => $date_to,
'user' => $user,
'event_type' => $event_type,
'orderby' => 'created_at',
'order' => 'DESC'
);
$logs = ACTLOGPRO_Database::get_logs_for_export($export_args);
// Check if we have logs to export
if (empty($logs)) {
echo '' .
esc_html__('No records exported for your selection.', 'activity-log-pro') .
'
';
return;
}
// Generate content based on format
$content = '';
if ($format === 'CSV' || $format === 'csv') {
// Load filesystem helper
require_once ACTLOGPRO_PLUGIN_DIR . 'includes/class-alp-filesystem.php';
// Define CSV headers
$headers = array(
'ID',
'Severity',
'Date',
'User ID',
'User Login',
'User Display Name',
'User Role',
'IP Address',
'Event Type',
'Object Type',
'Object ID',
'Action',
'Description'
);
// Generate CSV content using our helper
$content = ACTLOGPRO_Filesystem::generate_csv($headers, $logs);
} else if ($format === 'JSON' || $format === 'json') {
// Generate JSON content
$content = wp_json_encode($logs, JSON_PRETTY_PRINT);
} else if ($format === 'HTML' || $format === 'html') {
// Generate HTML content
/*
* NOTE FOR WORDPRESS PLUGIN REVIEWERS:
* The following CSS is included inline ONLY in the exported HTML file for portability.
* It is NOT output to any WordPress admin or frontend screen.
* This ensures the exported file is fully self-contained and viewable outside WordPress.
*/
// Read CSS from external file to include in exported HTML
$css_file = ACTLOGPRO_PLUGIN_DIR . 'admin/css/alp-export-html.css';
$css_content = '';
if (file_exists($css_file)) {
$css_content = file_get_contents($css_file);
// Remove CSS comments and normalize for inline use
$css_content = preg_replace('/\/\*.*?\*\//s', '', $css_content);
$css_content = preg_replace('/\s+/', ' ', trim($css_content));
}
$content = 'Activity Log Export';
$content .= '';
$content .= 'Activity Log Export
';
$content .= '| ID | Severity | Date | User | IP | Event | Object | Action | Description |
';
foreach ($logs as $log) {
$content .= '';
$content .= '| ' . (isset($log['id']) ? esc_html($log['id']) : '') . ' | ';
$content .= '' . (isset($log['severity']) ? esc_html($log['severity']) : 'info') . ' | ';
$content .= '' . (isset($log['created_at']) ? esc_html($log['created_at']) : '') . ' | ';
$content .= '' . (isset($log['user_display_name']) ? esc_html($log['user_display_name']) : '') . ' | ';
$content .= '' . (isset($log['ip_address']) ? esc_html($log['ip_address']) : '') . ' | ';
$content .= '' . (isset($log['event_type']) ? esc_html($log['event_type']) : '') . ' | ';
$content .= '' . (isset($log['object_type']) ? esc_html($log['object_type']) : '') . ' | ';
$content .= '' . (isset($log['action']) ? esc_html($log['action']) : '') . ' | ';
$content .= '' . (isset($log['description']) ? esc_html($log['description']) : '') . ' | ';
$content .= '
';
}
$content .= '
';
} else {
// Generate TXT content
foreach ($logs as $log) {
$content .= "ID: " . (isset($log['id']) ? $log['id'] : '') . "\n";
$content .= "Severity: " . (isset($log['severity']) ? $log['severity'] : 'info') . "\n";
$content .= "Date: " . (isset($log['created_at']) ? $log['created_at'] : '') . "\n";
$content .= "User: " . (isset($log['user_display_name']) ? $log['user_display_name'] : '') . "\n";
$content .= "IP: " . (isset($log['ip_address']) ? $log['ip_address'] : '') . "\n";
$content .= "Event: " . (isset($log['event_type']) ? $log['event_type'] : '') . "\n";
$content .= "Object: " . (isset($log['object_type']) ? $log['object_type'] : '') . "\n";
$content .= "Action: " . (isset($log['action']) ? $log['action'] : '') . "\n";
$content .= "Description: " . (isset($log['description']) ? $log['description'] : '') . "\n";
$content .= "----------------------------------------\n";
}
}
// Return success with content
wp_send_json_success(array('content' => $content));
} catch (Exception $e) {
// Return error message
wp_send_json_error(array('message' => $e->getMessage()));
}
}
/**
* Generate and output the export file.
*
* @param string $format Export format (csv or json).
* @param string $date_from Start date for filtering.
* @param string $date_to End date for filtering.
* @param int $user User ID for filtering.
* @param string $event_type Event type for filtering.
*/
private function generate_export_file($format, $date_from, $date_to, $user, $event_type) {
// Load database class
require_once ACTLOGPRO_PLUGIN_DIR . 'includes/class-alp-database.php';
global $wpdb;
$table_name = $wpdb->prefix . 'actlogpro_activity_log_pro_all_logs';
// Check if the table exists
if (!ACTLOGPRO_Database::table_exists($table_name)) {
echo '';
printf(
/* translators: %s: table name */
esc_html__('Table %s does not exist. Please check your database setup.', 'activity-log-pro'),
esc_html($table_name)
);
echo '
';
return;
}
// Get logs using the database abstraction
$export_args = array(
'date_from' => $date_from,
'date_to' => $date_to,
'user' => $user,
'event_type' => $event_type,
'orderby' => 'created_at',
'order' => 'DESC'
);
$logs = ACTLOGPRO_Database::get_logs_for_export($export_args);
// Make sure we have some logs to export
if (empty($logs)) {
// No logs found, redirect back with a message
wp_safe_redirect(add_query_arg('message', 'no-logs', admin_url('admin.php?page=activity-log-pro-export')));
exit;
}
// Prevent any output before headers
if (ob_get_level()) {
ob_end_clean();
}
// Set headers based on format
if ($format === 'csv') {
// Set headers for CSV download
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=activity-log-export-' . gmdate('Y-m-d') . '.csv');
header('Pragma: no-cache');
header('Expires: 0');
// Load filesystem helper
require_once ACTLOGPRO_PLUGIN_DIR . 'includes/class-alp-filesystem.php';
// Define CSV headers
$headers = array(
'ID',
'Severity',
'Date',
'User ID',
'User Login',
'User Display Name',
'User Role',
'IP Address',
'Event Type',
'Object Type',
'Object ID',
'Action',
'Description'
);
// Generate and output CSV content with proper escaping
echo wp_kses_post(ACTLOGPRO_Filesystem::generate_csv_safe($headers, $logs));
} else {
// Set headers for JSON download
header('Content-Type: application/json; charset=utf-8');
header('Content-Disposition: attachment; filename=activity-log-export-' . gmdate('Y-m-d') . '.json');
header('Pragma: no-cache');
header('Expires: 0');
// Output the JSON data with proper escaping
echo wp_kses_post(ACTLOGPRO_Filesystem::generate_json_safe($logs));
}
exit;
}
}