PHPでブラウザ判定するにはget_browser()というものがあるけどクソ重たいので軽くする努力をしてみた

$HTTP_USER_AGENTでスマフォ判定をする、という記事は山ほどあるが、あれ、確かPHPに専用機能があった気が。

get_browser()ってあったよね

http://php.net/manual/ja/function.get-browser.php

あったあった。

Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3

Array
(
    [browser_name_regex] => ^mozilla/5\.0 (windows; .; windows nt 5\.1; .*rv:.*) gecko/.* firefox/0\.9.*$
    [browser_name_pattern] => Mozilla/5.0 (Windows; ?; Windows NT 5.1; *rv:*) Gecko/* Firefox/0.9*
    [parent] => Firefox 0.9
    [platform] => WinXP
    [browser] => Firefox
    [version] => 0.9
    [majorver] => 0
    [minorver] => 9
    [cssversion] => 2
    [frames] => 1
    [iframes] => 1
    [tables] => 1
    [cookies] => 1
    [backgroundsounds] =>
    [vbscript] =>
    [javascript] => 1
    [javaapplets] => 1
    [activexcontrols] =>
    [cdf] =>
    [aol] =>
    [beta] => 1
    [win16] =>
    [crawler] =>
    [stripper] =>
    [wap] =>
    [netclr] =>
)

めっちゃ頼もしいことが書いてある。

試してみる

getbr.php
<?php

print_r(get_browser());
$ bash -x getbr.sh
+ HTTP_USER_AGENT='Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3'
+ php -q getbr.php
PHP Warning:  get_browser(): browscap ini directive not set in $HOME/getbr.php on line 6
bool(false)

ん?false おっといけねえ、browscap.iniというやつが必要らしい。http://browscap.org でもらってくる。

browcap.ini を調達する。は?448034行??

$ aria2c "https://browscap.org/stream?q=PHP_BrowsCapINI"

なんとファイルサイズ14MB。行にして448万。なんだこれ。嫌な予感がする。
本来は php.ini でbrowcapセクションの設定が必要だが、コマンドライン指定で今回は凌ぐ。

チェックだけで0.6秒て

$ bash -x getbr.sh
+ HTTP_USER_AGENT='Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3'
+ time php -dbrowscap=$HOME/php_browscap.ini -q getbr.php
0.60user 0.05system 0:00.66elapsed 98%CPU (0avgtext+0avgdata 52860maxresident)k
0inputs+0outputs (0major+8090minor)pagefaults 0swaps

出たことは出たが、0.6秒もかかっとるがな。
このままでは実用にはならない。セルフDoS攻撃になってしまう。

遅い原因は、php_browscap.iniを読めば明らかだ。$HTTP_USER_AGENTに対するパターンマッチ定義が大量にある。

減らしてみる

ということは、必要最小限にすれば早くなるのではないか?

バッサリ削ってみた。

https://gist.github.com/kamawanu/48c8bf867c68f235f2189ff7ce96f636#file-php_browscap-ini

※試行錯誤中はブラウザで確認してたので、chromebook/iPhone/androidのみ対応。下記スクリプトはその結果を再現するもの。

$ bash -x getbr.sh
+ HTTP_USER_AGENT='Mozilla/5.0 (X11; CrOS armv7l 10176.76.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.190 Safari/537.36'
+ time php -dbrowscap=$HOME/php_browscap.ini -q getbr.php
stdClass Object
(
    [browser_name_regex] => ~^mozilla/5\.0 \(.*cros.*\) applewebkit.* \(.*khtml.*like.*gecko.*\) chrome/64\.0.*safari/.*$~
    [browser_name_pattern] => Mozilla/5.0 (*CrOS*) applewebkit* (*khtml*like*gecko*) Chrome/64.0*Safari/*
    [parent] => Chrome 64.0
    [platform] => ChromeOS
    [comment] => Chrome 64.0
    [browser] => Chrome
    [browser_maker] => Google Inc
    [version] => 64.0
    [majorver] => 64
    [device_type] => Desktop
    [device_pointing_method] => mouse
    [minorver] => 0
    [ismobiledevice] => 
    [istablet] => 
    [crawler] => 
)
0.03user 0.02system 0:00.06elapsed 96%CPU (0avgtext+0avgdata 17632maxresident)k
0inputs+0outputs (0major+1100minor)pagefaults 0swaps

+ HTTP_USER_AGENT='Mozilla/5.0 (Linux; Android 7.1.1; XT1635-02 Build/NPNS26.118-22-2-17; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/65.0.3325.109 Mobile Safari/537.36'
+ time php -dbrowscap=$HOME/php_browscap.ini -q getbr.php
stdClass Object
(
    [browser_name_regex] => ~^mozilla/5\.0 \(.*linux.*android.7\.1.*\).*applewebkit.*\(.*khtml.*like.*gecko.*\).*version/4\.0.*chrome.*mobile.*safari.*$~
    [browser_name_pattern] => Mozilla/5.0 (*Linux*Android?7.1*)*applewebkit*(*khtml*like*gecko*)*Version/4.0*Chrome*Mobile*Safari*
    [parent] => Android WebView 4.0
    [comment] => Android WebView 4.0
    [browser] => Android WebView
    [browser_maker] => Google Inc
    [version] => 4.0
    [majorver] => 4
    [platform] => Android
    [ismobiledevice] => 1
    [device_type] => Mobile Phone
    [device_pointing_method] => touchscreen
    [minorver] => 0
    [istablet] => 
    [crawler] => 
)
0.03user 0.01system 0:00.06elapsed 91%CPU (0avgtext+0avgdata 17600maxresident)k
0inputs+0outputs (0major+1101minor)pagefaults 0swaps

+ HTTP_USER_AGENT='Mozilla/5.0 (iPhone; CPU iPhone OS 11_0_3 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A432 Safari/604.1'
+ time php -dbrowscap=$HOME/php_browscap.ini -q getbr.php
stdClass Object
(
    [browser_name_regex] => ~^mozilla/5\.0 \(.*cpu iphone os .* like mac os x.*\).*applewebkit.*\(.*khtml.*like.*gecko.*\).*version/11\.0.*safari/.*$~
    [browser_name_pattern] => Mozilla/5.0 (*CPU iPhone OS * like Mac OS X*)*applewebkit*(*khtml*like*gecko*)*Version/11.0*Safari/*
    [parent] => Mobile Safari 11.0
    [comment] => Mobile Safari 11.0
    [browser] => Safari
    [browser_maker] => Apple Inc
    [version] => 11.0
    [majorver] => 11
    [platform] => iOS
    [ismobiledevice] => 1
    [device_type] => Mobile Device
    [device_pointing_method] => touchscreen
    [minorver] => 0
    [istablet] => 
    [crawler] => 
)
0.02user 0.01system 0:00.04elapsed 95%CPU (0avgtext+0avgdata 17688maxresident)k
0inputs+0outputs (0major+1101minor)pagefaults 0swaps
$

0.02秒。これなら頻度を減らせば実用圏内かなー。

結論

  • 使えなくはないけど、努力に見合わない気が
  • じゃあ、preg_match( $HTTP_USER_AGENT ) で良いよね
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.