Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

phpPress、goPress、rubyPress、nodePressでのお問い合わせフォーム実装ガイド

フラットファイルシステムで構築したウェブサイトで、ユーザーからのフィードバックを受け取りたいとします。DisqusのようなJavaScriptベースのコメントシステムを導入するのは簡単ですが、ここではユーザーが直接メールを送信し、それに個別に返信できる仕組みを作ります。

ブラウザ側だけで完結するJavaScriptのみのメール送信システムを作ることもできますが、ソースコードにメールアドレスが露見するとスパムボットに収集されてしまいます。したがって、メールアドレスはサーバー側で隠蔽する必要があります。

このチュートリアルでは、PressCMSphpPressgoPressrubyPressnodePress)にメール送信フォーム機能を追加する手順を解説します。最初に共通のフロントエンドを作成し、その後各サーバーのバックエンド実装を説明します。これらのサーバーがすでに環境にインストールされていることを前提としています。

ブラウザ側のフォーム作成

フロントエンドのコードはすべてのサーバーで共通なので、各サーバーのディレクトリに同じファイルを配置します。以下のパスはサーバーのルートディレクトリからの相対パスで表記します。

テーマにフォーム専用のスタイルを追加する代わりに、このフォーム用スクリプトにはスタイルも含めてすべてを一箇所にまとめます。ウェブサイトの site/parts ディレクトリに questions.html というファイルを作成し、以下の内容を記述します。

<!-- フォーム用スタイル -->
<style>
    form {
        margin:        20px auto;
        width:         400px;
        padding:       1em;
        border:        1px solid #f0d5ad;
        border-radius: 1em;
    }

    form div + div {
        margin-top:    1em;
    }

    label {
        display:       inline-block;
        width:         90px;
        text-align:    right;
    }

    input, textarea {
        width:           300px;
        -moz-box-sizing: border-box;
        box-sizing:      border-box;
    }

    input:focus, textarea:focus {
        border-color:    #000;
    }

    textarea {
        vertical-align: top;
        height:         5em;
        resize:         vertical;
    }

    button {
        margin-top:     10px;
        margin-left:    8em;
    }
</style>

<!-- フォームのHTML -->

<form action="/api/message" method="post">
    <div>
        <label for="Name">Name:</label>
        <input id="Name" name="Name" type="text" value="" pattern="[a-zA-Z]{3} [a-zA-Z]{3}" title="First and Last name." autofocus required />
    </div>
    <div>
        <label for="Email">Email:</label>
        <input id="Email" name="Email" type="email" pattern="[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2}" title="Valid Email only." value="" required />
    </div>
    <div>
        <label for="Message">Message:</label>
        <textarea id="Message" name="Message" type="text" value="" required></textarea>
    </div>
    <button type="submit">Send Message</button>
</form>

このフォームは、氏名(名と姓)、メールアドレス、メッセージを入力してもらうシンプルなものです。pattern 属性に正規表現を指定することで、氏名とメールアドレスの形式を検証しています。入力内容がパターンと一致しない場合、フォームは送信されず、title 属性に指定したメッセージがポップアップで表示されます。また、すべての入力項目に required 属性をつけ、未入力での送信を防いでいます。これはフロントエンドで行う最低限のバリデーションです。

form 要素の action 属性は、フォームデータの送信先アドレスを指定します。method 属性で post メソッドを指定すると、フォームデータはリクエストボディ(クエリ文字列形式)としてサーバーに送信されます。サーバー側ではこのクエリ文字列を解析して処理します。

ページテンプレートの作成

site/pages ディレクトリに contact.md ファイルを作成し、以下の内容を保存します。

### Contact Us

This is a simple contact form. Please fill in your name, first and last, email address, and message. I will get back to you as soon as possible. Thanks.

{{{question}}}

保存後、ブラウザで https://localhost:8081/contact にアクセスして動作を確認できます。

phpPress、goPress、rubyPress、nodePressでのお問い合わせフォーム実装ガイド phpPress、goPress、rubyPress、nodePressでのお問い合わせフォーム実装ガイド phpPress、goPress、rubyPress、nodePressでのお問い合わせフォーム実装ガイド
お問い合わせフォームページ

ページ読み込み時に氏名入力欄が自動的にフォーカスされるのは、autofocus 属性の効果です。ユーザーが最初に入力すべきフィールドに自動でフォーカスを当てるのは、良いUX設計の基本です。

送信完了ページ

メッセージ送信後にユーザーへ確認メッセージを表示するため、site/pages ディレクトリに messagesent.md を作成します。

### Message was sent

Thank you so much for taking time to send me a message. I will reply as soon as possible.

シンプルな完了メッセージです。必要に応じて拡張してください。

phpPress、goPress、rubyPress、nodePressでのお問い合わせフォーム実装ガイド phpPress、goPress、rubyPress、nodePressでのお問い合わせフォーム実装ガイド phpPress、goPress、rubyPress、nodePressでのお問い合わせフォーム実装ガイド
メッセージ送信完了ページ

goPressでのフォーム処理

ユーザーから送信されたメッセージをサニタイズするために Blue Monday ライブラリを使用します。以下のコマンドでインストールしてください。

go get github.com/microcosm-cc/bluemonday

goPressServer.go ファイルの import ブロックに以下を追加します。

import (
    "fmt"
    "github.com/hoisie/web"
    "net/smtp"
    "github.com/microcosm-cc/bluemonday"
)

goPress.DefaultRoutes() の呼び出しの後ろに、以下のルート設定を追加します。

//
// フォーム処理用の特別なPOSTルートを設定
//

goPress.SetPostRoute('/api/message', postMessage)

ファイルの末尾に、以下の2つの関数を追加します。

//
// Function:         postMessage
//
// Description:      フォームから送信されたメッセージを
//                   サイト運営者宛にメール送信する
//
// Inputs:
//                   ctx     Webサーバーのコンテキスト
//
func postMessage(ctx *web.Context) string {
    // POSTデータを取得し、メール送信
    name := ctx.Params["Name"]
    from := ctx.Params["Email"]
    p := bluemonday.UGCPolicy()
    message := p.Sanitize(ctx.Params["Message"])
    to := "<your email address>"
    subject := "Message from User:" + name + " of CustomCT.com"
    sendEmail(to, from, subject, message)

    // 送信完了ページを表示
    pgloc := goPress.SiteData.Sitebase + "pages/messagesent"
    return goPress.RenderPageContents(ctx, goPress.GetPageContents(pgloc), pgloc)
}

//
// Function:         sendEmail
//
// Description:      メールを送信する
//
// Inputs:
//                   to      宛先メールアドレス
//                   from    送信者メールアドレス
//                   subject 件名
//                   message 本文
//
func sendEmail(to string, from string, subject string, message string) {
    body := fmt.Sprintf("To: %s\r\nSubject: %s\r\n\r\n%s", to, subject, message)
    auth := smtp.PlainAuth("", "<your email address>", "<your password>", "smtp.gmail.com")
    err := smtp.SendMail("smtp.gmail.com:587", auth, from, []string{to}, []byte(body))
    if err != nil {
        // エラー処理(ここでは省略)
    }
}

/api/message ルートが postMessage() を呼び出し、フォームデータを取得、Blue Mondayでサニタイズし、sendEmail() でメールを送信します。プレースホルダーの <your email address><your password> は、実際のGmailアドレスとパスワード(またはアプリパスワード)に置き換えてください。

goPress.go ファイルの SetGetRoute() 関数の後ろに、以下の関数を追加します。

//
// Function:           SetPostRoute
//
// Description:       POSTルートを簡単に設定するためのラッパー
//
// Inputs:
//      route         設定するルート
//      handler       実行するハンドラ関数
//
func SetPostRoute(route string, handler interface{}) {
    web.Post(route, handler)
}

これにより、goPressサーバーでフォーム送信メールを処理できるようになります。

nodePressでのフォーム処理

Node.jsでメールを送信するには nodemailer とリクエストボディをパースする body-parser が必要です。以下のコマンドでインストールします。

npm install -save nodemailer
npm install -save body-parser

nodePress.js の冒頭、ライブラリ読み込み部分に以下を追加します。

var nodemailer = require('nodemailer');  // https://nodemailer.com/
var bodyParser = require('body-parser'); // https://github.com/expressjs/body-parser

// 再利用可能なトランスポーターを作成(SMTP設定)
var transporter = nodemailer.createTransport('smtps://<your email name%40<your email domain>:<your password>@smtp.gmail.com');

<your email name>(@より前)、<your email domain>(ドメイン部分)、<your password> を自分のGmail情報に置き換えてください。2段階認証を有効にしている場合は、アプリパスワードを使用するか、Nodemailerのドキュメントを参照して設定してください。

nodePress 変数の初期化直後に、body-parserの設定を追加します。

// body-parserの設定
nodePress.use(bodyParser.urlencoded({
    extended: true
}));

最後の nodePress.get() 呼び出しの後ろに、POSTルートのハンドラを追加します。

nodePress.post('/api/message', function(request, response) {
    // メールオプションの設定
    var mailOptions = {
        from: request.body.Email,
        to: '<your email address>',
        subject: 'Message from ' + request.body.Name + ' on contact form.',
        text: request.body.Message,
        html: request.body.Message
    };

    // メール送信
    transporter.sendMail(mailOptions, function(error, info){
        if(error){
            return console.log(error);
        }
        // 送信完了ページを返す
        response.send(page("messagesent"));
    });
});

このハンドラはフォームデータを受け取り、メールを作成・送信し、完了ページを返します。body-parserミドルウェアにより、URLエンコードされたパラメータが request.body にパース済みで格納されます。

rubyPressでのフォーム処理

RubyでGmail経由でメールを送るには ruby-gmail gemをインストールします。

gem install ruby-gmail

環境によっては sudo が必要です。rubyPress.rb の冒頭にライブラリを読み込みます。

require 'gmail'       # https://github.com/dcparker/ruby-gmail

すべての get 定義の後ろに、以下のPOSTルートを追加します。

post '/api/message' do
  # フォームパラメータを取得
  name = params[:Name]
  email = params[:Email]
  message = params[:Message]

  # メール作成・送信
  Gmail.new('<your email address>', '<your password>') do |gmail|
    gmail.deliver do
      to "<your email address>"
      from email
      subject "Message from " + name
      text_part do
        body message
      end
    end
  end
  # 完了ページを表示
  page 'messagesent'
end

プレースホルダーを実際のメールアドレスとパスワードに置き換えれば完成です。

phpPressでのフォーム処理

PHPでメールを扱う定番ライブラリ PHPMailer をComposerでインストールします。phpPressディレクトリで以下を実行してください。

composer update
composer require phpmailer/phpmailer

composer updateLightnCandy も更新されますが、互換性のため index.phpProcessPage() 関数を以下のように書き換える必要があります(一時ファイルを使わずメモリ上で処理するようになり、高速化されます)。

//
// Function:        ProcessPage
//
// Description:     ページをテンプレートに埋め込み、Mustacheマクロと
//                  ショートコードを処理する
//
// Inputs:
//                  $layout     ページのレイアウト
//                  $page       ページのメインコンテンツ
//
function ProcessPage( $layout, $page ) {
   global $site, $parts, $helpers;

   // ページコンテンツを取得
   $parts['content'] = figurePage($page);

   // 1回目のHandlebars処理
   $phpStr = LightnCandy::compile($layout, $helpers);
   $renderer = LightnCandy::prepare($phpStr);
   $page = $renderer($parts);

   // ショートコード処理
   $pageShort = processShortcodes($page);

   // 2回目のHandlebars処理
   $phpStr = LightnCandy::compile($pageShort, $helpers);
   $renderer = LightnCandy::prepare($phpStr);
   $page = $renderer($parts);

   return($page);
}

index.php の冒頭、Jadeライブラリ読み込みの後ろにPHPMailerのオートローダーを追加します。

//
// PHP Mailer:  https://github.com/PHPMailer/PHPMailer
//
require 'vendor/phpmailer/phpmailer/PHPMailerAutoload.php';

最後の $app->get() の後ろに、POSTルートのハンドラを追加します。

//
// メールフォームからのPOSTリクエストを処理するルート
//
$app->post('/api/message', function(Request $request, Response $response) {
    global $_POST;

    // POST変数を取得
    $Name = $_POST['Name'];
    $Email = $_POST['Email'];
    $Message = $_POST['Message'];

    // メール作成・送信
    $mail = new PHPMailer;

    $mail->isSMTP();                            // SMTPを使用
    $mail->Host = 'smtp.gmail.com';             // SMTPサーバー
    $mail->SMTPAuth = true;                     // SMTP認証を有効化
    $mail->Username = '<your email address>';   // SMTPユーザー名
    $mail->Password = '<your password>';        // SMTPパスワード
    $mail->SMTPSecure = 'tls';                  // TLS暗号化(sslも可)
    $mail->Port = 587;                          // TCPポート

    $mail->setFrom($Email, $Name);
    $mail->addAddress('<your email>', '<your name>'); // 宛先追加

    $mail->Subject = "Message from $Name";
    $mail->Body    = $Message;

    if(!$mail->send()) {
        echo 'Message could not be sent.';
        echo 'Mailer Error: ' . $mail->ErrorInfo;
    } else {
        $newResponse = SetBasicHeader($response);
        $newResponse->getBody()->write(page('messagesent'));
        return($newResponse);
    }
});

このハンドラはフォームデータを受け取り、PHPMailerでメールを送信し、成功時は完了ページを返します。PHPはURLパラメータを自動的に $_POST 配列に格納します。プレースホルダーを実際の値に置き換え、Gmail以外のSMTPサーバーを使う場合は $mail->Host も適切に変更してください。

結論

PressCMSサイトにお問い合わせフォームを追加する方法を、4種類のバックエンドすべてで解説しました。このチュートリアルのダウンロードファイルには、すべての修正済みサーバーコードが含まれていますので、手入力せずに利用できます。最低限のエラー処理のみ実装していますが、さらなる堅牢化は読者の演習として残します。

ここではフォームデータをURLエンコードしてPOST送信する従来の方法を採用しましたが、近年はJSONボディを用いたREST API方式も一般的です。今回のルーチンはその方式にも容易に適応可能です(今後のチュートリアルまたは読者の挑戦として)。これで独自のフォームをサイトに追加する基礎が身につきました。カスタマイズの可能性はあなたの想像力次第です。

  1. SendGrid と Next.js でお問い合わせフォームを作成する方法

    連絡先フォームは、ユーザーが電子メールでやり取りできるようにする場合に Web サイトで役立ちます。そして、それらを構築する方法はたくさんあります。 従来は、サーバー経由でメールを送信するために PHP を使用するか、メール ロジックを処理するサード パーティのサービスを使用していました。 ただし、この記事では、SendGrid API を使用して Next.js アプリケーションからメールを送信する方法について説明します。 送信前に検証する入力フィールドを持つ単純なページ (React で構築された連絡フォーム) を作成します。フォームを SendGrid API に接続し、メールの

  2. 「Appleでサインイン」とは?使い方と安全性をわかりやすく解説

    WWDC 2019で、Appleは全デバイスに展開される新機能「Appleでサインイン(Sign in with Apple)」を発表しました。この機能は必ずしも画期的というわけではなく、MacBookやiPhoneを購入する決め手になるものでもありませんが、登場以来、Appleのデバイス機能群の中で高く評価される存在へと成長しています。 5年前に登場したApple Payは、最も関連性が高く比較しやすい機能です。Apple Payと「Appleでサインイン」はどちらも、ハードウェアやOSの観点だけでなく、サードパーティ製アプリにおいてさえ、よりシンプルで直感的な体験を実現しようとするApp