※ パクレゼルヴではWeb開発エンジニアを大募集中!詳細はこちら

Archive

Archive for the ‘キャリア’ Category

携帯電話の特定のキャリアではおかしくなる例  

2009/11/24 火曜日 11:02:53

またまた時間が空いてしまいました。

お久しぶりです。
のびーにょです。

さて、表題の件

ラジオボタンがまともに動作しない場合

ドコモ、ソフトバンクの2キャリアでは正常に動作します。
また、PC等の一般的なブラウザでも正常に動作します。
しかし、auのみ正常に動作しません。

以下サンプル
html

<form action="http://example.com" method="POST">
	<input type="hidden" name="jb" value="test2_ez"/>
	<input type="radio" name="mail_receive" value="ALL"/>ALL<br />
	<input type="radio" name="mail_receive" value="YES" checked/>YES<br />
	<select name="s_hour">
		<option value="00">00</option>
		<option value="01">01</option>
	</select>
	<br />
	<input type="radio" name="mail_receive" value="NO"/>NO<br />
	<div style="text-align:center;">
		<input type="submit" name="regist" value="設定する" /><br />
	</div>
</form>

以下のような表示になります。

20091118161336

複数個のラジオボタンがあってセレクトボックスがある普通のフォームです。

ラジオボタンのグループはすべて同じグループです。

au以外の端末の場合は正常に動作しますが、
auの一部の機種(かなり多そうな感じではありますが)では正常に動作しません。

以下の画像のようになります。
20091118161337

ラジオボタンが複数個選択できてしまいます。
ALLとNOの2個のラジオボタンにチェックが入ってしまう状態です。

もう一度言いますが、グループは同一です。

これでPOSTしてしまうとセレクトボックスの下側(NOの方)が優先されてしまい、
上にあるALL、YESが2度と選択できなくなります。

解決方法は以下のhtml

<form action="http://example.com" method="POST">
	<input type="hidden" name="jb" value="test2_ez"/>
	<input type="radio" name="mail_receive" value="NO"/>NO<br />
	<input type="radio" name="mail_receive" value="ALL"/>ALL<br />
	<input type="radio" name="mail_receive" value="YES" checked/>YES<br />
	<select name="s_hour">
		<option value="00">00</option>
		<option value="01">01</option>
	</select>
	<br />
	<div style="text-align:center;">
		<input type="submit" name="regist" value="設定する" /><br />
	</div>
</form>

ラジオボタンを一か所にまとめてしまい、間にセレクトボックスを挟まないようにします。

HTMLファイルを同一にて記述する場合や、1キャリアのソースをコンバートする場合は注意が必要です。

ドコモの端末で動くからOKとかは危険なので気を付けてください。

セレクトボックスを指定したのにラジオボタンになる

以下のようなHTMLはauでは

次のページにすらいけなくなるので注意が必要です。

<div style="text-align:center;">
	<form action="http://example.com" method="POST">
</div>
	<input type="hidden" name="jb" value="test2_ez"/>
	<select name="s_hour">
		<option value="00">00</option>
		<option value="01">01</option>
	</select>
	<div style="text-align:center;">
		<input type="submit" name="regist" value="設定する" /><br />
	</div>
	</form>

※意図的に上段のdivの<を大文字にしています。
syntaxHighlighterが勝手にformを補完するようなので。。。

HTML的にどうなんだという部分はありますが、このHTMLでも

PCのブラウザやDoCoMo,SoftBankの携帯端末だとまともに表示され、POST,GETが可能です。

普通にこう見えます。
20091118161338

しかしやはりEzWeb ここでもやってくれます。

以下の画像や
20091118161339
こんなことになります。
20091118161340

この状態だとどのボタンを押しても前の画面に戻ります。

次のページへ移動はできません。

解決方法は以下

<form action="http://example.com" method="POST">
	<input type="hidden" name="jb" value="test2_ez"/>
	<select name="s_hour">
		<option value="00">00</option>
		<option value="01">01</option>
	</select>
	<div style="text-align:center;">
		<input type="submit" name="regist" value="設定する" /><br />
	</div>
</form>

まぁ、divの指定が悪いのは見ての通りなので消してやるか、formすべてを囲ってやればOK

最近HTMLの話ばかりでプログラムに関することはほぼ書いてない気がします。
というか、投稿の間隔が空きすぎていますね・・・

なるべく書くようにします。。。

のびーにょ HTMLとか, キャリア, 携帯電話

携帯電話のキャリア毎のHTMLの解釈の差を吸収する  

2009/7/31 金曜日 18:00:20

お久しぶりです

のびーにょです。

さて、携帯電話のHTMLに関するお話でも。

<div>
	<div style = "background-color:#FFAAAA">TITLE</div>
	<div style = "background-color:#CCCCCC">
		コンテンツ<br />
		コンテンツ<br />
		コンテンツ<br />
	</div>
</div>

ってな感じで書いた場合
ドコモ端末だと
block_dc1
ってな感じで
au端末だと
block_au1
こんな感じになっちゃいます。

divタグとdivタグの間に隙間ができてしまって、何ともみっともないことになります。
CSSでどうにかして隙間を埋めてしまいたいのですが、これはほぼ不可能です。

で、これ実はHTMLの書き方だけで同じようなレイアウトになります。

それが以下

<div>
	<div style = "background-color:#CCCCCC">
		<div style = "background-color:#FFAAAA">TITLE</div>
		コンテンツ<br />
		コンテンツ<br />
		コンテンツ<br />
	</div>
</div>

htmlの概念的にはよくはないんですけどね
イメージとしては以下のような感じ
灰色の部分がコンテンツのdivでピンクの部分がタイトルのdiv
s2

普通のイメージは
s1
こんな感じで、タイトルとコンテンツ部分の隙間をなくすようなCSSを書いたりしますが
携帯の場合、サポートしていない場合が多いです。

上記のHTMLで書いた場合は
ドコモ
block_dc2

au
block_au2
ってな感じで表示されて両方同じ見え方になります


もう一個例を出しましょう
1エリアごとに交互に色を入れ変えたい場合
良くあるのがランキングとか一覧表示とか
そのあたり。

<div>
	<div style = "background-color:#FFAAAA">aaaaa</div>
	<div style = "background-color:#CCCCCC">aaaaa</div>
	<div style = "background-color:#FFAAAA">aaaaa</div>
	<div style = "background-color:#CCCCCC">aaaaa</div>
	<div style = "background-color:#FFAAAA">aaaaa</div>
	<div style = "background-color:#CCCCCC">aaaaa</div>
	<div style = "background-color:#FFAAAA">aaaaa</div>
	<div style = "background-color:#CCCCCC">aaaaa</div>
	<div style = "background-color:#FFAAAA">aaaaa</div>
</div>

こんな感じで書きたくなりますよね。
でも、こう書くと
list_dc1
ドコモは問題ない

list_au1
でもやっぱりauで問題が出ます。

これも、以下のようなイメージでHTMLを記述することでドコモと同じように見せることが可能です。

s4

htmlはこんな感じで

<div style = "background-color:#FFAAAA">
	aaaaa
	<div style = "background-color:#CCCCCC">aaaaa</div>
	aaaaa
	<div style = "background-color:#CCCCCC">aaaaa</div>
	aaaaa
	<div style = "background-color:#CCCCCC">aaaaa</div>
	aaaaa
	<div style = "background-color:#CCCCCC">aaaaa</div>
	aaaaa
</div>

そうすると、ドコモ、auが以下のように同じように見えます。
list_dc2
list_au2

まぁ、そんな感じで一つ下のdiv要素の色を上の階層に持ってきてやると意図しない隙間をなくすことができます。


色々めんどくさいですけど、結構HTMLだけでも表現できたり色々便利
例えば、以下のような色分けを隙間なく表示したいときとかも
s5

<div style = "background-color:#FFF0E5">
	<div style = "background-color:#FFD0BF">
		<div style = "background-color:#FDDAF0">
			<div style = "background-color:#FABBEA">
				<div style = "background-color:#A3F27B">
					<div style = "background-color:#C0E9FA">
						<div style = "background-color:#FFF09C">
							<div style = "background-color:#F4DA67">
								<div style = "background-color:#ccccff">
									<div style = "background-color:#9966ff">
										<div style = "background-color:#FFB6C1">
											<div style = "background-color:#FF3333">
												<a href ="">
												<span style = "font-size:medium">
												かおもじ友の会</span>
												</a>
												<br />
											</div>
											┗3000個以上の顔文字やAAを収録!オリジナルな作品も投稿できてみんなで共有できちゃう!
										</div>
										<a href ="">
										<span style = "font-size:medium">
										あなたの過ごした時間</span>
										</a>
										<br />
									</div>
									┗時は金なり。あなたが生まれて今日まで過ごした「時間」について色々な角度から詳しく知りたいと思いませんか?
								</div>
								<a href ="">
								<span style = "font-size:medium">
								ちょいネタフーズ</span>
								</a>
								<br />
								</div>
								┗お手軽料理からネタ料理まで、レシピをケータイで簡単検索!オリジナルレシピも投稿しよう
							</div>
							<a href ="">
							<span style = "font-size:medium">
							切なさ成分解析</span>
							</a>
							<br />
						</div>
						┗身近な素材に含まれる「切なさ」を解析。結果を読むと思わず切なくなるかも?
				</div>
				<a href ="">
				<span style = "font-size:medium">
				明日に向かって叫べ</span>
				</a>
				<br />
			</div>
			┗魂の叫びに賞金がかかります!アナタも賞金首となって追われてみる?
		</div>
		<a href ="">
		<span style = "font-size:medium">
		NAME&nbsp;de&nbsp;QUEST</span>
		</a>
		<br />
	</div>
	┗あなたは世界を救う勇者となって、日頃の鬱憤を晴らすべく魔王に戦いを挑みます!
</div>

のびーにょ HTMLとか, Tips, キャリア, 携帯電話

自社で使っているフレームワークの便利な機能  

2008/9/30 火曜日 21:11:36

お疲れ様です。

のびーにょです。

表題の件
簡単に説明すると社内PCからのアクセス時とモバイル端末からのアクセス時で表示が変わります
え?普通ですって?

まぁ普通です
以下画像を見てください。
lab1.jpg
こんな感じでPCでデバッグできるようになっています。

最近はめっきり減りましたが昔はHTMLの表示部分も意識して作っていたので、フレームワークの記述ルールに従えば
一つのソースでHTMLとXHTMLと表示が変わっていました。(サンプルの画像のソースはXHTMLのみの記述)

モバイルからアクセスした場合はきちんとモバイルのみが出力されてるわけです。

んで、右側

こっちはデバッグ領域
直接画面に出力するわけじゃないので実運用中でもある程度のデバッグが可能です。

設定ファイルを書き換えればデバッグ内容をログに出力することもでき、携帯からアクセスしてもデバッグできます。

絵文字もフレームワーク規定の書き方をすれば当然3キャリアごとの出力です。

こんなの使ってても、結局最後は端末でデバッグしますが、開発中のデバッグはかなり楽なので結構いい感じです。

のびーにょ PHP, キャリア, システム, 携帯電話

モバイル(携帯)でのHTTPSでの通信時に注意したいこと  

2008/6/11 水曜日 15:16:56

こんにちは
のびーにょです。

さて、表題の件について少し書きますか

ドコモの端末でiモードIDが取得できるようになったのがつい最近ですよね

さて、そのiモードIDですが、HTTPS通信時には取得できません。

何故か 理由は以下
・ドコモの端末にSSL証明書が標準でインストールされている
・暗号化はゲートウェイでなく端末上で行われてから送信される
・iモードIDはドコモのゲードウェイで付与される物なので暗号化通信時にはゲートウェイで『guid=on』が付いているかどうか判断できない

ってことです。

ちなみに公式にもきちんとそのあたりは明記されてます。
小さいけど。

ちなみにHTTPS時に『guid=on』ってやっても
X-DCMGUIDヘッダは当然空です

で、ならどうやってHTTPS時に端末を識別するかってことですね。
ちょっと凝ったサイト作るとHTTPSなんて割と使う可能性が高いので知らない人は注意です。

別途セッションID生成してiモードIDにひもづけてサーバ側で保存。
必要情報を別途付与したセッションIDより引き出すって感じでしょうか。

もしくはHTTPS時にはiモードIDを暗号化して『guid=on』ではなく『guid=XXXXXXX(暗号化した値を直接引数として渡す)』とかで渡して、受け取った方で複合化したIDを利用 とかですかね

あんまりどっちも変わらないですけど
どっちもハイジャックの危険性ありますよね
URL保存してれば ですけど

通信途中のデータは盗聴などの危険性はないと思いますが(HTTPS時なので)URLパラメータにてGETで送信した場合はユーザが任意に保存できる可能性があるということです。

できる限りそういう場面ではPOSTを利用し、ユーザの目に触れないようにしたいものですね。

HTMLソース見られれば一緒ですけど。
その時点のURLをユーザが公開するかしないかはそのユーザの責任なのでこちらの意図する部分ではありませんが、なるべくそうなっても大丈夫なようにワンタイムセッション的なものを工夫してあげた方が良いと思います。

ちなみに公式のuid取得部分でも似たようなものがあります。
それも当然HTTPS時には取得できません。

まぁ端末送信時より暗号化しているってことなのでしょうがないっちゃしょうがないんですけどね・・・

HTTPSで思い出しましたが携帯電話で利用する場合のSSL証明書って一昔前はVeriSignのものしか使えませんでした。
何故か
ふるーーーーーい端末ではそこ以外のルート証明書を搭載していなかったから

最近だと割と大丈夫だと見た記憶があります。

まぁ、その辺も含めて携帯電話のWebってそれなりに奥が深いんですよ?

のびーにょ Tips, キャリア, 携帯電話

モバイル端末の判定[USER AGENT]  

2008/5/26 月曜日 20:14:48

のびーにょです。

今回は端末判定のプログラム。キャリアとか端末によって表示変えたいとか多々あると思いますので
携帯用ページを作成する場合必須と言っても過言ではないでしょう。
ってことで行ってみたいと思います。

/**
 * 機種情報取得(おおよその端末データ取得)
 * @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, キャリア, 携帯電話