zerosp.blog > PHP > 2008/05/21 21:41 >

[学習 cakePHP #05] ポストされたデータをvalidateでチェック。

前回 #04はGuest Bookに投稿できるまでを作成したんだけど、フォームに何も入力せずに空でもポストできてしまうところで終了となりました。今回は入力されたデータの簡単なチェック処理を追加します。

あと編集・削除の処理があるのにDBテーブルにパスワードのフィールドを忘れていたので追加しました。フィールドは id、title、name、body、pwd、created、modifiedとなってます。

cakePHPのフォームから送られてくるデータ形式を知る。

フォームから送られてくるデータはcakePHPでは $this->data で参照できます。このdataはどんなデータ形式になっているのかを調べてみる。

単純にpr()関数を用いて出力してみました。

Array(
  [Board] => Array(
    [title] => 雨が降ってます。
    [name] => 雨男
    [body] => もうじき6月で梅雨の時期に入っちゃうね。
    [pwd] => 1111
    [id] => 
  )
)

こんな感じの配列データになってました。

Validateチェックする項目をモデルにて指定する。

このGuest Bookでは入力する項目に「タイトル」「名前」「本文」「パスワード」のフィールドがあります。今回は「タイトル」と「名前」「パスワード」に関しては入力なしでも可。「本文」に関しては空データだとエラーというようにしてみます。

validateチェックする項目はモデルで指定することができます。boardモデルを開いて。

<?php
  class Board extends AppModel {
    var $name = "Board";
    var $validate = array(
      "body" => VALID_NOT_EMPTY
    );
  }
?>

今回のvalidateチェックは本文(body)だけなので上記のようになった。VALID_NOT_EMPTYで空かどうかのチェックです。他にもVALID_NUMBER、VALID_EMAIL、VALID_YEARの指定ができる。正規表現でのチェックも可能。

このVALID_NOT_EMPTYやVALID_NUMBERなどは \cake\libs\validators.php に正規表現で定義されています。

define('VALID_NOT_EMPTY', '/.+/');

VALID_NOT_EMPTYは上記のような感じで定義がされている。同じように追加で定義していけば モデルのvalidateでチェックできるようになります。

他の項目は正規表現を用いてチェック。

続いてはタイトルと名前フィールドのチェック。投稿フォーム(data)は配列データだったので名前は $this->data["Board"]["name"] で参照することができます。このデータを正規表現でチェックです。

$pattern = '/^[ \s]*$/';
if (preg_match($pattern, $this->data["Board"]["title"])) {
  $this->data["Board"]["title"] = "no title";
}

空、半角スペース、全角スペースのときはtitleをno titleとします。preg_matchを使って正規表現チェック。最初はeregiを使ってやってみたんだけどなんか知らないけどうまく動作しなかったのでpreg_matchの方を使いました。パスワードが空白ならこちらで指定のパスワードに。まだパスワードの暗号化などは考慮していなくて平文のままです。

そんなこんなで出来上がったboardsコントローラーの投稿処理のところは、↓のような感じになった。

function post() {
  $pattern = '/^[ \s]*$/';
  if ($this->data) {
    if (preg_match($pattern, $this->data["Board"]["title"])) {
      $this->data["Board"]["title"] = "no title";
    }
    if (preg_match($pattern, $this->data["Board"]["name"])) {
      $this->data["Board"]["name"] = "no name";
    }
    if ($this->Board->validates($this->data)) {
      if ($this->data["Board"]["pwd"] == "") {
        $this->data["Board"]["pwd"] = "0123456789";
      }
      $this->Board->save($this->data);
      $this->flash("投稿しました。", "/boards/index", 1);
      return;
    } else {
      $this->validateErrors($this->Board);
      $this->render();
      exit;
    }
  } else {
    $this->redirect("/boards");
  }
  $this->redirect("/boards");
}

処理の流れ的には、フォームデータを受け取る → 名前・タイトルを正規表現でチェック → $this->data をBoardモデルのvalidateを通してチェック → OKなら保存。NGならエラー表示をする。といった流れ。

そしてエラー表示用のpost.thtmlはこのように、

<div id="form">
  <p id="fheader">メッセージフォーム</p>
  <form method="post" action="<?php echo $html->url("/boards/post") ?>">
  <dl>
    <dt>タイトル : </dt>
    <dd><?php echo $html->input("Board/title", array("size" => "35")) ?></dd>
    <dt>名前 : </dt>
    <dd><?php echo $html->input("Board/name", array("size" => "35")) ?></dd>
    <dt>本文 : </dt>
    <dd><?php echo $html->textarea("Board/body", array("rows" => "5", "cols" => "50")) ?>
        <?php echo $html->tagErrorMsg("Board/body", "本文を入力してください。") ?></dd>
  </dl>
  <p><?php echo $html->hidden("Board/id") ?>
    <?php echo $html->submit("post", array("class" => "sb")) ?></p>
  </form>
</div>

indexのビュー(index.thtml)からフォームの部分を抜き出してちょっと追加したものになります。今回は本文が空だったときにだけエラーにしましたけど、普通は名前やタイトルが空だった場合にもエラー出しますよね。

今回覚えた関数とか。

cakePHP → validates、validateErrors、tagErrorMsg、render
PHP → preg_match、eregi、

(追記 #1) 2008-05-27 今回覚えた関数について以下を追加に書いておきます。

validates

modelに定義されている関数。

Model::validates($options = array())

今回は $this->Board->validates($this->data) と使いました。フォームから受け取ったデータをモデルのvalidates関数に渡して validateにチェック指定された「body」をチェックしています。チェックがOKならばtrueがNGならfalseが返ってきます。

validateErrors

controlerに定義されているvalidate用の関数。

Controller::validateErrors()

パラメータとしてモデルを渡します。上の例では $this->validateErrors($this->Board); とこんな感じで使っています。

Array (
  [body] => 1
)

返り値は配列にて。validateチェックでNGの場合には 1が返されます。

tagErrorMsg

HtmlHelperで定義されている関数。

HtmlHelper::tagErrorMsg($field, $text)

fieldにて渡されたデータをチェックしてエラーならtextを表示。今回は $html->tagErrorMsg("Board/body", "本文を入力してください。") としてboardモデルのbodyを渡しています。

render

Controllerに定義されている関数。

Controller::render($action = null,
                  $layout = null,
                  $file = null)

デフォルトではビューはコントローラのメソッドの実行が終了した時点?でそのメソッドに対応するビューのテンプレが実行されます。editメソッドを終えるとedit.thtmlが実行される。render()関数を使うとこちらでビューに使うテンプレなどを指定することができます。パラメータ指定なしの $this->render()として使うとデフォルトのビューが呼び出されます。$this->render("index") とするとindex.thtmlが呼ばれます。普通にテンプレじゃなくてただのHTMLなんかも呼び出せるんだけどその場合は $this->render(null, null, "/path/filename") なんて感じでパス付でファイル名を指定します。

preg_match

正規表現のマッチングを行うPHP関数

preg_match($pattern, $str, $matches, $flags, $offset)

$strを正規表現($pattern)にて検索。

eregi

大文字小文字を区別せずに正規表現によるマッチングを行うPHP関数

eregi($pattern, $strg, $regs)

指定した正規表現($pattern)により、大文字小文字を区別せず$strを検索。

preg_matchとeregiはPHPリファレンスの説明を見るとほぼ同じみたいだったんだけど、なぜか今回eregiだとうまくマッチしなかったんだよな。正規表現の書き方が悪かったかしら・・・。

はい。このエントリにて覚えた関数を書き出してみたんだけど、書いている最中に postメソッドのコードのミスに気がついた。別でエントリを書きます。(追記 #1 ここまで)

(追記 #2) コードの修正箇所は[学習 cakePHP #06] 前回の#05のpostメソッドを修正。に書きました。(追記 #2ここまで)

投稿日 2008-05-21 21:41

当サイトのコメントとトラックバックの扱いについて。

スパム対策のため認証制となっています。受け取ったコメント、トラックバックは一旦保留扱いとなり管理人が許可したものだけ表示されます。

トラックバック

トラックバックの受付は停止中です。

コメント

コメントの受付は停止中です。