PHPの$_POST変数:初心者向けガイド

JavaScriptを有効にしてください

前書き

PHPプログラミングにおいて、$_POSTスーパーグローバル変数は、HTTP POSTリクエストを通じて送信されたデータを扱う際に不可欠です。
この記事では、$_POSTの基本的な使い方とフォームデータの安全な取り扱い方法を紹介します。

$_POST変数の基本

$_POSTは、HTTP POSTリクエストを通じて送信されたデータを含むPHPのスーパーグローバル配列です。
主にHTMLフォームからデータを受け取る際に使用されます。

基本的な使い方

HTMLフォームのデータは、フォームが送信された後のPHPスクリプトで$_POST配列を通じてアクセス可能です。

HTMLフォームの例

html
1
2
3
4
<form method="post" action="submit.php">
    <input type="text" name="username" />
    <input type="submit" value="Submit" />
</form>

PHPスクリプト

submit.php
1
2
3
4
5
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $username = $_POST['username'];
    echo "Submitted Username: " . $username;
}

この例では、ユーザー名を入力するフォームからデータを受け取り、表示しています。

フォームデータの取得

$_POSTを使用してフォームデータを取得する際、フォームの各入力要素のname属性が$_POST配列のキーに対応します。

セキュリティとバリデーション

  • データのバリデーション:$_POSTから取得したデータは、常にバリデーション(有効性確認)を行うべきです。これには、データの形式のチェックや、期待されるデータタイプへの変換が含まれます。
  • エスケープ処理:$_POSTデータをHTMLとして出力する前には、クロスサイトスクリプティング(XSS)攻撃を防ぐためにエスケープ処理を行う必要があります。

実際に動かしてみる

ここからはdocker composeを使用してフォームデータと$POST変数の実際の動作を確認してみましょう。

1. プロジェクトのディレクトリを作成

ターミナルで以下のコマンドを実行して、新しいディレクトリを作成します。

bash
1
2
mkdir php-form-test
cd php-form-test

2. docker-compose.yml の作成

docker-compose.yml を作成し、以下の内容を記述します。

docker-compose.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
version: '3.8'

services:
  php:
    image: php:8.2-fpm
    container_name: php-container
    volumes:
      - ./html:/var/www/html

  nginx:
    image: nginx:latest
    container_name: nginx-container
    ports:
      - "8080:80"
    volumes:
      - ./html:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php

3. Nginx の設定ファイルを作成

nginx ディレクトリを作成し、default.conf を作成します。

bash
1
mkdir nginx
default.conf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
server {
    listen 80;
    server_name localhost;
    root /var/www/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

4. PHP のフォームを作成

html ディレクトリを作成し、フォームを作る PHP ファイルを作成します。

bash
1
mkdir html
index.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>フォームのテスト</title>
</head>
<body>
    <h2>フォームのテスト</h2>
    <form method="POST" action="submit.php">
        <label for="name">名前:</label>
        <input type="text" id="name" name="name" required>
        <br><br>
        <input type="submit" value="送信">
    </form>
</body>
</html>
submit.php
1
2
3
4
5
6
7
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $name = htmlspecialchars($_POST['name'], ENT_QUOTES, 'UTF-8');
    echo "送信された名前: " . $name;
} else {
    echo "POSTリクエストではありません。";
}

5. フォルダ構成の確認

ここまでで下記のフォルダ構成になっていればOKです。

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ tree php-form-test
php-form-test
├── docker-compose.yml
├── html
│   ├── index.php
│   └── submit.php
└── nginx
    └── default.conf

2 directories, 4 files

6. Docker Compose を起動

php-form-testフォルダで以下のコマンドを実行して、コンテナを起動します。

bash
1
docker-compose up -d

7. ブラウザで確認

まず、ブラウザで http://localhost:8080 にアクセスすると、フォームが表示されます。
名前入力フォーム

フォームに名前を入力して送信すると、submit.php に POST データが送られ、その結果が画面に表示されます。
名前入力フォームに名前を入力して送信すると結果が表示される

一方、名前を入力せずに送信ボタンを押すと、フロントエンド側のバリデーションチェックにより送信がブロックされます。
名前入力フォームに名前を入力せずに送信しようとするとフロントエンドのバリデーションチェックで送信できない

これは、以下のように input タグに required 属性を指定しているためです。

html
1
<input type="text" id="name" name="name" required>

試しに、required を削除して名前を入力せずに送信ボタンを押すと、フロントエンドのバリデーションチェックが働かず送信できることが確認できます。
inputからrequiredを外して名前を入力せずに送信しようとするとフロントエンドのバリデーションチェックが実施されず送信できる

8. バックエンドのバリデーションチェック

フロントエンド側でバリデーションチェックを実装しているため「これで問題ない」と思われるかもしれませんが、実際は簡単にチェックをすり抜けることが可能です。

たとえば、入力フォーム画面で F12 キーを押して開発者ツールを開きます。
開発者ツール

開発者ツールの Elements タブで、対象の input タグを右クリックし「Edit as HTML」を選択します。
Edit as HTMLを選択

すると、input タグ全体が編集可能となるため、required="" の部分を削除し、適当な箇所をクリックして編集を確定します。
required=&ldquo;&ldquo;を削除

この状態で送信ボタンを押すと、先ほどのバリデーションチェックが働かずに送信できてしまいます。
バリデーションチェックが実施されず送信できてしまう

ここで重要なのは、フロントエンドでどんなバリデーションチェックを実装しても、悪意のあるユーザーによって必ず突破されるという点です。
もちろん、ユーザビリティの観点からフロントエンドでのチェックは必要ですが、その前提に立ち、バックエンド側でも必ずバリデーションチェックを行う必要があります。

9. バックエンドのバリデーションチェックを実装する

それでは、バックエンド側で name が未入力の場合の処理を追加してみましょう。
以下は、submit.php の修正例です。

php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
    if (empty($_POST['name'])) {
        echo "名前は必須項目です";
    } else {
        $name = htmlspecialchars($_POST['name'], ENT_QUOTES, 'UTF-8');
        echo "送信された名前: " . $name;
    }
} else {
    echo "POSTリクエストではありません。";
}

この例では、empty 関数を使って $_POST['name'] が空でないかを確認し、空の場合は「名前は必須項目です」というメッセージを出力するようにしています。

先ほどと同様に、フロントエンドのバリデーションチェックをすり抜ける手段で送信ボタンを押すと、今度は「送信された名前:」ではなく「名前は必須項目です」というメッセージが表示されることが確認できます。
バックエンドのバリデーションチェックが実施されている

これにより、バックエンド側でのバリデーションチェックが正しく実装されていることが確認できます。

実際の現場では、文字数制限や不正な文字が入力されていないかなど、さらに詳細なチェックが行われます。
また、今回の例では入力データの登録処理は実装していませんが、通常は入力されたデータをデータベースなどに登録する動作となります。
このような場合に不正なデータが登録されないよう、バックエンド側でのバリデーションチェックは非常に重要な処理です。

初学者の方はフロントエンドのみのバリデーションチェックに注目しがちですが、バックエンドのチェックも必須であることをしっかり認識していただければ幸いです。

10. コンテナの停止と削除

環境を停止・削除する場合は、以下のコマンドを実行してください。

sh
1
docker-compose down -v

これで PHP のフォームと POST の動作を簡単に試せる環境が構築できます。

まとめ

$_POSTスーパーグローバル変数は、PHPにおいてPOSTリクエストを介して送信されたデータを扱う基本的な方法です。
安全なウェブアプリケーションを開発するためには、受け取ったデータの適切なバリデーションとエスケープ処理が不可欠です。


スポンサーリンク

共有

もふもふ
著者
もふもふ
プログラマ。汎用系→ゲームエンジニア→Webエンジニア→QAエンジニア