parseAndExecute($formula, $variables); if (is_array($result)) { return $result; } return ['result' => $result]; } catch (\Exception $e) { Log::error('계산식 실행 실패', [ 'formula' => $formula, 'variables' => $variables, 'error' => $e->getMessage() ]); throw new \RuntimeException("계산식 실행 실패: {$e->getMessage()}"); } } /** * 계산식 파싱 및 실행 */ protected function parseAndExecute(string $formula, array $variables): array|float { // 미리 정의된 함수 패턴들 처리 if ($this->isPreDefinedFunction($formula)) { return $this->executePreDefinedFunction($formula, $variables); } // 단순 수학 표현식 처리 if ($this->isSimpleMathExpression($formula)) { return $this->executeSimpleMath($formula, $variables); } // 조건식 처리 (IF문 등) if ($this->isConditionalExpression($formula)) { return $this->executeConditionalExpression($formula, $variables); } throw new \InvalidArgumentException("지원되지 않는 계산식 형태: {$formula}"); } /** * 미리 정의된 함수 실행 */ protected function executePreDefinedFunction(string $formula, array $variables): array { // 경동기업 스크린 제작사이즈 계산 if ($formula === 'kyungdong_screen_size') { return [ 'W1' => ($variables['W0'] ?? 0) + 160, 'H1' => ($variables['H0'] ?? 0) + 350 ]; } // 경동기업 철재 제작사이즈 계산 if ($formula === 'kyungdong_steel_size') { return [ 'W1' => ($variables['W0'] ?? 0) + 110, 'H1' => ($variables['H0'] ?? 0) + 350 ]; } // 스크린 중량 계산 if ($formula === 'screen_weight_calculation') { $W0 = $variables['W0'] ?? 0; $W1 = $variables['W1'] ?? 0; $H1 = $variables['H1'] ?? 0; $area = ($W1 * $H1) / 1000000; return [ 'area' => $area, 'weight' => ($area * 2) + ($W0 / 1000 * 14.17) ]; } // 브라켓 수량 계산 if ($formula === 'bracket_quantity') { $W1 = $variables['W1'] ?? 0; if ($W1 <= 3000) return ['result' => 2]; if ($W1 <= 6000) return ['result' => 3]; if ($W1 <= 9000) return ['result' => 4]; if ($W1 <= 12000) return ['result' => 5]; return ['result' => 5]; // 최대값 } // 5130 시스템 브라켓 사이즈 계산 (중량+인치 기반) if ($formula === 'motor_bracket_size') { return $this->calculateMotorBracketSize($variables); } // 환봉 수량 계산 if ($formula === 'round_bar_quantity') { $W1 = $variables['W1'] ?? 0; $qty = $variables['qty'] ?? 1; if ($W1 <= 3000) return ['result' => 1 * $qty]; if ($W1 <= 6000) return ['result' => 2 * $qty]; if ($W1 <= 9000) return ['result' => 3 * $qty]; if ($W1 <= 12000) return ['result' => 4 * $qty]; return ['result' => 4 * $qty]; } // 샤프트 규격 결정 if ($formula === 'shaft_size_determination') { $W1 = $variables['W1'] ?? 0; if ($W1 <= 6000) return ['result' => 4]; // 4인치 if ($W1 <= 8200) return ['result' => 5]; // 5인치 return ['result' => 0]; // 미정의 } // 모터 용량 결정 if ($formula === 'motor_capacity_determination') { $shaftSize = $variables['shaft_size'] ?? 4; $weight = $variables['weight'] ?? 0; // 샤프트별 중량 매트릭스 if ($shaftSize == 4) { if ($weight <= 150) return ['result' => '150K']; if ($weight <= 300) return ['result' => '300K']; if ($weight <= 400) return ['result' => '400K']; } elseif ($shaftSize == 5) { if ($weight <= 123) return ['result' => '150K']; if ($weight <= 246) return ['result' => '300K']; if ($weight <= 327) return ['result' => '400K']; if ($weight <= 500) return ['result' => '500K']; if ($weight <= 600) return ['result' => '600K']; } elseif ($shaftSize == 6) { if ($weight <= 104) return ['result' => '150K']; if ($weight <= 208) return ['result' => '300K']; if ($weight <= 300) return ['result' => '400K']; if ($weight <= 424) return ['result' => '500K']; if ($weight <= 508) return ['result' => '600K']; if ($weight <= 800) return ['result' => '800K']; if ($weight <= 1000) return ['result' => '1000K']; } return ['result' => '미정의']; } throw new \InvalidArgumentException("알 수 없는 미리 정의된 함수: {$formula}"); } /** * 단순 수학 표현식 실행 */ protected function executeSimpleMath(string $formula, array $variables): float { // 변수 치환 $expression = $formula; foreach ($variables as $key => $value) { $expression = str_replace($key, (string)$value, $expression); } // 안전한 수학 표현식 검증 if (!$this->isSafeMathExpression($expression)) { throw new \InvalidArgumentException("안전하지 않은 수학 표현식: {$expression}"); } // 계산 실행 return eval("return {$expression};"); } /** * 조건식 실행 */ protected function executeConditionalExpression(string $formula, array $variables): float { // 간단한 IF 조건식 파싱 // 예: "IF(W1 <= 3000, 2, IF(W1 <= 6000, 3, 4))" $pattern = '/IF\s*\(\s*([^,]+),\s*([^,]+),\s*(.+)\)/i'; if (preg_match($pattern, $formula, $matches)) { $condition = trim($matches[1]); $trueValue = trim($matches[2]); $falseValue = trim($matches[3]); // 조건 평가 if ($this->evaluateCondition($condition, $variables)) { return is_numeric($trueValue) ? (float)$trueValue : $this->execute($trueValue, $variables)['result']; } else { return is_numeric($falseValue) ? (float)$falseValue : $this->execute($falseValue, $variables)['result']; } } throw new \InvalidArgumentException("지원되지 않는 조건식: {$formula}"); } /** * 조건 평가 */ protected function evaluateCondition(string $condition, array $variables): bool { // 변수 치환 $expression = $condition; foreach ($variables as $key => $value) { $expression = str_replace($key, (string)$value, $expression); } // 안전한 조건식 검증 if (!$this->isSafeConditionExpression($expression)) { throw new \InvalidArgumentException("안전하지 않은 조건식: {$expression}"); } return eval("return {$expression};"); } /** * 5130 시스템 모터 브라켓 사이즈 계산 (중량+인치 기반) */ protected function calculateMotorBracketSize(array $variables): array { $weight = floatval($variables['weight'] ?? 0); $inch = is_numeric($variables['inch'] ?? null) ? intval($variables['inch']) : 0; $motorCapacity = 0; if ($inch > 0) { // 중량 + 인치 기준 판단 (철재 기준) if ( ($inch == 4 && $weight <= 300) || ($inch == 5 && $weight <= 246) || ($inch == 6 && $weight <= 208) ) { $motorCapacity = 300; } elseif ( ($inch == 4 && $weight > 300 && $weight <= 400) || ($inch == 5 && $weight > 246 && $weight <= 327) || ($inch == 6 && $weight > 208 && $weight <= 277) ) { $motorCapacity = 400; } elseif ( ($inch == 5 && $weight > 327 && $weight <= 500) || ($inch == 6 && $weight > 277 && $weight <= 424) || ($inch == 8 && $weight <= 324) ) { $motorCapacity = 500; } elseif ( ($inch == 5 && $weight > 500 && $weight <= 600) || ($inch == 6 && $weight > 424 && $weight <= 508) || ($inch == 8 && $weight > 324 && $weight <= 388) ) { $motorCapacity = 600; } elseif ( ($inch == 6 && $weight > 600 && $weight <= 800) || ($inch == 6 && $weight > 508 && $weight <= 800) || ($inch == 8 && $weight > 388 && $weight <= 611) ) { $motorCapacity = 800; } elseif ( ($inch == 6 && $weight > 800 && $weight <= 1000) || ($inch == 8 && $weight > 611 && $weight <= 1000) ) { $motorCapacity = 1000; } } else { // 인치가 없으면 중량만으로 판단 if ($weight <= 300) { $motorCapacity = 300; } elseif ($weight <= 400) { $motorCapacity = 400; } elseif ($weight <= 500) { $motorCapacity = 500; } elseif ($weight <= 600) { $motorCapacity = 600; } elseif ($weight <= 800) { $motorCapacity = 800; } elseif ($weight <= 1000) { $motorCapacity = 1000; } } // 용량별 브라켓 사이즈 매핑 $bracketSize = '530*320'; // 기본값 if (in_array($motorCapacity, [300, 400])) { $bracketSize = '530*320'; } elseif (in_array($motorCapacity, [500, 600])) { $bracketSize = '600*350'; } elseif (in_array($motorCapacity, [800, 1000])) { $bracketSize = '690*390'; } return [ 'bracket_size' => $bracketSize, 'motor_capacity' => $motorCapacity, 'calculated_weight' => $weight, 'shaft_inch' => $inch ]; } /** * 미리 정의된 함수인지 확인 */ protected function isPreDefinedFunction(string $formula): bool { $predefinedFunctions = [ 'kyungdong_screen_size', 'kyungdong_steel_size', 'screen_weight_calculation', 'bracket_quantity', 'motor_bracket_size', 'round_bar_quantity', 'shaft_size_determination', 'motor_capacity_determination' ]; return in_array($formula, $predefinedFunctions); } /** * 단순 수학 표현식인지 확인 */ protected function isSimpleMathExpression(string $formula): bool { return preg_match('/^[A-Za-z0-9_+\-*\/().\s]+$/', $formula); } /** * 조건식인지 확인 */ protected function isConditionalExpression(string $formula): bool { return preg_match('/IF\s*\(/i', $formula); } /** * 안전한 수학 표현식인지 검증 */ protected function isSafeMathExpression(string $expression): bool { // 위험한 함수나 키워드 차단 $dangerous = ['exec', 'system', 'shell_exec', 'eval', 'file', 'fopen', 'include', 'require']; foreach ($dangerous as $func) { if (stripos($expression, $func) !== false) { return false; } } // 허용된 문자만 포함하는지 확인 return preg_match('/^[0-9+\-*\/().\s]+$/', $expression); } /** * 안전한 조건식인지 검증 */ protected function isSafeConditionExpression(string $expression): bool { // 허용된 연산자: ==, !=, <, >, <=, >=, &&, || $allowedPattern = '/^[0-9+\-*\/().\s<>=!&|]+$/'; return preg_match($allowedPattern, $expression); } }