CodeIgniter 3 User Agent 类库实战指南:识别浏览器、移动设备与爬虫访问
2026/9/21 16:06:20 网站建设 项目流程

CodeIgniter 3 User Agent 类库实战指南:识别浏览器、移动设备与爬虫访问

【免费下载链接】CodeIgniterOpen Source PHP Framework (originally from EllisLab)项目地址: https://gitcode.com/gh_mirrors/co/CodeIgniter

User Agent 类库是 CodeIgniter 框架内置的客户端识别组件,通过解析 HTTP 请求头中的User-Agent字符串,帮助开发者判断访问者的浏览器类型与版本、操作系统平台、是否为移动设备或搜索引擎爬虫,并进一步获取来源页(Referrer)、浏览器接受的语言与字符集信息。阅读完本文,你将掌握 User Agent 类库的初始化方式、四个用户代理定义数组的定制方法、全部类方法的用法与返回约定,并通过源码级剖析理解其底层匹配算法,从而在移动端分流、SEO 统计、访问日志分析等场景中落地实践。

User Agent 类库能做什么

在 Web 开发中,User-Agent字符串是客户端(浏览器、手机、爬虫)主动上报的自我描述,内容形如:

Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.0.4) Gecko/20060613 Camino/1.0.2

CodeIgniter 的 User Agent 类(CI_User_agent,实现于 system/libraries/User_agent.php)负责解析这类字符串,并输出以下信息:

  • 浏览器:名称与版本号(如 Safari 533.20.27、Firefox 13.0);
  • 平台:操作系统信息(Windows、Linux、Mac OS X、Android、iOS 等);
  • 移动设备:手机品牌或设备类型(iPhone、Nokia、Samsung、PlayStation 等);
  • 机器人/爬虫:搜索引擎蜘蛛等(Googlebot、Baiduspider、Bing 等);
  • 来源与偏好:来源页面(Referrer)、接受的Accept-Language语言列表、接受的Accept-Charset字符集列表。

它本质上是一套基于正则/子串匹配的分类引擎:将当前请求的 User-Agent 字符串与预置定义数组逐项比对,命中后记录类型并输出规范化名称。所有定义均可在配置文件中自由扩充,无需修改框架核心代码。

初始化 User Agent 类库

与 CodeIgniter 大多数类库一致,User Agent 类在控制器中通过$this->load->library()加载:

$this->load->library('user_agent');

加载完成后,实例会以$this->agent的形式挂载到当前控制器(可通过 Loader 的库加载机制全局访问)。加载时构造函数即开始工作(见 system/libraries/User_agent.php):

  1. 调用_load_agent_file()读取配置文件中的定义数组;
  2. $_SERVER['HTTP_USER_AGENT']存在,将其存入$this->agent并调用_compile_data()完成平台、机器人、浏览器、移动设备的分类判定;
  3. 写入一条User Agent Class Initialized的 info 级日志。

如果请求没有携带HTTP_USER_AGENT头,类仍会正常初始化,只是各类型标志位保持默认的FALSE,相关取值方法返回空字符串。

用户代理定义文件:application/config/user_agents.php

所有识别规则集中在配置文件 application/config/user_agents.php 中,类库通过 system/libraries/User_agent.php 的_load_agent_file()加载它。加载逻辑支持两层配置:

  • 默认读取APPPATH.'config/user_agents.php'
  • 若存在APPPATH.'config/'.ENVIRONMENT.'/user_agents.php'(环境专属配置),则追加覆盖,实现按development/testing/production环境差异化定制。

配置文件中包含四个关联数组,数组的键用于在 User-Agent 字符串中匹配的特征片段,数组的值用于输出为可读名称

数组变量用途匹配方式(见源码)
$platforms操作系统/平台识别preg_quote($key)转义后正则匹配
$browsers浏览器识别并提取版本键作为正则模式,.*?([0-9\.]+)捕获版本号
$mobiles移动设备识别大小写不敏感的stripos子串匹配
$robots爬虫/机器人识别preg_quote($key)转义后正则匹配

$platforms:平台定义

$platforms = array( 'windows nt 10.0' => 'Windows 10', 'windows nt 6.3' => 'Windows 8.1', 'windows nt 6.1' => 'Windows 7', 'android' => 'Android', 'iphone' => 'iOS', 'ipad' => 'iOS', 'os x' => 'Mac OS X', 'linux' => 'Linux', // ... );

平台匹配由_set_platform()(system/libraries/User_agent.php)完成:将每个键preg_quote转义后与 User-Agent 字符串做大小写不敏感正则比对,首个命中即写入$this->platform。一个值得注意的细节是:数组中同时存在'windows nt 6.3' => 'Windows 8.1'等带具体版本号的键,以及'windows' => 'Unknown Windows OS'这类兜底键,因此数组顺序即匹配优先级——具体版本应排在笼统键之前。全部未命中时返回'Unknown Platform'

$browsers:浏览器定义与版本提取

// 顺序不要更改:许多浏览器会在 UA 中上报多个类型,须先识别子类型 $browsers = array( 'OPR' => 'Opera', 'Edge' => 'Edge', 'Chrome' => 'Chrome', 'Opera.*?Version' => 'Opera', // Opera 10+ 上报 Opera/9.80,真实版本在 Version/ 后 'Opera' => 'Opera', 'MSIE' => 'Internet Explorer', 'Firefox' => 'Firefox', 'Safari' => 'Safari', 'Mozilla' => 'Mozilla', // ... );

配置文件顶部特别注释强调:数组顺序不应更改——许多浏览器会在同一 UA 中上报多个类型(例如 Chrome 的 UA 里同时包含Mozilla/5.0Safari/537.36),因此必须把子类型(Chrome、Edge、Opera)排在通用兜底项(Mozilla)之前。_set_browser()(system/libraries/User_agent.php)使用模式|'.$key.'.*?([0-9\.]+)|i匹配,命中后:

  • $this->is_browser = TRUE
  • 用捕获组([0-9\.]+)提取版本号存入$this->version
  • 将定义值存入$this->browser

值得注意的特殊条目'Opera.*?Version':Opera 10+ 的 UA 恒为Opera/9.80 (...)并追加Version/<真实版本>,因此用正则键提取其后真实版本号,这正是配置键可含正则语法的典型例证。

$mobiles:移动设备定义

$mobiles = array( 'motorola' => 'Motorola', 'nokia' => 'Nokia', 'nexus' => 'Nexus', 'iphone' => 'Apple iPhone', 'ipad' => 'iPad', 'blackberry' => 'BlackBerry', 'samsung' => 'Samsung', 'huawei' => 'Huawei', 'xiaomi' => 'Xiaomi', 'oppo' => 'Oppo', 'vivo' => 'Vivo', 'android' => 'Android', 'windows ce' => 'Windows CE', 'operamini' => 'Opera Mini', 'opera mini' => 'Opera Mini', 'mobile' => 'Generic Mobile', // 兜底 'wireless' => 'Generic Mobile', 'j2me' => 'Generic Mobile', // ... );

列表覆盖手机厂商、操作系统与移动浏览器三类,并以'mobile''wireless''j2me''midp''cldc'等通用词作为兜底。_set_mobile()(system/libraries/User_agent.php)使用stripos做大小写不敏感子串匹配,首个命中即返回TRUE

$robots:爬虫定义

// 爬虫有数百种,这里只收录最常见的 $robots = array( 'googlebot' => 'Googlebot', 'msnbot' => 'MSNBot', 'baiduspider' => 'Baiduspider', 'bingbot' => 'Bing', 'slurp' => 'Inktomi Slurp', 'yahoo' => 'Yahoo', 'yandex' => 'YandexBot', 'ia_archiver' => 'Alexa Crawler', 'MJ12bot' => 'Majestic-12', 'UptimeRobot' => 'UptimeRobot', // ... );

如官方文档所述,爬虫数量庞大(数百种),逐一收录并不现实,因此该库仅内置最常见的蜘蛛。若你的站点常被某些未收录的爬虫访问,直接在application/config/user_agents.php$robots数组中追加键值对即可,无需修改框架源码。

典型实战示例:类型分流与平台输出

官方文档给出的标准示例完整覆盖了三种类型的判断分支与平台输出,可直接放入控制器方法中使用:

$this->load->library('user_agent'); if ($this->agent->is_browser()) { $agent = $this->agent->browser().' '.$this->agent->version(); } elseif ($this->agent->is_robot()) { $agent = $this->agent->robot(); } elseif ($this->agent->is_mobile()) { $agent = $this->agent->mobile(); } else { $agent = 'Unidentified User Agent'; } echo $agent; echo $this->agent->platform(); // 平台信息(Windows、Linux、Mac 等)

该示例也反映了类库的内部判定顺序:构造函数中的_compile_data()(system/libraries/User_agent.php)先固定执行_set_platform(),随后按_set_robot()_set_browser()_set_mobile()的顺序依次尝试,一旦某个方法返回TRUE立即break,即同一 UA 在"机器人→浏览器→移动设备"三个类别中只归属首个命中的类别。这是is_browser()is_robot()is_mobile()三类互斥判断的底层依据。

类方法参考(Class Reference)

类型判断方法

is_browser([$key = NULL])

返回布尔值,判断当前 UA 是否为已知浏览器;传入$key时可进一步判断是否为指定浏览器:

if ($this->agent->is_browser('Safari')) { echo 'You are using Safari.'; } elseif ($this->agent->is_browser()) { echo 'You are using a browser.'; }

注意:'Safari'这类字符串就是 application/config/user_agents.php 中$browsers数组的。源码实现(system/libraries/User_agent.php)中,$key === NULL时直接返回is_browser标志;否则校验$this->browser === $this->browsers[$key],即当前浏览器名与定义值完全一致才返回TRUE

is_mobile([$key = NULL])

返回布尔值,判断是否为已知移动设备,可传入设备键精确匹配。典型场景是按设备类型分流视图

if ($this->agent->is_mobile('iphone')) { $this->load->view('iphone/home'); } elseif ($this->agent->is_mobile()) { $this->load->view('mobile/home'); } else { $this->load->view('web/home'); }

is_robot([$key = NULL])

返回布尔值,判断是否为已知爬虫,可传入机器人键精确匹配。由于内置列表仅含最常见爬虫,若发现常访问站点的机器人缺失,可在配置文件的$robots数组中补充。

is_referral()

返回布尔值,判断访问者是否从其他站点跳转而来。源码实现(system/libraries/User_agent.php)使用parse_url()解析HTTP_REFERERconfig_item('base_url')的主机名并比较:HTTP_REFERER存在且其主机与本站base_url主机不同,才判定为外部来源。判定结果缓存于$this->referer,同一请求内重复调用不再重新解析。

信息获取方法

方法返回说明
browser()string浏览器名称,未识别返回空字符串
version()string浏览器版本号,未识别返回空字符串
mobile()string移动设备品牌/名称,未识别返回空字符串
robot()string爬虫名称,未识别返回空字符串
platform()string操作系统名称(Linux、Windows、OS X 等),未识别返回'Unknown Platform'
referrer()string来源页完整 URL,无HTTP_REFERER时返回空字符串
agent_string()string完整的原始 User-Agent 字符串

其中referrer()的典型用法是配合is_referral()

if ($this->agent->is_referral()) { echo $this->agent->referrer(); }

agent_string()直接返回构造/解析时保存的原始 UA(如Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.0.4) Gecko/20060613 Camino/1.0.2),可用于日志记录与原始审计。

语言与字符集方法

accept_lang([$lang = 'en'])

判断访问者是否接受指定语言。默认参数为'en'

if ($this->agent->accept_lang('en')) { echo 'You accept English!'; }

实现(system/libraries/User_agent.php)为in_array(strtolower($lang), $this->languages(), TRUE)的严格匹配。languages()首次调用时触发_set_languages()(system/libraries/User_agent.php):解析HTTP_ACCEPT_LANGUAGE,用正则/(;\s?q=[0-9\.]+)|\s/i剔除q=权重值与空白后按逗号拆分,全部转为小写;请求头缺失时返回array('Undefined')

accept_charset([$charset = 'utf-8'])

判断访问者是否接受指定字符集:

if ($this->agent->accept_charset('utf-8')) { echo 'You browser supports UTF-8!'; }

charsets()首次调用时由_set_charsets()(system/libraries/User_agent.php)解析HTTP_ACCEPT_CHARSET,同样剔除q=权重并按逗号拆分,缺省返回array('Undefined')

可靠性提示:官方文档明确指出,accept_lang()accept_charset()并非总是可靠——部分浏览器不发送语言/字符集信息,即便发送也未必准确。它们更适合做渐进增强判断,不应作为业务硬性依赖。

languages() / charsets()

分别返回访问者接受的语言列表与字符集列表(数组形式),未提供相应请求头时返回array('Undefined')

parse($string):解析自定义 User-Agent

$this->agent->parse('Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0');

parse()(system/libraries/User_agent.php)允许解析与当前访问者不同的自定义 UA 字符串,典型场景是测试、日志重放或离线分析。它会先将is_browseris_robotis_mobilebrowserversionmobilerobot全部重置,再写入新字符串并重新执行_compile_data();传入空字符串时仅重置不解析。

测试用例验证:行为与预期

仓库测试 tests/codeigniter/libraries/Useragent_test.php 覆盖了上述核心行为,可用于对照理解类库语义:

  • test_is_functions():以Mozilla/5.0 (Macintosh; ...) AppleWebKit/533.20.25 ... Version/5.0.4 Safari/533.20.27为基线,断言is_browser()is_browser('Safari')TRUEis_browser('Firefox')FALSEis_robot()is_mobile()FALSE
  • test_browser_info():同一 UA 下断言platform()'Mac OS X'browser()'Safari'version()'533.20.27'(验证.*?([0-9\.]+)正则对版本号的提取);
  • test_referrer():设置外部来源HTTP_REFERER后断言is_referral()TRUEreferrer()返回完整 URL;清除请求头后两者分别返回FALSE与空字符串;
  • test_accept_lang()/test_charsets():验证语言与字符集解析,包括q=权重剔除、Undefined兜底;
  • test_parse():传入 Firefox/Android 自定义 UA,断言平台为'Android'、浏览器为'Firefox'、版本为'13.0'、移动设备为'Android',且is_mobile('android')TRUE

测试基类CI_TestCase通过 VFS 克隆application/config/user_agents.php后实例化CI_User_agent,说明配置定义是类库行为的直接输入,也印证了扩展配置即可扩展识别能力的设计理念。

扩展与最佳实践建议

综合文档与源码,给出以下几点落地建议:

  1. 新增识别项只需改配置:在 application/config/user_agents.php 的对应数组中追加"键(UA 特征片段)/值(可读名称)"即可。新增平台/爬虫时键会被preg_quote转义,可按字面片段书写;新增浏览器时键会被当作正则模式,可像'Opera.*?Version'一样编写正则,但要留意版本捕获组([0-9\.]+)的配合。
  2. 注意数组顺序$platforms中笼统键(如'windows')应排在具体键(如'windows nt 10.0')之后;$browsers中通用兜底键(如'Mozilla')必须排在子类型之后,否则识别结果会被兜底项抢占。
  3. 环境差异化配置:可通过application/config/{ENVIRONMENT}/user_agents.php为指定环境覆盖定义,例如生产环境追加内部监控爬虫的识别。
  4. 结合日志与分析:用agent_string()保留原始 UA,用is_robot()过滤爬虫流量,使访问统计更贴近真实用户。
  5. 保持审慎:User-Agent 可由客户端任意伪造,类库判定结果仅代表"UA 声称的身份",涉及安全、计费等敏感逻辑时应另行核验(如配合 Input 类 的 IP 与请求校验)。

总结

CodeIgniter 的 User Agent 类库以"配置文件定义 + 正则/子串匹配"的轻量架构,为浏览器、移动设备、爬虫与平台识别提供了开箱即用的能力:加载一行$this->load->library('user_agent')即可通过$this->agent调用十余个语义清晰的方法。其全部识别规则集中在 application/config/user_agents.php,实现位于 system/libraries/User_agent.php,并有 Useragent_test.php 提供行为回归保障——理解这三者的协作关系,你就能在移动端分流、SEO 分析与访问统计中快速落地一套可扩展的客户端识别方案。

【免费下载链接】CodeIgniterOpen Source PHP Framework (originally from EllisLab)项目地址: https://gitcode.com/gh_mirrors/co/CodeIgniter

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询