HTTPのGETとPOSTの違いを知るために、簡単なフォームを作成します。
まずは、PHPとHTMLを使ったフォームに何かを入力して、ボタンを押すとGETメソッドによりサーバーにデータが送信されて、
サーバーがリクエストされたパラメータを元に画面を表示する仕組みを作成します。
その後、同じようにPOSTメソッドでもフォームを作成し、GETとPOSTの違いを確認します。
また、GETとPOSTの特徴を活かした使い分けも紹介します。
先に結論です。GETはパラメータをURLの末尾(?name=値)に付けて送り、PHPでは$_GETで受け取ります。POSTはパラメータをリクエストのBodyに入れて送り、$_POSTで受け取ります。
検索条件やページ番号のように「URLを共有しても困らず、何度読み込んでも同じ結果になる」ものはGET、パスワードの送信や記事の投稿のように「URLに残したくない、または送るたびにサーバー側のデータが変わる」ものはPOSTを使います。
どちらの方法で送るかは、フォームのmethod属性を変えるだけで切り替えられます。
GETメソッドでフォームを作成(index.php)
ファイル構成
∟index.php
∟get.php
<form action="get.php" method="GET">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit" value="送信">
<!-- <button type="submit">送信</button> -->
</form>
formタグのaction属性では、フォームの内容を送信する先のパスやURLを指定します。
ボタンなどが押されると、そのURLやパスに対してリクエストが送られます。
パスは相対パスでも絶対パスでも指定可能です。
ボタンは、inputタグかbuttonタグのtype属性をsubmitにすると送信ボタンとして機能します。
name属性は、送信された入力内容を区別するための名前です。
たとえば、passwordならpasswordというわかりやすいname属性の値にしておくと、受け取る側でどの項目か明確になります。
name属性の付け方で受け取り方が変わる配列送信については、PHPでフォームの値を配列・連想配列で送る方法で扱っています。
ボタンを押すことで、サーバー上にリクエストが送信されます。
リクエストを表示(get.php)
<p>入力された名前: <?php echo $_GET['username']; ?></p>
<p>入力されたpwd: <?php echo $_GET['password']; ?></p>
<!-- 入力された名前: 山田太郎 -->
<!-- 入力されたpwd: yamadataro -->
get.phpで、送られてきたパラメータを取得します。
getメソッドで取得するときは、$_GET[]の連想配列にパラメータが格納されます。
$_GET[]はスーパーグローバル変数で、PHPファイルのどこからでも参照できる自動設定の連想配列です。
連想配列のため、$_GET[]のカッコ内にほしいキーを指定するとその値を取得できます。
なお、上のサンプルは仕組みを確認するための最小形です。受け取った値をそのまま画面に出すと、入力にタグを混ぜられたときにそのままHTMLとして解釈されるため、実際のページではhtmlspecialchars($_GET['username'], ENT_QUOTES, 'UTF-8')のように変換してから表示します。
フォームでリクエストを送信
index.phpで値をusernameに山田太郎、パスワードにyamadataroと入力すると、
URLのパスは以下のようになります。
get.php?username=山田太郎&password=yamadataro
POSTメソッドでフォームを作成(index.php)
ファイル構成
∟index.php
∟post.php
<form action="post.php" method="POST">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit" value="送信">
<!-- <button type="submit">送信</button> -->
</form>
method部分でGETからPOSTに変更するだけで、
そのほかは同じです。
リクエストを表示(post.php)
<p>入力された名前: <?php echo $_POST['username']; ?></p>
<p>入力されたpwd: <?php echo $_POST['password']; ?></p>
<!-- 入力された名前: 山田太郎 -->
<!-- 入力されたpwd: yamadataro -->
post.phpで、送られてきたパラメータを取得します。
POSTメソッドで取得するときは、$_POST[]の連想配列にパラメータが格納されます。
$_POST[]も$_GET[]と同じスーパーグローバル変数で、PHPファイルのどこからでも参照できる自動設定の連想配列です。
連想配列のため、$_POST[]のカッコ内にほしいキーを指定するとその値を取得できます。
フォームでリクエストを送信
index.phpで値をusernameに山田太郎、パスワードにyamadataroと入力すると、
URLのパスは以下のようになります。
post.php
GETメソッドと違い、URLにパラメータはありません。
その代わり、検証ツールのPayload部分にForm Dataという項目があり、そこにusernameとpasswordが表示されます。これがリクエストのBody部分に入って送られたパラメータです。
URLに出ないとはいえ、通信そのものを暗号化しているわけではありません。パスワードのような値は、HTTPS(https://で始まるURL)で送ることが前提です。
検証ツールでの確認方法
Chromeの検証などの開発ツールを開き、Networkタブを開いてcontrol+Rもしくはcommand+Rで更新すると、
リクエストの内容を確認できます。
GETメソッドの場合は、Request URLという項目に、パラメータがあります。
また、Payloadでも送信したパラメータの内容を確認できます。
GETとPOSTの使い分け
GETはその特性上、データを取得する際に使うメソッドです。
POSTは基本的にはデータの更新や作成をする際に使うメソッドです。
どういうことか、下の例で確認してみます。
- POSTではパラメータをURLに出さずに送れる
- URLは最大2000文字程度までしか設定できない
- GETではパラメータを含めてURLをシェアできる
- ブラウザの「戻る」や再読み込みで、GETは同じページを取得するだけだが、POSTは再送信の確認が出る
最後の項目が、GETとPOSTの使い分けでいちばん実害につながる違いです。
投稿や購入のような「もう一度送ると二重に登録される」処理にGETを使うと、再読み込みや検索エンジンのクロールだけで処理が走ってしまいます。
逆に、検索結果のような「何度取得しても同じ」ページをPOSTにすると、URLを共有できず、戻るボタンのたびに再送信の確認が出て使いにくくなります。
たとえば、ブログの記事本文は文字数が多くなるので、URLに含めるには適していません。
そのため、GETではなくPOSTを使って、BODYにパラメータを設定します。
このように、URLにパラメータを設定するか、BODYにパラメータを設定すべきかでGETとPOSTを使い分けます。
GETではパラメータを含めてURLをシェア
こちらは以下の例で確認できます。
<?php
// 連想配列データ(本来はデータベースからとってくる)
$participants = [
'1' => [
'name' => 'ken',
'age' => 25,
],
'2' => [
'name' => 'nanako',
'age' => 16,
],
'3' => [
'name' => 'yoiko',
'age' => 62,
],
];
// idがないときは1を代入
$id = $_GET['id'] ?? 1;
$participant = $participants[$id];
$name = $participant['name'];
$age = $participant['age'];
?>
<div><?php echo "{$name}さんは{$age}才です。"; ?></div>
<!-- idが1、もしくは未入力のとき→kenさんは25才です。 -->
<!-- idが2→nanakoさんは16才です。 -->
<!-- idが3→yoikoさんは62才です。 -->
??はnull合体演算子です。
もしGETのidのパラメータが設定されていないときは、1を代入します。
null合体演算子についてはnull合体演算子の使い方を参考にしてみてください。
上の連想配列部分は、本来はデータベースからデータを取得してきます。
idを変更すると、取得できるデータが変化します。
GETメソッドを使用しているため、URLはurl?id=1などの形式になり、簡単にURLを共有できます。
POSTで送るとき、画面には出したくないが一緒に送りたい値(編集対象のidなど)は、type属性をhiddenにしたinputに入れます。hiddenの値は利用者が書き換えられるため、受け取り側での検証とあわせてPHPでhiddenフィールドを送信・取得する方法で解説しています。