ユーザ登録(仮登録・メール・本登録)
ここ最近は、メールアドレスだけでなく、SNSのアカウントと連携してユーザ登録することもできるWebサービスが増えてきましたね。ユーザは割合としてどちらを選んでるのか気になるところですが。私はできるだけ連携は避けて、棄アドレスで登録することにしてます。
今回はメールアドレスでのユーザ登録機能。仕様は以下にしました。
- 「ユーザ登録画面(/signup」)にて、メールアドレス/パスワードでユーザ登録
- 「仮登録完了画面(/thanks)」へ遷移する。この時点では仮登録とし、ユーザに本登録用のリンクをメールで送付する。**メール送信機能は、qdmailを使用する。
- ユーザはメール送付されたリンクをクリックして「本登録完了(activate)」とする。
usersテーブル
statusを用意し、デフォルトを1としています。"1"を仮登録状態でログイン不可、"0"を本登録としログイン可能にします。その制御は、userScopeが使えそうです。
// usersテーブル
CREATE TABLE IF NOT EXISTS `Users` (
`id` INT NOT NULL AUTO_INCREMENT ,
`username` VARCHAR(50) NOT NULL ,
`password` VARCHAR(50) NOT NULL ,
`status` TINYINT NOT NULL DEFAULT 1 ,
`created` DATETIME NOT NULL ,
`modified` DATETIME NOT NULL ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `username_UNIQUE` (`username` ASC) )
ENGINE = InnoDB DEFAULT
CHARACTER SET = utf8
COLLATE = utf8_general_ci
COMMENT = 'User';
usersコントローラ
// app/controllers/users_controller.php
class UsersController extends AppController {
var $name = 'Users';
var $uses = array( 'User');
var $components = array( 'Qdmail');
function beforefilter(){
// 非ログイン状態でアクセス可能にするアクションを指定
$this->Auth->allow(array( 'signup','thanks','activate'));
}
function signup(){
if (!empty($this->data)) {
// save OK
if ($this->User->save( $this->data)) {
// 登録データ再取得
$account = $this->User->FindByUsername( $this->data['User']['username']);
// メール送信
$this->_SendMail( $account);
// thanks画面へ遷移
$this->redirect( '/users/thanks');
// save NG
} else {
$this->set( 'valerror', $this->User->validationErrors);
}
}
}
function thanks(){
// Viewの表示のみ。
}
function activate( $user_id = null, $in_hash = null) {
$this->User->id = $user_id;
if ($this->User->exists() && ($in_hash == $this->User->getActivationHash())) {
// statusを0(本登録)に更新
$this->User->saveField( 'status', 0);
$this->Session->setFlash( 'Your account has been activated, please log in below');
$this->redirect( 'login');
}
}
function _SendMail( $account = null){
// 本登録用URL
$this->activate_url = 'http://' . env('SERVER_NAME') . '/users/activate/' . $account['User']['id'] .'/' . $this->User->getActivationHash();
// メール本文
$text = "Activate via " . $this->activate_url;
// メール送信
$this->Qdmail->subject( 'Thank you for Signup!');
$this->Qdmail->text( $text);
$this->Qdmail->smtp( true);
$this->Qdmail->smtpServer( $this->mail_param);
$this->Qdmail->to( $account['User']['username'], 'Reciever');
$this->Qdmail->from( '送信者のメールアドレス', '');
$this->Qdmail->send();
}
signupアクション
登録データの(バリデーション+)保存を行い、メール送信を行います。送信データ内に含める本登録用のリンク(activate_url)を作成します。activate_urlは以下のフォーマットとします。
- env('SERVER_NAME'):ドメイン名が入ります。正しく作成されない場合はSERVER_NAMEの設定を確認する必要があります。
- ユーザID:再取得したUserデータのID
- ハッシュ値:getActivationHash()で該当ユーザ用のハッシュ値を生成します。
thanksアクション
ページの表示のみ行います。
activateアクション
idの存在確認を行い、getActivationHashを再度呼び出し第2引数のハッシュ値の検証を行います。
statusは、テーブル作成時にデフォルトで1を設定しています。0に更新します。
(1:「仮登録済み」/0:「本登録済み」。)
userモデル
// app/models/User.php
class User extends AppModel {
var $name = 'User';
public $validate = array(
'username' => array(
'validEmail' => array( // email
'rule' => array( 'email', true),
'message' => 'Please supply a valid & active email address'
),
'emailExists' => array( // 登録済みであるか
'rule' => 'isUnique',
'message' => 'Sorry, this email address is already in use'
),
),
'password1' => array(
'match' => array( // パスワード・確認パスワードの一致
'rule' => array( 'confirmPassword', 'password1', 'password2'),
'message' => 'Passwords do not match'
),
'minRequirements' => array( // パスワード長
'rule' => array( 'minLength', 6),
'message' => 'Passwords need to be at least 6 characters long'
)
),
);
function getActivationHash(){
if (!isset( $this->id)) {
return false;
}
return substr(
Security::hash( Configure::read( 'Security.salt') . $this->field( 'modifed')), 0, 16);
}
public function confirmPassword( $field, $password1, $password2) {
if ($this->data['User']['password1'] == $this->data['User']['password2']) {
$this->data['User']['password'] = Security::hash( $this->data['User']['password1'], null, true);
return true;
}
}
}
getActivationHash
activateの認証用ハッシュキーを作成します。以下の2つを繋ぎ合わせハッシュ化し、先頭16バイトを抽出しています。
- app/config/core.php内にあるSecurity.salt → Configure::read('Security.salt')
- 登録されたユーザのmodified → $this->field('modified')
また、リンクに時限を設ける場合は、時間locatime()などを付与して、activate時に24時間以上経過している場合は無効にするなどの処理をするという方法もありかもしれません。
confirmPassword
設定パスワードと確認用パスワードの合致を確認するためのメソッドです。
[ソース:/cake/libs/security.php]
与えられた文字列をハッシュ化します。$Auth->passwordと同じ(Security::hashを呼出)です。モデル内では、Authコンポーネントが使えないため、こちらを使用できます。
- $string:ハッシュ対象の文字列
- $type:hashメソッドのタイプ // sha1・sha256(mhash)・md5 (指定なしの場合は、sha1)
- $salt:core.php内のSecurity.saltを付与してハッシュ化するか否か。
signupビュー
// app/views/users/signup.ctp
<?php
if (($session->check('Message.flash'))){
echo $session->flash();?>
}
if (!empty($valerror['username'])){
echo $valerror['username'];
}
echo $form->create('User', array( 'type'=>'post', 'controller'=>'users', 'action' => 'signup'));
echo $form->text( 'username',array());
echo $this->Form->submit( 'Sign up');
echo $form->end();
?>
thanksビュー
// app/views/users/thanks.ctp 「登録ありがとうございます。」など
activateビュー
// app/views/users/activate.ctp 「リンクが無効です。」など
関連記事
-
-
複数データベースの追加と切替
CakePHPで複数のデータベースに切替を行うということがあると思います。(個人的にはあまりない) 今回、CakePHPからWordpressのデータベースへの接続を行う機会があったので設定を試して
-
-
recursive設定によるfind()性能改善
CakePHPでは、モデルにアソシエーションを設定している場合、recursive(=>joinする階層)はデフォルトで0に設定されています。「recursiveゼロ」の意味するところとは、「1跨ぎま
-
-
WYSIWYGエディタを実装
WYSIWYGエディタをCakePHPにいくつか試してみました。 CKEditor 実装 // head // View(~.ctp) 解凍してwebroot/jsフ
-
-
CakePHP 1.3 インストール
使い古されている手ではありますが、表題の件とレンタルサーバへの配置方法などにも使えますので参考にしていただけたらと思います。 まずはレンタルサーバでCakePHPを動作させる CakePHPア
-
-
Sessionコンポーネント
ソース: /cake/libs/controller/components/session.php read read($name = null) セッションの情報を読み込みます。 $
-
-
メール送信(qdmail)
CakePHP(+qdmail)でメール送信する処理を実装しました。 準備 2つのライブラリ(.php)をダウンロードし、以下のように配置して下さい。 app/controllers/compo
-
-
シンプルに設置できる数字Captcha「MathCaptcha」
スパム防止などで利用されているCaptchaですが、数字版で使えるものがないか探してみました。 この「MathCapthca」は非常にシンプルに設置できるのはいいですが、やっぱりクエスチョンの部分は
-
-
Jsヘルパーを使用してAjax更新
更新処理でページ遷移を伴う場合、ページ全体をレスポンスするのに対して、Ajax処理ではページの一部のレスポンスが可能となるためサーバからの通信量を抑えることが可能となります。 Jsヘルパーを使用して
-
-
複数ファイルアップロード
CakePHPで複数ファイルのアップロードについて調べてみました。といっても普通のPHPのコードと同じではありますが、postするフィールド名に[]を付与して配列にします。 view
-
-
ログローテーション
CakePHP1.3では標準ではログはタイプごとに出力されるだけで、定期的なローテーションを行ってくれません。放っておくとひたすら1つのファイルにアペンドされていきます。app/tmp/logs以下に



Comment
CakePHP: ユーザ登録(仮登録・メール・本登録) http://kwski.net/cakephp-1-3/880/ … @kwski3さんから
[...] CakePHP: ユーザ登録(仮登録・メール・本登録) | Think deeply, Do less, More effective. [...]