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 .= ''; foreach ($logs as $log) { $content .= ''; $content .= ''; $content .= ''; $content .= ''; $content .= ''; $content .= ''; $content .= ''; $content .= ''; $content .= ''; $content .= ''; $content .= ''; } $content .= '
IDSeverityDateUserIPEventObjectActionDescription
' . (isset($log['id']) ? esc_html($log['id']) : '') . '' . (isset($log['severity']) ? esc_html($log['severity']) : 'info') . '' . (isset($log['created_at']) ? esc_html($log['created_at']) : '') . '' . (isset($log['user_display_name']) ? esc_html($log['user_display_name']) : '') . '' . (isset($log['ip_address']) ? esc_html($log['ip_address']) : '') . '' . (isset($log['event_type']) ? esc_html($log['event_type']) : '') . '' . (isset($log['object_type']) ? esc_html($log['object_type']) : '') . '' . (isset($log['action']) ? esc_html($log['action']) : '') . '' . (isset($log['description']) ? esc_html($log['description']) : '') . '
'; } 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; } }