ユーザ登録(仮登録・メール・本登録)

ここ最近は、メールアドレスだけでなく、SNSのアカウントと連携してユーザ登録することもできるWebサービスが増えてきましたね。ユーザは割合としてどちらを選んでるのか気になるところですが。私はできるだけ連携は避けて、棄アドレスで登録することにしてます。

今回はメールアドレスでのユーザ登録機能。仕様は以下にしました。

  1. 「ユーザ登録画面(/signup」)にて、メールアドレス/パスワードでユーザ登録
  2. 「仮登録完了画面(/thanks)」へ遷移する。この時点では仮登録とし、ユーザに本登録用のリンクをメールで送付する。**メール送信機能は、qdmailを使用する。
  3. ユーザはメール送付されたリンクをクリックして「本登録完了(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は以下のフォーマットとします。

http://[domain]/users/activate/「ユーザID」/「ハッシュ値」

  • 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

設定パスワードと確認用パスワードの合致を確認するためのメソッドです。

Security::hash($string, $type = null, $salt = false)
[ソース:/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
「リンクが無効です。」など
  • このエントリーをはてなブックマークに追加

関連記事

no image

recursive設定によるfind()性能改善

CakePHPでは、モデルにアソシエーションを設定している場合、recursive(=>joinする階層)はデフォルトで0に設定されています。「recursiveゼロ」の意味するところとは、「1跨ぎま

no image

独自のバリデーションルール

CakePHPで組み込みバリデーションをつくる方法は色々あります。 参考:Data Validation — CakePHP Cookbook v1.3 documentation 上記リンク内に

no image

Secutiryユーティリティ

CakePHPでは、データのハッシュ化もしくは暗号化のためのメソッドSecurityユーティリティが用意されています。 ソース: /cake/libs/security.php Security:

no image

シンプルに設置できる数字Captcha「MathCaptcha」

スパム防止などで利用されているCaptchaですが、数字版で使えるものがないか探してみました。 この「MathCapthca」は非常にシンプルに設置できるのはいいですが、やっぱりクエスチョンの部分は

no image

Jsヘルパーを使用してAjax更新

更新処理でページ遷移を伴う場合、ページ全体をレスポンスするのに対して、Ajax処理ではページの一部のレスポンスが可能となるためサーバからの通信量を抑えることが可能となります。 Jsヘルパーを使用して

no image

WYSIWYGエディタを実装

WYSIWYGエディタをCakePHPにいくつか試してみました。 CKEditor 実装 // head // View(~.ctp) 解凍してwebroot/jsフ

フィールド単位でバリデーション無効化

save処理の際に条件付でモデルのバリデーションをフィールド単位でスキップする処理のメモです。(最終的に使うことはなかったのでメモ) 関数は unset( $this->->validate[

no image

ログローテーション

CakePHP1.3では標準ではログはタイプごとに出力されるだけで、定期的なローテーションを行ってくれません。放っておくとひたすら1つのファイルにアペンドされていきます。app/tmp/logs以下に

複数データベースの追加と切替

CakePHPで複数のデータベースに切替を行うということがあると思います。(個人的にはあまりない) 今回、CakePHPからWordpressのデータベースへの接続を行う機会があったので設定を試して

コントローラ内でバリデーション処理を呼び出す

通常、saveメソッドの際にバリデーション処理も自動で行われますが、save処理と切り離してバリデーションを行うこともできます。このときは、save時と若干異なる処理体系になります。 バリデーシ

Comment

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

    PAGE TOP ↑