PHP - WEB - 5. HTTPリクエストの詳細

引き続きHTTPリクエストについて学習していきましょう。さきほどログインプログラムを作成する過程でログイン画面である login.html ファイルと、ログイン画面からのリクエストを処理する login.php ファイルの2つを作成しました。ここでは2つのファイルの間で具体的にどのようなデータのやりとりが発生するのかを見ていくことにします。

HTTPリクエストのキャプチャー(GETリクエスト)

通常、WebブラウザからWebサーバに送信されるデータ(HTTPリクエスト)はユーザの目には触れない仕組みになっています。そのため従来は、通信データのキャプチャーを取得するに専用のソフトウェアを用意する必要がありましたが、最近のWebブラウザには「開発者ツール」や「デベロッパーツール」といった機能が提供されており、それらを使えば簡単に通信データを確認できるようになっています。

Google Chromeの場合は「その他のツール」 => 「デベロッパーツール」にアクセスすることでデベロッパーツールを起動できます。

F12キーで起動することもできます。

ChromeのデベロッパーツールにはWebアプリケーションの開発に役に立つ様々な機能が提供されています。その中にはWebブラウザとWebサーバ間の通信データのキャプチャーをとる機能も含まれています。それでは実際に通信データのキャプチャーを取得してみましょう。

まずはデベロッパーツールのNetworkタブを選択します。

Networkタブを開いた状態でリンクやボタンをクリックすると、その際に発生したHTTPリクエスト(レスポンス)のキャプチャーを取得できます。

それではさきほどのログインプログラム( login.html )を使って通信データのキャプチャーの取得にチャレンジしてみましょう。ここでは以下のように GET リクエストを送信するものとします。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>PHP Sample</title>
</head>
<body>
    <h3>Login</h3>
    <hr>
    <form action="login.php" method="get">
        <input type="text" name="id">
        <input type="password" name="password">
        <input type="submit" value="login">
    </form>
</body>
</html>

また送信されたリクエストを処理するプログラム( login.php )は以下のとおりです。こちらも前回と変更はありません。

<?php
$id = $_GET["id"];
$password = $_GET["password"];
$message = "NG";
if ($id === "Andy" && $password === "secret") {
    $message = "OK";
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>PHP Sample</title>
</head>
<body>
  <h1>Login <?php echo $message; ?></h1>
</body>
</html>

まずは以下のURLを入力してログイン画面( login.html )にアクセスします。

http://localhost:8000/login.html

次にデベロッパーツールを開いてNetworkタブを選択します。もし不要な通信データのキャプチャーが表示されている場合は「Clear」ボタンをクリックすることで通信データのキャプチャーを削除できます。

それではデベロッパーツール(Networkタブ)を開いた状態で、IDとパスワードを入力して送信ボタンをクリックしてみましょう。そうするとデベロッパーツール上に通信データが1件表示されるでしょう。

データにはStatusやTypeといった情報も合わせて出力されています。次のこの通信データをクリックすると画面の表示が次のようになるでしょう。

ここに表示されている情報がHTTPリクエストとHTTPレスポンスの通信データです。まずはHTTPリクエストに注目して見ていきましょう。画面をスクロールすると「Request Headers」というセクションがあります。

「view source」というメニューがあるのでクリックすると以下のような表示になります。

ここに表示されている内容がHTTPリクエスト(厳密にはリクエストラインとヘッダフィールド)です。実際にデベロッパーツールに表示されている内容をコピーすると次のようになります。

GET /login.php?id=Andy&password=secret HTTP/1.1
Host: localhost:8000
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6)...省略
Accept: text/html,application/xhtml+xml,application/xml;q=0.9...省略
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:8000/login.html
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8

表示されている内容はWebブラウザの種類やバージョンによって異なる可能性があります。

それではHTTPリクエストの通信データを解析していきましょう。まず前提知識としてHTTPリクエストは3つのパートで構成されています。

先頭行はリクエストライン、2行目以降の空行までの範囲をヘッダフィールド、空行の後のパートをボディパートと呼びます。または単純にヘッダフィールドのことをリクエストヘッダ、ボディパートのことをリクエストボディなどと呼びます。さきほどの通信データキャプチャーを見るとボディパートがないことに気づいたかもしれません。実はGETリクエストはボディパートを使わないデータ構造です。

まずは先頭行であるリクエストラインを見てみましょう。リクエストラインは以下の形式に従います。

リクエストメソッド URI HTTPバージョン

今回のGETリクエストの場合、リクエストラインは以下のようになっています。

GET /login.php?id=Andy&password=secret HTTP/1.1

この場合はリクエストメソッドが GET 、URIは /login.php?id=Andy&password=secret 、HTTPバージョンは HTTP/1.1 と読み取ることができます。 GETリクエストはその特徴として、画面からの入力パラメータをリクエストラインに含みます。ログイン処理において、GETリクエスト時のIDやパスワードがアドレスバーに表示されるのもこのためです。URIに含まれるリクエストパラメータは ? 記号の後にキーと値を = でつないで表現します。また2つ目以降のパラメータの境界には & 記号を使います。GETリクエストにおける ?id=Andy&password=secret の部分をクエリストリングやクエリパラメータと呼ぶこともあります。

2行目以降は見慣れない項目が並びますが、1行ずつ : で区切られているのがわかります。これらはヘッダフィールドと呼ばれるもので ヘッダ名: 値 という形式で並びます。たとえば Host ヘッダの値は localhost:8000 という具合です。これらのヘッダフィールドはWebブラウザによって自動的に付与されるデータで、Webサーバはこれらのヘッダ情報を参照しながらリクエストを処理します。

HTTPリクエストのキャプチャー(POSTリクエスト)

続いてログインプログラム( login.html )について、 POST リクエストを送信するように修正してみましょう。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>PHP Sample</title>
</head>
<body>
    <h3>Login</h3>
    <hr>
    <form action="login.php" method="post">
        <input type="text" name="id">
        <input type="password" name="password">
        <input type="submit" value="login">
    </form>
</body>
</html>

form タグの method 属性を post に修正します。

同様にPOSTリクエストを処理するプログラム( login.php )も $_GET 変数から $_POST 変数に修正します。

<?php
$id = $_POST["id"];
$password = $_POST["password"];
$message = "NG";
if ($id === "Andy" && $password === "secret") {
    $message = "OK";
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>PHP Sample</title>
</head>
<body>
  <h1>Login <?php echo $message; ?></h1>
</body>
</html>

それでは実際にPOSTリクエストのキャプチャーを取得してみましょう。まずは以下のURLを入力してログイン画面( login.html )にアクセスします。

http://localhost:8000/login.html

次にデベロッパーツールを開いてNetworkタブを選択します。もし不要な通信データのキャプチャーが表示されている場合は「Clear」ボタンをクリックすることで通信データのキャプチャーを削除できます。

デベロッパーツール(Networkタブ)を開いた状態で、IDとパスワードを入力して送信ボタンをクリックしてみましょう。GETリクエスト時と同様にデベロッパーツール上に通信データが1件表示されるでしょう。

次のこの通信データをクリックすると次のように表示されるでしょう。画面をスクロールすると「Request Headers」というセクションがあります。「view source」メニューをクリックすると次のように表示されます。

表示された内容をコピーしてテキストエディタに貼り付けてみましょう。

POST /login.php HTTP/1.1
Host: localhost:8000
Connection: keep-alive
Content-Length: 23
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
Origin: http://localhost:8000
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6)...省略
Accept: text/html,application/xhtml+xml,application/xml;q=0.9...省略
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:8000/login.html
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8

またPOSTリクエストの場合は、ヘッダフィールド(リクエストライン含む)だけでなく、ボディパートも存在します。デベロッパーツールをスクロールすると「Request Body」というセクションがあります。ここに表示されている内容がボディパートに含まれる送信データです。こちらも「view source」メニューをクリックすると次のように表示されます。

ここには入力フォームに入力したパラメータが次のように表示されているのがわかります。

id=Andy&password=secret

これをコピーして、さきほどのヘッダフィールドの後に空行を挟んで貼り付けてみましょう。

POST /login.php HTTP/1.1
Host: localhost:8000
Connection: keep-alive
Content-Length: 23
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
Origin: http://localhost:8000
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6)...省略
Accept: text/html,application/xhtml+xml,application/xml;q=0.9...省略
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:8000/login.html
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8

id=Andy&password=secret

上記のデータがPOSTリクエストの実体です。このようにPOSTリクエストも先頭行はリクエストライン、2行目以降、改行が続くまでの範囲をヘッダフィールド、空の改行を挟んだ後のパートをボディパートと呼びます。

まずは先頭行であるリクエストラインを見てみましょう。今回のPOSTリクエストの場合、リクエストラインは以下のようになっています。

POST /login.php HTTP/1.1

この場合はHTTPリクエストメソッドが POST 、URIは /login.php 、HTTPバージョンは HTTP/1.1 と読み取ることができます。 GET リクエストのようにURIにクエリパラメータ( ?id=Andy&password=secret )が存在しない点に注意してください。POSTリクエストは送信パラメータをボディパートに含むためです。

2行目以降ヘッダフィールドが続きます。ここではヘッダフィールドの詳細な説明は割愛しますが、POSTリクエストの場合は Content-Type ヘッダや Content-Length ヘッダなどボディパートに含まれるデータに関連するヘッダ情報が含まれているのがわかります。

さいごに空行を挟んでボディパートと呼ばれるパートが続きます。

id=Andy&password=secret

このように画面の入力フォームから入力されたパラメータは、POSTリクエストの場合、ボディパートに含まれることになります。

まとめ

  • GETリクエストとPOSTリクエストでデータの送信方法が異なる
  • GETリクエストはリクエストパラメータをリクエストライン(1行目)に含む
  • POSTリクエストはリクエストパラメータをボディパートに含む