From 29e46fae600cac931e76e43be8da18febbdbdfc7 Mon Sep 17 00:00:00 2001 From: Andreas Kristiansen <6977712+AndreasK79@users.noreply.github.com> Date: Tue, 20 Jan 2026 17:21:56 +0100 Subject: [PATCH] [DXCC Class] Added logging --- src/Dxcc/Dxcc.php | 228 ++++++++++++++++++++++++++++------------------ 1 file changed, 140 insertions(+), 88 deletions(-) diff --git a/src/Dxcc/Dxcc.php b/src/Dxcc/Dxcc.php index 8b0c616b8..779b49f4d 100644 --- a/src/Dxcc/Dxcc.php +++ b/src/Dxcc/Dxcc.php @@ -6,16 +6,22 @@ class Dxcc { protected $dxcc = array(); protected $dxccexceptions = array(); - function __construct($date) - { + protected $csadditions = '/^X$|^D$|^T$|^P$|^R$|^B$|^A$|^M$|^LH$|^L$|^J$|^SK$/'; + protected $lidadditions = '/^QRP$|^LGT$/'; + protected $noneadditions = '/^MM$|^AM$/'; + + function __construct($date) { $this->read_data($date); } + /** + * Helper method to log DXCC-related errors + */ + private function logError($message, $context = []) { + log_message("Error", "DXCC Error: " . $message . (empty($context) ? '' : ' - Context: ' . json_encode($context))); + } + public function dxcc_lookup($call, $date) { - - $csadditions = '/^X$|^D$|^T$|^P$|^R$|^B$|^A$|^M$|^LH$|^L$|^J$|^SK$/'; - $CI =& get_instance(); - if (array_key_exists($call, $this->dxccexceptions)) { $exceptions = $this->dxccexceptions[$call]; @@ -35,81 +41,89 @@ class Dxcc { } } - if (preg_match('/(^KG4)[A-Z09]{3}/', $call)) { // KG4/ and KG4 5 char calls are Guantanamo Bay. If 4 or 6 char, it is USA - $call = "K"; - } elseif (preg_match('/(^OH\/)|(\/OH[1-9]?$)/', $call)) { # non-Aland prefix! - $call = "OH"; # make callsign OH = finland - } elseif (preg_match('/(^CX\/)|(\/CX[1-9]?$)/', $call)) { # non-Antarctica prefix! - $call = "CX"; # make callsign CX = Uruguay - } elseif (preg_match('/(^3D2R)|(^3D2.+\/R)/', $call)) { # seems to be from Rotuma - $call = "3D2/R"; # will match with Rotuma - } elseif (preg_match('/^3D2C/', $call)) { # seems to be from Conway Reef - $call = "3D2/C"; # will match with Conway - } elseif (preg_match('/(^LZ\/)|(\/LZ[1-9]?$)/', $call)) { # LZ/ is LZ0 by DXCC but this is VP8h - $call = "LZ"; - } elseif (preg_match('/(^KG4)[A-Z09]{2}/', $call)) { - $call = "KG4"; - } elseif (preg_match('/(^KG4)[A-Z09]{1}/', $call)) { - $call = "K"; - } elseif (preg_match('/\w\/\w/', $call)) { - if (preg_match_all('/^((\d|[A-Z])+\/)?((\d|[A-Z]){3,})(\/(\d|[A-Z])+)?(\/(\d|[A-Z])+)?$/', $call, $matches)) { - $prefix = $matches[1][0]; - $callsign = $matches[3][0]; - $suffix = $matches[5][0]; + if (preg_match('/(^KG4)[A-Z09]{3}/', $call)) { // KG4/ and KG4 5 char calls are Guantanamo Bay. If 4 or 6 char, it is USA + $call = "K"; + } elseif (preg_match('/(^OH\/)|(\/OH[1-9]?$)/', $call)) { # non-Aland prefix! + $call = "OH"; # make callsign OH = finland + } elseif (preg_match('/(^CX\/)|(\/CX[1-9]?$)/', $call)) { # non-Antarctica prefix! + $call = "CX"; # make callsign CX = Uruguay + } elseif (preg_match('/(^3D2R)|(^3D2.+\/R)/', $call)) { # seems to be from Rotuma + $call = "3D2/R"; # will match with Rotuma + } elseif (preg_match('/^3D2C/', $call)) { # seems to be from Conway Reef + $call = "3D2/C"; # will match with Conway + } elseif (preg_match('/(^LZ\/)|(\/LZ[1-9]?$)/', $call)) { # LZ/ is LZ0 by DXCC but this is VP8h + $call = "LZ"; + } elseif (preg_match('/(^KG4)[A-Z09]{2}/', $call)) { + $call = "KG4"; + } elseif (preg_match('/(^KG4)[A-Z09]{1}/', $call)) { + $call = "K"; + } elseif (preg_match('/\w\/\w/', $call)) { + if (preg_match_all('/^((\d|[A-Z])+\/)?((\d|[A-Z]){3,})(\/(\d|[A-Z])+)?(\/(\d|[A-Z])+)?$/', $call, $matches)) { + $prefix = $matches[1][0]; + $callsign = $matches[3][0]; + $suffix = $matches[5][0]; + + if (!$callsign) { + $this->logError('Failed to parse callsign', [ + 'call' => $call, + 'date' => $date, + 'matches' => $matches + ]); + } + if ($prefix) { + $prefix = substr($prefix, 0, -1); # Remove the / at the end + } + if ($suffix) { + $suffix = substr($suffix, 1); # Remove the / at the beginning + }; + if (preg_match($this->csadditions, $suffix)) { if ($prefix) { - $prefix = substr($prefix, 0, -1); # Remove the / at the end - } - if ($suffix) { - $suffix = substr($suffix, 1); # Remove the / at the beginning - }; - if (preg_match($csadditions, $suffix)) { - if ($prefix) { - $call = $prefix; - } else { - $call = $callsign; - } + $call = $prefix; } else { - $result = $this->wpx($call, 1); # use the wpx prefix instead - if ($result == '') { - $row['adif'] = 0; - $row['entity'] = '- NONE -'; - $row['cqz'] = 0; - $row['long'] = '0'; - $row['lat'] = '0'; - return $row; - } else { - $call = $result . "AA"; - } + $call = $callsign; + } + } else { + $result = $this->wpx($call, 1); # use the wpx prefix instead + if ($result == '') { + $row['adif'] = 0; + $row['entity'] = '- NONE -'; + $row['cqz'] = 0; + $row['long'] = '0'; + $row['lat'] = '0'; + return $row; + } else { + $call = $result . "AA"; } } } + } - $len = strlen($call); + $len = strlen($call); - // query the table, removing a character from the right until a match - for ($i = $len; $i > 0; $i--){ - $result = ''; + // query the table, removing a character from the right until a match + for ($i = $len; $i > 0; $i--){ + $result = ''; - if (array_key_exists(substr($call, 0, $i), $this->dxcc)) { - $arraykey = substr($call, 0, $i); - $dxccEntries = $this->dxcc[substr($call, 0, $i)]; + if (array_key_exists(substr($call, 0, $i), $this->dxcc)) { + $arraykey = substr($call, 0, $i); + $dxccEntries = $this->dxcc[substr($call, 0, $i)]; - // Loop through all entries for this call prefix - foreach ($dxccEntries as $dxccEntry) { - $startDate = !empty($dxccEntry['start']) ? $dxccEntry['start'] : null; - $endDate = !empty($dxccEntry['end']) ? $dxccEntry['end'] : null; + // Loop through all entries for this call prefix + foreach ($dxccEntries as $dxccEntry) { + $startDate = !empty($dxccEntry['start']) ? $dxccEntry['start'] : null; + $endDate = !empty($dxccEntry['end']) ? $dxccEntry['end'] : null; - if ($startDate == null && $endDate == null) - return $dxccEntry; - if ($date <= $endDate && $date >= $startDate) - return $dxccEntry; - if ($endDate == null && $date >= $startDate) - return $dxccEntry; - if ($date <= $endDate && $startDate == null) - return $dxccEntry; - } + if ($startDate == null && $endDate == null) + return $dxccEntry; + if ($date <= $endDate && $date >= $startDate) + return $dxccEntry; + if ($endDate == null && $date >= $startDate) + return $dxccEntry; + if ($date <= $endDate && $startDate == null) + return $dxccEntry; } } + } return array("Not Found", "Not Found"); } @@ -120,10 +134,6 @@ class Dxcc { $b = ''; $c = ''; - $lidadditions = '/^QRP$|^LGT$/'; - $csadditions = '/^X$|^D$|^T$|^P$|^R$|^B$|^A$|^M$|^LH$|^L$|^J$|^SK$/'; - $noneadditions = '/^MM$|^AM$/'; - # First check if the call is in the proper format, A/B/C where A and C # are optional (prefix of guest country and P, MM, AM etc) and B is the # callsign. Only letters, figures and "/" is accepted, no further check if the @@ -157,7 +167,7 @@ class Dxcc { # 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 + if (preg_match($this->lidadditions, $b) || preg_match('/^[0-9]+$/', $b)) { # check if $b is a lid-addition $b = $a; $a = null; # $a goes to $b, delete lid-add } elseif ((preg_match('/\d[A-Z]+$/', $a)) && (preg_match('/\d$/', $b) || preg_match('/^[A-Z]\d[A-Z]$/', $b))) { # check for call in $a @@ -189,7 +199,13 @@ class Dxcc { if (($a == null) && ($c == null)) { # Case 1 if (preg_match('/\d/', $b)) { # Case 1.1, contains number - preg_match('/(.+\d)[A-Z]*/', $b, $matches); # Prefix is all but the last + if (!preg_match('/(.+\d)[A-Z]*/', $b, $matches)) { + $this->logError('preg_match failed to extract prefix from callsign', [ + 'testcall' => $testcall, + 'b' => $b + ]); + return ''; + } $prefix = $matches[1]; # Letters } else { # Case 1.2, no number $prefix = substr($b, 0, 2) . "0"; # first two + 0 @@ -204,19 +220,50 @@ class Dxcc { # think that's rather irrelevant cos such calls rarely appear # and if they do, it's very unlikely for them to have a number # attached. You can still edit it by hand anyway.. + if (!isset($matches[1]) || $matches[1] === null) { + $this->logError('preg_match failed to capture prefix in $b', [ + 'testcall' => $testcall, + 'b' => $b, + 'c' => $c, + 'matches' => $matches + ]); + return ''; + } if (preg_match('/^([A-Z]\d)\d$/', $matches[1])) { # e.g. A45 $c = 0 $prefix = $matches[1] . $c; # -> A40 } else { # Otherwise cut all numbers - preg_match('/(.*[A-Z])\d+/', $matches[1], $match); # Prefix w/o number in $1 + if (!preg_match('/(.*[A-Z])\d+/', $matches[1], $match)) { + $this->logError('preg_match failed to extract prefix without number', [ + 'testcall' => $testcall, + 'matches1' => $matches[1], + 'b' => $b, + 'c' => $c + ]); + return ''; + } $prefix = $match[1] . $c; # Add attached number } - } elseif (preg_match($csadditions, $c)) { - preg_match('/(.+\d)[A-Z]*/', $b, $matches); # Known attachment -> like Case 1.1 + } elseif (preg_match($this->csadditions, $c)) { + if (!preg_match('/(.+\d)[A-Z]*/', $b, $matches)) { + $this->logError('preg_match failed for csadditions case', [ + 'testcall' => $testcall, + 'b' => $b, + 'c' => $c + ]); + return ''; + } $prefix = $matches[1]; - } elseif (preg_match($noneadditions, $c)) { + } elseif (preg_match($this->noneadditions, $c)) { return ''; } elseif (preg_match('/^\d\d+$/', $c)) { # more than 2 numbers -> ignore - preg_match('/(.+\d)[A-Z]* /', $b, $matches); # see above + if (!preg_match('/(.+\d)[A-Z]* /', $b, $matches)) { + $this->logError('preg_match failed for multi-digit case', [ + 'testcall' => $testcall, + 'b' => $b, + 'c' => $c + ]); + return ''; + } $prefix = $matches[1][0]; } else { # Must be a Prefix! if (preg_match('/\d$/', $c)) { # ends in number -> good prefix @@ -225,8 +272,8 @@ class Dxcc { $prefix = $c . "0"; } } - } elseif (($a) && (preg_match($noneadditions, $c))) { # Case 2.1, X/CALL/X ie TF/DL2NWK/MM - DXCC none - return ''; + } elseif (($a) && (preg_match($this->noneadditions, $c))) { # Case 2.1, X/CALL/X ie TF/DL2NWK/MM - DXCC none + return ''; } elseif ($a) { # $a contains the prefix we want if (preg_match('/\d$/', $a)) { # ends in number -> good prefix @@ -242,7 +289,15 @@ class Dxcc { # extra parameter $_[1]; this will happen when invoking it from &dxcc. if (preg_match('/(\w+\d)[A-Z]+\d/', $prefix, $matches) && $i == null) { - $prefix = $matches[1][0]; + if (!isset($matches[1][0])) { + $this->logError('preg_match failed to extract prefix in rare case', [ + 'testcall' => $testcall, + 'prefix' => $prefix, + 'matches' => $matches + ]); + } else { + $prefix = $matches[1][0]; + } } return $prefix; } else { @@ -250,11 +305,11 @@ class Dxcc { } } - /* + /* * Read cty.dat from AD1C */ function read_data($date = null) { - $CI =& get_instance(); + $CI = &get_instance(); if ($date == null) { $dxcc_exceptions = $CI->db->select('entity, adif, cqz, start, end, call, cont, long, lat') @@ -307,7 +362,6 @@ class Dxcc { ->get('dxcc_prefixes'); } - if ($dxcc_result->num_rows() > 0){ foreach ($dxcc_result->result() as $dx) { $this->dxcc[$dx->call][] = [ @@ -322,7 +376,5 @@ class Dxcc { ]; } } - } - }