CakePHP1.3.6:Authコンポーネントで認証する(その2)
前回のログに引き続き、usersテーブルをメンテナンスするプログラムを作成する。
今回は、hasOneの関係を試すために、user_attrsテーブルを以下のようなスキーマで作成する。
CREATE TABLE IF NOT EXISTS `user_attrs` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `yomi` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `mail` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `tel` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `memo` text COLLATE utf8_unicode_ci NOT NULL, `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
面倒だった点は、
- usersテーブルのpasswordフィールドはハッシュ化されて保存されるが、未入力の場合にそれがハッシュ化されてしまい、未入力のチェックができない
こと。これには、こちらのサイトを参考にさせていただいた。感謝。
こちらのサイトで、実際にテーブルに無いフィールドに関して、モデルにvalidateを定義できることを知った。これは面白い!!と思ってやってみた。それで分かったことは、
- save時にvalidateされてエラーが帰ってくるが、saveされてしまう。
ということ。save前にvalidate()して、戻り値を取得すれば充分使えると思った。
また、実運用上、ハッシュ化されたパスワードが保管されると、
- パスワードを忘れたときには、再発行するしかない
ことになる。パスワードを忘れた場合に、メイルで送ってもらう、という運用があるが、管理人にもパスワードが分からないことは漏洩、なりすましの軽減になる。
Authに関しては、パスワードのハッシュ化がmustではないが、デフォルトの仕様を利用することにした。
モデル
users.php
user_attrとhasOneの関係を結び、カスケード・デリートの設定をする。
<?php class User extends AppModel { public $name = 'User'; public $hasOne = array( "UserAttr" => array( 'className' => 'UserAttr', 'dependent' => true ) ); public $validate = array( 'username'=>array( array( 'rule' => 'notEmpty', 'message' =>'入力してください'), array( 'rule' => 'isUnique', 'message' =>'すでに登録されています'), array( 'rule' => 'alphaNumeric', 'message' =>'半角英数字以外は入力できません') ), /* 'new_password'=>array( array( 'rule' => 'notEmpty', 'message' =>'入力してください'), array( 'rule' => 'alphaNumeric', 'required' => true, 'message' =>'半角英数字以外は入力できません' ), array( 'rule' => array('between', 6, 20), 'required' => true, 'message' => 'パスワードは6〜20文字以下で入力して下さい。' ) ) */ ); } ?>
user_attr.php
<?php require_once '../vendors/MyValidator.class.php'; require_once '../vendors/MyMBValidator.class.php'; class UserAttr extends AppModel { public $name = 'UserAttr'; public $validate = array( 'name'=>array( array( 'rule' => 'notEmpty', 'message' =>'入力してください'), array( 'rule' => 'isUnique', 'message' =>'すでに登録されています'), ), 'yomi'=>array( array( 'rule' => 'notEmpty', 'message' =>'入力してください'), array( 'rule' => array('checkHiragana','yomi'), 'message' =>'ひらがなで入力してください'), ), 'tel'=>array( array( 'rule' => 'notEmpty', 'message' =>'入力してください') ), 'mail'=>array( array( 'rule' => 'notEmpty', 'message' =>'入力してください'), array( 'rule' => array('checkMail','mail'), 'message' =>'メイルの形式がただしくありません'), ), ); public function checkHiragana($data,$name){ return MyMBValidator::validate('isHiragana', $data[$name]); } public function checkMail($data,$name){ return MyValidator::validate('ja','isEmail', $data[$name]); } } ?>
画面
index.ctp
<h2>ユーザーの一覧</h2> <br> 名前で絞り込みをします。 <?php // 絞り込み用フォーム echo $form->create(null,array('type'=>'post','action'=>'.')); echo $form->text('UserAttr.name', array('size' => 20)); echo $form->end('送信'); ?> <?php // ページネーション echo $paginator->numbers( array( 'before'=>$paginator->hasPrev() ? $paginator->first('<<').' ' : '', 'after'=>$paginator->hasNext() ? ' '.$paginator->last('>>') : '', 'modulus'=>4, 'separator'=>' ' ) ); ?> <table> <tr> <th><?php echo $paginator->sort('ID','User.id') ?></th> <th><?php echo $paginator->sort('ユーザーID','User.username') ?></th> <th><?php echo $paginator->sort('名前','UserAttr.name') ?></th> <th><?php echo $paginator->sort('電話','UserAttr.tel') ?></th> <th><?php echo $paginator->sort('更新日','User.timestamp') ?></th> </tr> <?php foreach ($data as $arr){ echo '<tr>'; echo '<td>'.$html->link($arr['User']['id'], array('controller'=>'users', 'action'=>'show',$arr['User']['id'])).'</td>'; echo "<td>{$arr['User']['username']}</td>"; echo "<td>{$arr['UserAttr']['name']}</td>"; echo "<td>{$arr['UserAttr']['tel']}</td>"; echo "<td>{$arr['User']['timestamp']}</td>"; echo '</tr>'; } ?> </table> <?php echo $html->link('メニューへ戻る', array('controller'=>'main', 'action'=>'index')); echo ' '; echo $html->link('登録', array('controller'=>'users', 'action'=>'add')); ?>
add.ctp
<h2>ユーザーの登録</h2> <?php echo $form->create('User',array('action'=>'add')); ?> <table> <?php echo "<tr><th>ユーザー名</th>"; echo "<td>{$form->text('User.username',array('size'=>'30'))}{$form->error('User.username')} </td>"; echo "</tr>"; echo "<tr><th>パスワード</th>"; echo "<td>{$form->text('User.new_password',array('size'=>'30'))}{$form->error('User.new_password')}</td>"; echo "</tr>"; echo "<tr><th>名前</th>"; echo "<td>{$form->text('UserAttr.name',array('size'=>'20'))}{$form->error('UserAttr.name')}</td>"; echo "</tr>"; echo "<tr><th>よみ</th>"; echo "<td>{$form->text('UserAttr.yomi',array('size'=>'20'))}{$form->error('UserAttr.yomi')}</td>"; echo "</tr>"; echo "<tr><th>電話</th>"; echo "<td>{$form->text('UserAttr.tel',array('size'=>'20'))}{$form->error('UserAttr.tel')}</td>"; echo "</tr>"; echo "<tr><th>メイル</th>"; echo "<td>{$form->text('UserAttr.mail',array('size'=>'30'))}{$form->error('UserAttr.mail')}</td>"; echo "</tr>"; echo "<tr><th>メモ</th>"; echo "<td>{$form->textarea('UserAttr.memo')}</td>"; echo "</tr>"; echo $form->end('登録'); ?> </table> <a href=".">リストに戻る</a>
show.ctp
<h2>売上の詳細</h2> <br> <table> <?php echo "<tr><th>商品名</th>"; echo "<td>{$data['User']['username']}</td>"; echo "</tr>"; echo "<tr><th>名前</th>"; echo "<td>{$data['UserAttr']['name']}</td>"; echo "</tr>"; echo "<tr><th>よみ</th>"; echo "<td>{$data['UserAttr']['yomi']}</td>"; echo "</tr>"; echo "<tr><th>電話</th>"; echo "<td>{$data['UserAttr']['tel']}</td>"; echo "</tr>"; echo "<tr><th>メイル</th>"; echo "<td>{$data['UserAttr']['mail']}</td>"; echo "</tr>"; echo "<tr><th>メモ</th>"; echo "<td>{$data['UserAttr']['memo']}</td>"; echo "</tr>"; echo "<tr><th>最新更新日</th>"; echo "<td>{$data['User']['timestamp']}</td>"; echo "</tr>"; ?> </table> <a href="../">リストに戻る</a> <?php echo $html->link('更新', array('controller'=>'users', 'action'=>'edit', $data["User"]["id"])); ?>
edit.ctp
<h2>ユーザー情報の更新</h2> <?php echo $form->create('User',array('type'=>'post','action'=>'edit')); // UserとUserAttrのそれぞれを更新するので、hiddenで保持すること。 echo $form->hidden('User.id'); echo $form->hidden('UserAttr.id'); ?> <table> <?php echo "<tr><th>ユーザー名</th>"; echo "<td>{$form->text('User.username',array('size'=>'30'))}{$form->error('User.username')} </td>"; echo "</tr>"; echo "<tr><th>パスワード</th>"; echo "<td>{$form->text('User.new_password',array('size'=>'30'))}{$form->error('User.new_password')}</td>"; echo "</tr>"; echo "<tr><th>名前</th>"; echo "<td>{$form->text('UserAttr.name',array('size'=>'20'))}{$form->error('UserAttr.name')}</td>"; echo "</tr>"; echo "<tr><th>よみ</th>"; echo "<td>{$form->text('UserAttr.yomi',array('size'=>'20'))}{$form->error('UserAttr.yomi')}</td>"; echo "</tr>"; echo "<tr><th>電話</th>"; echo "<td>{$form->text('UserAttr.tel',array('size'=>'20'))}{$form->error('UserAttr.tel')}</td>"; echo "</tr>"; echo "<tr><th>メイル</th>"; echo "<td>{$form->text('UserAttr.mail',array('size'=>'30'))}{$form->error('UserAttr.mail')}</td>"; echo "</tr>"; echo "<tr><th>メモ</th>"; echo "<td>{$form->textarea('UserAttr.memo')}</td>"; echo "</tr>"; echo $form->end('更新'); ?> </table> <a href="../">リストに戻る</a> <?php echo $html->link('削除', array('controller'=>'users', 'action'=>'delete', $data["User"]["id"]), array(), "削除してもいいですか?"); ?>
コントローラー
/app/controllers/users_controller.php
<?php require_once '../vendors/MyConverter.class.php'; class UsersController extends AppController{ public $name = 'Users'; public $uses = array('User','UserAttr'); public $components = array('Auth'); public $layout = 'myznala'; /* * Paginatorの定義 */ public $paginate = array( 'page'=>1, 'conditions'=>array(), 'fields'=>array(), 'order'=>array('User.timestamp'=>'desc'), 'limit'=>5, 'recursive'=>1 ); function beforeFilter(){ $this->Auth->allow('add'); $this->Auth->allow('logout'); $this->Auth->authError= 'ログインしてください'; $this->Auth->loginError = 'ログインに失敗しました'; } /** * 認証後の処理 * * セッションにユーザー名を保管する。 */ /* function isAuthorized(){ $this->Session->write('Login.username',$this->Auth->user('username')); echo $this->Auth->user('username'); } */ /** * * ログイン */ function login(){ $this->set('title_for_layout', "ログイン"); } /** * * ログアウト */ function logout(){ $this->set('title_for_layout', "ログアウト"); $this->Session->destroy(); $this->Auth->logout(); } /** * * 初期画面(一覧表示) */ function index(){ $this->set('title_for_layout', "ユーザーの一覧"); $req=null; if(!empty($this->data)){ //サニタイズ $req = MyConverter::getRequestParams($this->data["UserAttr"]); //絞り込みの場合には、コンディションを書き換える。 $this->paginate['conditions'] = array('UserAttr.name like ?' => array("%{$req["name"]}%")); } $data = $this->paginate(); $this->set('data',$data); } /** * ユーザーの登録 */ function add(){ $this->set('title_for_layout', "ユーザーの登録"); if(!empty($this->data)){ // サニタイズ $this->data["User"] = MyConverter::getRequestParams($this->data["User"]); $this->data["UserAttr"] = MyConverter::getRequestParams($this->data["UserAttr"]); if ($this -> data["User"]["new_password"]) { $this -> data["User"]["password"] = $this -> Auth -> password($this -> data['User']['new_password']); $this->User->saveAll($this->data); if($this->User->validates() && $this->UserAttr->validates()){ // 登録できたらリダイレクト $this->redirect('.'); } } else { $this->User->invalidate('new_password','入力してください'); } } } /** * * データの照会 * $paramsにIdが入ってくる。 * */ function show($param){ $this->set('title_for_layout', "ユーザー情報の詳細"); $result=null; if(!empty($param)){ // Idフィールドによる検索 $this->data=$this->User->findById($param); if(!$this->data){ // 存在しないIDを参照された場合。 $this->Session->setFlash('存在しません'); $this->redirect('.'); } } $this->set('data',$this->data); } /** * * データの更新 * (注記) パスワードは表示しない。入力があったら変更する。 * */ function edit($param){ $this->set('title_for_layout', "ユーザー情報の更新"); // データの更新 if(!empty($this->data)){ // サニタイズ $this->data["User"] = MyConverter::getRequestParams($this->data["User"]); $this->data["UserAttr"] = MyConverter::getRequestParams($this->data["UserAttr"]); // Idフィールドによる検索 $check=$this->User->findById($param); if(!$check){ // 存在しないIDを更新しようとした場合。 $this->Session->setFlash('存在しません'); $this->redirect('.'); }else{ // パスワードは入力があったら変更 if ($this -> data["User"]["new_password"]) { $this -> data["User"]["password"] = $this -> Auth -> password($this -> data['User']['new_password']); } // 更新 $this->User->saveAll($this->data); if($this->User->validates() && $this->UserAttr->validates()){ // 更新できたらリダイレクト $this->redirect('.'); } } // 更新データのセット(初期値) }else{ if(!empty($param)){ // Idフィールドによる検索 $check=$this->User->findById($param); if(!$check){ // 存在しないIDを更新しようとした場合。 $this->Session->setFlash('存在しません'); $this->redirect('.'); }else{ // Idフィールドによる検索 $this->data=$this->User->findById($param); } } } // エラーの場合も通るようにする $this->set('data',$this->data); } /** * * データの削除 * */ function delete($param){ if(!empty($param)){ $check=$this->User->findById($param); if(!$check){ // 存在しないIDを削除しようとした場合。 $this->Session->setFlash('存在しません'); }else{ // Idフィールドによる削除 $this->data=$this->User->delete($param); } $this->redirect('.'); } } } ?>