のびーにょです。
今回は端末判定のプログラム。キャリアとか端末によって表示変えたいとか多々あると思いますので
携帯用ページを作成する場合必須と言っても過言ではないでしょう。
ってことで行ってみたいと思います。
/**
* 機種情報取得(おおよその端末データ取得)
* @auther のびー
*/
class MobileProfile{
static $ins= null;
// モバイルの情報
var $ua;
var $carrier;
var $minor;
var $width;
var $height;
var $htmltype;
var $uid;
//モバイルのプロフィール詳細
var $id;
var $device_name;
var $name;
var $maker;
var $series;
var $language;
var $language_ver;
var $browser_size;
var $display_size;
var $is_decome;
var $decome_ver;
var $connect_type;
var $color;
var $is_gif;
var $is_jpg;
var $is_png;
var $camera;
var $sub_camera;
var $appli;
var $appli_ver;
var $appli_size;
var $arrival_melody;
var $is_arrival_music;
var $is_arrival_full_music;
var $is_arrival_movie;
var $movie_type;
var $flash;
var $is_gps;
var $is_ssl;
var $mobile_customize;
var $device_cash;
var $release_date;
var $modify_deta;
var $mobileData;
/**
* CONSTRUCTOR
*/
function MobileProfile()
{
self::$ins =& $this;
self::$ins->setUa($_SERVER['HTTP_USER_AGENT']);
self::$ins->carrierSet();
self::$ins->setMobile();
}
/**
* 静的に呼び出された時に自身でインスタンスを取得する
*/
function getInstance(){
if (null === self::$ins){
new MobileProfile();
}
}
/**
* METHOD
*/
function carrierSet()
{
self::getInstance();
self::$ins->ins->carrier = "";
self::$ins->minor = "";
switch(TRUE){
//DOCOMO端末
case (self::$ins->isDocomo()):
self::$ins->setCarrier("DoCoMo");
break;
//SOFTBANK端末
case (self::$ins->isSoftbank()):
self::$ins->setCarrier("Softbank");
break;
//KDDI端末
case (self::$ins->isEzweb()):
self::$ins->setCarrier("au");
break;
//WILLCOM端末
case (self::$ins->isWillcom()):
self::$ins->setCarrier("WILLCOM");
break;
//googlebot判定
case (self::$ins->isGooglebot()):
self::$ins->setCarrier("GOOGLE");
break;
//i-robot判定
case (self::$ins->isIrobot()):
self::$ins->setCarrier("I-ROBOT");
break;
//検証用PC
default:
self::$ins->setCarrier('OTHER');
}
}
/**
* 端末の詳細情報をセット
*/
function setMobile()
{
self::getInstance();
switch(self::$ins->carrier){
case ('DoCoMo'):
preg_match("/^DoCoMo/[0-9.]{3}[ /]([^/( ]*)/",
self::$ins->ua,$ma);
$deviceName = $ma[1];
preg_match("/[(|/]c([0-9]{2,3})[)|;|/]/",
self::$ins->ua."/",$ma);
self::$ins->setDeviceCash($ma[1]*1000);
//下位端末レベルのFOMAはMOVA扱い
$lowar =
array("F2051"=>true,"N2051"=>true,
"P2102V"=>true,"F2102V"=>true,
"N2102V"=>true,"N2701"=>true,
"NM850iG"=>true,"N2001"=>true,
"N2002"=>true,"P2002"=>true,
"D2101V"=>true,"P2101V"=>true,
"SH2101V"=>true,"T2101V"=>true
);
//MOVA(一部FOMA端末を含む)
if(preg_match("/^DoCoMo/1.0/",self::$ins->ua) ||
isset($lowar[$deviceName])){
self::$ins->setMinor('MOVA');
if($ma[1] < '20'){
self::$ins->setWidth(120);
self::$ins->setHeight(180);
}else{
self::$ins->setWidth(200);
self::$ins->setHeight(180);
}
self::$ins->setHtmlType("HTML");
$buf = explode("/",self::$ins->ua);
self::$ins->setDeviceName($buf[2]);
//FOMA
}else{
self::$ins->setMinor('FOMA');
self::$ins->setWidth(240);
self::$ins->setHeight(320);
self::$ins->setHtmlType("XHTML");
self::$ins->setDeviceName($deviceName);
}
break;
case('au'):
//WAP1
if (preg_match("/^UP.Browser/",
self::$ins->ua)) {
self::$ins->setMinor('WAP1');
self::$ins->setHtmlType("HTML");
//WAP2
}else{
self::$ins->setMinor('WAP2');
self::$ins->setHtmlType("XHTML");
}
if(isset(
$_SERVER['HTTP_X_UP_DEVCAP_SCREENPIXELS'])){
list($w,$h) = split(',',
$_SERVER['HTTP_X_UP_DEVCAP_SCREENPIXELS']);
}else{
$w = 96;
$h = 96;
}
self::$ins->setWidth($w);
self::$ins->setHeight($h);
if(isset($_SERVER['HTTP_X_UP_DEVCAP_MAX_PDU'])){
self::$ins->setDeviceCash(
$_SERVER['HTTP_X_UP_DEVCAP_MAX_PDU']);
}else{
self::$ins->setDeviceCash(200000);
}
$n = explode("-",self::$ins->ua);
$device = explode(" ",$n[1]);
self::$ins->setDeviceName($device[0]);
break;
case('Softbank'):
if(preg_match("/^J-PHONE/2/",self::$ins->ua) ||
preg_match("/^J-PHONE/3/",self::$ins->ua)){
//C型
self::$ins->setMinor("TYPEC");
self::$ins->setHtmlType("HTML");
self::$ins->setDeviceCash(6000);
}elseif(
preg_match("/^J-PHONE/4/",self::$ins->ua)){
//P型
self::$ins->setMinor("TYPEP");
self::$ins->setHtmlType("HTML");
self::$ins->setDeviceCash(12000);
}else if(
preg_match("/^J-PHONE/5/",self::$ins->ua)){
//W型
self::$ins->setMinor("TYPEW");
self::$ins->setHtmlType("XHTML");
self::$ins->setDeviceCash(200000);
}else if(preg_match("/^MOT-/",self::$ins->ua) ||
preg_match("/^Vodafone//",self::$ins->ua) ||
preg_match("/^SoftBank//",self::$ins->ua)){
//3GC型
self::$ins->setMinor("3GC");
self::$ins->setHtmlType("XHTML");
self::$ins->setDeviceCash(300000);
}
if(isset($_SERVER['HTTP_X_JPHONE_DISPLAY'])){
list($w,$h) =
split('*',
$_SERVER['HTTP_X_JPHONE_DISPLAY']);
}else{
$w = 96;
$h = 96;
}
self::$ins->setWidth($w);
self::$ins->setHeight($h);
if(isset($_SERVER['HTTP_X_JPHONE_MSNAME'])){
self::$ins->setDeviceName(
$_SERVER['HTTP_X_JPHONE_MSNAME']);
}else{
self::$ins->setDeviceName("");
}
break;
case('OTHER'):
self::$ins->setMinor("PC");
self::$ins->setWidth(240);
self::$ins->setHeight(320);
self::$ins->setHtmlType("XHTML");
self::$ins->setDeviceCash(99999999);
$pc =
(isset($_REQUEST['pc']))?$_REQUEST['pc']:"";
self::$ins->setDeviceName("PC");
break;
}
}
/**
* 端末詳細データ取得(共通管理ファイルより)
* @param String device_name 端末ID
*/
function getMobileDetail($device_name=null)
{
self::getInstance();
if(!$device_name){
$device_name = self::$ins->device_name;
}
$dirfile = __FILE__;
$dir_name =
str_replace(basename(__FILE__),'',$dirfile);
$dir_name .= 'MobileProfileData/';
$carrier = self::$ins->carrier;
$carrier = strtolower($carrier);
//データ配列読み込み
if(file_exists($dir_name.$carrier.'Data.php')){
require_once $dir_name.$carrier.'Data.php';
if(!$this->mobileData){
$this->mobileData = $modile_detail;
}
}else{
return FALSE;
}
if(isset($this->mobileData[$device_name])){
foreach(
$this->mobileData[$device_name] as
$key => $val){
self::$ins->{$key} = $val;
}
if(isset(self::$ins->display_size)){
list(self::$ins->height,self::$ins->width) =
explode('*',self::$ins->display_size);
}
return $this->mobileData[$device_name];
//TODO
//すでにセットしてあるプロパティの値を上書き
}else{
return FALSE;
}
}
/**
* 公式UIDの取得
*/
function getPublicUid()
{
self::getInstance();
$uid = '';
switch(self::$ins->carrier){
case('DOCOMO'):
//CPの守秘義務に引っかかるかもなので消しときます
break;
case('EZWEB'):
//CPの守秘義務に引っかかるかもなので消しときます
break;
case('SOFTBANK'):
//CPの守秘義務に引っかかるかもなので消しときます
break;
default :
$uid = TESTUID; //定数で適当なUIDを定義
break;
}
return $uid;
}
/**
* 非公式UTN取得
*
*/
function getNotPublicUid()
{
$uid = FALSE;
switch(self::$ins->carrier){
case('DOCOMO'):
//FOMAの場合はFOMAカード識別番号を使う
if(ereg("DoCoMo/2.0.*;icc(.*))$",
self::$ins->ua,$regs1) == TRUE){
$uid = $regs1[1];
}elseif(ereg("DoCoMo/1.0/.*ser(.*)$",
self::$ins->ua,$regs2) == TRUE){
//movaの場合は端末製造番号を使う
$uid = $regs2[1];
}
break;
case('EZWEB'):
if(isset($_SERVER['HTTP_X_UP_SUBNO'])){
$uid = $_SERVER['HTTP_X_UP_SUBNO'];
}
break;
case('SOFTBANK'):
if(isset($_SERVER['HTTP_X_JPHONE_UID'])){
$uid =
substr($_SERVER['HTTP_X_JPHONE_UID'],1);
}elseif(isset($_SERVER["x-jphone-uid"])){
$uid = $_SERVER["x-jphone-uid"];
}
break;
default :
$uid = 'TESTUID';
break;
}
return $uid;
}
/**
* キャリア判定(DOCOMO)
*/
function isDocomo()
{
if(preg_match("/^DoCoMo/",self::$ins->ua)){
return TRUE;
}else{
return FALSE;
}
}
/**
* キャリア判定(SOFTBANK)
*/
function isSoftbank()
{
if(preg_match("/^J-PHONE/",self::$ins->ua) ||
preg_match("/^MOT-/",self::$ins->ua) ||
preg_match("/^Vodafone//",self::$ins->ua) ||
preg_match("/^SoftBank//",self::$ins->ua)){
return TRUE;
}else{
return FALSE;
}
}
/**
* キャリア判定(EZWEB)
*/
function isEzweb()
{
if(preg_match("/^UP.Browser/",self::$ins->ua) ||
preg_match("/^KDDI/",self::$ins->ua)){
return TRUE;
}else{
return FALSE;
}
}
/**
* キャリア判定(WILLCOM)
*/
function isWillcom()
{
return FALSE;
}
/**
* キャリア判定(GOOGLEBOT)
*/
function isGooglebot()
{
return FALSE;
}
function isIrobot()
{
return FALSE;
}
/**
* SETTER
*/
function setDeviceName($arg)
{
self::$ins->device_name = $arg;
}
function setHtmlType($arg)
{
self::$ins->htmltype = $arg;
}
function setUa($arg)
{
self::$ins->ua = $arg;
}
function setUid($arg)
{
self::$ins->uid = $arg;
}
function setDeviceCash($arg)
{
self::$ins->device_cash = $arg;
}
function setWidth($arg)
{
self::$ins->width = $arg;
}
function setHeight($arg)
{
self::$ins->height = $arg;
}
function setMinor($arg)
{
self::$ins->minor = $arg;
}
function setCarrier($arg)
{
self::$ins->carrier = $arg;
}
/**
* GETTER
*/
//自由に取得できるgeter
function get($arg)
{
self::getInstance();
if(!$arg){
return FALSE;
}
$ret = FALSE;
if(is_array($arg)){
foreach($arg as $val){
if(isset(self::$ins->{$val})){
$ret[$val] = self::$ins->{$val};
}
}
}else{
if(isset(self::$ins->{$arg})){
$ret = self::$ins->{$arg};
}else{
return FALSE;
}
}
return $ret;
}
}
長いですねぇ・・・
検索エンジン回りが常にFALSEなのはわざとです。
後、WILLCOMも未対応です。(サイトまだ作ってないので放置です)
クラスと同一ディレクトリ内に
『MobileProfileData』
ってディレクトリを作成して
その中に
auData.php ←au用の端末詳細情報配列
docomoData.php ←ドコモ用
otherData.php ←全キャリア用
softbankData.php←ソフトバンク用
って各ファイルを作成
ファイルの中身は
'SH904i' => array('id' => '395',
'device_name' => 'SH904i',
'name' => 'SH904i',
'carrier' => 'DoCoMo',
'maker' => 'SHARP',
'series' => 'FOMA904i',
'language' => 'XHTML',
'language_ver' => '2.1',
'browser_size' => '320*240',
'display_size' => '400*240',
'is_decome' => 'YES',
'decome_ver' => '3',
'connect_type' => 'WCDMA',
'color' => '262144',
'is_gif' => 'YES',
'is_jpg' => 'YES',
'is_png' => 'NO',
'camera' => '320',
'sub_camera' => '11',
'appli' => 'Java',
'appli_ver' => '5',
'appli_size' => '1024',
'arrival_melody' => '128',
'is_arrival_music' => 'YES',
'is_arrival_full_music' => 'YES',
'is_arrival_movie' => 'YES',
'movie_type' => '3gp',
'flash' => 'FL1.1',
'is_gps' => 'YES',
'is_ssl' => 'YES',
'mobile_customize' => '',
'device_cash' => '102400',
'release_date' => '2007-05-25 00:00:00',
'modify_deta' => '0000-00-00 00:00:00',
),・・・
って配列が大量に並んでます。
ちなみに弊社ではこの配列はDBで保存して端末が発売されるたびに更新かけてます
バッチ組んで各キャリアごとの上記ファイルを生成。
配列が大きすぎるとか思うなら世代ごとにさらに詳細にファイル分割してやればすむかなぁと思ってますよ。
んで、使い方
超簡単
//newしてやって(この時点で大雑把な一般的な数値が取得可能)
$LIB_MP = new MobileProfile();
//端末名称取得
$device_name = $LIB_MP->get("device_name");
//PCからのアクセスの場合、
//もしくは端末名が取れなかった場合(登録漏れ等)
if($device_name == 'PC' || $device_name == FALSE){
//SH904用の端末情報を取得する
$device_name = 'SH904i';
}
//で、詳細情報取得
$LIB_ARR_MP = $LIB_MP->getMobileDetail($device_name);
//とりあえず出力してみる
if($LIB_ARR_MP){
foreach($LIB_ARR_MP as $key => $val){
$str .= $key,":".$val."n";
}
}
上記をやってやれば
id :395
device_name :SH904i
name :SH904i
carrier :DoCoMo
maker :SHARP
series :FOMA904i
language :XHTML
language_ver :2.1
browser_size :320*240
display_size :400*240
is_decome :YES
decome_ver :3
connect_type :WCDMA
color :262144
is_gif :YES
is_jpg :YES
is_png :NO
camera :320
sub_camera :11
appli :Java
appli_ver :5
appli_size :1024
arrival_melody :128
is_arrival_music :YES
is_arrival_full_music:YES
is_arrival_movie :YES
movie_type :3gp
flash :FL1.1
is_gps :YES
is_ssl :YES
mobile_customize :
device_cash :102400
release_date :2007-05-2500:00:00
modify_deta :0000-00-0000:00:00
というような実行結果が得られると思います。
ってことで上記方法で端末判定行ってます。
DBさえ作ってしまえば端末発売毎の登録の煩わしさだけで済むので
普段の対応考えると管理画面を作っちゃえば割りと楽です。
PEAR::Net_UserAgent_Mobileなんかもありますが
端末情報がベタ書きな上に情報が足りない部分が多々あるので
自作クラスで対応しています。
後更新してないみたいですし。
0.31.0 2008-02-10 beta
↑この間1年更新がなかった(自分で端末情報更新してもいいと思いますけどね)
0.30.0 2007-02-20 beta
0.29.0 2006-11-07 beta
0.28.0 2006-09-25 beta
0.27.0 2006-07-13 beta
0.26.0 2006-02-01 beta
最近RC1が出たみたいですけどね
端末情報は色々な企業さんが販売してますね。
今までに発売した端末情報すべてとか。
買い切りだと4,5万だと思うので、携帯サイトをがっつりやる場合は買って損はないと思います。
後は発売される度に管理画面から追加って形取ればそこまでめんどくさくないですし。
公式CP(IP)やってると詳細情報を手に入れることができるのでそのデータを自社内だけだと存分に活用できるのも含めて
自社オリジナルクラス使ってます。
色々なやり方あるとは思いますが、弊社の一部のコンテンツはこんな感じで運用しております
のびーにょ PHP, キャリア, 携帯電話