【CakePHP2】お問い合わせフォームをつくる(確認画面あり)

CakePHP2で簡単なコンタクトフォームをつくります。

  • メール送信にCakeEmailを使用。
  • バリデーション用にContactモデルを作成。
  • 確認画面を挟む。
環境
PHP
5.6
CakePHP
2.8.0

今回作成するファイル

app/
|-- Config/
|   `-- email.php
|-- Controller/
|   `-- ContactController.php
|-- Model/
|   `-- Contact.php
|-- View/
|   |-- Contact/
|   |   `-- ContactController.php
|   |-- Emails/
|   |   `-- text/
|   |       `-- contact.ctp
|   `-- Emails/
|       `-- text/
|           `-- contact.ctp
`-- Layouts/
    `-- Emails/
        `-- text/
            `-- contact.ctp

メールの設定

/Config/email.php.default/Config/email.phpとリネームし、基本設定を書いていきます。コントローラー側でも追記できますが、可能な限りここで定義しておきます。Gmailなど外部のメールサーバーも使用できます。

/Config/email.php
public $contact = array(
    'transport' => 'Mail',
    'from' => array('mail@example.com' => 'My Site'),
    'to' => 'mail@example.com',
    'subject' => 'お問い合わせ'
);

public $gmail = array(
    'transport' => 'Smtp',
    'host' => 'ssl://smtp.gmail.com',
    'port' => 465,
    'username' => 'my@gmail.com',
    'password' => 'secret'
);

モデル

今回、データベースにcontactsテーブルは作っていませんが、バリデーションで使用するためにContactモデルを用意します。

バリデーション名が変更

空文字のバリデーション名がCakePHP2.7からnotBlankとなっています。2.7未満ではnotEmptyに変更してください。

/Model/Contact.php
<?php
class Contact extends AppModel
{
    public $useTable = false;   
    public $_schema = array(
        'name' => array('type' => 'string', 'length' => 255),
        'email' => array('type' => 'string', 'length' => 255),
        'subject' => array('type' => 'string', 'length' => 255),
        'body' => array('type' => 'text'),
    );

    public $validate = array(
        'name' => array(
            'notBlank' => array(
                'rule' => array('notBlank'),
                'message' => '未入力です。',
                'required' => true,
            ),
            'maxLength' => array(
                'rule' => array('maxLength', 255),
                'message' => '255文字以内で入力してくだい。',
                'required' => true,
            ),
        ),
        'email' => array(
            'notBlank' => array(
                'rule' => array('notBlank'),
                'message' => '未入力です。',
                'required' => true,
            ),
            'email' => array(
                'rule' => array('email'),
                'message' => 'メールアドレス以外が入力されています。',
                'required' => true,
            ),
            'maxLength' => array(
                'rule' => array('maxLength', 255),
                'message' => '255文字以内で入力してくだい。',
                'required' => true,
            ),
        ),
        'subject' => array(
            'notBlank' => array(
                'rule' => array('notBlank'),
                'message' => '未入力です。',
                'required' => true,
            ),
            'maxLength' => array(
                'rule' => array('maxLength', 255),
                'message' => '255文字以内で入力してくだい。',
                'required' => true,
            ),
        ),
        'body' => array(
            'notBlank' => array(
                'rule' => array('notBlank'),
                'message' => '未入力です。',
                'required' => true,
            ),
            'maxLength' => array(
                'rule' => array('maxLength', 3000),
                'message' => '3000文字以内で入力してくだい。',
                'required' => true,
            ),
        ),
    );
}

ビュー

フォーム画面(入出力)のビューと、メールテンプレート用のビューを書いていきます。

フォーム入力画面

バリデーションのエラー表示をしたいので、容易にできるFormヘルパーを使用しています。

/View/Contact/contact.ctp
<?php
echo $this->Session->flash();

echo $this->Form->create('Contact');

echo $this->Form->input('name', array(
        'type' => 'text',
        'label' => 'お名前',
        'maxlength' => 255,
        )
     );

echo $this->Form->input('email', array(
        'type' => 'email',
        'label' => 'メールアドレス',
        'maxlength' => 255,
        )
     );

echo $this->Form->input('subject', array(
        'type' => 'text',
        'label' => '題名',
        'maxlength' => 255,
        )
    );

echo $this->Form->input('body', array(
        'type' => 'textarea',
        'label' => 'お問い合わせ内容',
        'maxlength' => 3000,
        )
    );

echo $this->Form->button('確認する', array(
        'type' => 'submit',
        'name' => 'confirm',
        'value' => 'confirm'
    ));

echo $this->Form->end();

フォーム確認画面

送信データをhiddenへ。

/View/Contact/contact_confirm.ctp
<dl>
<?php foreach ($this->request->data['Contact'] as $name => $val): ?>
    <dt><?php echo h($name); ?></dt>
    <dd><?php echo h($val); ?></dd>
<?php endforeach; ?>
</dl>

<?php
echo $this->Form->create('Contact');

foreach ($this->request->data['Contact'] as $name => $val) {
    echo $this->Form->hidden($name, array('value' => $val));
}

echo $this->Form->button('修正する', array(
        'type' => 'submit',
        'name' => 'confirm',
        'value' => 'revise'
    ));

echo $this->Form->button('送信する', array(
        'type' => 'submit',
        'name' => 'confirm',
        'value' => 'send'
    ));

echo $this->Form->end();

メール本文の表示

メール本文表示用のビューを書きます。コントローラー $email->viewVars($content) でセットされます。

/View/Emails/text/contact.ctp
お問い合わせ:
<?php echo $subject; ?>

名前:
<?php echo $name; ?>

メールアドレス:
<?php echo $email; ?>

本文:
<?php echo $body;

メールレイアウト

/View/Layouts/Emails/text/contact.ctp
<?php echo $this->fetch('content'); ?>
---------------------------------------
署名などの雛形

コントローラー

まずはフォームから受け取ったデータをバリデーション。エラーが無ければ確認ページを表示。その後、送信ボタンをクリックでメール送信処理をします。確認画面、送信処理前の両方でバリデーションしているのは改変対策のためです。

/Controller/ContactController.php
public function contact()
{
    if (!$this->request->is('post') || !$this->request->data) {
        return;
    }

    $this->Contact->set($this->request->data);

    if (!$this->Contact->validates()) {
        $this->Session->setFlash('入力内容に不備があります。');
        return;
    }

    switch ($this->request->data['confirm']) {
        case 'confirm':
            $this->render('contact_confirm');
            break;
        case 'send':
            if ($this->sendContact($this->request->data['Contact'])) {
                $this->Session->setFlash('お問い合わせを受け付けました。');
                $this->redirect('/');
            } else {
                $this->Session->setFlash('エラーが発生しました。');
            }
            break;
    }
}

private function sendContact($content)
{
    App::uses('CakeEmail', 'Network/Email');
    $email = new CakeEmail('contact');

    return $email
        ->from(array($content['email'] => $content['subject']))
        ->viewVars($content)
        ->template('contact', 'contact')
        ->send();
}

以上で簡単なコンタクトフォームができました。

おわりに

今回は使用しませんでしたが、セキュリティコンポーネントを使って改変対策やワンタイムトークンを追加したほうが安全です。また、IPやユーザーエージェントなども取得しておくとイタズラ対策にもなります。