PHPでのUserAgentパーサ(ブラウザ判定)ライブラリは何がいいかベンチマークしてみた

ブラウザ種別、バージョン、OSなどを判定する「UserAgentパーサ」について、PHPで利用できる以下の5つをベンチマークしてみました。

ベンチマーク環境

  • XAMPP 1.8.3-4 for Linux (32bit)
    • PHP 5.5.11
      • Zend OPcache v7.0.4-dev

ベンチマーク結果

1つのUserAgent文字列からブラウザの種類などを判定する処理についてのベンチマークです。

処理時間:
timeベンチマークのグラフ

get_browser()関数が非常に遅いです。Crossjoin\Browscapとwoothee-phpはバーが見えませんが、それだけ速いということです。

最大使用メモリ:
memoryベンチマークのグラフ

browscap-phpが非常にメモリを必要とします。get_browser()関数がもっともメモリ消費が少ないです。

実際の数値:

{
  "crossjoin-browscap":{"time":0.00087594985961914,"memory":524288},
  "get_browser":       {"time":1.3734579086304,    "memory":262144},
  "browscap-php":      {"time":0.13754391670227,   "memory":8388608},
  "ua-parser":         {"time":0.0085458755493164, "memory":524288},
  "woothee":           {"time":0.0011758804321289, "memory":524288}
}

結論

軽量高速なのは、以下の2つです。

  • Crossjoin\Browscap
  • woothee-php

browscap.iniを利用するものがよい場合はCrossjoin\Browscapが、多言語対応あるいは日本製がよい場合はwootheeがよいでしょう。

(2014-11-07 追記) ベンチマーク結果が状況により大きく異なることがわかりましたので、【訂正】PHPでのUserAgentパーサ(ブラウザ判定)ライブラリのベンチマークを書きました。

ベンチマーク方法

ベンチマーク方法については、以下のリポジトリで公開してます。

実際の環境でベンチマークされることをお薦めします。

なお、UserAgent文字列を判定した結果はcacheフォルダ内のoutput-*.txtnormalize-output-*.txt(出力を標準化したもの)にあります。

判定結果は同じbrowscap.iniを使うものでさえも微妙に異なりますので、ご自分のニーズに合っているか確認し、必要な場合は、バグ修正(バグ報告)や自分用パーサを追加してから使うことをお薦めします。

Tags: php, benchmark

PukiWikiが7年ぶりにアップデートしてPHP 5.4/5.5に対応

PHP 5.4/5.5に対応したPukiWiki 1.5.0が2014/07/19にリリースされていました。

PukiWikiダウンロードページのスクリーンショット

はい、私も知りませんでした。ということでこの記事を書きました。

アップデートパッチもリリースされており、既存の1.4.7サイトを簡単にアップグレードできました。

素晴らしい!ありがとう、開発者のみなさん。

参考

Tags: php

FuelPHPのAgentクラスが重い問題と暫定的な対処方法

問題の所在

FuelPHPには、ブラウザ種別、バージョン、プラットフォーム、OSなどを取得するAgentクラスがありますが、その処理が重いという問題です。

どうやらAgentクラスが使用するブラウザ情報が記録された「browscap.iniファイル」が大きくなったことに比例して、処理が重くなってしまったようです。

以下のベンチマークはすべてMac OS X、MAMPでの結果です。LinuxではMacほど劇的には重くならないようです。

まず、FuelPHP 1.8/developをインストールしてWelcomeページを表示します。ページの下に処理時間とメモリ消費量が表示されます。

Welcomeページ:

Page rendered in 0.0093s using 0.438mb of memory.

次に、Welcomeコントローラのaction_index()メソッドにecho Agent::browser();を追加します。すると以下のように劇的に重くなりました。

WelcomeページにAgent::browser()を追加:

初回   Page rendered in 23.3956s using 112.952mb of memory.
二度目 Page rendered in 3.6668s using 44.826mb of memory.

Agentクラスの仕様

Agentクラスは、PHPのget_browser()関数が使えない場合、自力でBrowser Capabilities Projectからlite_php_browscap.iniファイル(現在、5,902 KB)をダウンロードしてパースして処理します。

Agentクラスを最初に使った時に、このダウンロードとパースの処理が実行されるため、時間がものすごくかかり、メモリも恐ろしく必要になります。

二度目以降は、パースした結果のキャッシュを使うため改善しますが、それでも非常に遅く、メモリも必要です。

キャッシュファイルは定期的に自動更新されます。

対処方法

1. get_brower()関数を使う

lite_php_browscap.iniファイルを手動でダウンロードし、php.iniのbrowsecapにパスを設定することで、get_browser()関数が使えるようになります。

この場合、browscap.iniファイルはcronなどで別途更新する必要があります。

php.ini

@@ -729,6 +729,7 @@

 [browscap]
 ;browscap = extra/browscap.ini
+browscap = /Users/kenji/work/fuelphp/fuel/app/tmp/browscap.ini

 [Informix]
 ; Default host for ifx_connect() (doesn't apply in safe mode).

browscap.iniファイルをPHPの内部関数でパース処理するため、その処理速度の向上が期待できますが、一方で毎回パースするという欠点もあります。

Page rendered in 3.5592s using 0.459mb of memory.

メモリ使用量が劇的に改善しましたが、処理速度はほとんど変わりませんでした。

2. browscap/browscap-phpを使う

内部関数を使っても速度があまり改善しなかったので、全く別の実装に置き換えるか、現状の処理をチューニングするしかありません。

しかし、完全に別の実装だと現状とのブラウザ判定の仕様の微妙な違いが結構生じるかも知れません。

幸い、Browser Capabilities Projectが公式にサポートしているbrowscap/browscap-phpというのがありました。

browscap/browscap-phpを使う処理に置き換えることで、メモリ消費量を極端には増やさずに、処理速度を向上させることができました。

Page rendered in 0.0513s using 6.456mb of memory.

まず、browscap/browscap-phpをComposerでインストールしてください。

--- a/composer.json
+++ b/composer.json
@@ -137,7 +137,8 @@
         "fuel/parser": "1.7.2",
         "fuelphp/upload": "2.0.2",
         "monolog/monolog": "1.5.*",
-        "michelf/php-markdown": "1.4.0"
+        "michelf/php-markdown": "1.4.0",
+        "browscap/browscap-php": "2.0.*"
     },
     "suggest": {
         "dwoo/dwoo" : "Allow Dwoo templating with the Parser package",

Agentクラスへの暫定的な修正パッチは以下になります。

--- a/classes/agent.php
+++ b/classes/agent.php
@@ -195,8 +195,15 @@ class Agent
            // try the build in get_browser() method
            if (ini_get('browscap') == '' or false === $browser = get_browser(static::$user_agent, true))
            {
+             // if it fails, use browscap/browscap-php
+             $cacheDir = APPPATH.'cache/fuel/agent';
+             $browscap = new \phpbrowscap\Browscap($cacheDir);
+             $browscap->remoteIniUrl = 'http://browscap.org/stream?q=Lite_PHP_BrowsCapINI';
+             $browscap->doAutoUpdate = false;
+             $browser = $browscap->getBrowser(static::$user_agent, true);
+
                // if it fails, emulate get_browser()
-               $browser = static::get_from_browscap();
+             //$browser = static::get_from_browscap();
            }

            if ($browser)
@@ -236,11 +243,11 @@ class Agent
    /**
     * Get the Browser Version
     *
-    * @return  string
+  * @return  float
     */
    public static function version()
    {
-       return static::$properties['version'];
+     return (float) static::$properties['version'];
    }

    // --------------------------------------------------------------------

この場合も、cronなどで以下の処理を実行し、browscap.iniファイルを別途更新する必要があります。

$cacheDir = APPPATH.'cache/fuel/agent';
$browscap = new \phpbrowscap\Browscap($cacheDir);
$browscap->remoteIniUrl = 'http://browscap.org/stream?q=Lite_PHP_BrowsCapINI';
$browscap->updateCache();

関連

Tags: fuelphp