CakePHP::携帯の端末ID(uid)で「かんたんログイン」

12月 13th, 2007 admin

よく考えたらCakePHPとは直接関係無いか・・・
usersテーブルでユーザ管理している場合のuidのセットとアンセット例
mobile_codeというカラムにuidを保存します。

uidの取得にはPEAR::Net_UserAgent_Mobileを使用しました。
説明不十分なところが多いですが脳内補完でお願いします。

user_controller.php

function add_mobile_code(){
	//セット
	if(isset($this->data['set'])){
		$this->cleanUpFields();

		$serialNumber = $this->_getMobileUID();

		$this->data['User']['id'] = $this->current_user_id;
		$this->data['User']['mobile_code'] = $serialNumber;
		if (empty($this->data['User']['mobile_code']) || $this->User->save($this->data)) {
			$this->Session->setFlash('かんたんログインを設定しました。');
		} else {
			$this->Session->setFlash('かんたんログインを設定できませんでした。');
		}
			$this->redirect('/users/add_mobile_code');
	}

	//解除
	if(isset($this->data['unset'])){
		$this->cleanUpFields();

		$this->data['User']['id'] = $this->current_user_id;
		$this->data['User']['mobile_code'] = "";
		if ($this->User->save($this->data)) {
			$this->Session->setFlash('かんたんログインを解除しました。');
		} else {
			$this->Session->setFlash('かんたんログインを解除できませんでした。');
		}
			$this->redirect('/users/add_mobile_code');
	}
}

function _getMobileUID(){
	//個別IDを取得
	vendor('PEAR/Net/UserAgent/Mobile');
	$mobObj = Net_UserAgent_Mobile::singleton();
	// get serial number
	$serialNumber = "";
	switch( true )
	{
	  case ($mobObj->isDoCoMo()):   // DoCoMoかどうか
	  case ($mobObj->isVodafone()): // softbankかどうか
		 if( method_exists( $mobObj, "getSerialNumber" ) )
			$serialNumber = $mobObj->getSerialNumber();
		 break;
	  case ($mobObj->isEZweb()):    // ezwebかどうか
		 if( isset( $_SERVER['HTTP_X_UP_SUBNO'] ) )
			$serialNumber = $_SERVER['HTTP_X_UP_SUBNO'];
		 break;
	  default:
		 break;
	}

	return $serialNumber;
}

add_mobile_code.thtml

<h2>かんたんログインの設定</h2>
<p>携帯の端末情報を登録することで次回ログインからIDとパスワードを省略できます</p>
<hr />
現在は「<?php if(!empty($me['User']['mobile_code'])){ ?>設定済み<?php }else{ ?>未設定<?php } ?>」です。

<hr />

<form action="<?php echo $html->url('/m/users/add_mobile_code/'); ?>" method="post" utn>

<?php echo $html->hidden("set");?>
<div class="submit">
	<?php echo $html->submit('かんたんログインを設定する');?>
</div>
</form>

<form action="<?php echo $html->url('/m/users/add_mobile_code/'); ?>" method="post" utn>

<?php echo $html->hidden("unset");?>
<div class="submit">
	<?php echo $html->submit('かんたんログインを解除する');?>
</div>
</form>
<ul class="actions">
<li><?php echo $html->link('トップに戻る', '/m/orders/add/');?></li>
</ul>

CakePHP::DoCoMoの端末ID(utn)取得で認証エラー

12月 13th, 2007 admin

CakePHPで構築したサイトで、DoCoMoの端末で端末ID(UID?)を取得しようとしても認証エラーで取得が出来ない・・・
原因は認証のところで$this->Session->valid();とセッションの正当性のチェックをしていたこと。

端末IDを取得するとユーザーエージェントが変更されるので、直前のアクセスと現在のアクセスでユーザーエージェントが違うということになり「セッションハイジャックじゃね?」と認証エラーになっていました。

あと少しはまったのが、CakePHPにおいてini_set(‘session.use_trans_sid’, 1);が効かない件で、よく読んでみたら/cake/libs/session.phpの__initSession()でini_set(‘session.use_trans_sid’, 0);に設定されていましたので/cake/libs/controllers/components/session.phpを/app/controllers/components/session.phpにコピーして、メソッドを上書きして解決しました。

↓こんな感じでモバイルとそうでないのを分けた

case 'php':
	if (!isset($_SESSION)) {
		if (function_exists('ini_set')) {
			if(defined('MOBILE')){
				ini_set('session.use_trans_sid', 1);
			}else{
				ini_set('session.use_trans_sid', 0);
			}
			ini_set('session.name', CAKE_SESSION_COOKIE);
			ini_set('session.cookie_lifetime', $this->cookieLifeTime);
			ini_set('session.cookie_path', $this->path);
		}
	}
break;

リニアサーチ

12月 5th, 2007 admin

最初に扱うのはリニアサーチという、配列なら先頭から順番に探索していくという最も単純なアルゴリズムです。
ソートのアルゴリズムで一番単純なバブルソートがバカ扱いされていたのに対して、こちらのアルゴリズムは「応用範囲が広く、意外と頻繁に利用されている」と紹介されています。

番兵(番人)

普通にwhileで書こうと思うと

while (探索の数字ではない) and (配列の最後でない)
   i += 1
end

みたいな感じで、常に配列の最後まで探索したかどうかを調べる必要があると思う(var.eachとかは自動でやってくれる)
しかも毎回毎回それを調べるのはコストがかかる、そのコストをなくすのが番兵である。
どういうことかというと、あらかじめ配列の最後に探索する数字をいれてから探索を行う。こうすれば必ず最後には探索する数字が見つかる。
探索が終わってからキーの値が最後の数字なら、それはNOT FOUNDだったということになる。
この説明では分からない人が多いと思うので「番兵 – Wikipedia」とかをみて欲しい。

コード

#リニアサーチ(番兵版)
require 'pp'
before = Time.now
t = Time.now
srand(t.sec ^ t.usec ^ Process.pid)

#探索する要素数
Num = 10000

def linearSearch(target,a)
	n = 0
	t = a[Num-1]
	a[Num-1] = target
	while target != a[n]
		n+=1
	end

	a[Num-1] = t
	if n < (Num-1)
		return n
	end
	if target == t
		return n
	end

	return -1
end

#ランダムな値の入った配列を作成
a = Array.new
Num.times{|i|
	a.push i
}

#探す数値
target = rand(Num)

#出力
p "serch:" + target.to_s
pp a

p linearSearch(target,a);

#処理時間
p Time.now - before

ふつうのRuby

普通にRubyで書くと関数部分はこう書き換えられる

def linearSearch(target,a)
	a.index(target)
end

キーの値を必要としないのならarray.include?で真偽値を得られる

まとめ

Rubyではi++という書き方がないらしく10分ぐらい悩んだ。MLになぜならiはオブジェクトだからで・・というRubyっぽい説明がありました
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/126

※このシリーズは私がRubyでアルゴリズムとデータ構造を基礎から学ぶ記録です。全体の目次はこちらへ。