|
|
@@ -0,0 +1,376 @@ |
|
|
# PHP Form submitting |
|
|
|
|
|
If we have the following structure in our application: |
|
|
|
|
|
* 📁 application_folder_name |
|
|
- 📄 index.php |
|
|
- 📄 handle_form.php |
|
|
- 📄 main.js |
|
|
|
|
|
And we fill our `index.php` with the following content just to get a basic website with a form working. You should be able to run this through a php-server of your choice. |
|
|
|
|
|
```html |
|
|
<!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> |
|
|
``` |
|
|
|
|
|
### Submitting a form with PHP |
|
|
|
|
|
Lets focus on the form. To successfully submit a form you need to have your inputs inside of the `form`-element, this indicates that the inputs shall be sent along with the form if we submit the form "like normal". To send the form without JavaScript all inputs need to have a `name`, in fact they should have a `name` regardless if you are sending the data via JavaScript or PHP. The actual form needs **3** things: |
|
|
|
|
|
* `action` - telling the form to **which** file should this information be sent, in this case `handle_form.php` which is located in the same folder as `index.php` |
|
|
* `method` - **how** should this information be sent: `POST` or `GET`. Default is `GET` |
|
|
* `<input type="submit">` - To be able to send the form via click, even if you handle this via JavaScript, you should always ha a "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> |
|
|
``` |
|
|
|
|
|
All this information needs to exists in HTML to successfully send a request. If this markup is correct we should be able to submit the form to the file `handle_form.php`: |
|
|
|
|
|
```php |
|
|
<?php |
|
|
echo $_POST["username"]; |
|
|
echo $_POST["favorite_number"]; |
|
|
``` |
|
|
|
|
|
`<input name="username">` will result in the value of the input field being stored in `$_POST["username"]`. So the `name` of the input field will decide what the variable is called in PHP. |
|
|
|
|
|
* If we use `method="POST"` on the form the values will be stored in `$_POST` |
|
|
* If we use `method="GET"` or do not supply a `method` to the form the values will be stored in `$_GET` |
|
|
|
|
|
`$_POST` and `$_GET` will always be an _Associative Array_, this is how we would write the variable if it wouldn't get created for us: |
|
|
```php |
|
|
<?php |
|
|
$_POST = [ |
|
|
"username" => "zero_cool", |
|
|
"favorite_number" => "10" |
|
|
]; |
|
|
``` |
|
|
|
|
|
The JavaScript equivalent would be: |
|
|
|
|
|
```js |
|
|
var $_POST = { |
|
|
username: "zero_cool", |
|
|
favorite_number: "10" |
|
|
}; |
|
|
``` |
|
|
|
|
|
#### Using `GET` instead of `$_POST` |
|
|
|
|
|
We can send the same information with `GET` instead: |
|
|
|
|
|
```html |
|
|
<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> |
|
|
``` |
|
|
|
|
|
The only difference in this case is that we store the data inside of `$_GET` instead of `$_POST`. |
|
|
|
|
|
```php |
|
|
<?php |
|
|
// Inside of `handle_form.php` |
|
|
echo $_GET["username"]; |
|
|
echo $_GET["favorite_number"]; |
|
|
``` |
|
|
|
|
|
_example_ |
|
|
```php |
|
|
<?php |
|
|
$_GET = [ |
|
|
"username" => "zero_cool", |
|
|
"favorite_number" => "10" |
|
|
]; |
|
|
``` |
|
|
|
|
|
The JavaScript equivalent would be: |
|
|
|
|
|
```js |
|
|
var $_GET = { |
|
|
username: "zero_cool", |
|
|
favorite_number: "10" |
|
|
}; |
|
|
``` |
|
|
|
|
|
The other difference is that the information will be available inside of the URL: |
|
|
|
|
|
```http |
|
|
http://localhost:8888/handle_form.php?username=zero_cool&favorite_number=10 |
|
|
``` |
|
|
|
|
|
This also means that we can basically call PHP-files like the one handling our form with a link instead. So if we where to write the code below, we would get the same result. This is only possible with `GET`-requests because the information is always sent via the URL and **not** inside of body like with `POST`. |
|
|
|
|
|
```html |
|
|
<a href="http://localhost:8888/handle_form.php?username=zero_cool&favorite_number=10"> |
|
|
Click me to submit |
|
|
</a> |
|
|
``` |
|
|
|
|
|
### Submitting a form with JavaScript |
|
|
|
|
|
We can submit the same form with the use of JavaScript without reloading the page. The same logic will be applied inside of the PHP-file and most of the work must be done in JavaScript. If we have the same form as above we must first make sure the form **isn't** being submitted. A forms default behavior is to redirect you to a new site, which is fine if we don't have JavaScript. But in this case we can use JavaScript to our advantage. |
|
|
|
|
|
```js |
|
|
// Get the whole form, not the individual input-fields |
|
|
const form = document.getElementById('example_form'); |
|
|
|
|
|
/** |
|
|
* Add an onclick-listener to the whole form, the callback-function |
|
|
* will always know what you have clicked and supply your function with |
|
|
* an event-object as first parameter, `addEvenListener` creates this for us |
|
|
*/ |
|
|
form.addEventListener('click', function(event){ |
|
|
//Prevent the event from submitting the form, no redirect or page reload |
|
|
event.preventDefault(); |
|
|
}); |
|
|
``` |
|
|
|
|
|
No we have stopped the form from behaving like it normally would. That also means that we need to specify what it should do instead. So we know that we need to communicate with the backend. Even though the client side and the server side are on the same domain, JavaScript can't communicate back to PHP without going through AJAX. AJAX must always be used. Let's use the native built in way of using AJAX: `fetch`. Notice that the first code below will not work, it is just a first step |
|
|
|
|
|
```js |
|
|
// Get the whole form, not the individual input-fields |
|
|
const form = document.getElementById('example_form'); |
|
|
|
|
|
/** |
|
|
* Add an onclick-listener to the whole form, the callback-function |
|
|
* will always know what you have clicked and supply your function with |
|
|
* an event-object as first parameter, `addEvenListener` creates this for us |
|
|
*/ |
|
|
form.addEventListener('click', function(event){ |
|
|
//Prevent the event from submitting the form, no redirect or page reload |
|
|
event.preventDefault(); |
|
|
postData(); |
|
|
}); |
|
|
|
|
|
async function postData(){ |
|
|
/* |
|
|
* We are still using the same file as before and we are still not touching |
|
|
* either the backend code or the actual form. We could grab |
|
|
* the action-attribute from the form but it's easier to just put |
|
|
* in the 'URL' here. We don't need to supply PORT or 'localhost' |
|
|
*/ |
|
|
const response = await fetch('handle_form.php'); |
|
|
/* |
|
|
* Because we are using `echo` inside of `handle_form.php` the response |
|
|
* will be a string and not JSON-data. Because of this we need to use |
|
|
* `response.text()` instead of `response.json()` to convert it to someting |
|
|
* that JavaScript understands |
|
|
*/ |
|
|
const data = await response.text(); |
|
|
//This should later print out the values submitted through the form |
|
|
console.log(data); |
|
|
} |
|
|
``` |
|
|
|
|
|
But we are still missing the information to be sent. In raw PHP/HTML the form handles converting the data and sending it to `handle_form.php`. If we write our own logic for sending the data we must also make sure that the data is properly formatted. |
|
|
|
|
|
The data needs to be formatted to [`x-www-form-urlencoded`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST) or [`multipart/form-data`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST) which is what PHP is expecting to recieve. The easiest way to handle this is via the [`FormData`-object](https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects). We can also make it accept JSON but it's easier to use the `FormData`-object. |
|
|
|
|
|
```js |
|
|
// Get the whole form, not the individual input-fields |
|
|
const form = document.getElementById('example_form'); |
|
|
|
|
|
/** |
|
|
* Add an onclick-listener to the whole form, the callback-function |
|
|
* will always know what you have clicked and supply your function with |
|
|
* an event-object as first parameter, `addEvenListener` creates this for us |
|
|
*/ |
|
|
form.addEventListener('click', function(event){ |
|
|
//Prevent the event from submitting the form, no redirect or page reload |
|
|
event.preventDefault(); |
|
|
/** |
|
|
* If we want to use every input-value inside of the form we can call |
|
|
* `new FormData()` with the form we are submitting as an argument |
|
|
* This will create a body-object that PHP can read properly |
|
|
*/ |
|
|
const formattedFormData = new FormData(form); |
|
|
fetchData(formattedFormData); |
|
|
}); |
|
|
|
|
|
async function postData(formattedFormData){ |
|
|
/** |
|
|
* If we want to 'POST' something we need to change the `method` to 'POST' |
|
|
* 'POST' also expectes the request to send along values inside of `body` |
|
|
* so we must specify that property too. We use the earlier created |
|
|
* FormData()-object and just pass it along. |
|
|
*/ |
|
|
const response = await fetch('handle_form.php',{ |
|
|
method: 'POST', |
|
|
body: formattedFormData |
|
|
}); |
|
|
/* |
|
|
* Because we are using `echo` inside of `handle_form.php` the response |
|
|
* will be a string and not JSON-data. Because of this we need to use |
|
|
* `response.text()` instead of `response.json()` to convert it to someting |
|
|
* that JavaScript understands |
|
|
*/ |
|
|
const data = await response.text(); |
|
|
//This should now print out the values that we sent to the backend-side |
|
|
console.log(data); |
|
|
} |
|
|
``` |
|
|
|
|
|
#### Adding more values to `FormData` in JavaScript |
|
|
|
|
|
If we want to add stuff that isn't inside of the form to this object we can use the `.append()`-method on the `FormData`-object: |
|
|
|
|
|
```js |
|
|
form.addEventListener('click', function(event){ |
|
|
event.preventDefault(); |
|
|
const formattedFormData = new FormData(form); |
|
|
formattedFormData.append('property', 'value'); |
|
|
fetchData(formattedFormData); |
|
|
}); |
|
|
``` |
|
|
|
|
|
|
|
|
#### Sending both `GET` AND `POST` |
|
|
|
|
|
The form and the `fetch`-call will only either use `GET` or `POST`. A request can only be one of these requests. We can however send along values in the URL and these will be stored inside of the `$_GET`-variable even though our request is a `POST`. |
|
|
|
|
|
```js |
|
|
const form = document.getElementById('example_form'); |
|
|
form.addEventListener('click', function(event){ |
|
|
event.preventDefault(); |
|
|
const formattedFormData = new FormData(form); |
|
|
fetchData(formattedFormData); |
|
|
}); |
|
|
|
|
|
async function postData(formattedFormData){ |
|
|
/** |
|
|
* The request is still 'POST' but the $_GET variable |
|
|
* will get values too: 'name' and '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); |
|
|
} |
|
|
``` |
|
|
|
|
|
This would result in the following variables being set inside of `handle_form.php`: |
|
|
|
|
|
```php |
|
|
<?php |
|
|
// Inside of `handle_form.php` |
|
|
echo $_POST["username"]; |
|
|
echo $_POST["favorite_number"]; |
|
|
echo $_GET["name"]; |
|
|
echo $_GET["favorite_color"]; |
|
|
``` |
|
|
|
|
|
#### Using `JSON` |
|
|
|
|
|
`FormData` is used when the server expects to recieve data in the form of `x-www-form-urlencoded`. This isn't always the case, some servers prefer that you instead send the data as a `JSON`-object. This means that we have to make some changes to both the frontend and the backend. If we use the same form as earlier: |
|
|
|
|
|
```js |
|
|
const form = document.getElementById('example_form'); |
|
|
form.addEventListener('click', function(event){ |
|
|
event.preventDefault(); |
|
|
/* |
|
|
* There is no shortcut like with 'new FormData(this)', we need |
|
|
* to construct the form-object ourselves. We are creating a regular |
|
|
* object instead of a FormData-object. `this` refers to the form, |
|
|
* we could also write: form.username.value and form.favorite_number.value |
|
|
*/ |
|
|
const formattedFormData = { |
|
|
username: this.username.value, |
|
|
favorite_number: this.favorite_number.value |
|
|
} |
|
|
fetchData(formattedFormData); |
|
|
}); |
|
|
|
|
|
async function postData(formattedFormData){ |
|
|
/** |
|
|
* The request is still 'POST' but the $_GET variable |
|
|
* will get values too: 'name' and 'favorite_color' |
|
|
*/ |
|
|
const response = await fetch( |
|
|
'handle_form.php', |
|
|
{ |
|
|
method: 'POST', |
|
|
/* |
|
|
* We also need to stringify the values, turn the |
|
|
* JavaScript object to a single string that is accepted |
|
|
* as JSON. So we are sending one string that contains |
|
|
* all our values |
|
|
*/ |
|
|
body: JSON.stringify(formattedFormData) |
|
|
} |
|
|
); |
|
|
const data = await response.text(); |
|
|
console.log(data); |
|
|
} |
|
|
``` |
|
|
|
|
|
If we choose to send the data like this we also need to tell PHP to expect the data to be accepted like this: |
|
|
|
|
|
```php |
|
|
<?php |
|
|
//inside of 'handle_form.php' |
|
|
|
|
|
/* We are parsing all the data that is being sent as JSON. `json_decode` |
|
|
* turn our JSON-object into a PHP Associative array and stores it inside of |
|
|
* `$data` |
|
|
*/ |
|
|
$data = json_decode(file_get_contents('php://input'), true); |
|
|
echo $data["username"]; |
|
|
echo $data["favorite_number"]; |
|
|
``` |
|
|
|
|
|
If we choose to accept data as JSON we should probably also send back JSON. So if we want to '`echo`' back some value in the form of json, we should use `json_encode` before sending it. This is a bit dumb example tho because we are not doing anything with the data, but it's more to get a hang of the syntax and how it works. |
|
|
|
|
|
```php |
|
|
<?php |
|
|
//inside of '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: |
|
|
|
|
|
```js |
|
|
const data = await response.text(); |
|
|
``` |
|
|
|
|
|
```js |
|
|
const data = await response.json(); |
|
|
``` |
|
|
|