feat: 实现TCP Server

This commit is contained in:
zimoyin
2026-03-02 21:59:43 +08:00
parent 043306819b
commit a79dfae57d
144 changed files with 15785 additions and 140 deletions
+232
View File
@@ -0,0 +1,232 @@
<?php
namespace app\config;
use app\config\DatabaseConfig;
use app\utils\Logger;
class Config
{
/**
* 是否使用自定义流程配置(从Config加载)
*/
public bool $flowUseCustomProcess {
get => $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;
}
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);
}
/**
* 获取服务器MAC地址并散列成2位数字(00-99)作为机器ID
* 兼容Linux/Windows系统,失败时降级使用IP散列
*
* @return string 2位机器ID00-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));
}
}