響應式設計雖普及,但仍有場景需服務端區分裝置:行動版專用頁面、廣告投放差異、功能降級、統計分析。本文提供兩種成熟方案:特徵標頭優先 + UA 關鍵字備援 以及 完整 UA 關鍵字庫匹配,附完整可用代碼與維護建議。
邏輯:先檢查行動裝置特有 HTTP 標頭 (WAP/舊裝置),再解析 User-Agent 關鍵字。
<?php
function isMobileDevice(): bool
{
// 1. 特徵標頭檢查 (極快、無需解析 UA)
if (isset($_SERVER['HTTP_VIA'])) return true; // 代理/轉碼閘道
if (isset($_SERVER['HTTP_X_NOKIA_CONNECTION_MODE'])) return true; // Nokia
if (isset($_SERVER['HTTP_X_UP_CALLING_LINE_ID'])) return true; // Openwave
// 2. Accept 標頭檢查 WML
$accept = $_SERVER['HTTP_ACCEPT'] ?? '';
if (stripos($accept, 'vnd.wap.wml') !== false) return true;
// 3. User-Agent 關鍵字匹配
$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
if (empty($ua)) return true; // 無 UA 視為行動裝置 (保守策略)
// 作業系統/平台關鍵字
$mobileOs = [
'Google Wireless Transcoder', 'Windows CE', 'WindowsCE',
'Symbian', 'Android', 'armv6l', 'armv5', 'Mobile',
'CentOS', 'mowser', 'AvantGo', 'Opera Mobi', 'J2ME/MIDP',
'Smartphone', 'Go.Web', 'Palm', 'iPAQ',
];
// 瀏覽器/裝置特徵關鍵字
$mobileTokens = [
'Profile/MIDP', 'Configuration/CLDC-', '160×160', '176×220',
'240×240', '240×320', '320×240', 'UP.Browser', 'UP.Link',
'SymbianOS', 'PalmOS', 'PocketPC', 'SonyEricsson', 'Nokia',
'BlackBerry', 'Vodafone', 'BenQ', 'Novarra-Vision', 'Iris',
'NetFront', 'HTC_', 'Xda_', 'SAMSUNG-SGH', 'Wapaka', 'DoCoMo',
'iPhone', 'iPod',
];
$found = false;
foreach ($mobileOs as $keyword) {
if (stripos($ua, $keyword) !== false) { $found = true; break; }
}
if (!$found) {
foreach ($mobileTokens as $keyword) {
if (stripos($ua, $keyword) !== false) { $found = true; break; }
}
}
return $found;
}
// 使用
if (isMobileDevice()) {
echo "行動裝置";
// include 'mobile/header.php';
} else {
echo "桌面瀏覽器";
// include 'desktop/header.php';
}
?>
收集 200+ 行動裝置關鍵字,涵蓋品牌、瀏覽器、作業系統、解析度特徵。
<?php
function isMobileUA(string $ua = ''): bool
{
if (empty($ua)) $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
$ua = strtolower($ua);
$mobileAgents = [
// 解析度特徵
'240x320', '320x240', '176x220', '160x160', '240x240',
// 品牌/裝置
'acer', 'acoon', 'acs-', 'abacho', 'ahong', 'airness', 'alcatel', 'amoi',
'android', 'anywhereyougo.com', 'applewebkit/525', 'applewebkit/532',
'asus', 'audio', 'au-mic', 'avantogo', 'becker', 'benq', 'bilbo', 'bird',
'blackberry', 'blazer', 'bleu', 'cdm-', 'compal', 'coolpad', 'danger',
'dbtel', 'dopod', 'elaine', 'eric', 'etouch', 'fly ', 'fly_', 'fly-',
'go.web', 'goodaccess', 'gradiente', 'grundig', 'haier', 'hedy', 'hitachi',
'htc', 'huawei', 'hutchison', 'inno', 'ipad', 'ipaq', 'ipod', 'jbrowser',
'kddi', 'kgt', 'kwc', 'lenovo', 'lg ', 'lg2', 'lg3', 'lg4', 'lg5', 'lg7',
'lg8', 'lg9', 'lg-', 'lge-', 'lge9', 'longcos', 'maemo', 'mercator',
'meridian', 'micromax', 'midp', 'mini', 'mitsu', 'mmm', 'mmp', 'mobi',
'mot-', 'moto', 'nec-', 'netfront', 'newgen', 'nexian', 'nf-browser',
'nintendo', 'nitro', 'nokia', 'nook', 'novarra', 'obigo', 'palm',
'panasonic', 'pantech', 'philips', 'phone', 'pg-', 'playstation', 'pocket',
'pt-', 'qc-', 'qtek', 'rover', 'sagem', 'sama', 'samu', 'sanyo', 'samsung',
'sch-', 'scooter', 'sec-', 'sendo', 'sgh-', 'sharp', 'siemens', 'sie-',
'softbank', 'sony', 'spice', 'sprint', 'spv', 'symbian', 'tablet',
'talkabout', 'tcl-', 'teleca', 'telit', 'tianyu', 'tim-', 'toshiba', 'tsm',
'up.browser', 'utec', 'utstar', 'verykool', 'virgin', 'vk-', 'voda',
'voxtel', 'vx', 'wap', 'wellco', 'wig browser', 'wii', 'windows ce',
'wireless', 'xda', 'xde', 'zte',
];
foreach ($mobileAgents as $device) {
if (strpos($ua, $device) !== false) {
return true;
}
}
return false;
}
// 使用
header('Content-Type: text/html; charset=utf-8');
echo isMobileUA() ? '手機' : '電腦';
?>
<?php
function detectDeviceType(string $ua = ''): string
{
if (empty($ua)) $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
$ua = strtolower($ua);
// 平板優先檢查 (避免被手機規則誤判)
$tabletKeywords = ['ipad', 'tablet', 'playbook', 'kindle', 'silk', 'gt-p', 'sch-i', 'sm-t'];
foreach ($tabletKeywords as $kw) {
if (strpos($ua, $kw) !== false) return 'tablet';
}
// 手機
$mobileKeywords = ['mobile', 'iphone', 'android.*mobile', 'blackberry', 'windows phone', 'opera mini', 'opera mobi'];
foreach ($mobileKeywords as $kw) {
if (preg_match('/' . $kw . '/', $ua)) return 'mobile';
}
// 智慧電視
$tvKeywords = ['smarttv', 'googletv', 'appletv', 'hbbtv', 'nettv', 'viera', 'bravia'];
foreach ($tvKeywords as $kw) {
if (strpos($ua, $kw) !== false) return 'tv';
}
// 機器人/爬蟲
$botKeywords = ['bot', 'crawler', 'spider', 'slurp', 'facebookexternalhit', 'twitterbot'];
foreach ($botKeywords as $kw) {
if (strpos($ua, $kw) !== false) return 'bot';
}
return 'desktop';
}
?>
| 面向 | 建議 |
|---|---|
| 關鍵字庫更新 | 定期從 Matomo DeviceDetector、UA-Parser 同步最新規則 |
| 效能優化 | 將關鍵字編譯為單一正則 /keyword1|keyword2|.../i,一次 preg_match 替代迴圈 |
| 快取結果 | 同一 Session/Request 內多次呼叫時,靜態變數快取結果 |
| 響應式優先 | CSS Media Queries 解決 90%+ 佈局差異,服務端判斷僅用於無法用 CSS 解決的業務邏輯 |
| 測試驗證 | 收集真實 UA 字串建立測試套件,包含主流手機、平板、桌面、爬蟲、智慧電視 |
User-Agent 字串混亂、易偽裝、隱私爭議。Chrome/Edge 逐步凍結 UA,推廣 Client Hints:
// 請求標頭 (需伺服器回應 Accept-CH 啟用)
Sec-CH-UA: "Chromium";v="118", "Google Chrome";v="118", "Not=A?Brand";v="99"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "Windows"
Sec-CH-UA-Platform-Version: "15.0.0"
Sec-CH-UA-Model: ""
Sec-CH-UA-Full-Version-List: ...
// PHP 讀取
$isMobile = ($_SERVER['HTTP_SEC_CH_UA_MOBILE'] ?? '?0') === '?1';
$platform = $_SERVER['HTTP_SEC_CH_UA_PLATFORM'] ?? '';
Client Hints 需 HTTPS、需回應
Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform、受權限政策控制。漸進式增強:優先用 Client Hints,回退 UA 解析。
方案一 邏輯清晰、標頭優先、適合舊裝置相容;方案二 關鍵字庫完整、覆蓋率高、易擴展。生產環境建議:整合成熟庫 (DeviceDetector/UA-Parser) + Client Hints 漸進增強 + Session 快取,並以響應式設計為主、服務端判斷為輔。