在进行Web应用程序开发的时候,人们经常会用Session存储数据。但可能有人不知道,在PHP中,Session使用不当可能会引起并发问题。印度医疗行业软件解决方案提供商Plus91 Technologies高级工程师Kishan Gor在个人博客上对这个问题进行了阐释。 如果同一个客户端并发发送多个请求,而每个请求都使用了Session,那么PHP Session锁的存在会导致服务器串行响应这些请求,而不是并行。这是因为在默认情况下,PHP使用文件存储Session数据。对于每一个新的 Session,PHP会创建一个文件,并持续向其中写入数据。所以,每次调用session_start()方法,就会打开Session文件,并取得 文件的独占锁。这样,如果服务器脚本正在处理一个请求,而客户端又发送了一个同样需要使用Session的请求,那么后一个请求会阻塞,直至前一个请求处 理完成释放了文件上的独占锁。不过,这只限于来自同一个客户端的多个请求,也就是说,来自一个客户端的请求并不会阻塞另一个客户端的请求。 如果脚本很短,这通常没有问题。但如果脚本运行时间比较长,那就可能会产生问题。在现代Web应用程序开发中,有一个非常常见的情况,就是使用…
December 19, 2019
PHP获取浏览器信息, How to Parse a User Agent in PHP with Minimal Effort
用户代理包含大量存储在文本字符串中的数据。而且,从字面上看,任何人都可以为其浏览器和/或其漫游器的请求设置随机,任意,非标准的用户代理字符串。因此,从这些用户代理解析和提取信息可能比预期的要复杂,并且可能需要设计用于处理数千种极端情况的复杂解决方案。
您只需复制粘贴此PHP函数,它就可以正常工作。
这是一些代码。它是Francesco R自2016年以来在PHP文档页面上get_browser的文章中代码的扩展:
有两个主要更新:
- 虽然Francesco R的原始帖子中的代码对于大多数人类 案件都是准确的。如果您需要处理漫游器流量,则需要其他行。
- 原始帖子包含与strpos()函数相关的错误(请参见代码中显示的注释)
// Function written and tested December, 2018 function get_browser_name($user_agent) { // Make case insensitive. $t = strtolower($user_agent); // If the string *starts* with the string, strpos returns 0 (i.e., FALSE). Do a ghetto hack and start with a space. // "[strpos()] may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE." // http://php.net/manual/en/function.strpos.php $t = " " . $t; // Humans / Regular Users if (strpos($t, 'opera' ) || strpos($t, 'opr/') ) return 'Opera' ; elseif (strpos($t, 'edge' ) ) return 'Edge' ; elseif (strpos($t, 'chrome' ) ) return 'Chrome' ; elseif (strpos($t, 'safari' ) ) return 'Safari' ; elseif (strpos($t, 'firefox' ) ) return 'Firefox' ; elseif (strpos($t, 'msie' ) || strpos($t, 'trident/7')) return 'Internet Explorer'; // Search Engines elseif (strpos($t, 'google' ) ) return '[Bot] Googlebot' ; elseif (strpos($t, 'bing' ) ) return '[Bot] Bingbot' ; elseif (strpos($t, 'slurp' ) ) return '[Bot] Yahoo! Slurp'; elseif (strpos($t, 'duckduckgo') ) return '[Bot] DuckDuckBot' ; elseif (strpos($t, 'baidu' ) ) return '[Bot] Baidu' ; elseif (strpos($t, 'yandex' ) ) return '[Bot] Yandex' ; elseif (strpos($t, 'sogou' ) ) return '[Bot] Sogou' ; elseif (strpos($t, 'exabot' ) ) return '[Bot] Exabot' ; elseif (strpos($t, 'msn' ) ) return '[Bot] MSN' ; // Common Tools and Bots elseif (strpos($t, 'mj12bot' ) ) return '[Bot] Majestic' ; elseif (strpos($t, 'ahrefs' ) ) return '[Bot] Ahrefs' ; elseif (strpos($t, 'semrush' ) ) return '[Bot] SEMRush' ; elseif (strpos($t, 'rogerbot' ) || strpos($t, 'dotbot') ) return '[Bot] Moz or OpenSiteExplorer'; elseif (strpos($t, 'frog' ) || strpos($t, 'screaming')) return '[Bot] Screaming Frog'; elseif (strpos($t, 'blex' ) ) return '[Bot] BLEXBot' ; // Miscellaneous elseif (strpos($t, 'facebook' ) ) return '[Bot] Facebook' ; elseif (strpos($t, 'pinterest' ) ) return '[Bot] Pinterest' ; // Check for strings commonly used in bot user agents elseif (strpos($t, 'crawler' ) || strpos($t, 'api' ) || strpos($t, 'spider' ) || strpos($t, 'http' ) || strpos($t, 'bot' ) || strpos($t, 'archive') || strpos($t, 'info' ) || strpos($t, 'data' ) ) return '[Bot] Other' ; return 'Other (Unknown)'; }
在这142个用户代理上进行了测试
上面的功能已通过以下142个常见的bot和人类用户代理进行了测试,所有功能均按功能进行了分类。
结果可以在此表中看到:
浏览器 | 比赛次数 | 全部百分比 |
---|---|---|
铬 | 51 | 35.92% |
火狐浏览器 | 26 | 18.31% |
边缘 | 3 | 2.11% |
苹果浏览器 | 14 | 9.86% |
IE浏览器 | 5 | 3.52% |
歌剧 | 1个 | 0.70% |
[Bot]百度 | 2 | 1.41% |
[Bot] Googlebot | 4 | 2.82% |
[Bot] Yahoo! lur | 2 | 1.41% |
[Bot]雄伟 | 3 | 2.11% |
[Bot] Bingbot | 2 | 1.41% |
[Bot] Ahrefs | 3 | 2.11% |
[Bot] MSN | 8 | 5.63% |
[Bot] Yandex | 1个 | 0.70% |
[Bot] Moz或OpenSiteExplorer | 2 | 1.41% |
[Bot]其他 | 9 | 6.34% |
[Bot] Pinterest | 2 | 1.41% |
[Bot] Facebook | 1个 | 0.70% |
[Bot] DuckDuckBot | 1个 | 0.70% |
[Bot] Exabot | 1个 | 0.70% |
[Bot]搜狗 | 1个 | 0.70% |
— | 142 | 100% |
对于要求最低精度的一般用例,这是功能性的PHP get_browser()替代方法。
本文:PHP获取浏览器信息, How to Parse a User Agent in PHP with Minimal Effort