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

FuelPHPのAgentクラスが重い問題と暫定的な対処方法」の改訂版です。

問題の所在

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

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

詳細は、FuelPHPのAgentクラスが重い問題と暫定的な対処方法を参照してください。

前回は、browscap/browscap-phpを使う方法を書きましたが、その後も「browscap.iniファイル」が大きくなっており、更新時のメモリ消費が半端なく大きくなってしまっています。

対処方法

今回、新たに別のライブラリを使います。

3. Crossjoin\Browscapを使う

Crossjoin\Browscapは、「browscap.iniファイル」を利用してエージェントの判定をするライブラリです。

高速であり、メモリ消費を抑えた実装になっています。

現状では、Welcomeコントローラのaction_index()メソッドにecho Agent::browser();を追加すると、browscap-phpでは以下のようになりました(Mac OS Xでの結果)。

Page rendered in 0.0709s using 8.934mb of memory.

これが、Crossjoin\Browscapでは、以下のように改善されました。

Page rendered in 0.0656s using 0.59mb of memory

さらに詳細なライブラリのベンチマーク結果は以下を参照してください。

インストール方法

まず、Crossjoin\BrowscapをComposerでインストールしてください。

--- a/composer.json
+++ b/composer.json
@@ -24,7 +24,8 @@
         "fuel/parser": "dev-1.8/develop",
         "fuelphp/upload": "2.0.2",
         "monolog/monolog": "1.5.*",
-        "michelf/php-markdown": "1.4.0"
+        "michelf/php-markdown": "1.4.0",
+        "crossjoin/browscap": "1.0.*"
     },
     "require-dev": {
         "fuel/docs": "dev-1.8/develop"

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

--- a/classes/agent.php
+++ b/classes/agent.php
@@ -195,8 +195,33 @@ 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 Crossjoin\Browscap
+             $cacheDir = APPPATH.'cache/fuel/agent';
+             \Crossjoin\Browscap\Cache\File::setCacheDirectory($cacheDir);
+             \Crossjoin\Browscap\Browscap::setDatasetType(\Crossjoin\Browscap\Browscap::DATASET_TYPE_SMALL);
+             $updater = new \Crossjoin\Browscap\Updater\None();
+             \Crossjoin\Browscap\Browscap::setUpdater($updater);
+             $browscap = new \Crossjoin\Browscap\Browscap();
+             $browser = (array) $browscap->getBrowser(static::$user_agent)->getData();
+             // fix any type issues
+             foreach ($browser as $var => $value)
+             {
+                 if (is_numeric($value))
+                 {
+                     $browser[$var] = $value + 0;
+                 }
+                 elseif ($value == 'true')
+                 {
+                     $browser[$var] = true;
+                 }
+                 elseif ($value == 'false')
+                 {
+                     $browser[$var] = false;
+                 }
+             }
+
                // if it fails, emulate get_browser()
-               $browser = static::get_from_browscap();
+//               $browser = static::get_from_browscap();
            }

            if ($browser)

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

タスクは以下のようになります。

<?php

namespace Fuel\Tasks;

class Agent
{
    public static function update()
    {
        $cacheDir = APPPATH.'cache/fuel/agent';
        \Crossjoin\Browscap\Cache\File::setCacheDirectory($cacheDir);
        \Crossjoin\Browscap\Browscap::setDatasetType(\Crossjoin\Browscap\Browscap::DATASET_TYPE_SMALL);
        $browscap = new \Crossjoin\Browscap\Browscap();
        $settings = $browscap->getBrowser()->getData();
    }
}

また、Crossjoin\Browscapは、更新時のメモリ消費も抑えるような実装になっており、 browscap-phpで381,943,808バイト必要だったものが、Crossjoin\Browscapでは62,652,416バイト(約1/6)で済みました(CentOS 6.5 64bitでの結果)。

まとめ

get_browser()関数互換のbrowscap.iniを使ったユーザのブラウザ判定には、Crossjoin\Browscapをお薦めします。

関連

Date: 2015/02/26

Tags: fuelphp