You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP通过正则表达式解析Fortinet日志生成键值对数组问题咨询

PHP解析Fortinet日志正则匹配问题修复

问题背景

我正在尝试使用PHP解析Fortinet日志,使用的日志示例取自Fortinet官方cookbook手册。
目标是解析日志后生成以日志字段名为索引、对应字段值为元素值的数组,预期格式例如[date]=>2019-05-10 [time]=>11:50:48 ... [srcip]=>172.16.200.254。当前编写的正则代码运行后无法得到预期匹配结果,需要排查正则写法问题,实现正确的字段提取。

原有问题代码

$regex = '/[a-zA-Z]+=[0-9]{4}-[0-9]{2}-[0-9]{2} [a-zA-Z]+=[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]{1,3})? [a-zA-Z]+="[^"]*" [a-zA-Z]+="[a-zA-Z]+" [a-zA-Z]+="[^"]*" [a-zA-Z]+="[^"]*" [a-zA-Z]+="[^"]*" [a-zA-Z]+=[0-9]+ [a-zA-Z]+=\\b(?:(?:2(?:[0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9])\\.){3}(?:(?:2([0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9]))\\b [a-zA-Z]+=[0-9]+ [a-zA-Z]+="[^"]*" [a-zA-Z]+="[^"]*" [a-zA-Z]+=\\b(?:(?:2(?:[0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9])\\.){3}(?:(?:2([0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9]))\\b [a-zA-Z]+=[0-9]+ [a-zA-Z]+="[^"]*" [a-zA-Z]+="[^"]*" [a-zA-Z]+=[0-9]+ [a-zA-Z]+=[0-9]+ [a-zA-Z]+="[^"]*" [a-zA-Z]+=[0-9]+ [a-zA-Z]+="[^"]*" [a-zA-Z]+="[^"]*" [a-zA-Z]+="[^"]*" [a-zA-Z]+="[^"]*" [a-zA-Z]+="[^"]*" [a-zA-Z]+="[^"]*" [a-zA-Z]+=[0-9]+ [a-zA-Z]+=[0-9]+ [a-zA-Z]+=[0-9]+ [a-zA-Z]+=[0-9]+ [a-zA-Z]+=[0-9]+ [a-zA-Z]+="[^"]*"/i';

$str = 'date=2019-05-10 time=11:50:48 logid="0001000014" type="traffic" subtype="local" level="notice" vd="vdom1" eventtime=1557514248379911176 srcip=172.16.200.254 srcport=62024 srcintf="port11" srcintfrole="undefined" dstip=172.16.200.2 dstport=443 dstintf="vdom1" dstintfrole="undefined" sessionid=107478 proto=6 action="server-rst" policyid=0 policytype="local-in-policy" service="HTTPS" dstcountry="Reserved" srccountry="Reserved" trandisp="noop" app="Web Management(HTTPS)" duration=5 sentbyte=1247 rcvdbyte=1719 sentpkt=5 rcvdpkt=6 appcat="unscanned"';

preg_match_all($regex, $str, $matches, PREG_SET_ORDER, 0);

var_dump($matches);

问题原因

原有正则存在两个核心问题:

  • 硬编码了所有字段的出现顺序、值匹配规则,只要日志字段顺序调整、值包含特殊字符(比如server-rst中的横杠、Web Management(HTTPS)中的空格和括号)就会整体匹配失败,完全不具备通用性
  • 没有设置捕获分组,即使匹配成功也无法单独提取字段名和字段值,无法直接组装成目标关联数组

修复方案

Fortinet日志的字段统一遵循字段名=值的格式,值仅分两类:带双引号的字符串、不带引号的数字/IP,不需要针对单个字段写匹配规则,用通用键值对正则即可完成提取。
修复后的可运行代码:

<?php
// 通用键值对匹配正则,自动兼容带引号/不带引号的字段值
$regex = '/(\w+)=(".*?"|\S+)/i';

$str = 'date=2019-05-10 time=11:50:48 logid="0001000014" type="traffic" subtype="local" level="notice" vd="vdom1" eventtime=1557514248379911176 srcip=172.16.200.254 srcport=62024 srcintf="port11" srcintfrole="undefined" dstip=172.16.200.2 dstport=443 dstintf="vdom1" dstintfrole="undefined" sessionid=107478 proto=6 action="server-rst" policyid=0 policytype="local-in-policy" service="HTTPS" dstcountry="Reserved" srccountry="Reserved" trandisp="noop" app="Web Management(HTTPS)" duration=5 sentbyte=1247 rcvdbyte=1719 sentpkt=5 rcvdpkt=6 appcat="unscanned"';

preg_match_all($regex, $str, $matches);
// 直接将捕获到的键名、值数组组合为关联数组
$log = array_combine($matches[1], $matches[2]);
// 去除字符串值首尾的双引号,得到干净的字段值
foreach ($log as $key => $val) {
    $log[$key] = trim($val, '"');
}

var_dump($log);

正则逻辑说明

  • (\w+):第一捕获组,匹配由字母、数字、下划线组成的字段名
  • (".*?"|\S+):第二捕获组,优先匹配双引号包裹的字符串内容(支持含空格、特殊字符的值),匹配不到时匹配连续非空白字符,适配数字、IP这类不带引号的值
  • 该正则不依赖字段顺序、不限制字段数量,兼容不同型号、不同版本Fortinet设备输出的日志格式

内容的提问来源于stack exchange,提问作者toolost

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 12:51:24