本文展示一個BrowserDetector類,通過解析HTTP_USER_AGENT字符串,識別瀏覽器類型(IE、Netscape、Opera、Lynx)、操作系統平台、主/次版本號,代碼採用字符串分割與正則匹配組合策略。
class BrowserDetector {
var $UA = ""; // 原始User-Agent
var $BROWSER = "Unknown"; // 瀏覽器類型
var $PLATFORM = "Unknown"; // 操作系統
var $VERSION = ""; // 完整版本號
var $MAJORVER = ""; // 主版本號
var $MINORVER = ""; // 次版本號
function BrowserDetector() { ... }
}
function BrowserDetector() {
$this->UA = getenv("HTTP_USER_AGENT");
// 1. 分離括號內外內容:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
$i = strpos($this->UA, "(");
if ($i >= 0) {
$pre_parens = trim(substr($this->UA, 0, $i)); // 括號前:產品標識
$parens = substr($this->UA, $i+1, strlen($this->UA)); // 括號內:詳情
$j = strpos($parens, ")");
if ($j >= 0) $parens = substr($parens, 0, $j);
} else {
$pre_parens = $this->UA;
$parens = "";
}
$brow_ver = $pre_parens; // 默認版本信息來自括號前
// 2. 解析括號內標記(分號分隔)
$token = trim(strtok($parens, ";"));
while ($token) {
if ($token == "compatible") {
// 忽略
} elseif (preg_match("/MSIE/i", $token)) {
$brow_ver = $token; // MSIE 6.0
} elseif (preg_match("/Opera/i", $token)) {
$brow_ver = $token; // Opera 7.54
} elseif (preg_match("/X11|SunOS|Linux/i", $token)) {
$this->PLATFORM = "Unix";
} elseif (preg_match("/Win/i", $token)) {
$this->PLATFORM = $token; // Windows NT 5.1
} elseif (preg_match("/Mac|PPC/i", $token)) {
$this->PLATFORM = $token; // Macintosh
}
$token = strtok(";");
}
// 3. 從版本字符串提取瀏覽器類型與版本號
$msie_idx = strpos($brow_ver, "MSIE");
if ($msie_idx >= 0) $brow_ver = substr($brow_ver, $msie_idx);
$leftover = "";
if (substr($brow_ver, 0, strlen("Mozilla")) == "Mozilla") {
$this->BROWSER = "Netscape";
$leftover = substr($brow_ver, strlen("Mozilla")+1);
} elseif (substr($brow_ver, 0, strlen("Lynx")) == "Lynx") {
$this->BROWSER = "Lynx";
$leftover = substr($brow_ver, strlen("Lynx")+1);
} elseif (substr($brow_ver, 0, strlen("MSIE")) == "MSIE") {
$this->BROWSER = "IE";
$leftover = substr($brow_ver, strlen("MSIE")+1);
} elseif (substr($brow_ver, 0, strlen("Opera")) == "Opera") {
$this->BROWSER = "Opera";
$leftover = substr($brow_ver, strlen("Opera")+1);
}
// 4. 提取版本號(首個空格前)
$leftover = trim($leftover);
$i = strpos($leftover, " ");
if ($i > 0) {
$this->VERSION = substr($leftover, 0, $i);
// 可進一步按.分割獲取MAJORVER/MINORVER
}
}
<?php
$detector = new BrowserDetector();
echo "瀏覽器:{$detector->BROWSER}\n";
echo "版本:{$detector->VERSION}\n";
echo "平台:{$detector->PLATFORM}\n";
echo "主版本:{$detector->MAJORVER}\n";
echo "次版本:{$detector->MINORVER}\n";
?>
| 挑戰 | 說明 | 現代應對 |
|---|---|---|
| UA字符串混亂 | 歷史兼容導致包含大量無關標記(如所有IE都含Mozilla) | 使用成熟解析庫而非手工正則 |
| 偽造/自定義UA | 爬蟲、測試工具可任意修改 | 不依賴UA做關鍵安全決策 |
| 移動端碎片化 | 數千種設備/瀏覽器組合 | 設備指紋/Client Hints API輔助 |
| 新瀏覽器不斷出現 | Edge、Brave、Vivaldi等需持續更新規則 | 庫自動更新規則庫 |
piwik/device-detector(Matomo出品,準確率高、規則庫持續更新)、ua-parser/uap-php(Google UA Parser移植)ua-parser-js、bowserngx_http_user_agent_module、mod_ua(日誌/訪問控制層面)瀏覽器正逐步棄用User-Agent,改用Client Hints(Sec-CH-UA、Sec-CH-UA-Mobile、Sec-CH-UA-Platform等結構化頭部),提供標準化、可控的設備信息獲取方式。PHP中可通過$_SERVER['HTTP_SEC_CH_UA']等讀取。
此類雖屬早期手工解析典型,但展示了UA字符串結構分析、標記分割、版本提取的核心邏輯,對理解設備識別原理具教學價值。生產環境請務必使用成熟維護的解析庫。