Reworked some of the QRZ code for downloading
这个提交包含在:
		
							父节点
							
								
									b1a68d6c61
								
							
						
					
					
						当前提交
						0416d8446f
					
				
					共有  2 个文件被更改,包括 314 次插入 和 79 次删除
				
			
		|  | @ -195,89 +195,237 @@ class Qrz extends CI_Controller { | |||
| 			// Query the logbook to determine when the last LoTW confirmation was
 | ||||
| 			$qrz_last_date = null; | ||||
| 		} | ||||
| 		$this->download($this->session->userdata('user_id'),$qrz_last_date,true); | ||||
| 		$this->download($this->session->userdata('user_id'),true); | ||||
| 	} // end function
 | ||||
| 
 | ||||
| 	function download($user_id_to_load = null, $lastqrz = null, $show_views = false) { | ||||
| 	function download($user_id_to_load = null, $show_views = false) { // Remove $lastqrz parameter
 | ||||
| 		$this->load->model('user_model'); | ||||
| 		$this->load->model('logbook_model'); | ||||
| 
 | ||||
| 
 | ||||
| 		$api_keys = $this->logbook_model->get_qrz_apikeys(); | ||||
| 		$total_processed_count = 0; // Initialize total count here
 | ||||
| 		$data = []; // Initialize data array
 | ||||
| 
 | ||||
| 		if ($api_keys) { | ||||
| 			foreach ($api_keys as $station) { | ||||
| 				if ((($user_id_to_load != null) && ($user_id_to_load != $station->user_id))) {	// Skip User if we're called with a specific user_id
 | ||||
| 					continue; | ||||
| 				} | ||||
| 				if ($lastqrz == null) { | ||||
| 					$lastqrz = $this->logbook_model->qrz_last_qsl_date($station->user_id); | ||||
| 				} | ||||
| 
 | ||||
| 				// Remove the block checking for $lastqrz == null and fetching the date
 | ||||
| 				$qrz_api_key = $station->qrzapikey; | ||||
| 				$result=($this->mass_download_qsos($qrz_api_key, $lastqrz)); | ||||
| 				if (isset($result['tableheaders'])) { | ||||
| 					$data['tableheaders']=$result['tableheaders']; | ||||
| 				$result = $this->mass_download_qsos($qrz_api_key); // mass_download_qsos returns ['table_data' => ..., 'processed_count' => ...] or ['status' => 'error', 'message' => ...]
 | ||||
| 
 | ||||
| 
 | ||||
| 				if ($result !== false && isset($result['processed_count'])) { | ||||
| 					$total_processed_count += $result['processed_count']; // Accumulate count
 | ||||
| 					$table_data = $result['table_data']; | ||||
| 
 | ||||
| 					if (isset($table_data['tableheaders'])) { | ||||
| 						// Ensure headers are set only once
 | ||||
| 						if (!isset($data['tableheaders'])) { | ||||
| 							$data['tableheaders'] = $table_data['tableheaders']; | ||||
| 						} | ||||
| 						if (isset($table_data['table']) && $table_data['table'] != '') { | ||||
| 							if (isset($data['table'])) { | ||||
| 						$data['table'].=$result['table']; | ||||
| 								$data['table'] .= $table_data['table']; | ||||
| 							} else { | ||||
| 						$data['table']=$result['table']; | ||||
| 								$data['table'] = $table_data['table']; | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} else if (is_array($result) && isset($result['status']) && $result['status'] === 'error') { | ||||
| 					// Handle specific error structure returned by mass_download_qsos
 | ||||
| 					log_message('error', "Error during QRZ download for user_id: " . $station->user_id . ". Message: " . $result['message']); | ||||
| 					// Optionally echo error to user if $show_views is true, or add to $data['error']
 | ||||
| 					if ($show_views) { | ||||
| 						$data['errors'][] = "Error for user ID " . $station->user_id . ": " . $result['message']; | ||||
| 					} | ||||
| 				} else { | ||||
| 					// Catch-all for unexpected return values (like the old boolean false or other issues)
 | ||||
| 					log_message('error', "Unexpected error or empty result returned from mass_download_qsos for API key associated with user_id: " . $station->user_id); | ||||
| 					if ($show_views) { | ||||
| 						$data['errors'][] = "Unexpected error during download for user ID " . $station->user_id . ". Check system logs."; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} else { | ||||
| 			echo "No station profiles with a QRZ API Key found."; | ||||
| 			log_message('error', "No station profiles with a QRZ API Key found."); | ||||
| 			// If no keys, we can exit early if showing views, or just let it fall through if not.
 | ||||
| 			if ($show_views) { | ||||
| 				$data['page_title'] = "QRZ ADIF Information"; | ||||
| 				$data['error'] = "No station profiles with a QRZ API Key found."; | ||||
| 				$this->load->view('interface_assets/header', $data); | ||||
| 				$this->load->view('qrz/analysis', $data); // Assuming view can show $error
 | ||||
| 				$this->load->view('interface_assets/footer'); | ||||
| 				return; // Stop further processing
 | ||||
| 			} else { | ||||
| 				return ''; // Return empty if not showing views and no keys found
 | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		$this->load->model('user_model'); | ||||
| 		if ($this->user_model->authorize(2)) {	// Only Output results if authorized User
 | ||||
| 			if(isset($data['tableheaders'])) { | ||||
| 				if ($data['table'] != '') { | ||||
| 					$data['table'].='</table>'; | ||||
| 			// Pass potential errors to the view
 | ||||
| 			if (isset($data['errors'])) { | ||||
| 				$view_data['errors'] = $data['errors']; | ||||
| 			} | ||||
| 
 | ||||
| 			$has_matches_to_display = (isset($data['tableheaders']) && isset($data['table']) && $data['table'] != ''); | ||||
| 			$message = "Downloaded and processed " . $total_processed_count . " QSOs from QRZ."; | ||||
| 
 | ||||
| 			if ($has_matches_to_display) { | ||||
| 				$message .= " Matching QSOs found and updated."; | ||||
| 				if ($show_views == TRUE) { | ||||
| 					$data['page_title'] = "QRZ ADIF Information"; | ||||
| 					$this->load->view('interface_assets/header', $data); | ||||
| 					$this->load->view('qrz/analysis'); | ||||
| 					$view_data['tableheaders'] = $data['tableheaders']; | ||||
| 					$view_data['table'] = $data['table'] . '</table>'; | ||||
| 					$view_data['page_title'] = "QRZ ADIF Information"; | ||||
| 					$this->load->view('interface_assets/header', $view_data); | ||||
| 					$this->load->view('qrz/analysis', $view_data); // Pass $view_data containing table headers, rows, and errors
 | ||||
| 					$this->load->view('interface_assets/footer'); | ||||
| 				} else { | ||||
| 					echo $message; // Echo message when not showing views but matches were found
 | ||||
| 					// Optionally echo errors if any occurred
 | ||||
| 					if (isset($data['errors'])) { | ||||
| 						echo " Errors encountered: " . implode("; ", $data['errors']); | ||||
| 					} | ||||
| 					return ''; | ||||
| 				} | ||||
| 			} else { | ||||
| 				echo "Downloaded QRZ report contains no matches."; | ||||
| 				// No matches found in the logbook
 | ||||
| 				$message .= " No matching QSOs found in your logbook to update."; | ||||
| 				if ($show_views == TRUE) { | ||||
| 					$view_data['page_title'] = "QRZ ADIF Information"; | ||||
| 					$view_data['info_message'] = $message; // Pass the info message to the view
 | ||||
| 					// Errors are already in $view_data if they exist
 | ||||
| 					$this->load->view('interface_assets/header', $view_data); | ||||
| 					$this->load->view('qrz/analysis', $view_data); // Load view, assuming it checks for $info_message and $errors
 | ||||
| 					$this->load->view('interface_assets/footer'); | ||||
| 				} else { | ||||
| 					echo $message; // Echo message when not showing views and no matches found
 | ||||
| 					// Optionally echo errors if any occurred
 | ||||
| 					if (isset($data['errors'])) { | ||||
| 						echo " Errors encountered: " . implode("; ", $data['errors']); | ||||
| 					} | ||||
| 					return ''; | ||||
| 				} | ||||
| 			} | ||||
| 		} // End authorize check
 | ||||
| 	} | ||||
| 
 | ||||
| 	function mass_download_qsos($qrz_api_key = '', $lastqrz = '1900-01-01', $trusted = false) { | ||||
| 	function mass_download_qsos($qrz_api_key = '', $trusted = false) { // Remove $lastqrz parameter
 | ||||
| 		$config['upload_path'] = './uploads/'; | ||||
| 		$file = $config['upload_path'] . 'qrzcom_download_report.adi'; | ||||
| 		if (file_exists($file) && ! is_writable($file)) { | ||||
| 			$result = "Temporary download file ".$file." is not writable. Aborting!"; | ||||
| 			return false; | ||||
| 			// This part is fine - checks local file writability
 | ||||
| 			$error_message = "Temporary download file ".$file." is not writable. Aborting!"; | ||||
| 			// Return the structured error array here too for consistency
 | ||||
| 			return ['status' => 'error', 'message' => $error_message]; | ||||
| 		} | ||||
| 		$url = 'http://logbook.qrz.com/api';  | ||||
| 		$url = 'http://logbook.qrz.com/api'; // Correct URL
 | ||||
| 
 | ||||
| 		$post_data['KEY'] = $qrz_api_key; | ||||
| 		$post_data['ACTION'] = 'FETCH'; | ||||
| 		$post_data['OPTION'] = 'MODSINCE:'.$lastqrz.';STATUS:CONFIRMED;TYPE:ADIF'; | ||||
| 		$post_data['KEY'] = $qrz_api_key;      // Correct parameter
 | ||||
| 		$post_data['ACTION'] = 'FETCH';         // Correct parameter
 | ||||
| 		$post_data['OPTION'] = 'BAND:80m,TYPE:ADIF'; // Correct parameter for fetching all confirmed in ADIF
 | ||||
| 
 | ||||
| 		$ch = curl_init( $url ); | ||||
| 		curl_setopt( $ch, CURLOPT_POST, true); | ||||
| 		curl_setopt( $ch, CURLOPT_POSTFIELDS, $post_data); | ||||
| 		curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1); | ||||
| 		curl_setopt( $ch, CURLOPT_HEADER, 0); | ||||
| 		curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true); | ||||
| 		curl_setopt( $ch, CURLOPT_POST, true);            // Correct method
 | ||||
| 		curl_setopt( $ch, CURLOPT_POSTFIELDS, $post_data); // Correct data
 | ||||
| 		curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1);     // Okay
 | ||||
| 		curl_setopt( $ch, CURLOPT_HEADER, 0);             // Correct - don't need response headers
 | ||||
| 		curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true);  // Correct - get response as string
 | ||||
| 
 | ||||
| 		$content = htmlspecialchars_decode(curl_exec($ch)); | ||||
| 		file_put_contents($file, $content); | ||||
| 		if (strlen(file_get_contents($file, false, null, 0, 100))!=100) { | ||||
| 			$result = "QRZ downloading failed, either due to it being down or incorrect logins."; | ||||
| 			return "false"; | ||||
| 		$content = curl_exec($ch); // Get raw content
 | ||||
| 		$curl_error = curl_error($ch); // Check for cURL errors
 | ||||
| 		curl_close($ch); | ||||
| 
 | ||||
| 		// Find the start of the ADIF data after "ADIF="
 | ||||
| 		$adif_start_pos = strpos($content, 'ADIF='); | ||||
| 		if ($adif_start_pos !== false) { | ||||
| 			// Extract the content starting after "ADIF="
 | ||||
| 			$content = substr($content, $adif_start_pos + 5); | ||||
| 		} else { | ||||
| 			// If "ADIF=" is not found, check for potential errors before assuming it's just ADIF
 | ||||
| 			if (strpos($content, 'STATUS=FAIL') !== false || strpos($content, 'STATUS=AUTH') !== false) { | ||||
| 				// Handle API errors even if ADIF= is missing
 | ||||
| 				$reason = $content; | ||||
| 				if (preg_match('/REASON=([^&]+)/', $content, $matches)) { | ||||
| 					$reason = urldecode($matches[1]); // Decode URL encoded reason
 | ||||
| 				} | ||||
| 				$error_message = "QRZ API Error: " . $reason; | ||||
| 				log_message('error', $error_message . ' API Key used: ' . $qrz_api_key . ' Raw Response: ' . $content); | ||||
| 				return ['status' => 'error', 'message' => $error_message]; | ||||
| 			} | ||||
| 			// If no error status and no ADIF=, maybe it's just ADIF? Or an unknown error.
 | ||||
| 			// Log a warning if content seems unusual but doesn't match known error patterns.
 | ||||
| 			if (trim($content) === '' || strlen(trim($content)) < 10) { // Arbitrary small length check
 | ||||
| 				log_message('error', 'QRZ download: Received unexpected content without ADIF= prefix or known error status. Content: ' . $content); | ||||
| 				// Decide if this should be treated as an error or empty ADIF
 | ||||
| 				// For now, let's treat it as potentially empty/invalid ADIF and let loadFromFile handle it.
 | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// Also remove the trailing metadata like &RESULT=OK&COUNT=... or just &COUNT=...
 | ||||
| 		$result_pos = strpos($content, '&RESULT='); | ||||
| 		$count_pos = strpos($content, '&COUNT='); | ||||
| 
 | ||||
| 		$truncate_pos = false; | ||||
| 
 | ||||
| 		if ($result_pos !== false && $count_pos !== false) { | ||||
| 			// Both found, take the earlier one
 | ||||
| 			$truncate_pos = min($result_pos, $count_pos); | ||||
| 		} elseif ($result_pos !== false) { | ||||
| 			// Only RESULT found
 | ||||
| 			$truncate_pos = $result_pos; | ||||
| 		} elseif ($count_pos !== false) { | ||||
| 			// Only COUNT found
 | ||||
| 			$truncate_pos = $count_pos; | ||||
| 		} | ||||
| 
 | ||||
| 		if ($truncate_pos !== false) { | ||||
| 			$content = substr($content, 0, $truncate_pos); | ||||
| 		} | ||||
| 
 | ||||
| 		if ($curl_error) { // Check for cURL level errors first
 | ||||
| 			$error_message = "QRZ download cURL error: " . $curl_error; | ||||
| 			log_message('error', $error_message . ' API Key used: ' . $qrz_api_key); | ||||
| 			return ['status' => 'error', 'message' => $error_message]; | ||||
| 		} | ||||
| 
 | ||||
| 		if ($content === false || $content === '') { // Check if curl_exec failed or returned empty
 | ||||
| 			$error_message = "QRZ download failed: No content received from QRZ.com."; | ||||
| 			log_message('error', $error_message . ' API Key used: ' . $qrz_api_key); | ||||
| 			return ['status' => 'error', 'message' => $error_message]; | ||||
| 		} | ||||
| 
 | ||||
| 		// Check for QRZ API specific error messages
 | ||||
| 		if (strpos($content, 'STATUS=FAIL') !== false || strpos($content, 'STATUS=AUTH') !== false) { | ||||
| 			// Extract reason if possible, otherwise use full content
 | ||||
| 			$reason = $content; | ||||
| 			if (preg_match('/REASON=([^&]+)/', $content, $matches)) { | ||||
| 				$reason = urldecode($matches[1]); // Decode URL encoded reason
 | ||||
| 			} | ||||
| 			$error_message = "QRZ API Error: " . $reason; | ||||
| 			log_message('error', $error_message . ' API Key used: ' . $qrz_api_key . ' Raw Response: ' . $content); | ||||
| 			return ['status' => 'error', 'message' => $error_message]; | ||||
| 		} | ||||
| 
 | ||||
| 		$content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8'); | ||||
| 
 | ||||
| 		// Save the potentially valid content
 | ||||
| 		if (file_put_contents($file, $content) === false) { | ||||
| 			$error_message = "Failed to write downloaded QRZ data to temporary file: " . $file; | ||||
| 			log_message('error', $error_message); | ||||
| 			return ['status' => 'error', 'message' => $error_message]; | ||||
| 		} else { | ||||
| 			// echo "Downloaded QRZ data to temporary file: " . $file;
 | ||||
| 		} | ||||
| 
 | ||||
| 		// Proceed to load from the file
 | ||||
| 		ini_set('memory_limit', '-1'); | ||||
| 		$result = $this->loadFromFile($file); | ||||
| 		$result = $this->loadFromFile($file); // loadFromFile returns ['table_data' => ..., 'processed_count' => ...]
 | ||||
| 
 | ||||
| 		return $result; | ||||
| 	} | ||||
|  | @ -302,9 +450,17 @@ class Qrz extends CI_Controller { | |||
| 
 | ||||
| 		$this->load->library('adif_parser'); | ||||
| 
 | ||||
| 		$this->adif_parser->load_from_file($filepath); | ||||
| 		// Load the data from the file into the parser object
 | ||||
| 		$this->adif_parser->load_from_file($filepath); // <-- ADD THIS LINE
 | ||||
| 
 | ||||
| 		// Now initialize the parser with the loaded data
 | ||||
| 		if (!$this->adif_parser->initialize()) { // Check return value of initialize
 | ||||
| 			 // Handle initialization error (e.g., log it, return error structure)
 | ||||
| 			 log_message('error', 'ADIF Parser initialization failed for file: ' . $filepath); | ||||
| 			 // Return an error structure consistent with mass_download_qsos
 | ||||
| 			 return ['status' => 'error', 'message' => 'ADIF Parser initialization failed. Check logs.']; | ||||
| 		} | ||||
| 
 | ||||
| 		$this->adif_parser->initialize(); | ||||
| 		$tableheaders = "<table width=\"100%\">"; | ||||
| 		$tableheaders .= "<tr class=\"titles\">"; | ||||
| 		$tableheaders .= "<td>Station Callsign</td>"; | ||||
|  | @ -317,53 +473,51 @@ class Qrz extends CI_Controller { | |||
| 		$tableheaders .= "</tr>"; | ||||
| 
 | ||||
| 		$table = ""; | ||||
| 		$batch_data = []; | ||||
| 		$batch_size = 500; // Process 500 records at a time
 | ||||
| 		$record_count = 0; // Initialize record counter
 | ||||
| 		while ($record = $this->adif_parser->get_record()) { | ||||
| 			$record_count++; // Increment counter for each record read
 | ||||
| 			if ((!(isset($record['app_qrzlog_qsldate']))) || (!(isset($record['qso_date'])))) { | ||||
| 				continue; | ||||
| 			} | ||||
| 			$time_on = date('Y-m-d', strtotime($record['qso_date'])) ." ".date('H:i', strtotime($record['time_on'])); | ||||
| 
 | ||||
| 			$qsl_date = date('Y-m-d', strtotime($record['app_qrzlog_qsldate'])); | ||||
| 
 | ||||
| 			if (isset($record['time_off'])) { | ||||
| 				$time_off = date('Y-m-d', strtotime($record['qso_date'])) ." ".date('H:i', strtotime($record['time_off'])); | ||||
| 			} else { | ||||
| 				$time_off = date('Y-m-d', strtotime($record['qso_date'])) ." ".date('H:i', strtotime($record['time_on'])); | ||||
| 			} | ||||
| 
 | ||||
| 			// If we have a positive match from LoTW, record it in the DB according to the user's preferences
 | ||||
| 			if ($record['app_qrzlog_status'] == "C") { | ||||
| 				$record['qsl_rcvd'] = $config['qrz_rcvd_mark']; | ||||
| 			$qsl_rcvd = ''; // Default empty
 | ||||
| 			if (isset($record['app_qrzlog_status']) && $record['app_qrzlog_status'] == "C") { | ||||
| 				$qsl_rcvd = $config['qrz_rcvd_mark']; | ||||
| 			} | ||||
| 
 | ||||
| 			$record['call']=str_replace("_","/",$record['call']); | ||||
| 			$record['station_callsign']=str_replace("_","/",$record['station_callsign']); | ||||
| 			$status = $this->logbook_model->import_check($time_on, $record['call'], $record['band'], $record['mode'], $record['station_callsign']); | ||||
| 			$call = str_replace("_","/",$record['call']); | ||||
| 			$station_callsign = str_replace("_","/",$record['station_callsign']); | ||||
| 			$band = $record['band'] ?? ''; // Ensure band exists
 | ||||
| 			$mode = $record['mode'] ?? ''; // Ensure mode exists
 | ||||
| 
 | ||||
| 			if($status[0] == "Found") { | ||||
| 				$qrz_status = $this->logbook_model->qrz_update($time_on, $record['call'], $record['band'], $qsl_date, $record['qsl_rcvd'],$record['station_callsign']); | ||||
| 			// Add record data to batch
 | ||||
| 			$batch_data[] = [ | ||||
| 				'time_on' => $time_on, | ||||
| 				'call' => $call, | ||||
| 				'band' => $band, | ||||
| 				'mode' => $mode, | ||||
| 				'station_callsign' => $station_callsign, | ||||
| 				'qsl_date' => $qsl_date, | ||||
| 				'qsl_rcvd' => $qsl_rcvd | ||||
| 			]; | ||||
| 
 | ||||
| 				$table .= "<tr>"; | ||||
| 				$table .= "<td>".$record['station_callsign']."</td>"; | ||||
| 				$table .= "<td>".$time_on."</td>"; | ||||
| 				$table .= "<td>".$record['call']."</td>"; | ||||
| 				$table .= "<td>".$record['mode']."</td>"; | ||||
| 				$table .= "<td>".$record['qsl_rcvd']."</td>"; | ||||
| 				$table .= "<td>".$qsl_date."</td>"; | ||||
| 				$table .= "<td>QSO Record: ".$status[0]."</td>"; | ||||
| 				$table .= "</tr>"; | ||||
| 			} else { | ||||
| 				$table .= "<tr>"; | ||||
| 				$table .= "<td>".$record['station_callsign']."</td>"; | ||||
| 				$table .= "<td>".$time_on."</td>"; | ||||
| 				$table .= "<td>".$record['call']."</td>"; | ||||
| 				$table .= "<td>".$record['mode']."</td>"; | ||||
| 				$table .= "<td>".$record['qsl_rcvd']."</td>"; | ||||
| 				$table .= "<td>QSO Record: ".$status[0]."</td>"; | ||||
| 				$table .= "</tr>"; | ||||
| 			// If batch size reached, process it
 | ||||
| 			if (count($batch_data) >= $batch_size) { | ||||
| 				$table .= $this->logbook_model->process_qrz_batch($batch_data); | ||||
| 				$batch_data = []; // Reset batch
 | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// Process any remaining records in the last batch
 | ||||
| 		if (!empty($batch_data)) { | ||||
| 			$table .= $this->logbook_model->process_qrz_batch($batch_data); | ||||
| 		} | ||||
| 
 | ||||
| 		if ($table != "") { | ||||
| 			$data['tableheaders'] = $tableheaders; | ||||
| 			$data['table'] = $table; | ||||
|  | @ -372,8 +526,7 @@ class Qrz extends CI_Controller { | |||
| 		} | ||||
| 
 | ||||
| 		unlink($filepath); | ||||
| 		return $data; | ||||
| 
 | ||||
| 		// Return both table data and the count of processed records
 | ||||
| 		return ['table_data' => $data, 'processed_count' => $record_count]; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -4244,6 +4244,7 @@ class Logbook_model extends CI_Model | |||
|       # try: $a looks like a call (.\d[A-Z]) and $b doesn't (.\d), they are
 | ||||
|       # swapped. This still does not properly handle calls like DJ1YFK/KH7K where
 | ||||
|       # only the OP's experience says that it's DJ1YFK on KH7K.
 | ||||
| 
 | ||||
|       if (!$c && $a && $b) {                          # $a and $b exist, no $c
 | ||||
|         if (preg_match($lidadditions, $b)) {        # check if $b is a lid-addition
 | ||||
|           $b = $a; | ||||
|  | @ -4864,6 +4865,87 @@ class Logbook_model extends CI_Model | |||
|       return $row->oldest_qso_date; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|   * Processes a batch of QRZ ADIF records for efficient database updates. | ||||
|   * | ||||
|   * @param array $batch_data Array of records from the ADIF file. | ||||
|   * @return string HTML table rows for the processed batch. | ||||
|   */ | ||||
|   public function process_qrz_batch($batch_data) { | ||||
|     $table = ""; | ||||
|     $update_batch_data = []; | ||||
|     $this->load->model('Stations'); | ||||
| 
 | ||||
|     if (empty($batch_data)) { | ||||
|       return ''; | ||||
|     } | ||||
| 
 | ||||
|     // Step 1: Build WHERE clause for fetching potential matches
 | ||||
|     $this->db->select($this->config->item('table_name').'.COL_PRIMARY_KEY, '.$this->config->item('table_name').'.COL_CALL, '.$this->config->item('table_name').'.COL_TIME_ON, '.$this->config->item('table_name').'.COL_BAND, '.$this->config->item('table_name').'.COL_MODE, '.$this->config->item('table_name').'.COL_STATION_CALLSIGN'); | ||||
|     $this->db->from($this->config->item('table_name')); | ||||
|     $this->db->group_start(); // Start grouping OR conditions
 | ||||
|     foreach ($batch_data as $record) { | ||||
|       $this->db->or_group_start(); // Start group for this record's AND conditions
 | ||||
|       $this->db->where($this->config->item('table_name').'.COL_CALL', $record['call']); | ||||
|       $this->db->where($this->config->item('table_name').'.COL_TIME_ON', $record['time_on']); | ||||
|       $this->db->where($this->config->item('table_name').'.COL_BAND', $record['band']); | ||||
|       // Optional: Add mode check if necessary, but it might reduce matches if modes differ slightly (e.g., SSB vs USB)
 | ||||
|       // $this->db->where($this->config->item('table_name').'.COL_MODE', $record['mode']);
 | ||||
|       $this->db->where($this->config->item('table_name').'.COL_STATION_CALLSIGN', $record['station_callsign']); | ||||
|       $this->db->group_end(); // End group for this record's AND conditions
 | ||||
|     } | ||||
|     $this->db->group_end(); // End grouping OR conditions
 | ||||
| 
 | ||||
|     // Step 2: Fetch Matches
 | ||||
|     $query = $this->db->get(); | ||||
|     $db_results = $query->result_array(); | ||||
| 
 | ||||
|     // Index DB results for faster lookup
 | ||||
|     $indexed_results = []; | ||||
|     foreach ($db_results as $row) { | ||||
|       $key = $row['COL_CALL'] . '|' . $row['COL_TIME_ON'] . '|' . $row['COL_BAND'] . '|' . $row['COL_STATION_CALLSIGN']; | ||||
|       $indexed_results[$key] = $row['COL_PRIMARY_KEY']; | ||||
|     } | ||||
| 
 | ||||
|     // Step 3 & 4: Prepare Batch Update and Build Table Rows
 | ||||
|     foreach ($batch_data as $record) { | ||||
|       $match_key = $record['call'] . '|' . $record['time_on'] . '|' . $record['band'] . '|' . $record['station_callsign']; | ||||
|       $log_status = '<span class="badge text-bg-danger">Not Found</span>'; | ||||
|       $primary_key = null; | ||||
| 
 | ||||
|       if (isset($indexed_results[$match_key])) { | ||||
|         $primary_key = $indexed_results[$match_key]; | ||||
|         $log_status = '<span class="badge text-bg-success">Confirmed</span>'; | ||||
| 
 | ||||
|         // Prepare data for batch update
 | ||||
|         $update_batch_data[] = [ | ||||
|           'COL_PRIMARY_KEY' => $primary_key, | ||||
|           'COL_QRZCOM_QSO_DOWNLOAD_DATE' => $record['qsl_date'], | ||||
|           'COL_QRZCOM_QSO_UPLOAD_STATUS' => $record['qsl_rcvd'] // Should be 'Y' if confirmed
 | ||||
|         ]; | ||||
|       } | ||||
| 
 | ||||
|       // Build table row
 | ||||
|       $table .= "<tr>"; | ||||
|       $table .= "<td>" . $record['station_callsign'] . "</td>"; | ||||
|       $table .= "<td>" . $record['time_on'] . "</td>"; | ||||
|       $table .= "<td>" . $record['call'] . "</td>"; | ||||
|       $table .= "<td>" . $record['mode'] . "</td>"; | ||||
|       $table .= "<td>" . $record['qsl_date'] . "</td>"; | ||||
|       $table .= "<td>" . ($record['qsl_rcvd'] == 'Y' ? '<span class="badge text-bg-success">Yes</span>' : '<span class="badge text-bg-danger">No</span>') . "</td>"; | ||||
|       $table .= "<td>" . $log_status . "</td>"; | ||||
|       $table .= "</tr>"; | ||||
|     } | ||||
| 
 | ||||
|     // Step 5: Execute Batch Update
 | ||||
|     if (!empty($update_batch_data)) { | ||||
|       $this->db->update_batch($this->config->item('table_name'), $update_batch_data, 'COL_PRIMARY_KEY'); | ||||
|     } | ||||
| 
 | ||||
|     // Step 6: Return Table HTML
 | ||||
|     return $table; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function validateADIFDate($date, $format = 'Ymd') | ||||
|  |  | |||
		正在加载…
	
		在新工单中引用