CodeIgniter用スマートフォン判定ライブラリを作ってみた

CI2.x系の話題が活発な中、未だに1.7.3でコソコソやってる私です。
seezooもそのうち2系で動かしたいのですがね。

発端

「そろそろスマートフォンくらいは対応した方がいいかもね」という訳で、とりあえずアクセスしてきたユーザーのキャリアくらいは判定したいので、ライブラリを書いてみました。

やってることとコードとか

ガラケーのようにIPが云々とかそういうのがないので、単純にUser-Agentの文字列を見て判定するだけのものです。これだけだとライブラリである必要もないと思うので、キャリア名とOSのバージョンも取得するようにしてライブラリの体裁を整えたりしてます><

あ、Windows Mobileとかe-mobileの判定はできません。すいません。


以下、コードです。クラス名で悩みましたが、mobileipに習って「mobilesp」にしてみたり。ちょっと長いです。

_detect_sp();
}

// public methods ----------------------------------

/**
* get Accessed User-Agent
* @access public
* @return string
*/
public function get_agent()
{
return $this->_agent;
}

/**
* Access Agent is Smartphone carrier?
* @access public
* @return bool
*/
public function is_smartphone()
{
return $this->_is_sp;
}

/**
* get carrier OS name
* @access public
* @return string $OS
*/
public function os()
{
return $this->_sp_os;
}

/**
* get OS version
* @access public
* @retrurn float $os_version;
*/
public function version()
{
return $this->_os_version;
}

// version compare
public function version_compare($v, $cp = FALSE)
{
if ( $cp )
{
return version_compare($this->_os_version, $v, $cp);
}
else
{
return (version_compare($this->_os_version, $v));
}
}

// private methods ======================================================

/**
* _detect_sp
* SmartPhone carrier detection from User-Agent
* @access private
* @return void
*/
private function _detect_sp()
{
// get User-Agent
$ua = $this->_agent = (isset($_SERVER['HTTP_USER_AGENT']))
? $_SERVER['HTTP_USER_AGENT']
: FALSE;

if ( ! $ua )
{
return;
}

// detect sp
foreach ( $this->_sp_agents as $agent )
{
if ( strpos($ua, $agent) !== FALSE )
{
$this->_is_sp = TRUE;
$this->_sp_os = $agent;
// set carrier flag
$this->{'_is_' . strtolower($agent)} = TRUE;
break;
}
}

// If Smartphone access, detect OS version
if ( $this->_is_sp === TRUE )
{
$this->_detect_os_version();
}
}

/**
* Detect carrier OS version
* @access private
* @return void
*/
private function _detect_os_version()
{
if ( $this->is_android === TRUE )
{
$version = preg_replace('|(?:.+)Android ([0-9]+)\.([0-9]+)(?:.+)|', '$1.$2', $this->_agent);
}
else
{
switch ( $this->_sp_os )
{
case 'iPad':
$prefix = 'CPU';
break;
default:
$prefix = 'iPhone';
break;
}
$regex = '|(?:.+)' . $prefix . ' OS ([0-9]+)_([0-9]+)(?:.+)|';
$version = preg_replace($regex, '$1.$2', $this->_agent);
}

$this->_os_version = floatval($version);
}
}

やってる事は、

  1. User-Agentの値を取得
  2. 特定のスマートフォンの文字列があるかどうか判定
  3. あればOSのバージョンも取得(minorまで)

という感じです。未検証ですが、iOS2.x位からは取得できると思います。
(細かいUA文字列が分かりませんでした)


$this->{'_is_' . strtolower($agent)} = TRUE;とかキモチワルイですかね・・・。


あと、publicにis_androidなどのフラグを参照できるような簡単な形式なので、ちゃんとprivateにしてgetterを作った方がいいかもしれないです。

使い方とか

いつもどおりです。system/application/libraries/以下に配置して、


$this->load->library('mobilesp');
if ( $this->mobilesp->is_smartphone() === TRUE )
{
// スマフォ用の処理
if ( $this->mobilesp->is_android === TRUE )
{
// Android用の処理
if ( $this->mobilesp->version() > 1.6 )
{
// Android 1.6+用の処理
}
}
}

という感じで細かい制御ができますかね。
パパッと書いたものなので、ご自由にお使いください(責任は取れませんが><)
CI2.x系でも動くハズです。

感想

JavaScriptでもユーザーエージェントの判定はよくやりますが、いよいよキャリアが増えてきて手間がかかるようになりましたね・・・。
OSのバージョンを取るときに、iPhoneだと「iPhone OS 3_2_...」なのにiPadだと「CPU OS 3_2_...」となるのがちょっとよく分かりません。
もっと厳密な検出方法があればぜひ教えてください。