### CODE GATHERER OUTPUT ### # generated: Fri Nov 7 12:54:59 PM EST 2025 # directory: uac_system ===== DIRECTORY STRUCTURE ===== collect_cms_alarms.php networkList1.txt cms_session.php global.xml collect_smx_alarms.php collect_alarms_unified.php gathered_code_compendium.txt ===== BEGIN FILE CONTENTS ===== ---------------------------------------- File: /root/uac_system/collect_cms_alarms.php Modified: 2025-10-30 22:22:34.354624761 -0400 ---------------------------------------- #!/usr/bin/env php $_){ if($k!==$i++) return false; } return true; } } function now(): string { return date('Y-m-d H:i:s'); } function j(array $m): string { return json_encode($m, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE); } function loge(string $msg, array $ctx=[]): void { fwrite(STDERR, j(['ts'=>now(),'lvl'=>'ERROR','msg'=>$msg]+$ctx).PHP_EOL); } function logw(string $msg, array $ctx=[]): void { fwrite(STDERR, j(['ts'=>now(),'lvl'=>'WARN','msg'=>$msg]+$ctx).PHP_EOL); } /* ---------- networks ---------- */ if (!is_file($NETS)) { loge('network list not found',['path'=>$NETS]); echo json_encode(['data'=>[],'summary'=>['networks'=>0,'alarms_total'=>0]], JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE|($PRETTY?JSON_PRETTY_PRINT:0)).PHP_EOL; exit(2); } $nets=[]; foreach (file($NETS, FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES) as $ln) { $ln=trim($ln); if ($ln==='' || $ln[0]==='#') continue; $nets[]=$ln; } $nets = array_values(array_unique($nets)); if ($ONLY!=='') { $nets = array_values(array_filter($nets, fn($n)=>$n===$ONLY)); } if (!$nets) { echo json_encode(['data'=>[],'summary'=>['networks'=>0,'alarms_total'=>0]], JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE|($PRETTY?JSON_PRETTY_PRINT:0)).PHP_EOL; exit(0); } /* ---------- include persistent CMS session ---------- */ require __DIR__ . '/cms_session.php'; // exposes $sessionid and $session_status if ($DEBUG) fwrite(STDERR, "CMS Session Status: {$session_status}, Session ID: {$sessionid}\n"); $jsess = $COOKIE !== '' ? $COOKIE : '0C76878D1FB75F52F65346AFF7BFDD45'; /* ---------- SOAP ---------- */ function soapBody(string $network, string $sessionid, ?string $cursorOnt=null): string { $cursor = $cursorOnt ? 'Ont'.htmlspecialchars($cursorOnt,ENT_QUOTES|ENT_SUBSTITUTE,'UTF-8').'' : ''; return << show-alarms {$cursor} XML; } function cmsPost(string $url, string $jsession, string $body, bool $debug=false): string { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER=>true, CURLOPT_POST=>true, CURLOPT_POSTFIELDS=>$body, CURLOPT_HTTPHEADER=>[ 'Content-Type: text/soap+xml; charset=utf-8', 'User-Agent: perl-test-script', 'Cookie: JSESSIONID='.$jsession, ], CURLOPT_TIMEOUT=>45, ]); $resp = curl_exec($ch); $err = curl_error($ch); $code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE); curl_close($ch); if ($resp===false) throw new RuntimeException("curl: $err"); if ($code>=400) throw new RuntimeException("http $code"); if ($debug && stripos($resp,'substr($resp,0,300)]); } return $resp; } /* ---------- XML -> array ---------- */ function nodeToArray(DOMNode $node): mixed { if (!$node->hasChildNodes()) return null; $hasElementChild=false; foreach ($node->childNodes as $c){ if($c instanceof DOMElement){$hasElementChild=true;break;}} if (!$hasElementChild) return trim($node->textContent); $out=[]; foreach ($node->childNodes as $child) { if (!($child instanceof DOMElement)) continue; $key=$child->localName; $val=nodeToArray($child); if (array_key_exists($key,$out)) { if (!is_array($out[$key]) || array_is_list($out[$key])===false) $out[$key]=[$out[$key]]; $out[$key][]=$val; } else { $out[$key]=$val; } } if ($node->attributes && $node->attributes->length>0) { $attrs=[]; foreach ($node->attributes as $attr){ $attrs[$attr->localName]=$attr->value; } $out['@attrs']=$attrs; } return $out; } /* ---------- occur-time normalization ---------- */ function normalizeOccurTimes(mixed &$v): void { if (!is_array($v)) return; if (!array_is_list($v)) { if (isset($v['occur-time']) && is_scalar($v['occur-time'])) { $secRaw=(string)$v['occur-time']; $sec=ctype_digit($secRaw)?(int)$secRaw:(int)preg_replace('/\D+/','',$secRaw); try { $dt=(new DateTimeImmutable('@'.$sec))->setTimezone(new DateTimeZone(date_default_timezone_get())); $v['occur-time-string']=$dt->format('Y/m/d H:i:s'); } catch(Throwable $e){} } } foreach ($v as &$vv) if (is_array($vv)) normalizeOccurTimes($vv); } /* ---------- parse alarms ---------- */ function parseFullAlarms(string $xml, bool $includeRaw): array { $out=[]; libxml_use_internal_errors(true); $doc=new DOMDocument(); if(!$doc->loadXML($xml)) return $out; $xp=new DOMXPath($doc); $alarms=$xp->query('//*[local-name()="alarm"]'); if(!$alarms) return $out; foreach($alarms as $a){ $row=nodeToArray($a); normalizeOccurTimes($row); if($includeRaw) $row['_raw_xml']=trim($doc->saveXML($a)); $out[]=$row; } return $out; } /* ---------- pagination cursor ---------- */ function paginationCursor(string $xml): ?string { libxml_use_internal_errors(true); $doc=new DOMDocument(); if(!$doc->loadXML($xml)) return null; $xp=new DOMXPath($doc); $n=$xp->query('(//*[local-name()="alarm"])[last()]//*[local-name()="ont"]'); return $n && $n->length ? trim($n->item(0)->textContent) : null; } /* ---------- Postgres Connection ---------- */ $pg_conn = pg_connect('host=192.168.10.1 port=5432 dbname=postgres user=cmsuser password=cmsuser'); if (!$pg_conn) { fwrite(STDERR, "Could not connect to Postgres!\n"); exit(3); } pg_prepare($pg_conn, "mini_lookup", "SELECT subscr_id, node_straid, pon_descr, model, serno, mfg_serno FROM subscriber_mini_view WHERE node_straid=$1 LIMIT 1"); /* ---------- GIS SQL Server Connection ---------- */ $gis_server = "192.168.6.6"; $gis_conn = sqlsrv_connect($gis_server, [ "Database" => "gs18526_master", "Uid" => "c2kc", "PWD" => "9Z1pp3r!" ]); if (!$gis_conn) { fwrite(STDERR, "Warning: Could not connect to GIS SQL Server\n"); } // $gis_query = "SELECT TOP 1 latitude, longitude, gs_ivue_map_coordinate_1 FROM [dbo].[GS_SUBSCRIBER] WHERE Material_Co LIKE ?"; $gis_query = " SELECT TOP 1 latitude, longitude, gs_ivue_map_coordinate_1 FROM [dbo].[GS_SUBSCRIBER] WHERE LOWER(RTRIM(LTRIM(gs_type))) LIKE ? "; /* ---------- fetch alarms ---------- */ function fetchAllForNetwork(string $url, string $jsess, string $sessionid, string $network, bool $debug, bool $includeRaw): array { $all=[]; $seen=[]; $cursor=null; do { $body=soapBody($network,$sessionid,$cursor); $xml=cmsPost($url,$jsess,$body,$debug); if(stripos($xml,'error')!==false || stripos($xml,'Session does not exist')!==false) break; $rows=parseFullAlarms($xml,$includeRaw); foreach($rows as $r){ $h=sha1(json_encode($r)); if(!isset($seen[$h])){$seen[$h]=1; $all[]=$r;} } $next=paginationCursor($xml); $cursor=$next!==$cursor?$next:null; usleep(150000); } while($cursor!==null); return $all; } /* ---------- main run ---------- */ $data=[]; $summary=['networks'=>count($nets),'alarms_total'=>0,'by_network'=>[]]; foreach($nets as $n){ try { $alarms=fetchAllForNetwork($CMSURL,$jsess,$sessionid,$n,$DEBUG,$RAW); foreach($alarms as &$a){ $ont=$a['object']['id']['ont']??null; $ids=$a['sec-object']['id']??[]; if(isset($ids['shelf'],$ids['card'],$ids['gponport']) && $ont){ $json_node_straid=$n.'-'.$ids['shelf'].'-'.$ids['card'].'-'.$ids['gponport'].'-'.$ont; $res=pg_execute($pg_conn,"mini_lookup",[$json_node_straid]); if($res && pg_num_rows($res)>0){ $row=pg_fetch_assoc($res); foreach(['subscr_id','node_straid','pon_descr','model','serno','mfg_serno'] as $k) $a[$k]=$row[$k]??null; } else { foreach(['subscr_id','node_straid','pon_descr','model','serno','mfg_serno'] as $k) $a[$k]=null; } $a['json_node_straid']=$json_node_straid; // GIS lookup using serno -> Material_Co $serno = $a['serno'] ?? null; if ($serno && $gis_conn) { // $stmt = sqlsrv_query($gis_conn, $gis_query, [$serno]); $param = ['%' . strtolower($serno) . '%']; $stmt = sqlsrv_query($gis_conn, $gis_query, $param); if ($stmt && sqlsrv_has_rows($stmt)) { $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); $a['latitude'] = $row['latitude'] ?? null; $a['longitude'] = $row['longitude'] ?? null; $a['ivue_address'] = $row['gs_ivue_map_coordinate_1'] ?? null; } else { $a['latitude'] = $a['longitude'] = $a['ivue_address'] = null; } if ($stmt) sqlsrv_free_stmt($stmt); } else { $a['latitude'] = $a['longitude'] = $a['ivue_address'] = null; } } else { $a['json_node_straid']=null; } } unset($a); $data[]=['network'=>$n,'count'=>count($alarms),'alarms'=>$alarms]; $summary['alarms_total']+=count($alarms); } catch(Throwable $e){ loge('fetch_failed',['network'=>$n,'err'=>$e->getMessage()]); $data[]=['network'=>$n,'error'=>$e->getMessage(),'count'=>0,'alarms'=>[]]; } } if ($gis_conn) sqlsrv_close($gis_conn); /* ---------- output ---------- */ $flags=JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE; if($PRETTY)$flags|=JSON_PRETTY_PRINT; echo json_encode(['data'=>$data,'summary'=>$summary],$flags),PHP_EOL; /* ---------- MySQL insert + concurrency patch ---------- */ $mysql = new mysqli('127.0.0.1', 'c2kc', 'P@ssw0rd3211', 'minocDB'); if ($mysql->connect_errno) { fwrite(STDERR, "MySQL connection failed: " . $mysql->connect_error . "\n"); exit(4); } $mysql->set_charset('utf8mb4'); $mysql->autocommit(true); $mysql->options(MYSQLI_OPT_CONNECT_TIMEOUT,5); $mysql->options(MYSQLI_OPT_READ_TIMEOUT,30); foreach ($data as $net) { $network = $net['network'] ?? null; if (!$network) continue; $startNet = microtime(true); fwrite(STDERR, "[".now()."] Begin MySQL update for {$network}\n"); $stmt = $mysql->prepare("DELETE QUICK FROM standing_alarms WHERE network=?"); $stmt->bind_param('s', $network); $stmt->execute(); $deleted = $stmt->affected_rows; $stmt->close(); fwrite(STDERR, " Deleted {$deleted} old rows for {$network}\n"); $alarms = $net['alarms'] ?? []; if (empty($alarms)) { fwrite(STDERR, " No new alarms for {$network}\n"); continue; } $ins = $mysql->prepare(" INSERT INTO standing_alarms (network, alarm_type, occur_time, subscr_id, node_straid, pon_descr, model, serno, mfg_serno, latitude, longitude, ivue_address) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "); if(!$ins){ fwrite(STDERR, " Prepare failed for {$network}: ".$mysql->error."\n"); continue; } $inserted = 0; foreach ($alarms as $a) { $alarmType = $a['alarm-type'] ?? ($a['alarmId'] ?? 'unknown'); $occur = $a['occur-time-string'] ?? null; $subscr_id = $a['subscr_id'] ?? null; $node_straid = $a['node_straid'] ?? null; $pon_descr = $a['pon_descr'] ?? null; $model = $a['model'] ?? null; $serno = $a['serno'] ?? null; $mfg_serno = $a['mfg_serno'] ?? null; $latitude = $a['latitude'] ?? null; $longitude = $a['longitude'] ?? null; $ivue_addr = $a['ivue_address'] ?? null; if(!$ins->bind_param('ssssssssssss', $network,$alarmType,$occur,$subscr_id,$node_straid,$pon_descr,$model,$serno,$mfg_serno,$latitude,$longitude,$ivue_addr)){ fwrite(STDERR," Bind failed for {$network}: ".$ins->error."\n"); continue; } if(!$ins->execute()){ fwrite(STDERR," Insert failed for {$network}: ".$ins->error."\n"); continue; } $inserted++; } $ins->close(); $elapsed = number_format(microtime(true) - $startNet, 3); fwrite(STDERR, " Inserted {$inserted} new rows for {$network} in {$elapsed}s\n"); unset($stmt, $ins); gc_collect_cycles(); } $mysql->close(); unset($mysql); gc_collect_cycles(); /* ---------- Runtime Summary ---------- */ $endTime = microtime(true); $duration = number_format($endTime - $startTime, 3); fwrite(STDERR, "Execution time: {$duration} seconds\n"); exit(0); ---------------------------------------- File: /root/uac_system/cms_session.php Modified: 2025-10-30 22:17:21.381579387 -0400 ---------------------------------------- '127.0.0.1', 'user' => 'c2kc', 'pass' => 'P@ssw0rd3211', 'name' => 'minocDB' ]; $cms = [ 'url' => 'http://192.168.10.1:18080/cmsexc/ex/netconf', 'user' => 'alarmUser', 'password' => '9Z1pp3r!' ]; /* ---------- DB CONNECT ---------- */ $con = new mysqli($db['host'], $db['user'], $db['pass'], $db['name']); if ($con->connect_errno) { die('DB connection failed: '.$con->connect_error); } /* ---------- GET CURRENT SESSION ---------- */ $res = $con->query("SELECT sessionid FROM cms_session_store WHERE id=1 LIMIT 1"); $row = $res?->fetch_assoc(); $sessionid = trim($row['sessionid'] ?? ''); /* ---------- HELPER: POST SOAP ---------- */ function cms_post(string $url, string $xml): string { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $xml, CURLOPT_HTTPHEADER => ['Content-Type: text/soap+xml; charset=utf-8'], CURLOPT_TIMEOUT => 10 ]); $resp = curl_exec($ch); curl_close($ch); return $resp ?: ''; } /* ---------- CHECK SESSION VALIDITY ---------- */ $dummyXml = << Ont1model XML; $response = cms_post($cms['url'], $dummyXml); $is_bad = ( stripos($response, 'error') !== false || stripos($response, 'Session does not exist') !== false || $sessionid === '' ); /* ---------- RELOGIN IF NEEDED ---------- */ if ($is_bad) { $loginXml = << {$cms['user']} {$cms['password']} XML; $loginResp = cms_post($cms['url'], $loginXml); if (preg_match('/([^<]+)<\/SessionId>/', $loginResp, $m)) { $sessionid = trim($m[1]); $con->query("UPDATE cms_session_store SET sessionid='".$con->real_escape_string($sessionid)."', status='renewed', note='auto relogin success' WHERE id=1"); $session_status = 'renewed'; } else { $session_status = 'login_failed'; $con->query("UPDATE cms_session_store SET status='login_failed', note='login failed to obtain new session' WHERE id=1"); } } else { $session_status = 'alive'; $con->query("UPDATE cms_session_store SET status='alive', note='session verified ok' WHERE id=1"); } /* ---------- CLEANUP ---------- */ $con->close(); /* ---------- EXPORT VARIABLES ---------- */ $GLOBALS['sessionid'] = $sessionid; $GLOBALS['session_status'] = $session_status; // echo $sessionid; ?> ---------------------------------------- File: /root/uac_system/config/global.xml Modified: 2025-10-30 22:20:40.394244093 -0400 ---------------------------------------- America/Indiana/Vincennes ---------------------------------------- File: /root/uac_system/collect_smx_alarms.php Modified: 2025-10-31 01:12:40.969848612 -0400 ---------------------------------------- #!/usr/bin/env php attributes() as $k=>$v){$o[$k]=(string)$v;} return $o; } $cfg = [ 'tz' => (string)$xml->timezone, 'mysql' => xmlAttrs($xml->mysql), 'gis' => xmlAttrs($xml->gis), 'mongo' => xmlAttrs($xml->mongo) ]; date_default_timezone_set($cfg['tz']); mb_internal_encoding('UTF-8'); /* ---------- LOGGING ---------- */ function now(): string { return date('Y-m-d H:i:s'); } function j(array $m): string { return json_encode($m, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE); } function loge(string $m, array $c=[]): void { fwrite(STDERR, j(['ts'=>now(),'lvl'=>'ERROR','msg'=>$m]+$c).PHP_EOL); } function logi(string $m, array $c=[]): void { fwrite(STDERR, j(['ts'=>now(),'lvl'=>'INFO','msg'=>$m]+$c).PHP_EOL); } /* ---------- CONNECT ---------- */ $mysql = new mysqli($cfg['mysql']['host'], $cfg['mysql']['user'], $cfg['mysql']['pass'], $cfg['mysql']['db']); if ($mysql->connect_errno) { loge('MySQL connection failed',['err'=>$mysql->connect_error]); exit(2); } $mysql->set_charset('utf8mb4'); $mysql->autocommit(true); $gis_conn = sqlsrv_connect($cfg['gis']['server'], [ 'Database'=>$cfg['gis']['database'], 'Uid'=>$cfg['gis']['user'], 'PWD'=>$cfg['gis']['pass'] ]); if (!$gis_conn) loge('Could not connect to GIS SQL Server'); /* ---------- HELPERS ---------- */ function convertMongoDate($obj): ?string { $a = json_decode(json_encode($obj), true); if (isset($a['$date']['$numberLong'])) return date('Y/m/d H:i:s', (int)($a['$date']['$numberLong']/1000)); if (isset($a['$numberLong'])) return date('Y/m/d H:i:s', (int)($a['$numberLong']/1000)); return null; } function extractSerial(string $s): ?string { return preg_match('/SerialNo=([A-Za-z0-9]+)/', $s, $m) ? $m[1] : null; } function gisLookup($conn, ?string $serial): array { if(!$conn || !$serial) return [null,null,null]; $param=['%'.strtolower($serial).'%']; $sql="SELECT TOP 1 latitude,longitude,gs_ivue_map_coordinate_1 FROM [dbo].[GS_SUBSCRIBER] WHERE LOWER(RTRIM(LTRIM(gs_type))) LIKE ?"; $stmt=sqlsrv_query($conn,$sql,$param); if($stmt && sqlsrv_has_rows($stmt)){ $r=sqlsrv_fetch_array($stmt,SQLSRV_FETCH_ASSOC); return [$r['latitude']??null,$r['longitude']??null,$r['gs_ivue_map_coordinate_1']??null]; } if($stmt)sqlsrv_free_stmt($stmt); return [null,null,null]; } /* ---------- NODE STRAID BUILDER ---------- */ function buildNodeStraid(array $subDoc, string $device): string { $linked = str_replace('/', '-', $subDoc['LinkedPon'] ?? ''); $ont = $subDoc['OntId'] ?? ''; if ($device && $linked && $ont) return "{$device}-{$linked}-{$ont}"; return $device ?: 'UNKNOWN'; } /* ---------- MONGO ---------- */ $mgr = new MongoDB\Driver\Manager($cfg['mongo']['uri']); $cursor = $mgr->executeQuery($cfg['mongo']['alarms'], new MongoDB\Driver\Query([])); $docs = iterator_to_array($cursor, false); $data = []; foreach ($docs as $d) { $a = (array)$d; $device = $a['Device Name'] ?? 'UNKNOWN'; $atype = $a['Alarm Name'] ?? 'unknown'; $occur = convertMongoDate($a['EMS Time'] ?? null); $serno = extractSerial($a['Details'] ?? ''); $mfg = $serno; // --- subscriber lookup --- $subscr = null; $node_straid = null; $model = null; if ($serno) { $filter=['ONTSerialNo'=>['$regex'=>$serno,'$options'=>'i']]; $opts=['limit'=>1,'projection'=>[ 'SubscriberName'=>1, 'LinkedPon'=>1, 'OntId'=>1, 'DeviceName'=>1, 'ONTModel'=>1 ]]; $q=new MongoDB\Driver\Query($filter,$opts); $cur=$mgr->executeQuery($cfg['mongo']['subs'],$q); $r=iterator_to_array($cur,false); if($r){ $doc = (array)$r[0]; $subscr=is_array($doc['SubscriberName'])?implode(' ',$doc['SubscriberName']):(string)$doc['SubscriberName']; $node_straid = buildNodeStraid($doc, $device); $model = $doc['ONTModel'] ?? null; } } [$lat,$lon,$ivue]=gisLookup($gis_conn,$serno); $data[$device][]=[ 'network'=>$device, 'alarm_type'=>$atype, 'occur_time'=>$occur ?: date('Y/m/d H:i:s'), 'subscr_id'=>$subscr, 'node_straid'=>$node_straid, 'pon_descr'=>null, 'model'=>$model, 'serno'=>$serno, 'mfg_serno'=>$mfg, 'latitude'=>$lat, 'longitude'=>$lon, 'ivue_address'=>$ivue ]; } /* ---------- MYSQL INSERT ---------- */ foreach ($data as $network => $alarms) { logi("Begin MySQL update for {$network}"); $stmt = $mysql->prepare("DELETE QUICK FROM standing_alarms WHERE network=?"); $stmt->bind_param('s', $network); $stmt->execute(); $stmt->close(); if (empty($alarms)) { logi(" No new alarms for {$network}"); continue; } $ins = $mysql->prepare(" INSERT INTO standing_alarms (network, alarm_type, occur_time, subscr_id, node_straid, pon_descr, model, serno, mfg_serno, latitude, longitude, ivue_address) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "); if(!$ins){ loge("Prepare failed for {$network}",['err'=>$mysql->error]); continue; } $inserted = 0; foreach ($alarms as $a) { $ins->bind_param( 'ssssssssssss', $network, $a['alarm_type'], $a['occur_time'], $a['subscr_id'], $a['node_straid'], $a['pon_descr'], $a['model'], $a['serno'], $a['mfg_serno'], $a['latitude'], $a['longitude'], $a['ivue_address'] ); if($ins->execute()) $inserted++; else loge("Insert failed for {$network}",['err'=>$ins->error]); } $ins->close(); logi(" Inserted {$inserted} new rows for {$network}"); } /* ---------- CLEANUP ---------- */ if($gis_conn)sqlsrv_close($gis_conn); $mysql->close(); $dur = number_format(microtime(true) - $startTime, 3); logi("Execution time: {$dur}s"); exit(0); ---------------------------------------- File: /root/uac_system/collect_alarms_unified.php Modified: 2025-10-30 22:17:21.713580495 -0400 ---------------------------------------- #!/usr/bin/env php attributes() as$k=>$v){$o[$k]=(string)$v;}return$o;} $cfg=[ 'tz'=>(string)$xml->timezone, 'mysql'=>xmlAttrs($xml->mysql), 'gis'=>xmlAttrs($xml->gis), 'mongo'=>xmlAttrs($xml->mongo), 'cms'=>xmlAttrs($xml->cms), 'smx'=>xmlAttrs($xml->smx) ]; date_default_timezone_set($cfg['tz']); mb_internal_encoding('UTF-8'); /* ---------- CLI ---------- */ $opts=getopt('', ['cms','smx','pretty','debug']); $RUN_CMS=array_key_exists('cms',$opts); $RUN_SMX=array_key_exists('smx',$opts); $PRETTY=array_key_exists('pretty',$opts); $DEBUG=array_key_exists('debug',$opts); if(!$RUN_CMS && !$RUN_SMX){ fwrite(STDERR,"Usage: php collect_alarms_unified.php --cms|--smx|--cms --smx\n"); exit(1); } /* ---------- LOG ---------- */ function now():string{return date('Y-m-d H:i:s');} function j(array$m):string{return json_encode($m,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);} function logi(string$m,array$c=[]):void{fwrite(STDERR,j(['ts'=>now(),'lvl'=>'INFO','msg'=>$m]+$c).PHP_EOL);} function loge(string$m,array$c=[]):void{fwrite(STDERR,j(['ts'=>now(),'lvl'=>'ERROR','msg'=>$m]+$c).PHP_EOL);} /* ---------- RUNNERS ---------- */ function runCollector(string $file,bool $debug=false):array{ if(!file_exists($file)){loge("Collector missing",['path'=>$file]);return[];} exec("/usr/bin/php ".escapeshellarg($file)." 2>&1",$out,$rc); logi("Collector finished",['path'=>$file,'code'=>$rc]); if($debug)foreach($out as$ln)fwrite(STDERR,"[$file] $ln\n"); $joined=implode("\n",$out); if(preg_match('/(\{.*\})\s*$/s',$joined,$m))$json=$m[1];else$json=$joined; $d=json_decode($json,true); return is_array($d)?$d:[]; } /* ---------- MAIN ---------- */ $summary=[]; if($RUN_CMS){logi("Running CMS collector");$summary['cms']=runCollector($cfg['cms']['collector'],$DEBUG);} if($RUN_SMX){logi("Running SMx collector");$summary['smx']=runCollector($cfg['smx']['collector'],$DEBUG);} $flags=JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE; if($PRETTY)$flags|=JSON_PRETTY_PRINT; echo json_encode(['summary'=>$summary],$flags),PHP_EOL; $dur=number_format(microtime(true)-$startTime,3); fwrite(STDERR,"Execution time: {$dur}s\n"); exit(0);