この章から読み始める人へ
- 前回の章までの成果物はこちらにアップロードしてありますので、zipを展開してhtdocs以下にそのまま配置してください。データベースについてはyiiという名前のデータベース下にuser.sql(上記URL内よりダウンロード可)を展開してください。
- なおデータベースのユーザ名とパスワードはroot/unko9314になっています。
- これらの値が異なる方はprotected/config/main.phpに設定できる部分がありますので変更してください。
この章の目的
この章ではユーザ登録の機能を追加したいと思います。
ユーザ登録の流れとしては、まずはじめにE-mailを登録します。ただしE-mailを登録しただけではログインはできないようにします。E-mailが正しいかどうか確認するために登録されたメールアドレスに認証用のURLを送付します。そのメールを受け取って記載されたURLにアクセスしたらユーザ登録が完了し、ログインできるようにします。
用意してほしいもの
- 認証用のメールを送るためにGmailのアドレスを取得しておいてください。
下準備(メール送信ライブラリ)
メール送信機能を追加するためにエクステンションをこちらからダウンロードします。もしリンクが切れている場合は、こちらからダウンロードしてください。
ダウンロードしたら解凍してください。解凍して出てきたmailerディレクトリをprotected/extensions以下においてください。
次にprotected/config/main.phpを開いてください。以下のようにmailerコンポーネントの設定をします。内容は自分のGmailのアカウント内容に合わせて変えてください。‘Username’の部分と ‘Password’の部分を自分のGmailのアドレスとパスワードに変更してください。
'components'=>array( 'user'=>array( // 自分で定義したクラスに変更する 'class' => 'WebUser', // protected/components/WebUser.php // enable cookie-based authentication 'allowAutoLogin'=>true, ), // chap7: メール送信ライブラリを追加 'mailer'=>array( 'class' => 'application.extensions.mailer.EMailer', 'From' => 'yii.juncheng@gmail.com', // 送信者のアドレス 'FromName' => 'yii-juncheng',// 名前 'CharSet' => 'iso-2022-jp', //文字コード 'Encoding' => '7bit', 'Mailer'=>'smtp', 'Port'=>'587', 'SMTPSecure'=>'tls', 'Host'=> 'smtp.gmail.com', 'SMTPAuth' => true, 'Username' => 'yii.juncheng@gmail.com', // gmailのメールアドレスがユーザ名となる 'Password' => 'Gmailのパスワード', // ここにGmailのアドレスを入力する ),// ここまで追加
次にメール送信ライブラリを呼び出すためのクラスを作っておきます。
protected/components/myMail.phpというファイルを作ってください。以下の内容をコピーしてください。使い方は追って説明することにします。
<?php
    // メール送信用のライブラリ
    class myMail extends CComponent {
        public static function ($addresses,$subject,$view,$vars) {
            mb_language("ja");
            mb_internal_encoding("UTF-8");
            $mailer =& Yii::app()->mailer;
            foreach($addresses as $address) {
                $mailer->addAddress($address);
            }
            $mailer->Subject = mb_encode_mimeheader($subject);
            $mailer->getView($view,$vars);
            $mailer->Body = mb_convert_encoding($mailer->Body,Yii::app()->mailer->CharSet);
            $mailer->send();
            // アドレスをクリアしておく(再度呼び出した場合に重複送信を避けるため)
            $mailer->ClearAddresses();
        }
    }
?>
メニューを変更しよう
さて、次にサイトに表示されているメニューを変更することにします。protected/views/layouts/main.phpを開いてください。
29行目あたりから以下のように変更します。ついでに英語になっている部分を日本語にしました。
	<div id="mainmenu">
		<?php $this->widget('zii.widgets.CMenu',array(
			'items'=>array(
				array('label'=>'ホーム', 'url'=>array('/site/index')),
				array('label'=>'当サイトについて', 'url'=>array('/site/page', 'view'=>'about')),
				array('label'=>'お問い合わせ', 'url'=>array('/site/contact')),
				array('label'=>'ユーザ登録','url'=>array('/site/registration'),'visible'=>Yii::app()->user->isGuest),
				array('label'=>'ログイン', 'url'=>array('/site/login'), 'visible'=>Yii::app()->user->isGuest),
				array('label'=>'ログアウト ('.Yii::app()->user->name.')', 'url'=>array('/site/logout'), 'visible'=>!Yii::app()->user->isGuest)
			),
		)); ?>
	</div><!-- mainmenu -->
特に追加したのは、以下の部分です。visibleの部分は指定した条件がtrueになるときのみ表示されるというものです。ログインしているということはすでにユーザ登録が済んでいるということなので、ここではログインしていない場合に表示されるようにします。すなわちYii::app()->user->isGuestが、trueのときのみ表示するようにします。
またユーザ登録のページはhttp://localhost/site/registrationとなるようにします。
array('label'=>'ユーザ登録','url'=>array('/site/registration'),'visible'=>Yii::app()->user->isGuest),
Modelを用いたユーザ登録フォームの入力検証
さてまずはじめにユーザ登録をするためのフォームを作りましょう。ここでいじるファイルは
- protected/models/RegistrationForm.php 入力フォームのデータ検証に使う
- protected/controllers/SiteController.php
- proected/views/site/registration.php 入力フォームのViewファイル
の3点となります。
[1] RegistrationForm.phpの編集
さて、今までの解説では「Modelファイルはデータベース上の特定のテーブル(例えばuserとか)と紐付いているもの」だったと思います。
しかし、Model自体はデータベース上のテーブルとリンクさせて使う以外に、入力フォームのデータ検証にも用いることができます。
ここでRegistrationForm.phpというModelファイルを定義します。ただし、registration_formといった名前のテーブルが存在して、そのテーブルの内容とこのモデルがリンクしているというわけではありません。このModelファイルはあくまで、データ検証のみに用います。
ただしデータ検証後は、そのデータの一部をコピーして、新しいUserのレコードを作ります。(ようは、フォームの入力データに問題がなければ、そのデータをもとにして、Userのデータベースに新しいユーザを追加しますよ~ということ)
ではprotecte/models/Registration.phpというファイルを作ってください。それで以下の内容をコピーして使ってください。
<?php
/* chap7 */
class RegistrationForm extends CFormModel
{
	public $email;
	public $password;
	public $verifyCode;
	/**
	 * Declares the validation rules.
	 */
	public function rules()
	{
		return array(
			// emailの入力は必須
			array('email', 'required'),
			// emailとして入力されたデータが本当にemailの形式になっているかチェックする
			array('email', 'email'),
			// emailの長さに制限を加える
			array('email','length','max'=>128),
			// emailは、まだ登録されていない
			array('email','unregistered'),
			//----------------------------------------
			// password
			array('password','required'),
			array('password','length','min'=>6,'max'=>12), // パスワードは6文字~12文字
			array('password','match','pattern'=>'/^[a-zA-Z0-9]+$/u','message'=>'半角英数字のみ使用可'), // 英数字のみ使用可能
			//----------------------------------------
			// verifyCodeは正しく入力される必要がある
			array('verifyCode', 'captcha', 'allowEmpty'=>!CCaptcha::checkRequirements()),
		);
	}
	
	/**
	 * 既にメールアドレスが登録されている
	 * $attribute : 具体的には'email'が入る($this->$attribute はE-mail欄に入力された値)
	 */
	public function unregistered($attribute,$params) {
		// Userのデータベースを検索
		$user = User::model()->findByAttributes(array($attribute => $this->$attribute));
		// 検索して見つかったらエラー
		if(isset($user))
			 $this->addError($attribute, 'この'.$attribute.'は既にユーザ登録されています');
	}
	/**
	 * Declares customized attribute labels.
	 * If not declared here, an attribute would have a label that is
	 * the same as its name with the first letter in upper case.
	 */
	public function attributeLabels()
	{
		return array(
			'email' => 'メールアドレス',
			'password' => 'パスワード',
			'verifyCode'=>'Verification Code',
		);
	}
}
さてユーザ登録フォームに入力してもらう値は
- ログインに用いるメールアドレス email ($email)
- ログイン時に使用するパスワード password ($password)
あとはYiiframeworkから提供されている画像を用いた人間であることを判定するコードも入力してもらいます。これは$verifyCodeとして定義されています。
さてrules()を参照してください。ここにはemailやpasswordの入力の際にデータ検証のルールが書かれています。だいたいはコメントに書かれている内容のデータのチェックを行っています。ただしひとつだけ「unregistered」という名前のルールが書かれていることに気づくでしょう。
array('email','unregistered'),
ここのunregisterdは私自身が定義をした入力チェックのための独自のメソッドです(名前なども他とかぶっていなければ自由につけて良いです)。
これの定義は上記のファイル中のunregisterdメソッドの部分にかかれている以下の部分です。
	public function unregistered($attribute,$params) {
		// Userのデータベースを検索
		$user = User::model()->findByAttributes(array($attribute => $this->$attribute));
		// 検索して見つかったらエラー
		if(isset($user))
			 $this->addError($attribute, 'この'.$attribute.'は既にユーザ登録されています');
	}
ここでは何をしているかというと、入力されたE-mailが既にデータベース上に登録されていないかどうかをチェックしています。
もしこのチェックをしなければ、同じメールアドレスを持った人が二人以上存在していまいます。そうなると、ログインの際に、どちらのユーザがログインをしようとしているのか分からなくなります。ですので、メールアドレスは同じものを入力することは許してはいけません。
$attributeとは、このルールを呼び出した要素名が入ります。ここではemailの検証で呼び出しているので、“email”が代入されてると思ってください。また$this->$attributeは、ここでは、すなわち$this->emailですのでユーザが入力したemail欄の入力値が取得できます。 ※ もちろんpasswordの検証ルールの部分から呼び出したら、ここの内容はpasswordになります。いまはarray(‘email’,’unregistered’)というように、emailの部分から呼び出しているから、すべてemailとして読み替えているのです※
そしてUserのデータベースに問い合わせをして、既にそのメールアドレスで登録したユーザがいないかどうかをチェックしています。もし既に存在していたら$this->addErrorというメソッドを呼び出して「このチェック項目(email)でエラーが発生したよ」ということを教えてあげています。
次にpasswordの部分もついでに見ておきましょう。パスワード入力は必須で、長さは6文字~12文字で、指定した正規表現に合致しないとダメですよという入力ルールを設けています。
あとverifyCodeというものがありますが、この部分は決まり文句としてこう書くもんだと思っといてください。
[2] registration.php (ビューファイル)の編集
次にViewファイルを編集しましょう。protected/views/site/registration.phpを作って以下の内容をコピーします。
<?php
// chap7
$this->pageTitle=Yii::app()->name . ' - ユーザ登録';
$this->breadcrumbs=array(
	'ユーザ登録',
);
?>
<h1>ユーザ登録</h1>
<p>ユーザ登録を行うためにメール認証を行います。ここで使用したメールアドレスはログイン時に使用されます。</p>
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
	'id'=>'registration-form',    // formのidをregistration-formとする
	'enableAjaxValidation'=>true, // ajaxで検証処理できるように
	'clientOptions'=>array(
		'validateOnSubmit'=>true,
	),
)); ?>
	<?php echo $form->errorSummary($model); ?>
	<div class="row">
		<?php echo $form->labelEx($model,'email'); ?>
		<?php echo $form->textField($model,'email'); ?>
		<?php echo $form->error($model,'email'); ?>
	</div>
	
	<div class="row">
		<?php echo $form->labelEx($model,'password'); ?>
		<?php echo $form->textField($model,'password'); ?>
		<?php echo $form->error($model,'password'); ?>
	</div>
	
	<?php if(CCaptcha::checkRequirements()): ?>
	<div class="row">
		<?php echo $form->labelEx($model,'verifyCode'); ?>
		<div>
		<?php $this->widget('CCaptcha'); ?>
		<?php echo $form->textField($model,'verifyCode'); ?>
		</div>
		<div class="hint">表示されたアルファベットを入力してください。大文字小文字は区別しません。</div>
		<?php echo $form->error($model,'verifyCode'); ?>
	</div>
	<?php endif; ?>
	<div class="row buttons">
		<?php echo CHtml::submitButton('メール認証に進む'); ?>
	</div>
<?php $this->endWidget(); ?>
</div><!-- form -->
ここの内容も基本的に書き方は決まり文句としてこう書くんだと思っていただければと思います。今後、自分でフォームを作るときも上記の内容をコピーしてパラメータなどをいじれば応用ができると思います。
なお
'enableAjaxValidation'=>true, // ajaxで検証処理できるように
この部分を入れることAjaxでページ遷移を伴わずにフォーム検証ができるようになっています。
[3] SiteControllerの編集
SiteControllerに以下のメソッドを追加してください。ただしSiteControllerは、これ以後まだ追記をします。つまり以下はまだ未完成の状態です。
ただし、途中までの動きを確認するために、一旦途中の状態でもテストしてみます。
	/**
	 * ユーザ登録フォーム (chap7)
	 */
	public function actionRegistration()
	{
		$model = new RegistrationForm;
		
		// Ajax検証のための処理
		if(isset($_POST['ajax']) && $_POST['ajax']==='registration-form')
		{
			echo CActiveForm::validate($model);
			Yii::app()->end();
		}
		
		// フォームからの入力があった場合
		if(isset($_POST['RegistrationForm'])) {
			// フォームの入力データを$modelに格納する
			$model->attributes=$_POST['RegistrationForm'];
			
			// $modelの入力データを検査する
			if($model->validate())
			{
				// これ以下には入力データに問題がなかった場合の処理を書いていくが一旦未完成の状でテストをする
			}
		}
		$this->render('registration',array('model'=>$model));
	}
ここでも簡単に説明をしていきます。
以下の部分ですが、ここは実際にユーザが入力をして送信ボタンを押した際の処理をしています。意味としては、もし入力フォームにデータがあったら、まずRegistrationFormのモデルのオブジェクトに内容を格納してデータに問題がないかチェックします。
$model->validate()はデータ内容のチェックを行っています。もしここの返り値がtrueになっていればデータに問題がないという意味になります。これ以降は、まだ何も書いていませんが、今後はデータベースにユーザを登録していく作業を追記していきます。
		// フォームからの入力があった場合
		if(isset($_POST['RegistrationForm'])) {
			// フォームの入力データを$modelに格納する
			$model->attributes=$_POST['RegistrationForm'];
			
			// $modelの入力データを検査する
			if($model->validate())
			{
				// これ以下には入力データに問題がなかった場合の処理を書いていくが一旦未完成の状でテストをする
			}
		}
また先頭にあった以下の部分はAjaxでこっそりと通信される部分に対応した処理です。これもメソッドの先頭に追記する一種のおまじないだと思ってください。ただし以下のregistration-formというidは、上記のビューファイル(protected/views/site/registration.php)の中で設定したものと同じにしてください。
        // Ajax検証のための処理
        if(isset($_POST['ajax']) && $_POST['ajax']==='registration-form')
        {
            echo CActiveForm::validate($model);
            Yii::app()->end();
        }
さて、ここまでの状態を一旦テストしてみます。
http://localhost/site/registrationにアクセスして、フォームに適当な値を入力してください。
例えばE-mailの部分にyii@juncheng.orgと既に登録されているはずのアドレスを入力すると、きちんとエラーメッセージが表示されているのが分かるでしょう。
Userのデータベースにも変更を加えよう
http://localhost/phpmyadmin にログインしてyiiデータベース上で以下のSQLを実行します。これにより新たにvcodeとvalidという2つのカラムが追加されます。vcodeはメール認証の際に使用するランダムに生成するコードです。validはメール認証が済んでいるかどうかを表す変数です。ちなみに余談ですがboolean型を指定するとtinyint(1)になるようです。
ALTER TABLE user ADD vcode int(11) NOT NULL DEFAULT 0; ALTER TABLE user ADD valid boolean NOT NULL DEFAULT false;
次にModelの定義にも修正を加えましょう。protected/models/User.phpを開いてください。
まずrules()を以下のように書き換えます。今までのrules()のメソッドを消して以下を貼り付けてください。
    public function rules()
    {
        // NOTE: you should only define rules for those attributes that
        // will receive user inputs.
        return array(
            // email
            array('email', 'required'),
            array('email', 'length', 'max'=>128),
            array('email','email'), // chap7: emailがE-mailの形式であることが必要
            array('email','unique'),// chap7: emailの重複は許してはならない
            // name
            array('name', 'length', 'max'=>64),
            // password
            array('password','length','max'=>40), // chap7: sha1の出力長は40bytes
            // role
            array('role','in','range'=>array(0,1)),
            // vcode
            array('vcode','numerical','min'=>1000000), // chap7: メール認証の際のキー
            // valid
            array('valid','boolean'), // chap7: 真偽値のみ 0: 未認証 1: 認証済
            
            // The following rule is used by search().
            // @todo Please remove those attributes that should not be searched.
            array('id, email, name', 'safe', 'on'=>'search'),
        );
    }
- E-mailに関する検証でarray(‘email’,’email’),を追加しました。これによりUserのデータベース上のemailの値がメールアドレスの形式になっている必要があります。array(‘email’,’unique’),はデータベース上でメールアドレスが他と同じにならないことを表しています。既にRegistrationFormのモデルでこの重複はチェックしていますが、念のため(後々のため)ここにも記述しておきます。
- 次にpasswordの項目にも変更を加えます。以前はパスワードがそのままの形式で保存されていましたので今後は暗号化したパスワードを保存するようにします。暗号化されたパスワードの出力長は40文字ですので最大長を40としておきます。
- またvcodeというメール認証の際に使用するパスワードのようなものも追加しましたので、これに関しても検証ルールを加えます。ルールとしては数値のみで構成されたデータで(numerical)、なおかつ値は100,0000以上であることにします。
- validは認証済みかどうかの0,1のみを表す数値ですのでbooleanを指定します。
ついでにラベルの部分も変更しておきます。
    public function attributeLabels()
    {
        return array(
            'id' => 'ID',
            'email' => 'Email',
            'name' => 'Name',
            'password'=> 'Password', // passwordを追加
            'role' => 'Role', // roleを追加
            'vcode' => 'Validation Code', // chap7: 認証コード
            'valid' => 'Valid User', // chap7: 認証済みかどうか
        );
    }
SiteControllerを再度、修正してデータベースに登録するよう変更
題名の通りSiteControllerを再度、改造していきます。前はフォームのデータの入力内容をチェックするところまで行きました。ここではフォームの入力データが正しければ、実際にユーザをデータベース上に登録するように変更します。
内容をさらに以下のように変更しましょう。
	public function actionRegistration()
	{
		$model = new RegistrationForm;
		
		// Ajax検証のための処理
		if(isset($_POST['ajax']) && $_POST['ajax']==='registration-form')
		{
			echo CActiveForm::validate($model);
			Yii::app()->end();
		}
		
		// フォームからの入力があった場合
		if(isset($_POST['RegistrationForm'])) {
			// フォームの入力データを$modelに格納する
			$model->attributes=$_POST['RegistrationForm'];
			
			// $modelの入力データを検査する
			if($model->validate())
			{
				// 新規にデータベースにユーザを追加する
				$new = new User();
				$new->email = $model->email;              // E-mail
				$new->name  = '';                         // 名前は空にしておく
				$new->password = sha1($model->password);  // ユーザの入力したパスワードを暗号化
				$new->role  = 0;                          // 一般ユーザ
				$new->vcode = rand(1000000,9999999);      // メール認証用の認証コード(100万~1000万未満)
				$new->valid = false;                      // 認証済みか(未認証)
				
				// データベースに登録する
				if($new->validate()) {
					// データを記録する
					$new->save();
					// メールを送信する
					$addresses = array($new->email);             // 送信アドレス
					$subject   = 'メール認証を完了してください'; // メール件名
					myMail::send($addresses,$subject,'reg_code',array('id'=>$new->id, 'vcode'=>$new->vcode)); // protected/views/email/reg_code.php
					// ページを表示
					$this->render('registration_confirm');
					// 終了
					Yii::app()->end();
				}
			}
		}
		$this->render('registration',array('model'=>$model));
	}
ここでif($model->validate())以下の部分に着目してください。ここからがフォームの入力値のチェックに合格したあとの処理を書いています。主にやっていることはUserのデータベースに新しいユーザを登録しています。
データベースに新たにユーザを登録するにはnew User();でオブジェクトを作成し、各プロパティ(要素)にデータを代入したあと、save()メソッドを実行します。なおid(通し番号)は自動で挿入されるので自分で代入する必要はありません。(※MySQLでidがAUTO INCREMENTになっているからです。)
validの項目はfalseにしているのは、このあと行うメール認証を終えたあとで、ここがはじめてtrueになり、認証済みユーザになるようにします。(※ログイン時にパスワードが正しくてもvalidがfalseであればログインできないようにします。またメール認証は、メールにURLを記載し、そのURLにアクセスすれば認証が完了するようにします。そのURLの中にvcodeの値も含めます)
vcodeは メール認証のときに使う予定のランダムに発生させた数字です。100万から999万9999の間の値をランダムに発生させています。この数字をメールに記 載して、登録されたメールアドレスに送信します。ユーザがこの値を知っていれば、このメールアドレスが存在すると判定します。
また以下のパスワードへの代入ですがsha1のメソッドは入力されたパスワードを暗号化しています。
$new->password = sha1($model->password);
次に、メールの送信には先ほど自分で作ったmyMailのコンポーネントを使います。メールの文言自体は、protected/views/emailのディレクトリに入れておきます。第3引数にreg_codeを指定していますが、これはprotected/views/email/reg_code.phpをメール文言にせよという意味です。
protected/views/email/reg_code.phpの内容は以下の通りです。
メール認証を完了させるには以下のアドレスにアクセスしてください http://localhost/site/mailreg/id/<?php echo $id;?>/vcode/<?php echo $vcode;?>
またメール文言中に$idや$vcodeという変数がありますが、これらの変数への代入は命令の呼び出し時に、
array('id'=>$new->id, 'vcode'=>$new->vcode)
という部分があったと思いますが、こちらで行っています。
メール認証は、上記のメールの文言に記載されたURLにアクセスすれば完了するようにします。この部分の処理はまたあとで書いていきます。
最後にページのビューの表示をします。protected/views/site/registration_confirm.phpを作成して以下の内容をコピーしてください。
<?php // chap7 $this->pageTitle=Yii::app()->name . ' - ユーザ登録'; $this->breadcrumbs=array( 'ユーザ登録', ); ?> <h1>ユーザ登録</h1> <p>入力されたアドレスにメールを送信しました。メール内のURLをクリックしてください。</p>
ログイン処理を修正しよう
さてメール認証の処理を書く前に、ログイン処理を修正しましょう。修正内容としては
- データベースに記録したパスワードは暗号化したものになるように変更しました。そこでパスワードの正誤判定の際に、入力されたパスワードを暗号化してから、データベースのパスワードと照合するようにします。
- 認証が完了していないユーザ(validの値がfalse)はパスワードが正しくてもエラーになるようにします。
以上の内容を修正すると以下のようになります。
なおエラーコードの定数としてERROR_NOT_AUTHORIZEDを新しく自分で勝手に追加しました。そこで元々定義されていた定数も、すべて新たに自分でオーバーライドして定義しなおしました。
UserIdentity.php ※ 定数の部分に勝手にダブルクオーテーションが挿入されてしますが無視してください
<?php
/**
 * UserIdentity represents the data needed to identity a user.
 * It contains the authentication method that checks if the provided
 * data can identity the user.
 */
class UserIdentity extends CUserIdentity
{
    // プロパティを追加
    private $_id; 
    
    
    // 定数を再定義する
    const ERROR_NONE             = 0;
    const "ERROR_USERNAME_INVALID" = 1;
    const "ERROR_PASSWORD_INVALID" = 2;
    const ERROR_NOT_AUTHORIZED   = 3;
    
    /**
     * Authenticates a user.
     * The example implementation makes sure if the username and password
     * are both 'demo'.
     * In practical applications, this should be changed to authenticate
     * against some persistent user identity storage (e.g. database).
     * @return boolean whether authentication succeeds.
     */
    public function authenticate()
    {
        // E-mailで検索する
        $user = User::model()->findByAttributes(array('email'=>$this->username));
        // そんなE-mailのユーザは存在しない
        if(!isset($user))
            $this->errorCode=self::ERROR_USERNAME_INVALID;
        // パスワードが異なっている
        // 入力されたたパスワードを暗号化してから照合する
        elseif(strcmp($user->password,sha1($this->password)))
            $this->errorCode=self::ERROR_PASSWORD_INVALID;
        // 認証が完了していない
        elseif($user->valid == false)
            $this->errorCode=self::ERROR_NOT_AUTHORIZED; // 自分で追加したエラーコード
        // パスワードが正しい
        else {
            $this->_id = $user->id; // 取得した会員のidを格納する
            $this->errorCode=self::ERROR_NONE;
        }
        return !$this->errorCode;
    }
    // 以下を追加
    public function getID() {
        return $this->_id;
    }
}
メールの認証を完了させる部分
さて最後にメールの認証を完了させる部分を書きましょう。protected/views/email/reg_code.phpの中身は、メール認証の際に送るメール文言でした。そこでURLの形式は
http://localhost/site/mailreg/id/ユーザのID/vcode/認証コード/
となっていましたね。
このURLの解釈としてはSiteController.phpのactionMailregというメソッドが実行されるというものです。その後の/id/ユーザのID/vcode/認証コード/の部分ですが、actionMailregのメソッド内において
- $_GET[‘id’]
- $_GET[‘vcode’]
によってURL中のユーザIDと認証コードの部分が取得できるようになっています。
つまりメールの認証を完了させるための処理としては、
- SiteController中にactionMailregのメソッドを定義
- メソッドの中の処理は指定されたユーザIDをもつユーザをデータベースから探し出す
- そのユーザの認証コードと、URL中の認証コードが一致するか調べる
- 一致するならばそのユーザのデータベースのvalidの値ををfalseからtrueに変更する
という流れになります。
ソースコードとしては以下のようになります。
SiteController.php
	/**
	 * メール認証を完了させる
	 */
	public function actionMailreg() {
		try {
			// 入力チェック
			if(!isset($_GET['id']))
				throw new Exception('認証を行うユーザの通し番号が指定されていません');
			$id = intval($_GET['id']);
			if(!isset($_GET['vcode']))
				throw new Exception('認証コードが入力されていません');
			$vcode = intval($_GET['vcode']);
			// ユーザの取得
			$user = User::model()->findByPk($id);
			if(!isset($user))
				throw new Exception('このようなユーザは存在しません');
			if($user->valid == true)
				throw new Exception('既に認証の完了したユーザです');
			if($user->vcode != $vcode)
				throw new Exception('認証コードが誤っています');
			// 認証処理に進む
			$user->valid = true;
			if(!$user->validate())
				throw new Exception('データベースの更新に失敗しました');
			$user->save();
			// 結果を表示
			$this->render('registration_finish');
		} catch(Exception $ex) {
			// エラー画面の表示
			throw new CHttpException(503,$ex->getMessage());
		}
	}
また対応したビューファイルとしてprotected/views/site/registration_finish.phpを作って以下のコードを入力してください。
<?php // chap7 $this->pageTitle=Yii::app()->name . ' - メール認証完了'; $this->breadcrumbs=array( 'メール認証', ); ?> <h1>メール認証完了</h1> <p>メール認証が完了しました。登録時に入力したメールアドレスとパスワードでログインしてください</p>
最後に・・・
さてデータベース上に既に登録されているユーザのデータは一旦すべて削除しておきましょう。なぜならばパスワードが暗号化されていないのと、vcodeの値が0になっていてデータベースのモデルの検証ルールに反しているからです。
ユーザのデータの削除の方法はphpmyadminからuserのデータベースを表示させて画像にあるような削除ボタンを押します。
それが終わったら実際にユーザの登録→メール認証→ログインまでの手順が実際に動作するか確認してみてください。
今回の成果物
以下に今回の成果物のソースコードと、そのプログラムで使用可能なデーターベースのファイルを置いておきます。使用方法としてはいつもと同じでhtdocs以下に解凍して使ってください。またデータベースはyiiという空のデータベースを作ったあと、その下にuser.sqlをインポートしてください。
また設定項目としてはprotected/config/main.phpにおいて
- データベースのMySQLのパスワードを変更する必要があれば変更してください(本ブログにあわせてunko9314というパスワードにしていれば変更の必要はありません)
- またメール送信はGmailのsmtpサーバーを利用しているので、ご自身のGmailアカウントのユーザ名(※ユーザ名はメールアドレスと同一)とパスワードに変更してください。
以上で、みなさんのxamppの環境上でも動作するはずです。
ダウンロードはこちらから

