addClassPaths('Collector'); } public function getFormService(): CollectorForm { if ($this->_form === null) { $this->_form = new CollectorForm(); $this->_form->setAttributes([ 'pk_field' => $this->model->getPKField(), 'title_field' => $this->model->getTitleField(), 'table' => $this->model->getTable(), 'useAutoIncrement' => $this->model->useAutoIncrement(), 'class_path' => $this->getClassPaths(false), ]); } return $this->_form; } public function getHelper(): CollectorHelper { if ($this->_helper === null) { $this->_helper = new CollectorHelper(); $this->_helper->setAttributes([ 'pk_field' => $this->model->getPKField(), 'title_field' => $this->model->getTitleField(), 'table' => $this->model->getTable(), 'useAutoIncrement' => $this->model->useAutoIncrement(), 'class_path' => $this->getClassPaths(false), ]); } return $this->_helper; } //기본 기능부분 public function create(object $dto): CollectorEntity { if (!$dto instanceof CollectorDTO) { throw new RuntimeException(__METHOD__ . "에서 오류발생:" . get_class($dto) . "는 사용할수 없습니다."); } return parent::create($dto); } public function modify($uid, object $dto): CollectorEntity { if (!$dto instanceof CollectorDTO) { throw new RuntimeException(__METHOD__ . "에서 오류발생:" . get_class($dto) . "는 사용할수 없습니다."); } return parent::modify($uid, $dto); } //List 검색용 //FormFilter 조건절 처리 //검색어조건절처리 public function setSearchWord(string $word): void { $this->model->orLike($this->model->getTable() . "." . $this->model->getTitleField(), $word, 'both'); parent::setSearchWord($word); } //SNMP연결 private function getSNMPOctets(TrafficEntity $trafficEntity, string $oid): ?int { $fullOid = $oid . $trafficEntity->getInterface(); $community = $trafficEntity->getCommunity(); $ip = $trafficEntity->getIP(); // snmp2_get을 사용하여 SNMP v2c로 요청 // 💡 snmp2_get() 함수가 존재하지 않는다는 LSP 오류를 무시하기 위해 @suppress 태그 사용 /** @phpstan-ignore-next-line */ $result = @snmp2_get($ip, $community, $fullOid, 100000, 3); if ($result === false || $result === null) { log_message('error', "SNMP 통신 실패: {$ip} ({$fullOid}, Community: {$community})"); return null; } // 💡 정규식 수정: /\d+$/ (문자열 끝의 숫자만 추출) if (preg_match('/\d+$/', $result, $matches)) { // SNMP Counter는 BigInt가 될 수 있으므로 intval 대신 (int) 캐스팅을 사용하여 // 최대한 큰 정수로 변환합니다. PHP 64비트 환경이 필요합니다. return (int)$matches[0]; } return null; } public function getCalculatedData(TrafficEntity $trafficEntity): array { $currentInOctets = $this->getSNMPOctets($trafficEntity, self::OID_IF_IN_OCTETS); $currentOutOctets = $this->getSNMPOctets($trafficEntity, self::OID_IF_OUT_OCTETS); if ($currentInOctets === null || $currentOutOctets === null) { $message = "트래픽 수집 실패: {$trafficEntity->getIP()} - IF{$trafficEntity->getInterface()} (UID: {$trafficEntity->getPK()})"; log_message('warning', $message); throw new \Exception($message); } // 이전 데이터를 조회하여 Rate 계산에 사용 // $this->model은 TrafficDataModel의 인스턴스라고 가정 $lastEntity = $this->model->getLastEntity($trafficEntity->getPK()); $inKbitsSec = 0.0; $outKbitsSec = 0.0; // 이전 데이터가 있어야만 Rate 계산 가능 if ($lastEntity !== null) { $lastTime = Time::parse($lastEntity->getCreatedAt())->getTimestamp(); $deltaTime = Time::now()->getTimestamp() - $lastTime; if ($deltaTime > 0) { $lastIn = $lastEntity->getRawIn(); $lastOut = $lastEntity->getRawOut(); // 💡 1. 인바운드 Octets 차분 계산 (오버플로우 처리) if ($currentInOctets < $lastIn) { // 카운터 롤오버 발생: Delta = (MAX - Last) + Current $deltaInOctets = (self::MAX_COUNTER_32BIT - $lastIn) + $currentInOctets; log_message('info', "Inbound Rollover Detected for UID: {$trafficEntity->getPK()}. Delta: {$deltaInOctets}"); } else { // 정상적인 차분 $deltaInOctets = $currentInOctets - $lastIn; } // 💡 2. 아웃바운드 Octets 차분 계산 (오버플로우 처리) if ($currentOutOctets < $lastOut) { // 카운터 롤오버 발생 $deltaOutOctets = (self::MAX_COUNTER_32BIT - $lastOut) + $currentOutOctets; log_message('info', "Outbound Rollover Detected for UID: {$trafficEntity->getPK()}. Delta: {$deltaOutOctets}"); } else { // 정상적인 차분 $deltaOutOctets = $currentOutOctets - $lastOut; } // Kbit/s 계산: (Delta_Octets * 8 bits) / Delta_Time_Seconds / 1000 (-> Kbit/s) // 실수(float) 연산으로 정확도를 높입니다. $inKbitsSec = ($deltaInOctets * 8.0) / $deltaTime / 1000.0; $outKbitsSec = ($deltaOutOctets * 8.0) / $deltaTime / 1000.0; } else { log_message('error', "시간 차이 오류 발생: {$trafficEntity->getIP()} - {$deltaTime}초 (UID: {$trafficEntity->getPK()})"); } } // DB에 저장할 데이터를 배열로 반환 return [ // 💡 요청에 따라 'in'과 'out' 값을 정수형으로 캐스팅하여 소수점 이하를 버림 'trafficinfo_uid' => (int)$trafficEntity->getPK(), 'in' => (int)$inKbitsSec, // 정수형으로 반환 'out' => (int)$outKbitsSec, // 정수형으로 반환 'raw_in' => (int)$currentInOctets, 'raw_out' => (int)$currentOutOctets, ]; } }