アプリケーションに以下のような構造があるとします。
- 📁 application_folder_name
- 📄 index.php
- 📄 handle_form.php
- 📄 main.js
そして、フォームを備えた基本的なウェブサイトを動作させるために、index.php
に以下の内容を記述します。これは、お好みのphpサーバーで実行できるはずです。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>PHP</title>
</head>
<body>
<form action="handle_form.php" method="POST" id="example_form">
<label for="username">Username</label>
<input type="text" name="username" id="username">
<label for="favorite_number">Favorite number</label>
<input type="number" name="favorite_number" id="favorite_number">
<input type="submit" value="Skicka">
</form>
<script src="main.js"></script>
</body>
</html>
フォームに注目してみましょう。フォームを正常に送信するには、入力内容を form
要素の中に記述する必要があります。これは、「通常通り」にフォームを送信した場合に、入力内容も一緒に送信されることを示しています。JavaScript を使用せずにフォームを送信するには、すべての入力項目に name
が必要です。実際には、JavaScript や PHP を使用してデータを送信するかどうかにかかわらず、name
が必要です。実際のフォームには 3 つの項目が必要です。
action
- この情報をどのファイルに送るかをフォームに伝えます。ここでは、index.php
と同じフォルダーにあるhandle_form.php
を使います。method
- どのようにこの情報を送信するか。POST
またはGET
です。デフォルトはGET
です。<input type="submit">
- Tクリックでフォームを送信できるようにするためには、JavaScriptで処理する場合でも、必ず「送信」ボタンを設置する必要があります。このボタンは、<button type="submit"> Send </button>
とすることで、ボタンの中にHTMLを入れることができます(例えば、ボタンの中にアイコンを入れることができます)。
<form action="handle_form.php" method="POST" id="example_form">
<label for="username">Username</label>
<input type="text" name="username" id="username">
<label for="favorite_number">Favorite number</label>
<input type="number" name="favorite_number" id="favorite_number">
<input type="submit" value="Skicka">
</form>
リクエストを正常に送信するためには、これらの情報がすべてHTML内に存在する必要があります。このマークアップが正しければ、 handle_form.php
というファイルにフォームを送信することができるはずです。
<?php
echo $_POST["username"];
echo $_POST["favorite_number"];
<input name="username">
とすると、入力フィールドの値が $_POST["username"]
に格納されます。つまり、入力フィールドのname
によって、PHPでの変数の呼び名が決まるのです。
- フォームで
method="POST"
を使用すると、値は$_POST
に格納されます。 - もし、
method="GET"
を使用するか、method
をフォームに指定しない場合、値は$_GET
に格納されます。 - PHP には、これらの値を含むことができる
$_REQUEST
変数もあります。
$_POST
と $_GET
は常に連想配列であり、これは変数が作成されない場合の書き方です。
<?php
$_POST = [
"username" => "zero_cool",
"favorite_number" => "10"
];
JavaScriptに相当するものは以下の通りです。
var $_POST = {
username: "zero_cool",
favorite_number: "10"
};
代わりに GET
で同じ情報を送ることができます。
<form action="handle_form.php" method="GET" id="example_form">
<label for="username">Username</label>
<input type="text" name="username" id="username">
<label for="favorite_number">Favorite number</label>
<input type="number" name="favorite_number" id="favorite_number">
<input type="submit" value="Skicka">
</form>
この場合の唯一の違いは、$_POST
ではなく$_GET
の中にデータを格納することです。
<?php
// Inside of `handle_form.php`
echo $_GET["username"];
echo $_GET["favorite_number"];
example
<?php
$_GET = [
"username" => "zero_cool",
"favorite_number" => "10"
];
JavaScriptに相当するものは以下の通りです。
var $_GET = {
username: "zero_cool",
favorite_number: "10"
};
もう一つの違いは、URLの中に情報が入ってくることです。
http://localhost:8888/handle_form.php?username=zero_cool&favorite_number=10
これは、基本的に、フォームを処理するようなPHPファイルを、代わりにリンクで呼び出すことができることを意味します。つまり、以下のようなコードを書いても同じ結果が得られるということです。なぜなら、情報は常にURLを介して送信され、POST
のようにボディの中では ない からです。
<a href="http://localhost:8888/handle_form.php?username=zero_cool&favorite_number=10">
Click me to submit
</a>
ページをリロードすることなく、JavaScriptを使用して同じフォームを送信することができます。同じロジックがPHPファイルの中で適用され、作業のほとんどはJavaScriptで行われます。上記と同じフォームがある場合、まずフォームが 送信されていない ことを確認する必要があります。フォームのデフォルトの動作は、新しいサイトにリダイレクトすることで、これはJavaScriptがない場合には問題ありません。しかし、この場合には、JavaScriptを利用することができます。
// 個々の入力フィールドではなく、フォーム全体を取得する
const form = document.getElementById('example_form');
/**
* コールバック関数は常にあなたが何をクリックしたかを知り、
* 最初のパラメータとしてイベントオブジェクトを関数に与えます。
*/
form.addEventListener('click', function(event){
// イベントがフォームを送信するのを防ぎ、リダイレクトやページの再読み込みを行わない
event.preventDefault();
});
フォームが通常の動作をしないようにしました。つまり、代わりに何をすべきかを指定する必要があるということです。つまり、バックエンドと通信する必要があることがわかりました。クライアント側とサーバー側が同じドメイン上にあっても、JavaScriptはAJAXを経由せずにPHPに通信することができません。AJAXは必ず使用しなければなりません。それでは、ネイティブで組み込まれているAJAXの使用方法である fetch
を使用してみましょう。以下の最初のコードは動作しないことに注意してください。これは単なる最初のステップです。
// 個々の入力フィールドではなく、フォーム全体を取得する
const form = document.getElementById('example_form');
/**
* コールバック関数は常にあなたが何をクリックしたかを知り、
* 最初のパラメータとしてイベントオブジェクトを関数に与えます。
*/
form.addEventListener('click', function(event){
// イベントがフォームを送信するのを防ぎ、リダイレクトやページの再読み込みを行わない
event.preventDefault();
postData();
});
async function postData(){
/*
* 先ほどと同じファイルを使い、バックエンドのコードも実際のフォームも触らないようにしています。
* フォームから action 属性を取得することもできますが、ここでは単に 'URL' を入力する方が簡単です。
* PORTや'localhost'を指定する必要はありません。
*/
const response = await fetch('handle_form.php');
/*
* handle_form.php` の中で `echo` を使用しているので、
* 応答は JSON データではなく文字列になります。
* このため、`response.json()` ではなく `response.text()` を使用して、
* JavaScriptが理解できるように変換する必要があります。
*/
const data = await response.text();
// これで、フォームから送信された値が出力されます
console.log(data);
}
しかし、送信する情報がまだ不足しています。生のPHP/HTMLでは、フォームがデータを変換して handle_form.php
に送信します。データを送信するための独自のロジックを書く場合は、データが適切にフォーマットされていることを確認する必要があります。
データは x-www-form-urlencoded
または multipart/form-data
にフォーマットされている必要があり、これは PHP が受信することを期待しているものです。これを扱う最も簡単な方法は、FormData
-objectを使用することです。JSONを受け入れるようにすることもできますが、FormData
-object を使うほうが簡単です。
// 個々の入力フィールドではなく、フォーム全体を取得する
const form = document.getElementById('example_form');
/**
* コールバック関数は常にあなたが何をクリックしたかを知り、
* 最初のパラメータとしてイベントオブジェクトを関数に与えます。
*/
form.addEventListener('click', function(event){
// イベントがフォームを送信するのを防ぎ、リダイレクトやページの再読み込みを行わない
event.preventDefault();
/**
* フォーム内のすべての入力値を使用したい場合は、送信するフォームを引数として
* `new FormData()` を呼び出すことができます。
* これにより、PHPが適切に読める body オブジェクトが作成されます。
*/
const formattedFormData = new FormData(form);
postData(formattedFormData);
});
async function postData(formattedFormData){
/**
* 何かを'POST'したい場合には、`method`を'POST'に変更する必要があります。
* POST では、リクエストが `body` の中の値を送信することも想定しているので、
* このプロパティも指定する必要があります。
* ここでは、先ほど作成したFormData()オブジェクトを使って、それを渡すだけです。
*/
const response = await fetch('handle_form.php',{
method: 'POST',
body: formattedFormData
});
/*
* handle_form.php` の中で `echo` を使用しているので、レスポンスは
* JSON データではなく文字列になります。
* このため、`response.json()`ではなく`response.text()`を使用して、
* JavaScriptが理解できるように変換する必要があります。
*/
const data = await response.text();
// これで、バックエンド側に送信した値が出力されます。
console.log(data);
}
フォームの内部にないものをこのオブジェクトに追加したい場合は、FormData
-オブジェクトの.append()
メソッドを使用します。
form.addEventListener('click', function(event){
event.preventDefault();
const formattedFormData = new FormData(form);
formattedFormData.append('property', 'value');
postData(formattedFormData);
});
フォームと fetch
コールは GET
か POST
のどちらかしか使いません。1つのリクエストは、これらのリクエストのうちの1つだけです。しかし、URLで値を送ることは可能で、リクエストがPOST
であっても、これらは$_GET
変数の中に格納されます。
const form = document.getElementById('example_form');
form.addEventListener('click', function(event){
event.preventDefault();
const formattedFormData = new FormData(form);
postData(formattedFormData);
});
async function postData(formattedFormData){
/**
* リクエストはまだ'POST'ですが、$_GET変数には'name'と'favorite_color'という値も入ります。
*/
const response = await fetch(
'handle_form.php?name=Jesper&favorite_color=pink',
{
method: 'POST',
body: formattedFormData
}
);
const data = await response.text();
console.log(data);
}
これにより、handle_form.php
内に以下の変数が設定されることになります。
<?php
// handle_form.php`の内部
echo $_POST["username"];
echo $_POST["favorite_number"];
echo $_GET["name"];
echo $_GET["favorite_color"];
FormData
は、サーバーが x-www-form-urlencoded
形式でデータを受信することを期待する場合に使用します。サーバーによっては、データを JSON
オブジェクトとして送信することを好む場合もあります。つまり、フロントエンドとバックエンドの両方にいくつかの変更を加える必要があります。先ほどと同じフォームを使用する場合、以下のようになります。
const form = document.getElementById('example_form');
form.addEventListener('click', function(event){
event.preventDefault();
/*
* new FormData(this) "のようなショートカットはなく、自分でフォームオブジェクトを構築する必要があります。
* ここでは FormData オブジェクトではなく、通常のオブジェクトを作成しています。
* form.username.value や form.favorite_number.value と書くこともできます。
*/
const formattedFormData = {
username: this.username.value,
favorite_number: this.favorite_number.value
}
postData(formattedFormData);
});
async function postData(formattedFormData){
/**
* リクエストは'POST'のままですが、
* $_GET変数には'name'と'favorite_color'の値も入ります。
*/
const response = await fetch(
'handle_form.php',
{
method: 'POST',
/*
* また、値を文字列化して、JavaScriptオブジェクトをJSONとして
* 受け入れられる単一の文字列にする必要があります。
* そこで、すべての値を含む1つの文字列を送信します。
*/
body: JSON.stringify(formattedFormData)
}
);
const data = await response.text();
console.log(data);
}
このようにデータを送信する場合には、PHPにデータがこのように受け取られることを期待するように伝える必要があります。
<?php
// handle_form.php の内部
/* JSONとして送られてきたすべてのデータを解析しています。json_decode` は、JSON オブジェクトを PHP の連想配列に変換し、それを `$data` に格納します。
*/
$data = json_decode(file_get_contents('php://input'), true);
echo $data["username"];
echo $data["favorite_number"];
データをJSONとして受け取ることを選択した場合、おそらくJSONを送り返す必要があります。つまり、json形式の値を「echo
」で返したい場合は、データを送信する前にjson_encode
を使用する必要があります。これは、データに対して何もしていないので、ちょっと間抜けな例ですが、構文とその動作のコツを知るためのものです。
<?php
// 'handle_form.php' の内部
$data = json_decode(file_get_contents('php://input'), true);
echo json_encode($data);
If we return JSON we must also use .json()
instead of .text()
in JavaScript:
const data = await response.text();
const data = await response.json();
これは、一部のAPIがブラウザ経由でのAPIへのリクエストを許可していないことを意味する**CORS**によって制限されている場合に便利です。私はこの問題を回避するための小さなガイドをここに書きました。 Handle CORS Client-side
自分のサーバを経由してデータをリダイレクトするための小さなプロキシファイルを作ることができます。例として Pokémon API を見てみましょう。これはCORSを許可していないからです。そこで、APIを直接呼び出すのではなく、APIを呼び出す独自のファイルを呼び出します。
async function fetchPokemon(){
const response = await fetch('fetch_pokemon.php?pokemon=25');
const pokemon = await response.json();
console.log(pokemon);
}
fetch_pokemon.phpの中では、通常、APIからデータを取得するために使用される
file_get_contents`を使用しています。
<?php
$response = file_get_contents('http://pokeapi.co/api/v2/pokemon/' . $_GET["pokemon"]);
echo $response;
?
の後にクエリパラメータを追加することで、どのポケモンを取得するかを送信していることに注目してください。この場合、キーは $_GET["pokemon"]
となり、値は 25
となります。CORSエラーは発生しません。
** ユーザーからのデータを信用しないで、慎重に行動してください。このようなリクエストでユーザーからのデータを送信すると、有害な場合があります。送信する前に必ず入力内容を検証してください**