BEAR.Sundayでコンタクトフォームを作ってみる⑤

BEAR.Sundayでコンタクトフォームを作ってみる④の続きです。

今までMVCで言うところの「コントローラ」に対応する「ページリソース」しか使ってなかったので、今日は「モデル」に対応する「アプリケーションリソース」も使ってみます。

なお、言うまでもないことですが、BEAR.SundayはそもそもMVCパターンではないフレームワークなので、「コントローラ」と「ページリソース」や「モデル」と「アプリケーションリソース」が全く同じものということではありません。

それでは、フォームに関する処理はアプリケーションリソースに移動します。

アプリケーションリソースの作成

アプリケーションリソースContact\Formを作成し、フォームの処理とメール送信のロジックを移動します。

src/Resource/App/Contact/Form.php

<?php
/**
 * Kenjis.Contact
 *
 * @author     Kenji Suzuki <https://github.com/kenjis>
 * @license    MIT License
 * @copyright  2014 Kenji Suzuki
 * @link       https://github.com/kenjis/Kenjis.Contact
 */

namespace Kenjis\Contact\Resource\App\Contact;

use BEAR\Resource\ResourceObject;
use BEAR\Resource\Code;
use Kenjis\Contact\Service\SwiftMailerFactory;
use Ray\Di\Di\Inject;

class Form extends ResourceObject
{
    private $mailer;

    /**
     * @Inject
     */
    public function __construct(SwiftMailerFactory $mailer)
    {
        $this->mailer = $mailer;
    }

    /**
     * @BEAR\Sunday\Annotation\Form
     */
    public function onGet()
    {
        return $this;
    }

    /**
     * @BEAR\Sunday\Annotation\Form
     */
    public function onPost($name, $email, $comment)
    {
        $this->sendmail($name, $email, $comment);

        $this['code'] = $this->code = Code::CREATED;
        $this['name']    = $name;
        $this['email']   = $email;
        $this['comment'] = $comment;

        return $this;
    }

    private function sendmail($name, $email, $comment)
    {
        $data = [
            'name'    => $name,
            'email'   => $email,
            'comment' => $comment,
        ];

        $mailer = $this->mailer->create();
        $mailer->setSubject('コンタクトフォーム')
            ->setFrom($data['email'], $data['name'])
            ->setTo('admin@example.org', '管理者')
            ->setTemplate('mailer/contact_form.twig', $data);

//        echo '<pre>'
//            . htmlspecialchars($mailer, ENT_QUOTES, 'UTF-8')
//            . '</pre>';

        $result = $mailer->send();
        return $result;
    }
}

対応するテンプレートも作成します。ページリソースのものをほぼそのまま移動するだけです。

src/Resource/App/Contact/Form.twig

<div id="contact_form">
    <h1>Contact Form</h1>
{% if code == 201 %}
    <p>
    Name: {{ name }}<br>
    Email: {{ email }}<br>
    Comment: {{ comment }}
    </p>
    <p>Thank you!</p>
{% else %}
    <form role="form" action="" method="post" enctype="multipart/form-data">
        {{ form(form['__csrf_token']['hint']) }}

        <div class="form-group{%if form['name']['error'] %} has-error{% endif %}">
            <label class="control-label" for="name">Name</label>
            {{ form(form['name']['hint']) }}
            <label class="control-label" for="name">{{ form['name']['error'] }}</label>
        </div>

        <div class="form-group{%if form['email']['error'] %} has-error{% endif %}">
            <label class="control-label" for="email">Email</label>
            {{ form(form['email']['hint']) }}
            <label class="control-label" for="email">{{ form['email']['error'] }}</label>
        </div>

        <div class="form-group{%if form['comment']['error'] %} has-error{% endif %}">
            <label class="control-label" for="comment">Comment</label>
            {{ form(form['comment']['hint']) }}
            <label class="control-label" for="comment">{{ form['comment']['error'] }}</label>
        </div>

        <input class="btn btn-default" type="submit" name="submit" value="Send">
    </form>
{% endif %}
</div><!-- end of id="contact_form" -->

ページリソースの変更

アプリケーションリソースに移動したロジックを削除し、ページリソースからアプリケーションリソースを呼び出すように変更します。

--- a/src/Resource/Page/Contact.php
+++ b/src/Resource/Page/Contact.php
@@ -11,62 +11,30 @@
 namespace Kenjis\Contact\Resource\Page;

 use BEAR\Resource\ResourceObject;
-use Ray\Di\Di\Inject;
-use Kenjis\Contact\Service\SwiftMailerFactory;
-use BEAR\Resource\Code;
+use BEAR\Sunday\Inject\ResourceInject;

 class Contact extends ResourceObject
 {
-    /**
-     * @Inject
-     */
-    public function __construct(SwiftMailerFactory $mailer)
-    {
-        $this->mailer = $mailer;
-    }
+    use ResourceInject;

-    /**
-     * @BEAR\Sunday\Annotation\Form
-     */
     public function onGet()
     {
+        $this['contact_form'] = $this->resource->get
+            ->uri('app://self/contact/form')
+            ->eager->request();
+
         return $this;
     }

-    /**
-     * @BEAR\Sunday\Annotation\Form
-     */
     public function onPost($name, $email, $comment)
     {
-        $this->sendmail($name, $email, $comment);
+        $this['contact_form'] = $this->resource->post
+            ->uri('app://self/contact/form')
+            ->withQuery(['name' => $name, 'email' => $email, 'comment' => $comment])
+            ->eager->request();

-        $this['code'] = $this->code = Code::CREATED;
-        $this['name']    = $name;
-        $this['email']   = $email;
-        $this['comment'] = $comment;
+        $this->code = $this['contact_form']->code;

         return $this;
     }
-
-    private function sendmail($name, $email, $comment)
-    {
-        $data = [
-            'name'    => $name,
-            'email'   => $email,
-            'comment' => $comment,
-        ];
-
-        $mailer = $this->mailer->create();
-        $mailer->setSubject('コンタクトフォーム')
-            ->setFrom($data['email'], $data['name'])
-            ->setTo('admin@example.org', '管理者')
-            ->setTemplate('mailer/contact_form.twig', $data);
-
-//        echo '<pre>'
-//            . htmlspecialchars($mailer, ENT_QUOTES, 'UTF-8')
-//            . '</pre>';
-
-        $result = $mailer->send();
-        return $result;
-    }
 }

onGet()メソッドでは、以下のようにしてアプリケーションリソースContact\FormをGETでリクエストしています。

        $this['contact_form'] = $this->resource->get
            ->uri('app://self/contact/form')
            ->eager->request();

テンプレートも変更します。

--- a/src/Resource/Page/Contact.twig
+++ b/src/Resource/Page/Contact.twig
@@ -8,41 +8,7 @@
 </head>
 <body>
 <div class="container">
-    <h1>Contact Form</h1>
-
-{% if code == 201 %}
-    <p>
-    Name: {{ name }}<br>
-    Email: {{ email }}<br>
-    Comment: {{ comment }}
-    </p>
-    <p>Thank you!</p>
-{% else %}
-    <form role="form" action="" method="post" enctype="multipart/form-data">
-        {{ form(form['__csrf_token']['hint']) }}
-
-        <div class="form-group{%if form['name']['error'] %} has-error{% endif %}">
-            <label class="control-label" for="name">Name</label>
-            {{ form(form['name']['hint']) }}
-            <label class="control-label" for="name">{{ form['name']['error'] }}</label>
-        </div>
-
-        <div class="form-group{%if form['email']['error'] %} has-error{% endif %}">
-            <label class="control-label" for="email">Email</label>
-            {{ form(form['email']['hint']) }}
-            <label class="control-label" for="email">{{ form['email']['error'] }}</label>
-        </div>
-
-        <div class="form-group{%if form['comment']['error'] %} has-error{% endif %}">
-            <label class="control-label" for="comment">Comment</label>
-            {{ form(form['comment']['hint']) }}
-            <label class="control-label" for="comment">{{ form['comment']['error'] }}</label>
-        </div>
-
-        <input class="btn btn-default" type="submit" name="submit" value="Send">
-    </form>
-{% endif %}
-
+    {{ contact_form|raw }}
 </div>
 </body>
 </html>

フォーム部分は、変数contact_formにセットされていますので、以下のように変更します。contact_formはHTMLなので|rawを付けてエスケープされないようにします。

    {{ contact_form|raw }}

インターセプターの設定の変更

フォームを処理するクラスが変わりましたので、インターセプターをバインドするクラスも変更する必要があります。

--- a/src/Module/AppModule.php
+++ b/src/Module/AppModule.php
@@ -42,7 +42,7 @@ class AppModule extends AbstractModule

         // aspect @Form annotaion
         $this->bindInterceptor(
-            $this->matcher->subclassesOf('Kenjis\Contact\Resource\Page\Contact'),
+            $this->matcher->subclassesOf('Kenjis\Contact\Resource\App\Contact\Form'),
             $this->matcher->annotatedWith('BEAR\Sunday\Annotation\Form'),
             [$this->requestInjection('Kenjis\Contact\Interceptor\Contact\Form')]
         );

これで、フォームがアプリケーションリソースになりました。

ブラウザから http://0.0.0.0:8000/contact にアクセスしてみます。

▼コンタクトフォーム

フォームのまわりに枠ができ、その左上に「app://self/contact/form」と表示されています。この部分がアプリケーションリソースであることがわかります。

何も入力せずに[Send]ボタンを押すと、検証エラーが表示されます。

▼検証エラー

なお、このデフォルトで表示されるリソース名とアイコン(haloと呼ばれています)が邪魔でページが見づらく消したい場合があります。そのような場合は、URLに?halo=0を付けてアクセスするとオフになります(再度有効にしたい場合は?halo=1)。

▼haloをオフに

かなり完成してきました。今日はここまでにします。

BEAR.Sundayでコンタクトフォームを作ってみる⑥へ続く。

過去記事

関連

Tags: bear

BEAR.Sundayでコンタクトフォームを作ってみる④

BEAR.Sundayでコンタクトフォームを作ってみる③の続きです。

CSRF対策を入れたいところですが、その前にBEAR.Sunday(正確にはBEAR.Package)に含まれているAura Formを使うようにフォームをリファクタリングします。フォームの処理にAuraのライブラリ(Aura.Inputなど)を使うということです。

Aura FormにはCSRF対策も含まれているため、同時に目的も達成できます。

インターセプターの作成

まず、インターセプターを作成し、そこでフォームとそのバリデーションを定義します。

src/Interceptor/Contact/Form.php

<?php
/**
 * Kenjis.Contact
 *
 * @author     Kenji Suzuki <https://github.com/kenjis>
 * @license    MIT License
 * @copyright  2014 Kenji Suzuki
 * @link       https://github.com/kenjis/Kenjis.Contact
 */

namespace Kenjis\Contact\Interceptor\Contact;

use Ray\Aop\MethodInterceptor;
use Aura\Input\FilterInterface;
use BEAR\Package\Module\Form\AuraForm\AuraFormTrait;

/**
 * Aura.Input form
 *
 * @see https://github.com/auraphp/Aura.Input
 */
class Form implements MethodInterceptor
{
    use AuraFormTrait;

    /**
     * Set form
     *
     * @param FilterInterface $filter
     */
    private function setForm(FilterInterface &$filter)
    {
        $this->form
            ->setField('name')
            ->setAttribs(
                [
                    'class' => 'form-control',
                    'id' => 'name',
                    'name' => 'name',
                    'size' => 20,
                    'maxlength' => 50
                ]
            );
        $filter->setRule(
            'name',
            'Enter your name (max 50 letters).',
            function ($value) {
                if (mb_strlen($value) == 0) return false;
                if (mb_strlen($value) > 50) return false;
                return true;
            }
        );

        $this->form
            ->setField('email')
            ->setAttribs(
                [
                    'class' => 'form-control',
                    'id' => 'email',
                    'name' => 'email',
                    'size' => 20,
                    'maxlength' => 100,
                ]
            );
        $filter->setRule(
            'email',
            'Enter your email adrress (max 100 letters).',
            function ($value) {
                if (mb_strlen($value) > 100) return false;
                return filter_var($value, FILTER_VALIDATE_EMAIL);
            }
        );

        $this->form
            ->setField('comment', 'textarea')
            ->setAttribs(
                [
                    'class' => 'form-control',
                    'id' => 'comment',
                    'name' => 'comment',
                    'cols' => 40,
                    'rows' => 5,
                ]
            );
        $filter->setRule(
            'comment',
            'Enter comment (max 400 letters).',
            function ($value) {
                if (mb_strlen($value) == 0) return false;
                if (mb_strlen($value) > 400) return false;
                return true;
            }
        );
    }
}

テンプレートの変更

フォームのテンプレートをform()関数を使うように変更します。

form()関数はAuraのヘルパーをTwigの関数化したものです。引数にフォーム生成のための配列を受け取り、inputタグなどを生成します。

--- a/src/Resource/Page/Contact.twig
+++ b/src/Resource/Page/Contact.twig
@@ -19,21 +19,23 @@
     <p>Thank you!</p>
 {% else %}
     <form role="form" action="" method="post" enctype="multipart/form-data">
+        {{ form(form['__csrf_token']['hint']) }}
+
         <div class="form-group{%if form['name']['error'] %} has-error{% endif %}">
             <label class="control-label" for="name">Name</label>
-            <input id="name" type="text" name="name" class="form-control" size="20" maxlength="50" value="{{ form['name']['value'] }}" />
+            {{ form(form['name']['hint']) }}
             <label class="control-label" for="name">{{ form['name']['error'] }}</label>
         </div>

         <div class="form-group{%if form['email']['error'] %} has-error{% endif %}">
             <label class="control-label" for="email">Email</label>
-            <input id="email" type="text" name="email" class="form-control" size="20" maxlength="100" value="{{ form['email']['value'] }}" />
+            {{ form(form['email']['hint']) }}
             <label class="control-label" for="email">{{ form['email']['error'] }}</label>
         </div>

         <div class="form-group{%if form['comment']['error'] %} has-error{% endif %}">
             <label class="control-label" for="comment">Comment</label>
-            <textarea id="comment" name="comment" class="form-control" cols="40" rows="5">{{ form['comment']['value'] }}</textarea>
+            {{ form(form['comment']['hint']) }}

             <label class="control-label" for="comment">{{ form['comment']['error'] }}</label>
         </div>

最初の{{ form(form['__csrf_token']['hint']) }}はCSRF対策のためのトークンです。

ページコントローラの変更

ページコントローラContactを変更し、@BEAR\Sunday\Annotation\Formアノテーションを追加します。

このアノテーションがあるメソッドを先ほどのContact\Formインターセプターがインターセプトして処理するようにするということです。

それから、バリデーションのロジックはインターセプターに移りますので削除します。

--- a/src/Resource/Page/Contact.php
+++ b/src/Resource/Page/Contact.php
@@ -25,17 +25,19 @@ class Contact extends ResourceObject
         $this->mailer = $mailer;
     }

+    /**
+     * @BEAR\Sunday\Annotation\Form
+     */
     public function onGet()
     {
         return $this;
     }

+    /**
+     * @BEAR\Sunday\Annotation\Form
+     */
     public function onPost($name, $email, $comment)
     {
-        if (! $this->validation($name, $email, $comment)) {
-            return $this;
-        }
-
         $this->sendmail($name, $email, $comment);

         $this['code'] = $this->code = Code::CREATED;
@@ -46,34 +48,6 @@ class Contact extends ResourceObject
         return $this;
     }

-    private function validation($name, $email, $comment)
-    {
-        $pass = true;
-
-        if ((mb_strlen($name) == 0) || (mb_strlen($name) > 50)) {
-            $this->body['form']['name']['error'] = 'Enter your name (max 50 letters).';
-            $pass = false;
-        }
-
-        if ((mb_strlen($email) > 100) || ! filter_var($email, FILTER_VALIDATE_EMAIL)) {
-            $this->body['form']['email']['error'] = 'Enter your email adrress (max 100 letters).';
-            $pass = false;
-        }
-
-        if ((mb_strlen($comment) == 0) || (mb_strlen($comment) > 400)) {
-            $this->body['form']['comment']['error'] = 'Enter comment (max 400 letters).';
-            $pass = false;
-        }
-
-        if (! $pass) {
-            $this->body['form']['name']['value']    = $name;
-            $this->body['form']['email']['value']   = $email;
-            $this->body['form']['comment']['value'] = $comment;
-        }
-
-        return $pass;
-    }
-
     private function sendmail($name, $email, $comment)
     {
         $data = [

インターセプターの設定

AppModule.phpで、Aura Formに必要なAura.Sessionモジュールのインストール、および、インターセプターのバインドを定義します。

--- a/src/Module/AppModule.php
+++ b/src/Module/AppModule.php
@@ -6,6 +6,7 @@ use BEAR\Package\Module\Package\StandardPackageModule;
 use Ray\Di\AbstractModule;
 use Ray\Di\Di\Inject;
 use Ray\Di\Di\Named;
+use BEAR\Package\Module\Session\AuraSession\SessionModule;

 class AppModule extends AbstractModule
 {
@@ -35,6 +36,16 @@ class AppModule extends AbstractModule

         // override twig module
         $this->install(new Provider\TwigModule($this));
+
+        // install aura.session
+        $this->install(new SessionModule());
+
+        // aspect @Form annotaion
+        $this->bindInterceptor(
+            $this->matcher->subclassesOf('Kenjis\Contact\Resource\Page\Contact'),
+            $this->matcher->annotatedWith('BEAR\Sunday\Annotation\Form'),
+            [$this->requestInjection('Kenjis\Contact\Interceptor\Contact\Form')]
+        );

         // override module
         // $this->install(new SmartyModule($this));

これで、Resource\Page\Contactクラス(とそのサブクラス)のメソッドに@BEAR\Sunday\Annotation\Formというアノテーションがあると、Contact\Formインターセプターが処理をインターセプトするようになります。

これは、メソッドインターセプターによるアスペクト指向プログラミング(AOP)ということになります。メソッドインターセプターとは、メソッドの実行を横取り(intercept)して代理実行するものです。

メソッドインターセプターによる処理の解説

Resource\Page\ContactクラスのonGet()およびonPost()メソッドに@BEAR\Sunday\Annotation\Formアノテーションがありますので、これらのメソッドの実行はインターセプトされ、Interceptor\Contact\Formインターセプターで処理されます。

ただし、このFormインターセプターにはフォームの定義とバリデーションしかありません。実際の処理は、BEAR\Package\Module\Form\AuraForm\AuraFormTraitにまとめられています。

実際には、このAuraFormTraitのinvoke()メソッドが実行されます。

vendor/bear/package/src/Module/Form/AuraForm/AuraFormTrait.php

    public function invoke(MethodInvocation $invocation)
    {
        list($args, $hasSubmit) = $this->getSubmit();
        $page = $invocation->getThis();

        $this->setForm($this->filter);
        $hasSubmit && $this->form->fill($args);
        if ($this->form->filter()) {
            // action
            return $invocation->proceed();
        }

        // set hint and error message
        foreach ($this->form->getIterator() as $name => $value) {
            $errors = $this->form->getMessages($name);
            $error = ($hasSubmit && $errors) ? $this->getErrorMessage($this->form->getMessages($name)) : '';
            $page->body['form'][$name]['error'] = $error;
            $page->body['form'][$name]['hint'] = $this->form->get($name);
        }

        return $page->onGet();
    }

フォームをセット($this->setForm($this->filter))して、バリデーションを実行($this->form->filter())し、検証をパスしたら元のメソッドを実行($invocation->proceed())しています。

検証をパスしなかった場合は、エラーメッセージをセットしてページリソースのonGet()メソッドを実行して返しています。つまり、フォームが表示されるというわけです。

これで、CSRF対策もできました。今日はここまでにします。

BEAR.Sundayでコンタクトフォームを作ってみる⑤へ続く。

過去記事

関連

Tags: bear, aop, aura, validation

BEAR.Sundayでコンタクトフォームを作ってみる③

BEAR.Sundayでコンタクトフォームを作ってみる②の続きです。

まず、XSS脆弱性をつぶします。

Twigのautoescapeを有効にする

BEAR.SundayのTwigの設定は、vendor/bear/package/src/Provide/TemplateEngine/Twig/TwigProvider.php(つまり、BEAR.Packageの中)にあります。

ここで、以下のようになっており、autoescapefalseになっています。

vendor/bear/package/src/Provide/TemplateEngine/Twig/TwigProvider.php

        $twig = new Twig_Environment($loader, [
            'cache' => $this->tmpDir . '/twig/cache',
            'debug' => true,
            'autoescape' => false,
        ]);

これをtrueに変更します。

vendor/bear/package/src/Provide/TemplateEngine/Twigフォルダの中にある

  • TwigProvider.php
  • TwigModule.php

をsrc/Module/Providerフォルダを作成し、そこにコピーし変更します。

TwigProvider.phpを以下のように変更します。autoescapeをtrueに変更し、後はクラス名を調整しています。

--- vendor/bear/package/src/Provide/TemplateEngine/Twig/TwigProvider.php    2014-08-09 07:11:26.000000000 +0900
+++ src/Module/Provider/TwigProvider.php    2014-08-09 14:29:22.000000000 +0900
@@ -1,16 +1,13 @@
 <?php
-/**
- * This file is part of the BEAR.Package package
- *
- * @license http://opensource.org/licenses/bsd-license.php BSD
- */
-namespace BEAR\Package\Provide\TemplateEngine\Twig;
+
+namespace Kenjis\Contact\Module\Provider;

 use BEAR\Sunday\Inject\LibDirInject;
 use BEAR\Sunday\Inject\TmpDirInject;
 use Ray\Di\ProviderInterface as Provide;
 use Twig_Environment;
 use Twig_Loader_Filesystem;
+use BEAR\Package\Provide\TemplateEngine\Twig\Extension\AuraForm_Twig_Extension;

 /**
  * Twig
@@ -33,11 +30,11 @@
         $twig = new Twig_Environment($loader, [
             'cache' => $this->tmpDir . '/twig/cache',
             'debug' => true,
-            'autoescape' => false,
+            'autoescape' => true,
         ]);

         $twig->addExtension(new \Twig_Extension_Debug());
-        $twig->addExtension(new Extension\AuraForm_Twig_Extension());
+        $twig->addExtension(new AuraForm_Twig_Extension());

         $function = new \Twig_SimpleFunction(
             'href',

TwigModule.phpを以下のように変更します。変更したTwigProvider.phpがバインドされるようにクラス名を調整します。

--- vendor/bear/package/src/Provide/TemplateEngine/Twig/TwigModule.php  2014-08-09 07:11:26.000000000 +0900
+++ src/Module/Provider/TwigModule.php  2014-08-09 14:29:22.000000000 +0900
@@ -1,10 +1,6 @@
 <?php
-/**
- * This file is part of the BEAR.Package package
- *
- * @license http://opensource.org/licenses/bsd-license.php BSD
- */
-namespace BEAR\Package\Provide\TemplateEngine\Twig;
+
+namespace Kenjis\Contact\Module\Provider;

 use Ray\Di\AbstractModule;
 use Ray\Di\Scope;
@@ -18,7 +14,7 @@
     {
         $this
             ->bind('BEAR\Sunday\Extension\TemplateEngine\TemplateEngineAdapterInterface')
-            ->to(__NAMESPACE__ . '\TwigAdapter')
+            ->to('BEAR\Package\Provide\TemplateEngine\Twig\TwigAdapter')
             ->in(Scope::SINGLETON);
         $this
             ->bind('Twig_Environment')

最後に、src/Module/AppModule.phpに以下を追加して、作成したProvider\TwigModuleがインストールされるように設定します。

--- a/src/Module/AppModule.php
+++ b/src/Module/AppModule.php
@@ -33,6 +33,9 @@ class AppModule extends AbstractModule
     {
         $this->install(new StandardPackageModule('Kenjis\Contact', $this->context, dirname(dirname(__DIR__))));

+        // override twig module
+        $this->install(new Provider\TwigModule($this));
+
         // override module
         // $this->install(new SmartyModule($this));

これで、最初のStandardPackageModuleの中でインストールされたデフォルトのTwigの設定が、作成したProvider\TwigModuleでオーバーライドされます。設定をオーバライドするために、new Provider\TwigModule($this)$thisを忘れずに記載してください。

これでコンタクトフォームにHTMLタグを入力しても、表示では正しくエスケープされることを確認してみましょう。

文字化けの修正

実は、前回送信したメールの本文の日本語が文字化けしていました。

調査したところ、検証エラーのページでブラウザが文字エンコーディングを誤検知してShift_JISになっていました。

HTTPヘッダで文字エンコーディングが指定されていなかったので、 bootstrap/instance.phpでdefault_charsetを設定しておくことにします。

--- a/bootstrap/instance.php
+++ b/bootstrap/instance.php
@@ -10,6 +10,9 @@ namespace Kenjis\Contact;

 use BEAR\Package\Bootstrap\Bootstrap;

+// set default charset
+ini_set('default_charset', 'UTF-8');
+
 require_once __DIR__ . '/autoload.php';

 $app = Bootstrap::getApp(

これで、HTTPヘッダにUTF-8が指定されるようになりました。

XSS脆弱性とメールの文字化けが解消しましたので、CSRF対策はまだですが、今日はここまでにします。

BEAR.Sundayでコンタクトフォームを作ってみる④へ続く。

過去記事

関連

Tags: bear