【PHPフォーム入門】$_POSTでお問い合わせ内容を受け取って表示してみる

章: 2章

技術タグ: DevTools JavaScript PHP セキュリティ バリデーション フォーム

今回やること

前回は、JavaScriptの空欄チェックをあえて突破する考え方を学びました。

フロント側バリデーションは、ユーザーに優しくするための補助です。

しかし、システムを守る最終防衛ラインにはできません。

今回から、フォームは本格的にサーバー側へ進みます。

PHPの $_POST を使って、お問い合わせフォームから送られてきたデータを受け取ります。

フォームに入力する
↓
送信ボタンを押す
↓
POST通信でPHPへ送る
↓
PHPが$_POSTで受け取る
↓
受け取った内容を画面に表示する

今回はまず、受け取って表示するところまでを作ります。

ただし、あえて危険な状態も残します。その危険が、次回のXSSにつながります。


今回のゴール

今回のゴールは、以下です。

  • Laragon上でPHPフォームを動かす
  • HTMLフォームからPHPへPOST送信する
  • PHPの$_POSTで値を受け取る
  • 受け取った値を画面に表示する
  • フォーム画面と受信画面を分ける
  • 送られてきた値をそのまま表示する危険の入口を知る

今回は、まだデータベースには保存しません。メール送信もしません。

まずは、フォームからPHPへデータが届く流れを理解します。


今回必要なもの

今回はPHPを使うため、Live ServerではなくLaragonで確認します。

  • VS Code
  • Google Chrome
  • Laragon
  • Chrome DevTools
  • Git Bash(curl確認をしたい場合)

HTML・CSS・JavaScriptだけの回はLive Serverで十分でした。

しかし、PHPを実行するにはPHPが動くローカルサーバーが必要です。

今回はLaragonで以下のようなURLを使う想定です。





http://contact-form-app.test/

新しいフォルダを作った直後に .test のURLが開かない場合は、Laragonを再起動してみてください。


ファイル構成

今回は、以下の3ファイルで進めます。

contact-form-app/
├─ index.php
├─ receive.php
└─ style.css
ファイル役割
index.phpお問い合わせフォームを表示する
receive.phpPOST送信された値を受け取って表示する
style.cssフォームと確認画面の見た目を整える

前回までは index.html を使っていましたが、今回はPHP環境で動かすため index.php にします。

HTMLだけを書いているように見えても、PHP環境上で扱いやすくするために .php にしておきます。


index.phpを用意する

まずはフォーム画面を作ります。

index.php に以下を書きます。

<?php
/**
 * index.php
 *
 * 役割:
 * - お問い合わせフォームを表示する
 * - 入力された内容を receive.php にPOST送信する
 */
?>
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>お問い合わせフォーム</title>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
  <main class="contact-page">
    <h1 class="contact-page__title">お問い合わせフォーム</h1>

    <p class="contact-page__lead">
      ご質問やご相談があれば、以下のフォームから送信してください。
    </p>

    <form class="contact-form" action="receive.php" method="post">
      <div class="contact-form__field">
        <label class="contact-form__label" for="name">お名前</label>
        <input class="contact-form__control" type="text" id="name" name="name" />
      </div>

      <div class="contact-form__field">
        <label class="contact-form__label" for="email">メールアドレス</label>
        <input class="contact-form__control" type="email" id="email" name="email" />
      </div>

      <div class="contact-form__field">
        <label class="contact-form__label" for="message">お問い合わせ内容</label>
        <textarea class="contact-form__control contact-form__textarea" id="message" name="message"></textarea>
      </div>

      <button class="contact-form__button" type="submit">
        送信する
      </button>
    </form>
  </main>
</body>
</html>

今回のポイントは、form タグのこの部分です。

<form class="contact-form" action="receive.php" method="post">

action は、送信先のファイルを指定します。今回は receive.php に送信します。

method="post" は、POST通信で送るという意味です。

お問い合わせ内容のようなユーザー入力は、基本的にGETではなくPOSTで送ります。


name属性が$_POSTのキーになる

フォームの入力欄には、name 属性があります。

今回なら、以下のような指定です。

name="name"
name="email"
name="message"

この name 属性が、PHP側の $_POST のキーになります。

HTML側のname属性PHP側での受け取り
name=”name”$_POST[‘name’]
name=”email”$_POST[‘email’]
name=”message”$_POST[‘message’]

ここはかなり重要です。フォームの name とPHPの $_POST はつながっています。


style.cssを用意する

次にCSSです。今回は通信やPHPの受け取りが主役なので、見た目は最小限です。

ただし、色・余白・角丸は簡易デザイントークンで管理します。

これは、あとから修正しやすくするための怠惰です。

style.css に以下を書きます。

:root {
  --color-bg: #f5f5f5;
  --color-text: #222222;
  --color-surface: #ffffff;
  --color-border: #cccccc;
  --color-muted: #666666;

  --space-s: 8px;
  --space-m: 16px;
  --space-l: 24px;
  --space-xl: 32px;
  --space-2xl: 64px;

  --radius-m: 8px;
  --radius-l: 16px;
  --radius-pill: 999px;

  --font-base: sans-serif;
}

body {
  margin: 0;
  font-family: var(--font-base);
  background-color: var(--color-bg);
  color: var(--color-text);
}

.contact-page {
  max-width: 640px;
  margin-inline: auto;
  padding-block: var(--space-2xl);
  padding-inline: var(--space-l);
}

.contact-page__title {
  margin-block-start: 0;
  margin-block-end: var(--space-m);
  font-size: 32px;
  text-align: center;
}

.contact-page__lead {
  margin-block-start: 0;
  margin-block-end: var(--space-xl);
  line-height: 1.8;
  text-align: center;
}

.contact-form,
.result-box {
  display: grid;
  gap: var(--space-l);
  padding-block: var(--space-xl);
  padding-inline: var(--space-l);
  border-radius: var(--radius-l);
  background-color: var(--color-surface);
}

.contact-form__field,
.result-box__item {
  display: grid;
  gap: var(--space-s);
}

.contact-form__label,
.result-box__label {
  font-weight: bold;
}

.contact-form__control {
  width: 100%;
  padding-block: 12px;
  padding-inline: 12px;
  border-width: 1px;
  border-style: solid;
  border-color: var(--color-border);
  border-radius: var(--radius-m);
  font-size: 16px;
  box-sizing: border-box;
}

.contact-form__textarea {
  min-height: 160px;
  resize: vertical;
}

.contact-form__button,
.result-box__link {
  display: inline-block;
  padding-block: 14px;
  padding-inline: var(--space-l);
  border-width: 0;
  border-radius: var(--radius-pill);
  background-color: var(--color-text);
  color: var(--color-surface);
  font-size: 16px;
  font-weight: bold;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}

.contact-form__button:hover,
.result-box__link:hover {
  opacity: 0.8;
}

.result-box__value {
  margin-block-start: 0;
  margin-block-end: 0;
  color: var(--color-muted);
  line-height: 1.8;
  white-space: pre-wrap;
}

今回も、すべての数値を無理に変数化する必要はありません。

まずは、色・余白・角丸のように何度も使いそうな値から名前を付けるだけで十分です。


receive.phpを用意する

次に、フォームから送られてきた値を受け取るPHPファイルを作ります。

receive.php に以下を書きます。

<?php
/**
 * receive.php
 *
 * 役割:
 * - フォームからPOST送信された値を受け取る
 * - 受け取った値を画面に表示する
 *
 * 注意:
 * - 今回は学習のため、あえてエスケープ処理を入れていません。
 * - 次回、ここに潜むXSSの危険を確認します。
 */

$name = $_POST['name'] ?? '';
$email = $_POST['email'] ?? '';
$message = $_POST['message'] ?? '';
?>
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>送信内容の確認</title>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
  <main class="contact-page">
    <h1 class="contact-page__title">送信内容の確認</h1>

    <div class="result-box">
      <div class="result-box__item">
        <p class="result-box__label">お名前</p>
        <p class="result-box__value"><?php echo $name; ?></p>
      </div>

      <div class="result-box__item">
        <p class="result-box__label">メールアドレス</p>
        <p class="result-box__value"><?php echo $email; ?></p>
      </div>

      <div class="result-box__item">
        <p class="result-box__label">お問い合わせ内容</p>
        <p class="result-box__value"><?php echo $message; ?></p>
      </div>

      <a class="result-box__link" href="index.php">フォームへ戻る</a>
    </div>
  </main>
</body>
</html>

このファイルでは、$_POST を使ってフォームから送られてきた値を受け取っています。

$name = $_POST['name'] ?? '';
$email = $_POST['email'] ?? '';
$message = $_POST['message'] ?? '';

?? '' は、値が存在しなかった時に空文字を入れるための書き方です。

たとえば、$_POST['name'] が存在しない場合でも、エラーを出さずに '' を入れます。


$_POSTとは何か

$_POST は、POST送信されたデータをPHPで受け取るための特別な変数です。

PHPでは、このような特別な変数をスーパーグローバル変数と呼びます。

難しく聞こえますが、まずはこう理解すれば十分です。

$_POST
↓
POST送信で届いたデータが入っている箱

フォームから以下のようなデータが送られたとします。

name=Leon
email=leon@example.com
message=お問い合わせ内容のテストです。

すると、PHP側では次のように取り出せます。

$name = $_POST['name'];
$email = $_POST['email'];
$message = $_POST['message'];

つまり、フォームから送られた値は、PHP側で $_POST から取り出せます。


実際に送信してみる

Laragonで以下のURLを開きます。

http://contact-form-app.test/

フォームに入力して、送信ボタンを押します。

うまくいけば、receive.php に移動し、入力した内容が表示されます。

ここで大事なのは、画面が切り替わっていることです。

index.php
↓ POST送信
receive.php

これは、昔ながらのフォーム送信の基本です。

送信すると、ブラウザは receive.php へ移動します。


DevToolsのNetworkでPOST通信を見てみる

ここでもDevToolsのNetworkタブが役立ちます。

Networkタブを開いた状態でフォームを送信すると、receive.php への通信が見えるはずです。

見るポイントは以下です。

  • Request URL が receive.php になっているか
  • Request Method が POST になっているか
  • Status Code が 200 になっているか
  • Form Data に name / email / message が入っているか

ここまで見えると、フォーム送信がただの画面操作ではなく、HTTP通信であることがわかります。

フォーム送信は、ブラウザがPOSTリクエストを作ってPHPへ送っている仕組みです。


curlでもPOSTできる

フォーム画面から送るだけでなく、Git Bashの curl から直接POSTすることもできます。

たとえば、次のように送れます。

curl -X POST http://contact-form-app.test/receive.php \
  -d "name=Leon" \
  -d "email=leon@example.com" \
  -d "message=こんにちは。curlから送信しています。" 

これは、ブラウザのフォーム画面を使わずに、PHPへ直接POSTしている状態です。

この事実はかなり重要です。

フォーム画面を通らなくても
サーバーには直接データを送れる

だから、サーバー側では必ず入力チェックが必要になります。

このcurl確認は番外編で詳しく扱う予定です。


今回のコードには危険が残っている

ここまでで、フォームからPHPへデータを送れるようになりました。

しかし、今回の receive.php には、あえて危険を残しています。

それは、受け取った値をそのまま表示していることです。

<?php echo $name; ?>
<?php echo $email; ?>
<?php echo $message; ?>

一見すると普通に見えます。

しかし、ユーザーが送ってくる値は信用できません。

もし、入力欄にHTMLタグやJavaScriptのような文字列を入れられたらどうなるでしょうか。

次回は、ここに潜むXSSという危険を体験します。


今回わかったこと

今回は、PHPの $_POST を使ってお問い合わせフォームの内容を受け取りました。

学んだことは以下です。

  • PHPを動かすにはLaragonなどのローカル環境が必要
  • formのactionで送信先を指定する
  • method=postでPOST通信になる
  • name属性が$_POSTのキーになる
  • $_POSTでフォームの値を受け取れる
  • 受け取った値を画面に表示できる
  • NetworkタブでPOST通信を確認できる
  • curlでも直接POSTできる
  • 受け取った値をそのまま表示するのは危険

フォームは、ユーザーが自由にデータを送ってくる入口です。

受け取れたら終わりではありません。受け取ったあとに、どう扱うかが重要です。


次回予告

次回は、今回作った receive.php の危険を実際に確認します。

入力欄にHTMLタグやJavaScriptのような文字列を入れて、そのまま表示すると何が起きるのかを体験します。

次回のテーマは、以下です。

【XSS入門】送られてきた値をそのまま表示すると何が起きるのか

ユーザーが送ってきた値を信用してはいけない。

その理由を、次回は画面上で確認します。