POST メソッドで送信されたデータは受取先の $_POST 変数によってすべて文字列、あるいは配列として処理される。
POST メソッドの正体は Content-Type に「application/x-www-form-urlencoded」または「multipart/form-data」を用いた HTTP リクエストであり、$_POST は POST メソッドから現在のページ渡された変数の連想配列である。
Content-Type
Content-Type とは、HTTP 通信において、ファイル種類を表すための情報を設定するためのヘッダー項目のことで、ここで指定する内容はメディアタイプを指定することが多いが、文字エンコードである charset や、データ境界値である boundary も必要に応じて指定もすることができる。
メディアタイプとは、画像、音声、動画、テキストなど、ファイル種類を表すための情報のことで MIME タイプとも呼ばれている。
text/html のように A/B という形式で表現されており、A のことをタイプ、B のことをサブタイプと呼ぶ。タイプではそのデータ型が当てはまる大枠のカテゴリを表し、サブタイプではより正確なデータ型を表す。
OSやそのバージョン、データの保存方法によって MIME タイプが違っていることもあり(CSVなど)、バリデーション実装時は複数の MIME タイプで判断するか、拡張子で判断するかなど工夫しなくてはならない。
Content-Type と MIME タイプの違いは、MIME タイプが情報そのものであるのに対し、Content-type は HTTP 通信のヘッダーにおいて、送信する情報がどのデータ型かを設定する項目名となるため、以下のような指定となる。
Content-type = MIME タイプ + 文字コード + データ境界値
Content-Type「application/x-www-form-urlencoded」は、エンコードされた URL のデータフォーマットであり、たとえば「hoge=foo&bar=baz」をエンコードしたデータは「hoge%3Dfoo%26bar%3Dbaz」のような形式となる。
通常、POST メソッドでフォームデータを送信するとき 「application/x-www-form-urlencoded」
を利用するが、ファイル送信が必要な場合は「multipart/form-data」を指定する必要がある。
その理由として、ファイル送信では、ひとつのフィールドに対して「ファイル名・種類・内容」と複数の情報を送信する必要があるが、application/x-www-form-urlencoded
だとひとつのフィールドに対してひとつの情報しか送信できないからである。
ブラウザではレスポンスヘッダーの Content-Type で指定された MIME タイプをもとに挙動を変更するため、image/jpeg
などの MIME タイプである場合、ブラウザは画像をブラウザ上に表示する。
ブラウザ表示ではなく、ダウンロードさせたい場合は Content-Disposition
を活用することで対応が可能である。
# ウェブページとして表示可能であることを示す。
Content-Disposition: inline
# ダウンロードすべきであることを示す。
Content-Disposition: attachment
ちなみに、XHR2(XMLHttpRequest – Webブラウザなどに実装されている JavaScript API およびオブジェクトのひとつで、スクリプトから HTTP を利用して Web サーバにアクセスする機能を提供するもの)での POST 送信に使用できる FormData はテキストデータだけを送信しても「multipart/form-data」で送信され、URLSearchParams は「application/x-www-form-urlencoded」で送信されるため、FormData はファイル情報を扱うときのみに使用するよう注意する。
const form = new FormData();
// ファイルに見せかけたBLOB(Binary Large Object)
var file = new Blob(['this is my memo'], { type: "text/plain" });
form.append('fileName', 'memo.txt');
form.append('file', file);
xhr.send(form);
※BLOBとは
データベースのフィールド定義などで用いられるデータ型の一つで、テキスト(文字列)や整数のように既存のデータ型としては用意されていない任意のバイナリデータを格納するためのもの。
https://e-words.jp/w/BLOB.html
である、データベースの文脈では以下のように使用される。
データベース管理システム(DBMS)が用意している通常のデータ型のフィールドには格納することができない、画像や音声、動画、実行ファイル、圧縮ファイルなど様々な種類のバイナリデータをレコード中に直接格納することができる。
https://e-words.jp/w/BLOB.html
内部的にはテーブル本体とは別の記憶領域にまとめて保管され、テーブル上にはデータへの参照のみが格納される実装になっていることが多い。このため、他の形式のデータでは可能な検索や並べ替え、キー設定などの操作や機能のほとんどは利用できない。
GET と POST メソッドの違い
GET はリクエスト本体がなく「開始行」と「メッセージヘッダー」のみとなる。
パラメータを送りたい場合は、URLの中にパラメータを記載する(GET パラメーター)。
POSTは、「application/x-www-form-urlencoded」の場合、GET パラメーターと同様の内容が本体部にはいる。
また、GET と異なり、POST の場合はリクエストのメッセージには、「Content-Type」と「Content-Length(送信データのバイト数)」の2つのヘッダーフィールドが送信される。
例)
Content-Type:application/x-www-form-urlencoded
Content-Length:423
「multipart/form-data」の場合のメッセージヘッダーの Content-Type は以下のようになる。
boundaryは、リクエスト本体に設定されるデータを区切るための記号で、値はランダムに設定される。本体の中身はboundaryで指定された区切り文字で、項目ごとに区切られる。
例)foo=barという情報と、file.txtというテキストファイルを POST 送信した例
Content-Type:multipart/form-data; boundary=-----------26841326868719
-------------26841326868719
Content-Disposition: form-data; name="foo"
bar
-------------26841326868719
Content-Disposition: form-data; name="profile"; filename="file.txt"
Content-Type: text/plain
~~ファイルの中身~~
-------------26841326868719--
参考:https://www.ois-yokohama.co.jp/oisblog2018/archives/1012
このように「application/x-www-form-urlencoded」と「multipart/form-data」では内容は全く違うが、PHP の $_POST は同じように使用できるよう隠蔽して使いやすくしてくれている。
参考サイト:
http://ksk2aki.xsrv.jp/wp/programming/form_post_string/
https://note.com/shift_tech/n/n7b4f14e4bbcd
https://www.wakuwakubank.com/posts/799-it-content-type-content-disposition/
https://qiita.com/Jxck_/items/769766853a90b7b435b0
https://www.ois-yokohama.co.jp/oisblog2018/archives/1012