$this->flowUseCustomProcess; } /** * 自定义流程配置键名(默认使用 'standard' 注意:此次为空,并非使用自定义配置文件里面的 'standard') */ public string $flowProcessConfigKey { get => $this->flowProcessConfigKey; } /** * @var int 普通日志轮转时间默认 14 天 */ public int $logRotationTimeByDay { get => $this->logRotationTimeByDay; } /** * @var int 错误日志轮转时间默认 30 天 */ public int $errorLogRotationTimeByDay { get => $this->errorLogRotationTimeByDay; } public DatabaseConfig $database { get => $this->database; } public array $customProcess { get => $this->customProcess; } /** * 存储单读卡器模式 * true=单读卡器模式(一个读卡器交替入库/出库) * false=双读卡器模式(分别使用"内镜放入"和"内镜取出"读卡器) */ public bool $storageSingleReader { get => $this->storageSingleReader; } /** * 机器ID,用于分布式环境,确保唯一 */ public string $machineId { get => $this->machineId; } public bool $dbDebug { get => $this->dbDebug; } /** * 方式 类:方法 * 方式 类 * 方式 :方法 * 允许使用正则 * 作为通配符 * @var array 日志过滤器 */ public array $logFilter { get => $this->logFilter; } public int $logLevel { get => $this->logLevel; } /** * 阻断模式 */ public bool $blockMode { get => $this->blockMode; } /** * 人员刷卡记录缓存记录多久。然后是 0 表示不计算缓存时间,只要被使用了就删除 */ public int $openCardRecordCacheTime = 0 { get => $this->openCardRecordCacheTime; } /** * 人员刷卡记录记录哪些读卡器的 * 设置为空则表示所有读卡器 */ public array $openCardRecordReaders = [] { get => $this->openCardRecordReaders; } /** * 是否开启虚拟清洗机解析 */ public bool $enableVirtualCleanerParser { get => $this->enableVirtualCleanerParser; } private function __construct() { $this->database = new DatabaseConfig(); $this->customProcess = require __DIR__ . '/custom_process_config.php'; $this->machineId = self::getStringEnv("MACHINE_ID", "0"); if (empty($this->machineId) || $this->machineId == '0') { $this->machineId = $this->getMachineIdByMac(); } $this->dbDebug = self::getBoolEnv('DB_DEBUG'); $this->flowUseCustomProcess = self::getBoolEnv('FLOW_USE_CUSTOM_PROCESS', true); $this->flowProcessConfigKey = self::getStringEnv('FLOW_PROCESS_CONFIG_KEY', ''); $this->logRotationTimeByDay = self::getIntEnv('LOG_ROTATION_TIME_BY_DAY', 14); $this->errorLogRotationTimeByDay = self::getIntEnv('ERROR_LOG_ROTATION_TIME_BY_DAY', 30); $this->logFilter = self::getStringArrayEnv('LOG_FILTER', []); $this->logLevel = match (strtoupper(self::getStringEnv('LOG_LEVEL', 'DEBUG'))) { 'INFO' => \Monolog\Logger::INFO, 'WARNING' => \Monolog\Logger::WARNING, 'ERROR' => \Monolog\Logger::ERROR, 'ALERT' => \Monolog\Logger::ALERT, 'EMERGENCY' => \Monolog\Logger::EMERGENCY, 'CRITICAL' => \Monolog\Logger::CRITICAL, 'NOTICE' => \Monolog\Logger::NOTICE, default => \Monolog\Logger::DEBUG }; $this->blockMode = self::getBoolEnv('BLOCK_MODE', true); $this->openCardRecordCacheTime = self::getIntEnv('OPEN_CARD_RECORD_CACHE_TIME', 60); $this->openCardRecordReaders = self::getStringArrayEnv('OPEN_CARD_RECORD_READERS', []); $this->storageSingleReader = self::getBoolEnv('STORAGE_SINGLE_READER', false); $this->enableVirtualCleanerParser = self::getBoolEnv('ENABLE_VIRTUAL_CLEANER_PARSER', false); } /** * 获取服务器MAC地址并散列成2位数字(00-99)作为机器ID * 兼容Linux/Windows系统,失败时降级使用IP散列 * * @return string 2位机器ID(00-99) */ public function getMachineIdByMac(): string { try { // 步骤1:根据系统类型执行命令获取MAC地址 $mac = ''; if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { // Windows系统 $output = shell_exec('ipconfig /all'); if (preg_match('/物理地址[.:\s]+([0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2})/i', $output, $matches)) { $mac = str_replace(['-', ':'], '', strtolower($matches[1])); } } else { // Linux/Mac系统 $output = shell_exec('cat /sys/class/net/*/address 2>/dev/null || ifconfig'); if (preg_match('/([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2})/i', $output, $matches)) { // 过滤虚拟网卡(docker/lo等),取第一个有效物理网卡MAC $mac = str_replace(':', '', strtolower($matches[1])); // 排除回环地址、docker虚拟网卡等无效MAC $invalidPrefixes = ['00:00:00', '02:42:ac', '12:34:56']; $isInvalid = false; foreach ($invalidPrefixes as $prefix) { if (str_starts_with($matches[1], $prefix)) { $isInvalid = true; break; } } if ($isInvalid) { $mac = ''; } } } // 步骤2:若MAC获取失败,降级使用服务器IP if (empty($mac)) { // 获取外网/内网IP(优先内网) $ip = $_SERVER['SERVER_ADDR'] ?? gethostbyname(gethostname()); if (empty($ip) || $ip === '127.0.0.1') { $ip = '0.0.0.0'; // 兜底 } $mac = $ip; // 用IP替代MAC做散列 } $hash = md5($mac); // 生成32位哈希值 $hashInt = hexdec(substr($hash, 0, 4)); $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $base = 62; // 62进制基数 $char1 = $chars[$hashInt % $base]; $char2 = $chars[(int)($hashInt / $base) % $base]; $machineId = $char2 . $char1; // 步骤4:补零为2位(如5→05,99→99) return str_pad($machineId, 2, '0', STR_PAD_LEFT); } catch (\Exception $e) { // 极端异常时返回默认值(建议日志记录) Logger::error('获取机器ID失败:', ['error' => $e->getMessage()]); return '01'; // 默认机器ID } } public static function getBoolEnv($name, $default = false) { $value = getenv($name); return empty($value) ? $default : filter_var($value, FILTER_VALIDATE_BOOLEAN); } public static function getIntEnv($name, $default = 0) { $value = getenv($name); return empty($value) ? $default : (int)$value; } public static function getStringEnv($name, $default = null) { $value = getenv($name); return empty($value) ? $default : $value; } private static ?Config $instance = null; public static function getInstance(): Config { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } private static function getStringArrayEnv(string $string, array $array): array { $value = getenv($string); return empty($value) ? $array : array_map('trim', explode(';', $value)); } }