Secure GET and POST requests using PHP
Tags: codenewbie, php, beginners, webdev
Published: 2021-05-20 18:21:22

> This post is also available in the following languages:  [Portuguese](https://medium.com/@danilocsar/requisi%C3%A7%C3%B5es-get-e-post-de-maneira-segura-usando-php-b2978af162e8).

*In this article, we will cover two request methods: the* GET *and the* POST *methods, for sending and receiving data from an HTML form using PHP. Also, we will examine the most common problems involving information security, such as* Cross-Site Scripting (XSS) *and* SQL Injection, *and how to solve them with adequate sanitization.*

*Let's start with the theory: what are* GET *and* POST *requests, and how do they differ? – if you want to, you can skip to the next section, where we will start with the practice.*

## **Understanding the *GET* and *POST* methods**

The *Hypertext Transfer Protocol* (*HTTP*) was developed as a protocol to serve the transmission of documents, and works as an intermediary between internet browsers and web servers. You are used to reading it in the addresses of web pages – as well as its “brother”, the *HTTPS*, a more secure encrypted version (hence the “S” at the end, meaning “Secure”).

In other words, *HTTP* is a protocol that serves as a “bridge”: it collects a request from the internet browser; sends it to the server; waits for an answer; and, finally, it returns the new information to the *browser*.

Generally, these requests keep some metadata in their “header”, that contains messages used to perform certain behavior on the client or on the server. In addition, *HTTP* requests can assume different models.

The most used *HTTP* request types are *GET* and *POST*, but there are other types in their technical specification, such as `PUT`, `HEAD`, `DELETE`, `PATCH` and `OPTIONS`. For the purposes of this article, we will focus only on the two most common.

### **The *GET* request**

The [*GET request* method](https://tools.ietf.org/html/rfc7231#section-4.3.1) is used when you want to obtain data from a specific source or resource. It should only be used to retrieval data, because its query string are sent and displayed at *URL*, for example: `https://www.youtube.com/watch?v=fJ9rUzIMcZQ&t=3m5s`.

When we insert this *URL* into the *browser*, we are asking the YouTube server for a specific resource: to retrieve the data from the video `v` identified as `fJ9rUzIMcZQ`. As soon as the server “returns” the request, the *HTTP* protocol will tell the *browser* how to display the video, in this example, the official video for the song “Bohemian Rhapsody”, by the British band Queen.

Note that in our example, the second parameter of the *GET* request, the `t` parameter, informs the start time that we expect in our response, in this case, from 3min and 5s. The parameters `v` and `t` are separated by the character `&`, which indicates to the *HTTP* protocol where the “key-value” pairs of these parameters begin and end. So, the server knows exactly that you search for the video `v=fJ9rUzIMcZQ` at the time `t=3m5s`.

*GET* requests are generally limited in length — for most *browsers*, it is up to [8 KB, or 8192 bytes](https://stackoverflow.com/a/2659995) in *URI* — and, because they only serve to request data, they are not able to modify it. In addition, they can be stored in *cache*, in the browser's history and also in the bookmarks. That's why you should **never** use it to send sensitive data, such as Social Security Numbers and user passwords.

>💡 Some developers, however, ignore it and expose personal and sensitive data of people on the internet. In Brazil, due to the [General Personal Data Protection Law (LGPD)](http://www.planalto.gov.br/ccivil_03/_ato2015-2018/2018/lei/l13709.htm), this practice may cause big inconveniences, such as serious penalties to the company or to the ones who operate and manage this data, when a leak happens. So, the best practice is to **never** send sensitive personal data via the *GET* method.

### **The *POST* request**

The [*POST request* method](https://tools.ietf.org/html/rfc7231#section-4.3.3) is used to send data to the server, to update or create a new resource.

Unlike the *GET* method, the *POST* method does not expose the information at the *URL* address. In this case, the data is transmitted in the *HTTP* request body, as follows:

```
POST /update/webform.php HTTP/1.1
Host: youtube.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 42
user=Stevie&playlist=British&v=fJ9rUzIMcZQ
```

In this example, we are informing the `Host: youtube.com` server that we will make a `POST` method request to the `/update/webform.php` address, using the technical specifications of the `HTTP/1.1` protocol. We are also indicating that there is a 42 character information (`Content-Length: 42`), in the standard `Content-Type` content format, whose value is `application/x-www-form-urlencoded`. Finally, our information is on the bottom line, containing 3 parameters: `user`, `playlist`, and `v`.

>💡 The information traveling in the body of the *HTTP* request can be intercepted by bad agents. The best practice, then, is to make these transmissions using encryption, via the *HTTPS* protocol, so it makes harder to them read this information.

Let's assume the YouTube server recognized our request, and this address is valid. In our example, the informed video, which we received previously, will be added to the `British` playlist of the user identified as `Stevie`.

Note that this is a one-time request, which is unlikely to be repeated. As a rule, the *POST* method, unlike *GET*, is not stored in *cache* or in the client's browser history, nor can it be saved in bookmarks. *POST* requests have no restrictions on the size of messages, which allows us to send complete articles, such as this one, through an electronic HTML form, for example. Also, the *POST* method supports a wide variety of `Content-Type`s, including binary documents, *strings*, and numbers.

>💡 *POST* method is generally preferable over *GET*. However, there are situations in which we should include the requisition data in the address *URL*: for example, in search forms or by displaying documents and videos, because we want the client to be able to repeat it easily and to re-access the address through the browser's history.

## **Creating forms with HTML and PHP**

Now that we understand how the *GET* and *POST* methods work in the theory, let's go to the practices: let's create an HTML form, and have it to send and to receive information using PHP.

>💡 There are several ways to do this, like via JavaScript and *AJAX*, where the user don't have to refresh the page, because we are transmitting the information asynchronously. For the purposes of this article, we will focus only on HTML and PHP technologies.

### **Inserting the form on the page**

The first step to create our web page is to inform the structure of the `<form>` element that will contain the fields where user types the data, like this:

```html
<!-- origin.html -->
<form method="GET" id="webform" name="webform" action="target.php">
</form>
```

In this fragment, we are using the *GET* method, defined in `method="GET"`, to send the information that will be inserted into the form, whose name was defined in `name="webform"`, to the target page (`action="target.php"`).

### **Inserting the fields to the form**

The next step is to insert the fields, or `input`s to our form, where users can type the values. Let's update our source file like this:

```html
<!-- origin.html -->
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Electronic form</title>
</head>
<body>
	<form method="GET" id="webform" name="webform" action="target.php">
		<label for="iduser">User ID:</label>
		<input type="text" id="iduser" name="iduser"> <br />

		<label for="idplaylist">Playlist ID:</label>
		<input type="text" id="idplaylist" name="idplaylist"> <br />

		<label for="v">Video ID:</label>
		<input type="text" id="v" name="v" value="fJ9rUzIMcZQ"> <br />

		<button type="submit">Send data</button>
	</form>
</body>
</html>
```

We inserted 3 fields, defined by the *HTML* tag `<input>`, and also 1 button that sends the form's data, using `<button type="submit">`.

We also add labels to the text fields, using the `<label>` tags. Notice that each values on the `for` attributes, on each `label` element corresponds to an `id` attribute of one the `input` fields, like this: `<label for="idplaylist">` refers specifically to the field that contains the corresponding `id="idplaylist"` attribute, and vice versa.

>💡 It is possible to insert predefined values to the fields, adding the data corresponding to the `value` attribute in each HTML `<input>` element.

Finally, the `name` attribute in each `<input>` field will be used to obtain the values inserted by the user in the corresponding field when we move to PHP.

The final result, displayed in the client's *browser*, should look like this:

![en_1.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621533203977/gA6-X-OJP.png)

### **Reading data with PHP**

After completing our HTML form, we can move on to the next step. Let's define the elements of the target page using PHP.

The source code below, inserted in the file `target.php`, will be executed by PHP as soon as the user submits the form data that we created earlier.

```php
<!-- target.php -->
<?php
	// Prints the values of each field on the page
	echo(
	"The user identified as " . $_GET["iduser"] . " added the video whose ID is " . $_GET["v"] . " to the playlist " . $_GET["idplaylist"] . "."
	);
?>
```

Notice that we use the *superglobal* `$_GET[]` variable to obtain the values inserted by the user, that were transmitted using the *HTTP* protocol. For each `<input>` field that we previously created on the form, its corresponding `name` attribute must be informed within the *superglobal variable*. For example: the `<input>` field that shows the attribute `name="iduser"` can be found in PHP by using `$_GET["iduser]`.

PHP has some [native *superglobals* variables](https://www.php.net/manual/en/language.variables.superglobals.php), such as `$_GET`, `$_POST`, and `$_REQUEST`. Remember that we use them **according to the *HTTP* request method that we are using** for data transmission, so it must correspond to what been defined in the `method` attribute of our `<form>` element.

>💡 PHP's `$_REQUEST` *superglobal* variable can carry information from both `$_GET` and `$_POST` methods, in addition to any *cookies* transmitted in `$_COOKIE`. However, its use **is not** always recommended: the best practice is that developers know the methods used for inputs and outputs traveling on their server, in order to avoid more generic commands.

Then, we separate the *strings* and the variables in PHP with the `.` character, so each fragment of text is contained between the `"` characters, at the beginning and at the end of the sentence. Finally, we print on the user's screen the entire expression within the parentheses with the `echo()` function.

### 📝 Learn by doing

Did you notice that the *URL* address on `target.php` page shows the values typed in the source page?

**Test #1:** Rewrite the source code of the form we coded, using another requisition method, so that the information stays safe from reading by eavesdroppers and unauthorized people. After you finish, you can check [the final answer](https://gist.github.com/DaniloCeesar/b49ec6a77f3d75380fe0b689afbfe065).

## **Increasing HTML form security**

Our HTML form is finally done! However, we can increase the security of our page, protecting the reading of the information on PHP.

This is our last step. We will add an extra layer of security, although basic, to prevent PHP from executing commands at the moment it receives and displays the values reported by the client.

>💡 The rule in programming is to **never blindly trust the values inserted by the user**. Unfortunately, many bad agents have exploited technical problems on websites in order to collect sensitive information, or to damage servers by executing unexpected commands. For those reasons, it is very important that you **protect, beforehand, the transmitted requests and the server**, after all, if the users' interests are legitimate, they will also benefit from the increased security of your application.

The technique that filters and transforms the values entered by the user into simpler *strings* is called **sanitization**. By default, PHP has a collection of native functions that helps us on this step, such as the following:

- `htmlspecialchars()` - Converts special characters, such as `&“”<>`, to HTML entities;
- `htmlentities()` - Similar to the previous one, but it converts a larger number of characters to HTML entities;
- `strip_tags()` - Removes HTML and PHP *tags* from a *string*, such as *hyperlinks* and comments.

When we use adequate sanitization, as soon as the server receives an improper information — for example, `<script>alert('Intrusive alert');</script>` — it will be transformed, “sanitized”, and should not display a warning message on the users' screen in this case.

>💡 Notice that, in our example, we use a harmless, in theory, *script* — at most, uncomfortable for the user. However, it is important to reiterate: you must **always protect and sanitize information**. In other cases, a bad agent could transmit malicious *scripts* — this technique is known as *Cross-Site Scripting*, or *XSS* — or execute harmful commands to the database (usually called *SQL Injection*).

Let's edit the source code of our page, by adding one of these sanitizing functions. Our final code should look like this:

```php
<!-- target.php -->
<?php
	// Prints the values of each field on the page
	echo(
	"The user identified as " . htmlspecialchars($_GET["iduser"], ENT_QUOTES, "UTF-8") . " added the video whose ID is " . htmlspecialchars($_GET["v"], ENT_QUOTES, "UTF-8") . " to the playlist " . htmlspecialchars($_GET["idplaylist"], ENT_QUOTES, "UTF-8") . "."
	);
?>
```

The final result, displayed in the browser, should look like the figure below:

![en_2.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621533214749/2elZdyIK4.png)

### 📝 Learn by doing

Have you ever noticed that the majority of sites and search engines use the `q` parameter to transmit the data inserted by the user in the query requests to the server?

**Test #2:** Create a search form, using HTML and PHP, that contains at least 1 text field and 1 button to send the data, so that the address *URL* on the target page displays the `q` (or “query”) parameter. It should receive the values, sanitized, inserted by the user in the text field. After you finish, you can check [the final answer](https://gist.github.com/DaniloCeesar/95c63e7c93e56deb05fb150923d03fe8).

## **Conclusion**

So, we're done! We made our electronic form in HTML that is capable of transmitting data via *HTTP* request methods, in this case, *GET* or *POST* — and we also understand how they work —, and send them to the target page written in PHP. Then, it receives, handles the data, and displays the information on the user's screen. Also, we sanitized the values informed by the user in order to avoid serious problems of information security.

### **Next steps** 🚶

Internet security it is never too much, so there is always something more to learn and apply. In order to build safer applications, be sure to follow the next article on this series, and read the [Security topic in the PHP Manual](https://www.php.net/manual/en/security.php).

If you have any questions or suggestions on how to build more secure applications using PHP, share it in the comments. 📣

### **References**

[1] “HTTP Request Methods”, from *w3schools*: [https://www.w3schools.com/tags/ref_httpmethods.asp](https://www.w3schools.com/tags/ref_httpmethods.asp).

[2] “HTTP”, from *MDN Web Docs* (*Mozilla Developer Network*): [https://developer.mozilla.org/en-US/docs/Web/HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP).

[3] “GET”, from *MDN Web Docs* (*Mozilla Developer Network*): [https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET).

[4] “POST”, from *MDN Web Docs* (*Mozilla Developer Network*): [https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).

[5] “htmlspecialchars”, from *PHP Manual*: [https://www.php.net/htmlspecialchars](https://www.php.net/htmlspecialchars).

[6] “htmlentities”, from *PHP Manual*: [https://www.php.net/htmlentities](https://www.php.net/htmlentities).

[7] “strip_tags”, from *PHP Manual*: [https://www.php.net/strip_tags](https://www.php.net/strip_tags).

[8] “Superglobals”, from *PHP Manual*: [https://www.php.net/manual/en/language.variables.superglobals.php](https://www.php.net/manual/en/language.variables.superglobals.php).