「情報を保存する」オプションを有効にする(CakePHP修行 #34)

SPONSORED LINK

Pocket

さて続けてCakePHP修行。今度はログイン画面での「情報を保存する」オプションを有効にしてみます。

save_info.gif

↑ 今回はこれがターゲット!

淡々と作業を続けます。

■ クッキーを使う

今までログイン情報の保持にはセッションを使っていましたが、それだとブラウザを閉じた後にも情報を保持してくれません。というわけでクッキーを導入。で、調べてみるとどうやらセッションのようにComponentはない模様(1.1系には)。そこでそのままsetcookieやら$_COOKIEやらを使っていきます。

なお、セッションから完全移行というわけではなく、簡単なメッセージは相変わらずセッションを使って表示することにします。

■ データベーススキームの変更

次にユーザー個別のCookieを保持するためのUsersテーブルを変更します。id_hashというカラムを追加します。なお、この変数には「適当な文字列」「ID」「パスワード」を連結してハッシュ化したものを使います。そしてこのid_hashをCookieとしてブラウザに保持、ログインしているかどうかのチェックに使います。

結局、Usersテーブルはこんな感じ。

CREATE TABLE users (
  id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  id_hash VARCHAR(50),
  name VARCHAR(50),
  email VARCHAR(255) BINARY NOT NULL UNIQUE,
  pwd VARCHAR(255),
  pic VARCHAR(255),
  profile TEXT,
  created DATETIME DEFAULT NULL,
  modified DATETIME DEFAULT NULL
);

なお、適当な文字列にはパスワードを暗号化するために使ったPWD_KEYを使いまわします。よく考えたら使いまわすのよくないか、まぁ、いいや・・。

■ ログインチェックのロジックを変更

いままでログインチェックにはapp_controller.phpのcheckSession()を使っていましたが、セッションではなくなるので_checkLogin()を新しく作ることにします。変数の前には_をつけましたが、これでいいんすよね?

実際のコードはこんな感じ。

function _checkLogin() {
  // if cookie exists ...
  if (!isset($_COOKIE['my_id']) || !$this->User->FindById_hash($_COOKIE['my_id'])) {
    $this->Session->write('login_back_url',((getenv('SERVER_PORT')==443)?'https://':'http://').getenv('HTTP_HOST').getenv('REQUEST_URI'));
    $this->redirect('/users/login');
    exit();
  }
}

そしてusers_controller.php中のcheckSession()を_checkLogin()に変更します。

■ ログイン画面&ロジックの変更

まずはView(login.thtml)の変更。「情報を保存する」チェックボックスを有効にします。HTMLヘルパーを使って以下のように記述。

<tr><td width="40%">&nbsp;</td><td><?php echo $html->checkbox('User/save'); ?> save my info?</td></tr>

Usersのスキーマにないsaveってのを勝手に作ってしまったがいいのだろうか。ま、どちらにしろこれでコントローラー側で$this->data[‘save’]から受け取れるようになりました。

それでもってlogin()も次のように変更。データが入ってきたときに以下のように処理します。

$someone = $this->User->findByEmail($this->data['User']['email']);
if(!empty($someone['User']['pwd']) && $someone['User']['pwd'] == sha1(PWD_KEY.$this->data['User']['pwd']))
{
  if ($this->data['User']['save']) {
    setcookie('my_id', $someone['User']['id_hash'], time()+60*60*24*365*5, '/'); // save it for 5 years
  } else {
    setcookie('my_id', $someone['User']['id_hash'], NULL, '/');
  }
  if (isset($login_back_url))
  {
    $this->redirect($login_back_url);
    $this->Session->delete('login_back_url');
  } else {
    $this->redirect('/users/home/');
  }
}

これによってブラウザ側にCookieが保存されますが、チェックボックスを入れていると5年間、問答無用で保存します。まぁ、これぐらいあればいいですかね。チェックを入れていない場合はブラウザが終了するまで保持することとします。

それからsetcookie中でパス指定(今回は”/”)をしたのですが、これってなんかセキュリティ上、やばいんじゃなかったかな?でもこれを指定しないと”/users”のみで有効になってしまうという結果に・・。これでよかったのかな?

■ コントローラー中の処理

今回の処理で「セッション中にUser IDを保持」から「Cookie中にid_hashを保持」に変わったのでコントローラーの各処理を次のような感じにしておきます。

$me = $this->User->findById_hash($_COOKIE['my_id']);

さて、ここまでで「情報を保存する」オプションがきちんと有効になるようになりました・・・。

cookie_view.gif

↑ クッキーを確認。ちゃんと有効期限が5年後になっています。

■ ログアウト処理

おっと、忘れるところだった。ログイン処理を変えたのでログアウト処理も変更します。コードは以下のとおり。

function logout()
{
  setcookie('my_id','',time()-60*60,'/');
  $this->redirect('/users/home/');
}

やれやれ(JOJO)、ログイン画面だけでだいぶ時間を使ってしまった。次はいよいよ日記の投稿へ行きましょう。アソシエーションとか早くやってみたい。

※ CakePHP修業は百式管理人がSNSっぽいものをCakePHPで作ろうとして挫折するまでの日記です。前回までのあらすじはこちらへ。

ツイッターもやっています!

SPONSORED LINK

  1. No comments yet.