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

以前1.3版で投稿した「ユーザ登録」処理の2.x版を作成しました。フローは同じで以下のようにします。

1. メールアドレス・パスワードでユーザ登録
2. この時点では仮登録として、本登録用のURLリンクをメールで送付
3. 送付されたリンクをクリックして「本登録完了(activate)」とする

ユーザ(users) テーブル

statusを用意し、デフォルトを1としています。"1"を仮登録状態でログイン不可、"0"を本登録としログイン可能にします。その制御は、scopeが使えそうです。

-- usersテーブル
CREATE TABLE IF NOT EXISTS `users` (
    `id` INT NOT NULL AUTO_INCREMENT ,
    `username` VARCHAR(255) NOT NULL ,
    `password` CHAR(128) 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';

usernameカラムの長さですが、innoDB+utf8の場合は最長で設定できるのは255になります。(MySQL)
passwordカラムの長さは、使用するハッシュ関数によります。ハッシュ化を参考にして下さい。

Userモデル

confirmPasswordメソッドでパスワードと確認用パスワードの一致の確認を行い、ハッシュ化しています。
独自のバリデーションルールを作成
「isUnique」バリデーション

// app/Model/user.php
<?php
class User extends AppModel {
    var $name = 'User';
    var $useTable = 'users';
    public $validate = array(
        'username' => array(
            // メールアドレスであること。
            'validEmail' => array( 'rule' => array( 'email', true), 'message' => 'アドレスを入力して下さい'),
            // 一意性チェック
            'emailExists' => array( 'rule' => 'isUnique', 'message' => '既に登録されています'),
        ),
        'password' => array(
             // パスワード・確認用パスワードの一致
             'match' => array( 'rule' => array( 'confirmPassword', 'password_confirm'), 'message' => '一致しません'),
        )
    );

    public function confirmPassword( $field, $password_confirm) {
        if ($field['password'] === $this->data[$this->name][$password_confirm]) {
            // パスワードハッシュ化
            $this->data[$this->name]['password'] = Security::hash( $plain, 'sha512', true);
            return true;
        }
    }
}
?>

Usersコントローラー

// app/Controller/UsersController.php
<?php
class UsersController extends AppController {
    // Authコンポーネント
    var $components = array( 'Auth');

    public function beforeFilter() {
        parent::beforeFilter();
        // 非ログイン時にも実行可能とする
        $this->Auth->allow( array( 'signup', 'activate'));
    }
    public function signup(){
    }
    public function activate(){
    }
}
?>

ユーザ登録(signup) ビュー

メールアドレスとパスワードを入力するフォームです。ここでは、それぞれのフォームに意図的にtypeを指定していますが、自動的に付与する場合は以下を参照して下さい。

// app/View/Users/signup.ctp
<?php
    echo $this->Form->create( 'User', array( 'type'=>'post', 'url'=>'signup'));
    // ユーザ名
    echo $this->Form->text( 'username', array( 'maxlength' => '255', 'type' => 'email'));
    // パスワード
    echo $this->Form->text( 'password', array( 'maxlength' => '50', 'type' => 'password'));
    // パスワード確認用
    echo $this->Form->text( 'password_confirm', array( 'maxlength' => '50', 'type' => 'password'));
    echo $this->Form->end( 'Signup');
?>

signupアクション

// app/Controller/UsersController.php
public function signup() {
    if (!empty( $this->data)){
        //  保存
        if( $this->User->save( $this->data)){
            // ユーザアクティベート(本登録)用URLの作成
            $url = 
                DS . strtolower($this->name) .          // コントローラ
                DS . 'activate' .                       // アクション
                DS . $this->User->id .                  // ユーザID
                DS . $this->User->getActivationHash();  // ハッシュ値
            $url = Router::url( $url, true);  // ドメイン(+サブディレクトリ)を付与
            //  メール送信
            //  return
            $this->Session->setFlash( '仮登録成功。メール送信しました。');
        } else {
            //  バリデーションエラーメッセージを渡す
            $this->Session->setFlash( '入力エラー');
        }
    }
}

■passwordのハッシュ化
モデル内でパスワード確認(confirmPassword)の中で行っています。
ハッシュ化についてはここを参照して下さい。

■ユーザアクティベート(本登録)用URLの作成
ここでは、わかりやすく以下のようにしています。
サイトURL/サブディレクトリ/コントローラ/アクション/ユーザID/ハッシュ値

■ハッシュ値の生成
Userモデルに以下を追加して下さい。簡単に言うと更新日時をハッシュ化したものになります。ハッシュ関数はどれを使用するかは自由。(下の例だと'md5')
リンクに時限を設ける場合は、時間locatime()などを付与して、activate時に24時間以上経過している場合は無効にするなどの処理をするという方法もありかもしれません。

public function getActivationHash() {
    // ユーザIDの有無確認
    if (!isset($this->id)) {
        return false;
    }
    // 更新日時をハッシュ化
    return Security::hash( $this->field('modified'), 'md5', true);
}

■メール送信部分は、以下を参照してアクティベート用URLを送信して下さい。

本登録(activate)アクション

ユーザ側に無事メール送付できたところで、本登録を行ってもらいます。

public function activate( $user_id = null, $in_hash = null) {
    // UserモデルにIDをセット
    $this->User->id = $user_id;
    if ($this->User->exists() && $in_hash == $this->User->getActivationHash()) {
    // 本登録に有効なURL
        // statusフィールドを0に更新
        $this->User->saveField( 'status', 0);
        $this->Session->setFlash( 'Your account has been activated.');
    }else{
    // 本登録に無効なURL
        $this->Session->setFlash( 'Invalid activation URL');
    }
}

再度、ユーザの更新日時をもとにハッシュ値を確認して、有効な場合は'status'を0に更新、無効な場合はエラーメッセージを返します。

本登録(activate)ビュー

<?php 
    echo $this->Session->flash();
    echo $this->Html->link( 'ログイン画面へ', '/users/login');
?>
  • このエントリーをはてなブックマークに追加

関連記事

(メール・URL・電話・郵便・IP) データ バリデーション

今回は、プロフィール情報に使用されるデータに絞ったバリデーションルールです。 バリデーションルール 以下の5つのバリデーションルールがコアに用意されています。 email メールアドレス

バリデーションエラーメッセージの取得

CakePHP 2.xになってバリデーションエラー時に返却されるメッセージのデータ形式が変更になったようです。1.3系では、ひとつのフィールドに対して返却されるメッセージは一つのルールのみですが、2.

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

ユーザ登録では、仮登録処理(status=1)から送付したメール内のリンクをクリックしてもらい本登録(status=0)を行ってもらう実装をしました。仮登録の状態ではログインできないように実装するには

FullCalendarを使用してカレンダーアプリケーション

カレンダーアプリケーションを作成するため、カレンダー表示できるプラグインを探索して出会ったFullcalendarを試してみました。シンプルに使用できる上に、オプションがかなり豊富です。ダウンロード

多言語サイト向けに翻訳ファイルを使って翻訳を行う

CakePHPには、翻訳をビヘイビアを使用する方法と翻訳ファイルを使用する方法の2つがあるそうです。(他にもあるのかな?) 今回は、翻訳ファイルを使用して言語の切り替えを行い、その言語設定をCook

Cookieログイン

今回は、ログイン画面でよくみかけるクッキーログインの機能を使ってみます。 CakePHPには、Cookieコンポーネントがあります。(PHPのsetcookieメソッドのラッパー)メソッドはwr

バリデーション前後に処理を追加できる「beforeValidate」「afterValidate」

CakePHPでは、「beforeValidate」「afterValidate」というバリデーション処理の前後で追加の処理を実装できるコールバック関数が用意されています。 beforeVali

hasOne アソシエーション

hasOneアソシエーションはテーブル間で1つのレコードに対して他のテーブルに紐付くレコードが1つの場合にjoinする場合に使用します。 CakePHPのドキュメントにならってUserモデルとP

Markdown Plugin

「Markdown CakePHP Plugin」は、MarkDown書式をレンダリングしてくれるビューヘルパーです。MarkDownについて勉強しているうちに出会ったので試し打ちです。 ダウンロー

複数ファイルアップロードフォーム

CakePHP 2.0からはHTML5が標準でサポートとなり、複数ファイルアップロードのためのフォーム記述が容易になりました。 View (ビュー) 配列 Array (

Comment

  1. confirmPasswordですが、常にfalseになるため、以下の処理に書き換えましたが何か処理を忘れているのでしょうか

       public function confirmPassword( $field, $password, $password_confirm) {
            if ($this->data[$this->name][$password] == $this->data[$this->name][$password_confirm]) {
                // パスワードハッシュ化
                $this->request->data['User']['password'] = Security::hash( $password, 'sha512', true);
                return true;
            }
        }
    
    • コメントありがとうございます。
      いただいたコードが正しいようです。勝手ながら、修正に上記を使用させていただきます。
      ご指摘いただき、ありがとうございました。

  2. とても参考になります!ありがとうございます!

    1点質問がございます。
    signupアクションの5行目にて、

    $this->User->save( $this->data)
    

    がございますが、私のコントローラーでは都合上、項目ごとに登録する必要がございまして、

    'password' => $this->request->data['User']['password']
    

    としているのですが、上記だとパスワードがnullになります。
    かと言って、

    'password' => $this->request->data['User']['plain']
    

    とするとハッシュ化されていないパスが登録されてしまいます。

    上記の場合どのように指定すれば良いかお教え願えませんでしょうか。


    本登録(activate)アクションの3行目は、

    $this->User->id = user_id;
    ↓
    $this->User->id = $user_id;
    

    ですよね??

    • コメントありがとうございます。

      $this->User->save( $this->data)

      の前にハッシュ化する処理を追加してみて下さい。

      $this->request->data['User']['password'] = Security::hash( $this->request->data['User']['plain'], 「ハッシュタイプ」, true);

      (この投稿では、モデル内のconfirmPasswordバリデーションで行っています。)

      user_idの件、確かに!ありがとうございました。

Message

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

*

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

    PAGE TOP ↑