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

ここ最近は、メールアドレスだけでなく、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
「リンクが無効です。」など
  • このエントリーをはてなブックマークに追加

関連記事

ログインに追加の条件を付与する「userScope」

「ユーザ登録」の続きです。 ユーザ登録後、activate(statusを0に設定するを)せずに「仮登録」のままで、正しいusernameとpasswordでログインを試したところ認証に引っかかって

no image

Sessionコンポーネント

ソース: /cake/libs/controller/components/session.php read read($name = null) セッションの情報を読み込みます。 $

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

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

no image

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

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

Cookieログイン

今回は、「keep me logged in」などログイン画面でよくみかけるクッキーログインの機能を使ってみます。 CakePHPには、Cookieコンポーネントがあります。(PHPのsetcook

Textヘルパー

Textヘルパーには、テキスト処理に関する便利な機能があります。リンク付与やテキストの抜粋・ハイライトや切り取り処理など。ソース:/cake/libs/view/helpers/text.php

no image

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

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

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

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

no image

validateErrors と validationErrors

CakePHP試験中に気付いたことがあって、メモです。 $this->validateErrors自身バリデーション処理している 今まで、save時にバリデーションエラーメッセージををログに出力し

no image

Htmlヘルパー

ソース:\cake\libs\view\helpers\html.php charset / 文書の文字コードを設定する <?php echo $this->Html-

Comment

Message

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

*

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

    PAGE TOP ↑