From ab13ea1af0a706a09d799c84f77519bf4d5d903e Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 5 Dec 2025 05:52:59 +0000 Subject: [PATCH 1/8] Exportall as chunked export to avoid mem-exhaust --- application/controllers/Adif.php | 41 ++++++++++++++++++++++++++++--- application/models/Adif_data.php | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 4 deletions(-) diff --git a/application/controllers/Adif.php b/application/controllers/Adif.php index b1bb25194..e3dafd313 100644 --- a/application/controllers/Adif.php +++ b/application/controllers/Adif.php @@ -85,17 +85,50 @@ class adif extends CI_Controller { } - // Export all QSO Data in ASC Order of Date. + // Export all QSO Data in ASC Order of Date - use chunks to avoid memory exhaustion public function exportall() { - // Set memory limit to unlimited to allow heavy usage $this->require_tab_access('export'); + ini_set('memory_limit', '-1'); + set_time_limit(300); $this->load->model('adif_data'); + $this->load->library('AdifHelper'); - $data['qsos'] = $this->adif_data->export_all(null, $this->input->post('from', true), $this->input->post('to', true)); + $from = $this->input->post('from', true); + $to = $this->input->post('to', true); - $this->load->view('adif/data/exportall', $data); + $filename = $this->session->userdata('user_callsign').'-'.date('Ymd-Hi').'.adi'; + header('Content-Type: text/plain; charset=utf-8'); + header('Content-Disposition: attachment; filename="'.$filename.'"'); + + // Output ADIF header // No chance to use exportall-view any longer, because of chunking logic + echo "Wavelog ADIF export\n"; + echo "3.1.6\n"; + echo "config->item('app_name')).">".$this->config->item('app_name')."\r\n"; + echo "optionslib->get_option('version')).">".$this->optionslib->get_option('version')."\r\n"; + echo "\n\n"; + + // Stream QSOs in 5K chunks + $offset = 0; + $chunk_size = 5000; + + do { + $qsos = $this->adif_data->export_all_chunked(null, $from, $to, false, null, $offset, $chunk_size); + + if ($qsos->num_rows() > 0) { + foreach ($qsos->result() as $qso) { + echo $this->adifhelper->getAdifLine($qso); + } + + // Free memory + $qsos->free_result(); + } + + $offset += $chunk_size; + } while ($qsos->num_rows() > 0); + + exit; } diff --git a/application/models/Adif_data.php b/application/models/Adif_data.php index e34845546..55e3a569c 100644 --- a/application/models/Adif_data.php +++ b/application/models/Adif_data.php @@ -238,6 +238,48 @@ class adif_data extends CI_Model { return $this->db->get(); } + + function export_all_chunked($api_key = null, $from = null, $to = null, $exportLotw = false, $onlyop = null, $offset = 0, $limit = 5000) { + $this->load->model('logbooks_model'); + if ($api_key != null) { + $this->load->model('api_model'); + if (strpos($this->api_model->access($api_key), 'r') !== false) { + $this->api_model->update_last_used($api_key); + $user_id = $this->api_model->key_userid($api_key); + $logbooks_locations_array = $this->list_station_locations($user_id); + } + } else { + $this->load->model('stations'); + $logbooks_locations_array = $this->list_station_locations($this->session->userdata('user_id')); + } + + $this->db->select($this->config->item('table_name').'.*, station_profile.*, dxcc_entities.name as station_country'); + $this->db->order_by("COL_TIME_ON", "ASC"); + $this->db->join('station_profile', 'station_profile.station_id = '.$this->config->item('table_name').'.station_id'); + if ($from) { + $this->db->where("date(".$this->config->item('table_name').".COL_TIME_ON) >= ", $from); + } + if ($to) { + $this->db->where("date(".$this->config->item('table_name').".COL_TIME_ON) <= ",$to); + } + if ($onlyop) { + $this->db->where("upper(".$this->config->item('table_name').".col_operator)",$onlyop); + } + if ($exportLotw) { + $this->db->group_start(); + $this->db->where($this->config->item('table_name').".COL_LOTW_QSL_SENT != 'Y'"); + $this->db->or_where($this->config->item('table_name').".COL_LOTW_QSL_SENT", NULL); + $this->db->group_end(); + } + $this->db->where_in('station_profile.station_id', $logbooks_locations_array); + $this->db->join('dxcc_entities', 'station_profile.station_dxcc = dxcc_entities.adif'); + + // Add chunking + $this->db->limit($limit, $offset); + + $query = $this->db->get($this->config->item('table_name')); + return $query; + } } ?> From 1b2bb022e3bb0e911f7b7f1151cc548e38ee93b2 Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 5 Dec 2025 06:02:17 +0000 Subject: [PATCH 2/8] Use Chunking for Backup as well --- application/controllers/Backup.php | 44 ++++++++++------ application/models/Adif_data.php | 82 +++++++++++++++--------------- 2 files changed, 70 insertions(+), 56 deletions(-) diff --git a/application/controllers/Backup.php b/application/controllers/Backup.php index 5c65e2028..0711c8639 100644 --- a/application/controllers/Backup.php +++ b/application/controllers/Backup.php @@ -29,31 +29,43 @@ class Backup extends CI_Controller { $clean_key = $this->security->xss_clean($key); $this->load->helper('file'); + $this->load->library('AdifHelper'); // Set memory limit to unlimited to allow heavy usage ini_set('memory_limit', '-1'); $this->load->model('adif_data'); + $filename = 'backup/logbook'. date('_Y_m_d_H_i_s') .'.adi'; - $data['qsos'] = $this->adif_data->export_all($clean_key); + header('Content-Type: text/plain; charset=utf-8'); + header('Content-Disposition: attachment; filename="'.$filename.'"'); - $data['filename'] = 'backup/logbook'. date('_Y_m_d_H_i_s') .'.adi'; - - if ( ! write_file($data['filename'], $this->load->view('backup/exportall', $data, true))) - { - $data['status'] = false; - } - else - { - $data['status'] = true; - } + // Output ADIF header // No chance to use exportall-view any longer, because of chunking logic + echo "Wavelog ADIF export\n"; + echo "3.1.6\n"; + echo "config->item('app_name')).">".$this->config->item('app_name')."\r\n"; + echo "optionslib->get_option('version')).">".$this->optionslib->get_option('version')."\r\n"; + echo "\n\n"; - $data['page_title'] = __("ADIF - Backup"); - + // Stream QSOs in 5K chunks + $offset = 0; + $chunk_size = 5000; - $this->load->view('interface_assets/header', $data); - $this->load->view('backup/adif_view'); - $this->load->view('interface_assets/footer'); + do { + $qsos = $this->adif_data->export_all_chunked($clean_key, null, null, false, null, $offset, $chunk_size); + if ($qsos->num_rows() > 0) { + foreach ($qsos->result() as $qso) { + echo $this->adifhelper->getAdifLine($qso); + } + + // Free memory + $qsos->free_result(); + } + + $offset += $chunk_size; + } while ($qsos->num_rows() > 0); + + exit; } /* Export the notes to XML */ diff --git a/application/models/Adif_data.php b/application/models/Adif_data.php index 55e3a569c..ba0ad0de6 100644 --- a/application/models/Adif_data.php +++ b/application/models/Adif_data.php @@ -2,6 +2,48 @@ class adif_data extends CI_Model { + function export_all_chunked($api_key = null, $from = null, $to = null, $exportLotw = false, $onlyop = null, $offset = 0, $limit = 5000) { + $this->load->model('logbooks_model'); + if ($api_key != null) { + $this->load->model('api_model'); + if (strpos($this->api_model->access($api_key), 'r') !== false) { + $this->api_model->update_last_used($api_key); + $user_id = $this->api_model->key_userid($api_key); + $logbooks_locations_array = $this->list_station_locations($user_id); + } + } else { + $this->load->model('stations'); + $logbooks_locations_array = $this->list_station_locations($this->session->userdata('user_id')); + } + + $this->db->select($this->config->item('table_name').'.*, station_profile.*, dxcc_entities.name as station_country'); + $this->db->order_by("COL_TIME_ON", "ASC"); + $this->db->join('station_profile', 'station_profile.station_id = '.$this->config->item('table_name').'.station_id'); + if ($from) { + $this->db->where("date(".$this->config->item('table_name').".COL_TIME_ON) >= ", $from); + } + if ($to) { + $this->db->where("date(".$this->config->item('table_name').".COL_TIME_ON) <= ",$to); + } + if ($onlyop) { + $this->db->where("upper(".$this->config->item('table_name').".col_operator)",$onlyop); + } + if ($exportLotw) { + $this->db->group_start(); + $this->db->where($this->config->item('table_name').".COL_LOTW_QSL_SENT != 'Y'"); + $this->db->or_where($this->config->item('table_name').".COL_LOTW_QSL_SENT", NULL); + $this->db->group_end(); + } + $this->db->where_in('station_profile.station_id', $logbooks_locations_array); + $this->db->join('dxcc_entities', 'station_profile.station_dxcc = dxcc_entities.adif'); + + // Add chunking + $this->db->limit($limit, $offset); + + $query = $this->db->get($this->config->item('table_name')); + return $query; + } + function export_all($api_key = null,$from = null, $to = null, $exportLotw = false, $onlyop = null) { $this->load->model('logbooks_model'); if ($api_key != null) { @@ -239,47 +281,7 @@ class adif_data extends CI_Model { return $this->db->get(); } - function export_all_chunked($api_key = null, $from = null, $to = null, $exportLotw = false, $onlyop = null, $offset = 0, $limit = 5000) { - $this->load->model('logbooks_model'); - if ($api_key != null) { - $this->load->model('api_model'); - if (strpos($this->api_model->access($api_key), 'r') !== false) { - $this->api_model->update_last_used($api_key); - $user_id = $this->api_model->key_userid($api_key); - $logbooks_locations_array = $this->list_station_locations($user_id); - } - } else { - $this->load->model('stations'); - $logbooks_locations_array = $this->list_station_locations($this->session->userdata('user_id')); - } - $this->db->select($this->config->item('table_name').'.*, station_profile.*, dxcc_entities.name as station_country'); - $this->db->order_by("COL_TIME_ON", "ASC"); - $this->db->join('station_profile', 'station_profile.station_id = '.$this->config->item('table_name').'.station_id'); - if ($from) { - $this->db->where("date(".$this->config->item('table_name').".COL_TIME_ON) >= ", $from); - } - if ($to) { - $this->db->where("date(".$this->config->item('table_name').".COL_TIME_ON) <= ",$to); - } - if ($onlyop) { - $this->db->where("upper(".$this->config->item('table_name').".col_operator)",$onlyop); - } - if ($exportLotw) { - $this->db->group_start(); - $this->db->where($this->config->item('table_name').".COL_LOTW_QSL_SENT != 'Y'"); - $this->db->or_where($this->config->item('table_name').".COL_LOTW_QSL_SENT", NULL); - $this->db->group_end(); - } - $this->db->where_in('station_profile.station_id', $logbooks_locations_array); - $this->db->join('dxcc_entities', 'station_profile.station_dxcc = dxcc_entities.adif'); - - // Add chunking - $this->db->limit($limit, $offset); - - $query = $this->db->get($this->config->item('table_name')); - return $query; - } } ?> From bd3d4256e6bdcc43ab7485e34549da737afae90c Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 5 Dec 2025 06:39:44 +0000 Subject: [PATCH 3/8] Chunked also for custom_export --- application/controllers/Adif.php | 49 ++++++++++++++++++++++++++++---- application/models/Adif_data.php | 45 +++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/application/controllers/Adif.php b/application/controllers/Adif.php index e3dafd313..91528a274 100644 --- a/application/controllers/Adif.php +++ b/application/controllers/Adif.php @@ -176,10 +176,15 @@ class adif extends CI_Controller { // Set memory limit to unlimited to allow heavy usage ini_set('memory_limit', '-1'); + set_time_limit(300); $this->load->model('adif_data'); + $this->load->library('AdifHelper'); + // Get parameters $station_id = $this->security->xss_clean($this->input->post('station_profile')); + $from = $this->input->post('from'); + $to = $this->input->post('to'); // Used for exporting QSOs not previously exported to LoTW if ($this->input->post('exportLotw') == 1) { @@ -194,16 +199,50 @@ class adif extends CI_Controller { $onlyop=null; } - $data['qsos'] = $this->adif_data->export_custom($this->input->post('from'), $this->input->post('to'), $station_id, $exportLotw, $onlyop); + // Set headers for direct download + $filename = $this->session->userdata('user_callsign').'-'.date('Ymd-Hi').'.adi'; + header('Content-Type: text/plain; charset=utf-8'); + header('Content-Disposition: attachment; filename="'.$filename.'"'); - $this->load->view('adif/data/exportall', $data); + // Output ADIF header // No chance to use exportall-view any longer, because of chunking logic + echo "Wavelog ADIF export\n"; + echo "3.1.6\n"; + echo "config->item('app_name')).">".$this->config->item('app_name')."\r\n"; + echo "optionslib->get_option('version')).">".$this->optionslib->get_option('version')."\r\n"; + echo "\n\n"; + // Collect QSO IDs for LoTW marking (since we can't access all at once) + $qso_ids_for_lotw = []; - if ((clubaccess_check(9)) && ($this->input->post('markLotw') == 1)) { // Only allow marking if clubofficer or regular user! - foreach ($data['qsos']->result() as $qso) { - $this->adif_data->mark_lotw_sent($qso->COL_PRIMARY_KEY); + // Stream QSOs in 5K chunks + $offset = 0; + $chunk_size = 5000; + + do { + $qsos = $this->adif_data->export_custom_chunked($from, $to, $station_id, $exportLotw, $onlyop, $offset, $chunk_size); + + if ($qsos && $qsos->num_rows() > 0) { + foreach ($qsos->result() as $qso) { + echo $this->adifhelper->getAdifLine($qso); + // Collect IDs for LoTW marking + $qso_ids_for_lotw[] = $qso->COL_PRIMARY_KEY; + } + // Free memory + $qsos->free_result(); + } + + $offset += $chunk_size; + } while ($qsos && $qsos->num_rows() > 0); + + // Handle LoTW marking after export + if ((clubaccess_check(9)) && ($this->input->post('markLotw') == 1) && !empty($qso_ids_for_lotw)) { + foreach ($qso_ids_for_lotw as $qso_id) { + $this->adif_data->mark_lotw_sent($qso_id); } } + + // Stop execution + exit; } public function mark_lotw() { diff --git a/application/models/Adif_data.php b/application/models/Adif_data.php index ba0ad0de6..e54ef1a16 100644 --- a/application/models/Adif_data.php +++ b/application/models/Adif_data.php @@ -281,6 +281,51 @@ class adif_data extends CI_Model { return $this->db->get(); } + function export_custom_chunked($from, $to, $station_id, $exportLotw = false, $onlyop = null, $offset = 0, $limit = 5000) { + // Copy export_custom logic but add chunking for station_id > 0 + $this->load->model('Stations'); + if ($station_id == 0) { + // Use existing chunked export_all for all stations + return $this->export_all_chunked(null, $from, $to, $exportLotw, $onlyop, $offset, $limit); + } + + // Check station access + if (!$this->Stations->check_station_is_accessible($station_id)) { + return; + } + + // Build query identical to export_custom but add LIMIT/OFFSET + $this->db->select(''.$this->config->item('table_name').'.*, station_profile.*, dxcc_entities.name as station_country'); + $this->db->from($this->config->item('table_name')); + $this->db->where($this->config->item('table_name').'.station_id', $station_id); + + // Apply same filters as export_custom + if ($from) { + $this->db->where("date(".$this->config->item('table_name').".COL_TIME_ON) >= ", $from); + } + if ($to) { + $this->db->where("date(".$this->config->item('table_name').".COL_TIME_ON) <= ",$to); + } + if ($onlyop) { + $this->db->where("upper(".$this->config->item('table_name').".col_operator)",$onlyop); + } + if ($exportLotw) { + $this->db->group_start(); + $this->db->where($this->config->item('table_name').".COL_LOTW_QSL_SENT != 'Y'"); + $this->db->or_where($this->config->item('table_name').".COL_LOTW_QSL_SENT", NULL); + $this->db->group_end(); + } + + $this->db->order_by($this->config->item('table_name').".COL_TIME_ON", "ASC"); + $this->db->join('station_profile', 'station_profile.station_id = '.$this->config->item('table_name').'.station_id'); + $this->db->join('dxcc_entities', 'station_profile.station_dxcc = dxcc_entities.adif', 'left outer'); + + // Add chunking + $this->db->limit($limit, $offset); + + return $this->db->get(); + } + } From ad11abe84b52353832bf9d4c3428f3b98a86a545 Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 5 Dec 2025 06:57:14 +0000 Subject: [PATCH 4/8] Fix for API get_contacts_adif --- application/controllers/Api.php | 77 +++++++++++++++------ application/models/Adif_data.php | 115 +++++++++++++++---------------- 2 files changed, 113 insertions(+), 79 deletions(-) diff --git a/application/controllers/Api.php b/application/controllers/Api.php index 035e6fcd8..6995c5353 100644 --- a/application/controllers/Api.php +++ b/application/controllers/Api.php @@ -440,33 +440,68 @@ class API extends CI_Controller { //load adif data module $this->load->model('adif_data'); + $this->load->library('AdifHelper'); - //get qso data - $data['qsos'] = $this->adif_data->export_past_id($station_id, $fetchfromid, $limit); + // Initialize tracking variables + $total_fetched = 0; + $all_qso_ids = []; + $lastfetchedid = $fetchfromid; - //set internalonly attribute for adif creation - $data['internalrender'] = true; + // Process in chunks to avoid memory issues + $chunk_size = 5000; + $remaining_limit = $limit; + $offset = 0; - //if no new QSOs are ready, return that - $qso_count = count($data['qsos']->result()); - if($qso_count <= 0) { + // Start building ADIF content + $adif_content = "Wavelog ADIF export\n"; + $adif_content .= "3.1.6\n"; + $adif_content .= "config->item('app_name')).">".$this->config->item('app_name')."\r\n"; + $adif_content .= "optionslib->get_option('version')).">".$this->optionslib->get_option('version')."\r\n"; + $adif_content .= "\n\n"; + + do { + // Calculate chunk size for this iteration + $current_chunk_size = min($chunk_size, $remaining_limit); + + // Fetch chunk + $qsos = $this->adif_data->export_past_id_chunked($station_id, $fetchfromid, $current_chunk_size, null, $offset, $current_chunk_size); + + if ($qsos && $qsos->num_rows() > 0) { + // Process chunk + foreach ($qsos->result() as $row) { + // Build ADIF content directly + $adif_content .= $this->adifhelper->getAdifLine($row); + + // Track data for response + $all_qso_ids[] = $row->COL_PRIMARY_KEY; + $lastfetchedid = max($lastfetchedid, $row->COL_PRIMARY_KEY); + $total_fetched++; + } + + // Free memory + $qsos->free_result(); + + // Update tracking + $remaining_limit -= $qsos->num_rows(); + $offset += $qsos->num_rows(); + + // Stop if we've hit the requested limit + if ($total_fetched >= $limit) { + break; + } + } + + // Continue if we got a full chunk and haven't hit the limit + } while ($qsos && $qsos->num_rows() > 0 && $total_fetched < $limit); + + // Return response (same format as original) + if($total_fetched <= 0) { http_response_code(200); echo json_encode(['status' => 'successfull', 'message' => 'No new QSOs available.', 'lastfetchedid' => $fetchfromid, 'exported_qsos' => 0, 'adif' => null]); - return; + } else { + http_response_code(200); + echo json_encode(['status' => 'successfull', 'message' => 'Export successfull', 'lastfetchedid' => $lastfetchedid, 'exported_qsos' => $total_fetched, 'adif' => $adif_content]); } - - //convert data to ADIF - $adif_content = $this->load->view('adif/data/exportall', $data, TRUE); - - //get new goalpost - $lastfetchedid = 0; - foreach ($data['qsos']->result() as $row) { - $lastfetchedid = max($lastfetchedid, $row->COL_PRIMARY_KEY); - } - - //return API result - http_response_code(200); - echo json_encode(['status' => 'successfull', 'message' => 'Export successfull', 'lastfetchedid' => $lastfetchedid, 'exported_qsos' => $qso_count, 'adif' => $adif_content]); } diff --git a/application/models/Adif_data.php b/application/models/Adif_data.php index e54ef1a16..98828a557 100644 --- a/application/models/Adif_data.php +++ b/application/models/Adif_data.php @@ -167,6 +167,52 @@ class adif_data extends CI_Model { return $this->db->get(); } + function export_custom_chunked($from, $to, $station_id, $exportLotw = false, $onlyop = null, $offset = 0, $limit = 5000) { + // Copy export_custom logic but add chunking for station_id > 0 + $this->load->model('Stations'); + if ($station_id == 0) { + // Use existing chunked export_all for all stations + return $this->export_all_chunked(null, $from, $to, $exportLotw, $onlyop, $offset, $limit); + } + + // Check station access + if (!$this->Stations->check_station_is_accessible($station_id)) { + return; + } + + // Build query identical to export_custom but add LIMIT/OFFSET + $this->db->select(''.$this->config->item('table_name').'.*, station_profile.*, dxcc_entities.name as station_country'); + $this->db->from($this->config->item('table_name')); + $this->db->where($this->config->item('table_name').'.station_id', $station_id); + + // Apply same filters as export_custom + if ($from) { + $this->db->where("date(".$this->config->item('table_name').".COL_TIME_ON) >= ", $from); + } + if ($to) { + $this->db->where("date(".$this->config->item('table_name').".COL_TIME_ON) <= ",$to); + } + if ($onlyop) { + $this->db->where("upper(".$this->config->item('table_name').".col_operator)",$onlyop); + } + if ($exportLotw) { + $this->db->group_start(); + $this->db->where($this->config->item('table_name').".COL_LOTW_QSL_SENT != 'Y'"); + $this->db->or_where($this->config->item('table_name').".COL_LOTW_QSL_SENT", NULL); + $this->db->group_end(); + } + + $this->db->order_by($this->config->item('table_name').".COL_TIME_ON", "ASC"); + $this->db->join('station_profile', 'station_profile.station_id = '.$this->config->item('table_name').'.station_id'); + $this->db->join('dxcc_entities', 'station_profile.station_dxcc = dxcc_entities.adif', 'left outer'); + + // Add chunking + $this->db->limit($limit, $offset); + + return $this->db->get(); + } + + function export_custom($from, $to, $station_id, $exportLotw = false, $onlyop = null) { // be sure that station belongs to user $this->load->model('Stations'); @@ -207,25 +253,25 @@ class adif_data extends CI_Model { } } - function export_past_id($station_id, $fetchfromid, $limit, $onlyop = null) { - //create query + function export_past_id_chunked($station_id, $fetchfromid, $limit, $onlyop = null, $offset = 0, $chunk_size = 5000) { + // Copy export_past_id logic but add chunking support $this->db->select(''.$this->config->item('table_name').'.*, station_profile.*, dxcc_entities.name as station_country'); $this->db->from($this->config->item('table_name')); $this->db->where($this->config->item('table_name').'.station_id', $station_id); - $this->db->where($this->config->item('table_name').".COL_PRIMARY_KEY > " , $fetchfromid); //only get values past the fetchfromid value - $this->db->order_by($this->config->item('table_name').".COL_TIME_ON", "ASC"); - $this->db->join('station_profile', 'station_profile.station_id = '.$this->config->item('table_name').'.station_id'); - $this->db->join('dxcc_entities', 'station_profile.station_dxcc = dxcc_entities.adif', 'left outer'); + $this->db->where($this->config->item('table_name').".COL_PRIMARY_KEY > ", $fetchfromid); + if ($onlyop) { $this->db->where("upper(".$this->config->item('table_name').".col_operator)",$onlyop); } + + // Add chunking + $this->db->limit($chunk_size, $offset); + + $this->db->order_by($this->config->item('table_name').".COL_TIME_ON", "ASC"); $this->db->order_by("COL_PRIMARY_KEY", "ASC"); + $this->db->join('station_profile', 'station_profile.station_id = '.$this->config->item('table_name').'.station_id'); + $this->db->join('dxcc_entities', 'station_profile.station_dxcc = dxcc_entities.adif', 'left outer'); - if ($limit > -1) { - $this->db->limit($limit); - } - - //return result return $this->db->get(); } @@ -280,53 +326,6 @@ class adif_data extends CI_Model { return $this->db->get(); } - - function export_custom_chunked($from, $to, $station_id, $exportLotw = false, $onlyop = null, $offset = 0, $limit = 5000) { - // Copy export_custom logic but add chunking for station_id > 0 - $this->load->model('Stations'); - if ($station_id == 0) { - // Use existing chunked export_all for all stations - return $this->export_all_chunked(null, $from, $to, $exportLotw, $onlyop, $offset, $limit); - } - - // Check station access - if (!$this->Stations->check_station_is_accessible($station_id)) { - return; - } - - // Build query identical to export_custom but add LIMIT/OFFSET - $this->db->select(''.$this->config->item('table_name').'.*, station_profile.*, dxcc_entities.name as station_country'); - $this->db->from($this->config->item('table_name')); - $this->db->where($this->config->item('table_name').'.station_id', $station_id); - - // Apply same filters as export_custom - if ($from) { - $this->db->where("date(".$this->config->item('table_name').".COL_TIME_ON) >= ", $from); - } - if ($to) { - $this->db->where("date(".$this->config->item('table_name').".COL_TIME_ON) <= ",$to); - } - if ($onlyop) { - $this->db->where("upper(".$this->config->item('table_name').".col_operator)",$onlyop); - } - if ($exportLotw) { - $this->db->group_start(); - $this->db->where($this->config->item('table_name').".COL_LOTW_QSL_SENT != 'Y'"); - $this->db->or_where($this->config->item('table_name').".COL_LOTW_QSL_SENT", NULL); - $this->db->group_end(); - } - - $this->db->order_by($this->config->item('table_name').".COL_TIME_ON", "ASC"); - $this->db->join('station_profile', 'station_profile.station_id = '.$this->config->item('table_name').'.station_id'); - $this->db->join('dxcc_entities', 'station_profile.station_dxcc = dxcc_entities.adif', 'left outer'); - - // Add chunking - $this->db->limit($limit, $offset); - - return $this->db->get(); - } - - } ?> From 5e02b514aea36b8d9a0054fd334ed280f61cb209 Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 5 Dec 2025 08:01:12 +0000 Subject: [PATCH 5/8] Use central function to generate ADIF-Header --- application/controllers/Adif.php | 13 ++----------- application/controllers/Api.php | 6 +----- application/libraries/AdifHelper.php | 9 +++++++++ application/views/adif/data/exportall.php | 10 ++-------- 4 files changed, 14 insertions(+), 24 deletions(-) diff --git a/application/controllers/Adif.php b/application/controllers/Adif.php index 91528a274..00cc48a6c 100644 --- a/application/controllers/Adif.php +++ b/application/controllers/Adif.php @@ -103,11 +103,7 @@ class adif extends CI_Controller { header('Content-Disposition: attachment; filename="'.$filename.'"'); // Output ADIF header // No chance to use exportall-view any longer, because of chunking logic - echo "Wavelog ADIF export\n"; - echo "3.1.6\n"; - echo "config->item('app_name')).">".$this->config->item('app_name')."\r\n"; - echo "optionslib->get_option('version')).">".$this->optionslib->get_option('version')."\r\n"; - echo "\n\n"; + echo $this->adifhelper->getAdifHeader($this->config->item('app_name'),$this->optionslib->get_option('version')); // Stream QSOs in 5K chunks $offset = 0; @@ -204,12 +200,7 @@ class adif extends CI_Controller { header('Content-Type: text/plain; charset=utf-8'); header('Content-Disposition: attachment; filename="'.$filename.'"'); - // Output ADIF header // No chance to use exportall-view any longer, because of chunking logic - echo "Wavelog ADIF export\n"; - echo "3.1.6\n"; - echo "config->item('app_name')).">".$this->config->item('app_name')."\r\n"; - echo "optionslib->get_option('version')).">".$this->optionslib->get_option('version')."\r\n"; - echo "\n\n"; + echo $this->adifhelper->getAdifHeader($this->config->item('app_name'),$this->optionslib->get_option('version')); // Collect QSO IDs for LoTW marking (since we can't access all at once) $qso_ids_for_lotw = []; diff --git a/application/controllers/Api.php b/application/controllers/Api.php index 6995c5353..c07cb6e01 100644 --- a/application/controllers/Api.php +++ b/application/controllers/Api.php @@ -453,11 +453,7 @@ class API extends CI_Controller { $offset = 0; // Start building ADIF content - $adif_content = "Wavelog ADIF export\n"; - $adif_content .= "3.1.6\n"; - $adif_content .= "config->item('app_name')).">".$this->config->item('app_name')."\r\n"; - $adif_content .= "optionslib->get_option('version')).">".$this->optionslib->get_option('version')."\r\n"; - $adif_content .= "\n\n"; + $adif_content = $this->adifhelper->getAdifHeader($this->config->item('app_name'),$this->optionslib->get_option('version')); do { // Calculate chunk size for this iteration diff --git a/application/libraries/AdifHelper.php b/application/libraries/AdifHelper.php index 40adf9895..c317fd210 100644 --- a/application/libraries/AdifHelper.php +++ b/application/libraries/AdifHelper.php @@ -262,6 +262,15 @@ class AdifHelper { return $line; } + function getAdifHeader($app_name,$version) { + $adif_header = "Wavelog ADIF export\n"; + $adif_header .= "3.1.6\n"; + $adif_header .= "".$app_name."\r\n"; + $adif_header .= "".$version."\r\n"; + $adif_header .= "\n\n"; + return $adif_header; + } + function getAdifFieldLine($adifcolumn, $dbvalue) { if ($dbvalue !== "" && $dbvalue !== null && $dbvalue !== 0) { return "<" . $adifcolumn . ":" . mb_strlen($dbvalue, "UTF-8") . ">" . $dbvalue . "\r\n"; diff --git a/application/views/adif/data/exportall.php b/application/views/adif/data/exportall.php index 9f2b6b603..6f5aadb9a 100644 --- a/application/views/adif/data/exportall.php +++ b/application/views/adif/data/exportall.php @@ -5,19 +5,13 @@ header('Content-Type: text/plain; charset=utf-8'); header('Content-Disposition: attachment; filename="'.$this->session->userdata('user_callsign').'-'.date('Ymd-Hi').'.adi"'); } -?> -Wavelog ADIF export -3.1.6 -config->item('app_name')); ?>>config->item('app_name')."\r\n"; ?> -optionslib->get_option('version')); ?>>optionslib->get_option('version')."\r\n"; ?> - - -load->is_loaded('AdifHelper')) { $CI->load->library('AdifHelper'); } +echo $this->adifhelper->getAdifHeader($CI->config->item('app_name'),$CI->optionslib->get_option('version')); + foreach ($qsos->result() as $qso) { echo $CI->adifhelper->getAdifLine($qso); } From 5e1a2137266f850ebedf0196ff55e7c8ba0fa257 Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 5 Dec 2025 08:06:05 +0000 Subject: [PATCH 6/8] get_contacts_adif: Order only by PK / tnx DB4SCW --- application/models/Adif_data.php | 1 - 1 file changed, 1 deletion(-) diff --git a/application/models/Adif_data.php b/application/models/Adif_data.php index 98828a557..9dda46fce 100644 --- a/application/models/Adif_data.php +++ b/application/models/Adif_data.php @@ -267,7 +267,6 @@ class adif_data extends CI_Model { // Add chunking $this->db->limit($chunk_size, $offset); - $this->db->order_by($this->config->item('table_name').".COL_TIME_ON", "ASC"); $this->db->order_by("COL_PRIMARY_KEY", "ASC"); $this->db->join('station_profile', 'station_profile.station_id = '.$this->config->item('table_name').'.station_id'); $this->db->join('dxcc_entities', 'station_profile.station_dxcc = dxcc_entities.adif', 'left outer'); From 5e9f5411ac4cf1d6ba5c8abf2db0e54c3e9b3f5c Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 5 Dec 2025 08:08:03 +0000 Subject: [PATCH 7/8] Use Headergen as well at Backup --- application/controllers/Backup.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/application/controllers/Backup.php b/application/controllers/Backup.php index 0711c8639..945892e2e 100644 --- a/application/controllers/Backup.php +++ b/application/controllers/Backup.php @@ -40,11 +40,7 @@ class Backup extends CI_Controller { header('Content-Disposition: attachment; filename="'.$filename.'"'); // Output ADIF header // No chance to use exportall-view any longer, because of chunking logic - echo "Wavelog ADIF export\n"; - echo "3.1.6\n"; - echo "config->item('app_name')).">".$this->config->item('app_name')."\r\n"; - echo "optionslib->get_option('version')).">".$this->optionslib->get_option('version')."\r\n"; - echo "\n\n"; + echo $this->adifhelper->getAdifHeader($this->config->item('app_name'),$this->optionslib->get_option('version')); // Stream QSOs in 5K chunks $offset = 0; From d70c21f277fbd12451ba8f91b9f47e3e1da10c41 Mon Sep 17 00:00:00 2001 From: int2001 Date: Fri, 5 Dec 2025 08:15:53 +0000 Subject: [PATCH 8/8] Typo / Fix at exportall-view --- application/views/adif/data/exportall.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/application/views/adif/data/exportall.php b/application/views/adif/data/exportall.php index 6f5aadb9a..035eeb298 100644 --- a/application/views/adif/data/exportall.php +++ b/application/views/adif/data/exportall.php @@ -10,8 +10,9 @@ if (!$CI->load->is_loaded('AdifHelper')) { $CI->load->library('AdifHelper'); } -echo $this->adifhelper->getAdifHeader($CI->config->item('app_name'),$CI->optionslib->get_option('version')); +echo $CI->adifhelper->getAdifHeader($CI->config->item('app_name'),$CI->optionslib->get_option('version')); foreach ($qsos->result() as $qso) { echo $CI->adifhelper->getAdifLine($qso); } +?>