チュートリアル フォームの作成とDBの使い方
次 チュートリアル 複数のアプリケーションをフォルダごとにわける
おはようございます。いつまでも中二病を卒業できないゆうきんです。
今回はフォームの作成と、送信したデータをDBに書きこむということをやってみたいと思います。
現代のWebサイトでDBが絡まないということはとても少ないです。
というわけで、作って行きましょう。
あ、Smartyの使い方ってページ読みました?
今回からビューは全てSmartyを使って書いていくので、読んでおいて下さい。
ユーザに登録させる情報を決める
今回はユーザに ユーザ名、ユーザID、パスワード、e-mailアドレス、を登録させたいと思います。
ユーザ名は1〜8文字まで、ユーザIDとパスワードは半角英数字で4〜12文字という制約を設けます。
データベースの構造を考える
まず前提として文字列は全て utf8_general_ci を使います。
データベース名 test で、テーブル名は users としましょう。
プレイマリ は id というカラムで、オートインクリメントも有効にしておきます。
ame, userid, password, email というカラムも追加しましょう。
全部 text 形式でOKです。
画面遷移を決める
- 入力ページ
- 確認ページ
- 完了ページ
の3つを作成し、上から順に遷移していくものとします。
いろいろ決まった所で作っていきます。
こらから作るファイルはサブフォルダは作らず、controler, model, views のフォルダに配置するものとします。
入力ページの作成
こちらが、入力ページのソースです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>ユーザ情報登録入力ページ</title> </head> <body> {if (isset($errors))} {$errors} {/if} {Form::open('input/confirm')} <p> {Form::label('ユーザ名', 'username')} {Form::input('username', Input::post('username'), ['required'=>'required'])}<br /> </p> <p> {Form::label('ユーザID', 'userid')} {Form::input('userid', Input::post('userid'), ['required'=>'required'])}<br /> </p> <p> {Form::label('パスワード', 'password')} {Form::password('password', Input::post('password'), ['required'=>'required'])}<br /> </p> <p> {Form::label('e-mail', 'email')} {Form::input('email', Input::post('email'), ['required'=>'required', 'email' => 'email'])}<br /> </p> <p> {Form::submit('submit','送信')} </p> {Form::close()} </body> </html> |
Formクラスの説明をします。FormクラスはHTMLタグを生成するクラスです。
ここで使っているものを順次説明します。
Form::open
form開始タグを生成します。
第1引数 実行された時の動作、又は、属性の連想配列(例:array(‘action’ => ‘example/index’, ‘method’ => ‘post’))
Form::close
form終了タグを生成します。
引数はありません。
Form::label
labelタグを生成します。
第1引数 ラベル名
第2引数 関連付けたい部品のID
Form::input
inputタグを生成します。
第1引数 任意のID
第2引数 初期データ
第3引数 タグの属性
Form::password
inputタグを生成します。
使い方は Form::input と同じです。
input タグの属性が password になります。
他にもラジオボタンを生成したり、テキストエリアを生成したりできる関数がありますが、割愛します。
input関数の第2引数で Input::post(‘username’) としていますが、これは username が post されていたら、それを初期値で表示するとういことです。
入力内容に誤りがあったとき、確認ページで修正を選択したとき、などに前回入力したデータを初期値で持たせるということをしたいので、このようになっています。
続いて、こちらがコントローラです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
<?php use FuelCoreHttpNotFoundException; class Controller_Input extends Controller { /** * アクションインデックス */ public function action_index() { return View_Smarty::forge('input'); } /** * 確認ページ */ public function action_confirm() { // POST 以外のアクセスを禁止する if( Input::method() != 'POST' ) { throw new HttpNotFoundException; } // 入力チェック $val = $this->get_validation(); // 入力された値が正しかったか? if( $val->run() ) { // 正しい場合は確認ページに遷移 $data['input'] = $val->validated(); return View_Smarty::forge('confirm', $data); } else { // 正しくない倍位は入力ページに戻り、エラーを表示 $input_view = View_Smarty::forge('input'); $input_view->set_safe('errors', $val->show_errors()); return $input_view; } } /** * 入力検証 */ // 検証ルールの定義 public function get_validation() { $val = Validation::forge(); $val->add('username', 'ユーザ名') ->add_rule('required') ->add_rule('min_length', 1) ->add_rule('max_length', 8); $val->add('userid', 'ユーザID') ->add_rule('required') ->add_rule('min_length', 4) ->add_rule('max_length', 12); $val->add('password', 'パスワード') ->add_rule('required') ->add_rule('min_length', 4) ->add_rule('max_length', 12); $val->add('email', 'e-mail') ->add_rule('required') ->add_rule('valid_email'); return $val; } } |
action_index で input ビューを表示。
action_confirm で データが post されていたら、データチェックして confirm ビューを表示。
データに誤りがあれば。エラー内容を input ビューに渡して再表示。
action_confirm で行うデータチェックのルールは get_validation で定義しています。
validation とは?
form の input で入力するデータにルール付を行うことです。
例えばこの文字は30文字しか入力できないとか、4文字以上でなければ認めない、などです。
validation の使い方
Validation::forge メソッドでクラスのインスタンスを生成し、それにルールを加えていきます。
add メソッドで ルール付けを行う input の ID と、任意のフィールド名を指定します。
フィールド名は混乱を避けるために、 input ニ関連付けた label と同じ名前が好ましいです。
そして、 add_rule メソッドでルールを追加します。
ルールの内容はソースを見ていただければわかると思います。
※ メモ:私が悩んだことなのですが trim とは、文字列前後の空白を取り除くphpの標準関数のことです
ルール付けが終わったら run メソッドでデータチェックを行えます。
正しければ true 、間違っていれば false が返ってきます。
validated メソッドでチェックをかけた後のデータを配列で取得することができるので、 confirm ビューニ渡しています。
show_errors メソッドでエラー内容を表示できるので、set_safe メソッドで input ビューに渡しています。
set_safe を使うとエスケープされずに文字列をビューに渡すことが可能です。
確認ページの作成
続いて、 確認ページのソースです。
まずはビューです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>ユーザ情報登録確認ページ</title> </head> <body> <p> ユーザ名:{$input['username']} </p> <p> ユーザID:{$input['userid']} </p> <p> パスワード:{$input['password']} </p> <p> e-mail:{$input['email']} </p> {Form::open('input/')} {Form::hidden('username', $input['username'])} {Form::hidden('userid', $input['userid'])} {Form::hidden('password', $input['password'])} {Form::hidden('email', $input['email'])} <p> {Form::submit('submit','修正')} </p> {Form::close()} {Form::open('input/conplete')} {Form::hidden(Config::get('security.csrf_token_key'), Security::fetch_token())} {Form::hidden('username', $input['username'])} {Form::hidden('userid', $input['userid'])} {Form::hidden('password', $input['password'])} {Form::hidden('email', $input['email'])} <p> {Form::submit('submit','登録')} </p> {Form::close()} </body> </html> |
確認用に受け取ったデータを表示しています。
そして、修正ボタンを押したら入力ページに現在のデータを post して遷移します。
登録ボタンを押したら確認ページに現在のデータを post して遷移します。
そのためフォームタグは2つ用意しています。
以下が、見たことないと思われる関数の使い方と説明です。
Form::hidden
実際には表示されない input タグを生成します。
第1引数 任意のID
第2引数 送信したいデータ
Config::get
config.php の内容を取得できます。
第1引数 取得したい項目名
第2引数 指定した項目名がなかった場合に、代入するデータ
今回は CSRF 対策のため、security 内の csrf_token_key を取得しています。
CSRF 対策用のトークンを post する際の ID は必ず security.csrf_token_key を指定するようにして下さい。
Security::fetch_token
CSRF 対策のトークンを発行します。
引数なし
次に書くコントローラのソースで説明しますが、このトークンをチェックすることにより、CSRF 対策を行うことが出来ます。
続いてコントローラです。
入力ページで作成した Controller_Input クラスに追加して下さい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/** * 完了ページ */ public function action_conplete() { if( Input::method() != 'POST' ) { throw new HttpNotFoundException; } // CSRF対策 if( !Security::check_token() ) { return 'ページ遷移が正しくありません。'; } // DBに書きこむ Model_Input::push_user( Input::post('username'), Input::post('userid'), Input::post('password'), Input::post('email') ); // 完了ページ表示 return View_Smarty::forge('complete'); } |
Security::check_token
引数なし
CSRF 対策トークンをチェックします。
まず post されているかチェック、CSRF トークンチェックを行い、どちらも認証できれば、データベース操作に移ります。
Model_Input::push_user は独自に作ったクラスと関数です。
以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php class Model_Input extends Model { public static function push_user( $username, $userid, $password, $email ) { $result = DB::insert('users')->set(array( 'username' => $username, 'userid' => $userid, 'password' => $password, 'email' => $email, ) )->execute(); return $result; } } |
確認ページの作成
「登録完了しました」と表示しているだけなので、特に記載しません。
以上で、フォームの作り方の説明を終わります。
大分省きました。
本当は、ユーザ名、ユーザIDとe-mailアドレスの2重チェックとか、データベースに書き込み成功したかのチェックかけたりとかしなければなりません。
ここまで、少し調べれば出来ることだと思うので、気が向いたら書くかも知れないです。
以下、どうでもいい話
これ作ってる最中に、同僚に「e-mailアドレスの変数名って emal じゃなくて email_address じゃないの?」って言われました。
そこで「email_address だと長いから address は?」と返したんですが、「address だと住所じゃん(笑)」と言われてしまいました。
確かに email だと意味が違いますし、 address だと住所になっちゃうんで、 email_addressが正解ですね(笑)
でも、なんか間違いを認めると負けた気がするので、私はずっと emal で通しますよ!
同じ理由で職場のエアコンで暖房を付けることを、ストーブを付けると言いはってます。
では、おやすみなさい。