SITERAW

Sending Data with Forms

Forms are the main way for your visitors to input information on your site. They make interactivity possible.

For instance, on a forum, you type some text and click a button to send your message. Same thing with a guestbook or a mini-chat. Basically, we need forms everywhere to exchange data with our users.

You'll notice a lot of HTML coming back in this chapter... and that's no accident: PHP and HTML go hand in hand here. HTML is used to build the form, and PHP is used to handle the data the visitor submits.

This chapter is especially important — we'll be reusing what you learn here throughout the rest of the course. So stay focused!

Creating the Form's Foundation

In HTML, we use the <form> tag to create a form. It looks like this:

<form method="post" action="destination.php">

<p> This is where we'll insert the form elements. </p>

</form>

Everything that makes up our form will go between the opening and closing <form> tags. If you've already read my HTML/CSS course, a good chunk of this chapter will feel familiar, since I'll go over how to insert the form fields into your page. But here's the new part: we're also going to see how to process the data using PHP.

And if your memory's a bit fuzzy on how forms work in HTML, I highly recommend revisiting the chapter on forms in the HTML/CSS course. When I say you can't (really) do PHP web development without knowing HTML, I mean it!

Let me draw your attention to the very first line of the code. There are two crucial attributes to know for the <form> tag: method and action. You absolutely need to understand what they do.

The Method

There are several ways to send form data — different "methods." The two main ones are:

  • get: the data is sent through the URL, as we've seen before. You retrieve it using the $_GET array. This method is rarely used because you can't send much data via the URL (as I mentioned earlier, it's best not to exceed 256 characters).
  • post: the data is not passed through the URL, so the user won't see it in the address bar. You can send as much data as you want, which is why it's the most common method. However, the data isn't any more secure than with GET — you should always check that all the required values are present and valid, just like we did before. Don't blindly trust forms any more than URLs.

It's up to you to choose the method for sending your form data. If you're unsure, know this: in 99% of cases, we use post, so you'll most often write method="post" like I did above.

GET and POST aren't the only methods out there. There's also PUT, DELETE, PATCH, OPTIONS, TRACE, and HEAD, but they're mostly used in very specific cases. In most if not all of your projects, you'll be using either GET or POST.

The Action

The action attribute defines which page the form will send data to. That's the page that will receive and process the form's data.

Let's imagine the following setup:

form.php → destination.php

Here, the form is in form.php. This page doesn't do any processing, but once the form is submitted (by clicking the "Submit" button), the user is redirected to destination.php, which receives the form data.

The target page's name is set via the action attribute.

The target doesn't have to be called destination.php — I'm using that name to make it clear that it's the page being called. In fact, nothing stops the form from calling itself. You could simply write action="form.php". In that case, the same page must be able to both display the form and process the data. That's totally doable, but to avoid making things too complex right now, we'll steer clear of that. ;)

So, remember this: you'll usually be working with two different pages — the one that contains the form (form.php in our example), and the one that handles the data (destination.php).

Form Elements

As you may already know, forms can contain all kinds of elements: text fields, buttons, checkboxes, and more.

I'll go through each one and show you how to use them — and especially how to handle them in destination.php. You'll see, it's super easy: instead of receiving a $_GET array, you'll now be working with a $_POST array containing the form data!

Text Fields

Text fields are the most common form element. You use them to ask for a name, username, or anything else that doesn't require fancy formatting.

Here's how you insert one in HTML:

<input type="text" />

For passwords, just use type="password" — it hides the input. Other than that, it works exactly the same way.

There are two important attributes you can (or must) use:

  • name (required): This is the name of the field. Choose wisely, because it will determine the variable name in PHP. Example: <input type="text" name="username" />
  • value (optional): This sets the initial value of the field. By default, the field is empty, but it can be handy to pre-fill it. Example: <input type="text" name="username" value="SiteRawFan" />

I know, you're starting to worry — "Where's the PHP?" Don't panic. It's simple and familiar. Whatever the user types will be available in destination.php through a variable like $_POST['username'].

Let's do a quick demo: we'll make a form that asks for the visitor's first name and displays it proudly on the next page. So we'll have two separate files: the form page and the target page.

Here's the code for form.php:

<p>
    This page is pure HTML.<br />
    Please enter your first name:
</p>

<form action="destination.php" method="post"> <p> <input type="text" name="firstname" /> <input type="submit" value="Submit" /> </p> </form>

Just a reminder: the <input type="submit" /> creates the submit button that triggers the data to be sent — and thus the redirection to the target page.

Now let's build destination.php, which will retrieve the first name using the $_POST['firstname'] variable.

Here's the code for destination.php:

<p>Hello!</p>

<p>I know your name — mwahaha. You're called <?php echo $_POST['firstname']; ?>!</p>

<p>If you want to change your name, <a href="form.php">click here</a> to go back to the form.</p>

Textareas

Textareas (a.k.a. "multiline input fields") are like regular text fields... just bigger.

They're great for letting users write long messages.

Here's how you insert one in HTML:

<textarea name="message" rows="8" cols="45">
Your message here.
</textarea>

Once again, the name attribute defines the variable name on the next page — so here, you'll get $_POST['message'] in destination.php.

Notice there's no value attribute. The default text goes between the opening and closing <textarea> tags. If you want the field to start blank, just leave that part empty.

The rows and cols attributes control the height and width of the textarea, although you can use CSS too.

Drop-Down Lists

A dropdown list is just that — a menu where the user picks one of several options.

Here's how to make one:

<select name="choice">
    <option value="choice1">Choice 1</option>
    <option value="choice2">Choice 2</option>
    <option value="choice3">Choice 3</option>
    <option value="choice4">Choice 4</option>
</select>

We use the <select> tag, give it a name (like "choice"), add a bunch of <option> tags, and close it all with </select>.

The variable $_POST['choice'] will contain the selected option's value. If the user picked "Choice 3", the value will be "choice3".

To set a default selection, add selected="selected" to the corresponding option:

<option value="choice3" selected="selected">Choice 3</option>

Checkboxes

A checkbox is, well... a box you can check. Nothing too surprising there. 😄

Here's the HTML code:

<label for="box"><input type="checkbox" name="box" id="box" /> Check me</label>

Using <label> is optional but highly recommended. It links the label to the checkbox via the for and id attributes, letting users click the label to check the box — better usability all around! For more info, see the form chapter in the HTML/CSS course.

The name attribute defines the variable's name (e.g., $_POST['box']).

  • If the box is checked, $_POST['box'] will equal "on".
  • If it's unchecked, $_POST['box'] won't exist at all. You can use isset($_POST['box']) to test if it was checked.

Want it checked by default? Just add checked="checked":

<input type="checkbox" name="box" checked="checked" />

Radio Buttons

Radio buttons come in groups of at least two. They're like checkboxes, except users can only choose one option.

Here's an example:

Do you like potato fries?

<input type="radio" name="fries" value="yes" id="yes" checked="checked" /> <label for="yes">Yes</label> <input type="radio" name="fries" value="no" id="no" /> <label for="no">No</label>

As you can see, both radio buttons share the same name ("fries"). That's crucial: all radio buttons in the same group must have the same name, so the browser knows only one can be selected at a time. It would be silly to be able to pick both "Yes" and "No"! 😄

To pre-select one, just add checked="checked". Here, "Yes" is selected by default.

On the next page, you'll get a variable $_POST['fries'] containing the selected value. If the user picked "Yes," it will be "yes".

Always remember to set the value attribute — it determines the variable's value.

Hidden Fields

Hidden fields are a special kind of input. What do they do? Well, they don't show up on the screen, but they still send a variable with a value. You can use them to pass along fixed information.

Example: say you want to "remember" that the user's username is "SiteRawFan". You'd write:

<input type="hidden" name="username" value="SiteRawFan" />

On the webpage, the visitor sees nothing. But in destination.php, you'll get $_POST['username'] with the value "SiteRawFan"!

Sounds useless? Not at all — you'll see it's quite handy in some cases.

⚠️ Warning: Just because the field is hidden doesn't mean users can't see it. They can view the page's source and spot it in the HTML. Worse, with the right tools, they can change its value. So what's the takeaway? Never trust hidden fields blindly. As I said in the last chapter, that rule still holds strong!

Never Trust User Input

Remember the warnings I gave you in the previous chapter about data passed from one page to another? They didn't just apply to URL parameters — the same goes for form data!

But... I get how someone can tamper with a URL, sure. What I don't get is how a visitor could possibly modify the form on my site and mess with the data? :o

We often think visitors can't "fiddle" with forms — but that's just not true. First, I'll show you why forms aren't any safer than URLs, and then we'll dive into another big threat: the dreaded XSS vulnerability. After that, you'll be all set to browse in peace! :)

Why Forms Aren't Safe

Everything we covered in the last chapter about URLs still applies here. Anything coming from the user — that is, data in the $_GET or $_POST arrays — should be treated with extreme caution.

You cannot assume you'll receive the data you were expecting.

That rule is simple enough, but let me give you a real-life example to help drive it home. Say you ask your users to enter their birthdate in a field, "in MM/DD/YYYY format." How many will actually follow that format? How many will make a mistake? I guarantee that among your users — while you're expecting something like "05/23/2007" — someone will inevitably type "I was born on May 23rd, 2007." Sounds extreme, sure, but it will happen. So, when processing the date in PHP, you'll absolutely need to check if it matches the format you asked for.

To check whether a string matches a certain format like MM/DD/YYYY, you can use a regular expression. We'll dedicate two full chapters to regex later on in this course since it's a fairly advanced topic.

Just like with URL parameters, if you ask for a number between 1 and 100, someone will inevitably type in "58451254529." So always be on guard and never trust anything that comes from the user, meaning anything from $_GET or $_POST.

And here's another thing: with forms, you can't even assume that you'll receive all the fields you're expecting. A visitor could very well decide to remove a text field entirely — and in that case, your destination.php page will never receive the value it was supposed to! So you must check that all the required data is present before doing anything with it.

But the Form Page Is On My Website — How Could a Visitor Modify It?

Sure, your visitors can't change the web pages stored on your server... but nothing's stopping them from copying and tweaking those pages elsewhere. Let's go back to this setup:

form.php → destination.php

The form.php page holds your form, and destination.php processes the submitted data. While visitors can't see your PHP code, the HTML of the form is completely visible to everyone.

So what's stopping someone from grabbing your form's HTML, tweaking it slightly, and hosting it somewhere else?

https://www.siteraw.com/malicious_form.php → (your server's) destination.php

In the example above, the "bad guy" (let's just call him that) copied your form's HTML, modified it, and uploaded it to his server (or even just saved it locally). He changed the action attribute to the full URL of your destination page:

<form method="post" action="https://www.yoursite.com/destination.php">

Now, the bad guy can do whatever he wants: modify your form, add or remove fields, you name it! Your destination.php page will be none the wiser, because there's no way to reliably tell where the form submission came from (there is the HTTP referer header, but it can be spoofed).

This explanation is a bit technical — usually reserved for more advanced users — but I wanted you to see how it's possible. Even if it's not crystal clear right now, you've at least got the general idea.

The takeaway here is this: anyone can modify your forms, despite what you may think. So your destination.php page must be just as cautious as we were in the last chapter. Remember the programmer's mantra: Never trust user input. ;)

There's an Even Easier Way to Modify Your Form...

You don't even need server access to mess with a site's form. Web browsers are just tools that send and receive HTTP(s) requests to servers. And once you understand that, it's easy for someone to mimic a browser's behavior — that's the whole idea behind bots.

Also, many browsers like Edge, Brave, and Safari come with "developer tools." With just a right-click on any page element, a user can modify it on the fly... no need to copy your form or host it elsewhere. They can just tweak it (locally, of course) right in their browser. Sure, they're the only one who sees the changes, but they can still alter the form's behavior, change a hidden input, and so on.

XSS Vulnerability: Watch Out for Malicious HTML!

One last danger to cover — and then I promise I'll stop scaring you! :)

XSS (short for cross-site scripting) has been around forever (well, since the early days of the Web :-° ) and is still found on lots of websites — even professional ones! The idea is to inject HTML code with JavaScript into your page, which then runs in the browser of whoever visits it.

Let's go back to that page that displays the user's first name. It might contain code like this:

<p>I know your name, hehe. Your name is <?php echo $_POST['firstName']; ?>!</p>

Now, if the visitor types HTML instead of their name, it'll still work! For example, they could enter <strong>BigBossMan</strong> into the "First Name" field. The HTML output from PHP would look like this:

<p>I know your name, hehe. Your name is <strong>BigBossMan</strong>!</p>

So what? If they want their name in bold, that's their business, right?

Well, not quite. Beyond breaking your page's HTML (which isn't even the worst part), they could insert a <script> tag to run JavaScript in the browser of anyone viewing the page!

<p>I know your name, hehe. Your name is <script>alert('BigBossMan');</script>!</p>

Everyone who visits that page would see a JavaScript pop-up. Annoying, to say the least.

Now imagine a visitor who's clever enough to use this trick to steal your cookies. Cookies often store session data — sometimes even sensitive stuff like usernames or passwords! With JavaScript, a bad actor could force a visitor's browser to send their cookies to the attacker. This could lead to account theft. I won't go into the technical details here, but know that it's possible — and you must prevent visitors from injecting JavaScript into your pages!

Preventing XSS by Escaping HTML

Fortunately, the fix is simple: escape any HTML code, so it displays as text instead of being executed by the browser.

To escape HTML, use the htmlspecialchars function. It converts HTML brackets < and > into &lt; and &gt;, which makes the browser display them instead of running them.

<p>I know your name, hehe. Your name is <?php echo htmlspecialchars($_POST['firstName']); ?>!</p>

This will generate clean, safe HTML like:

<p>I know your name, hehe. Your name is &lt;strong&gt;BigBossMan&lt;/strong&gt;!</p>

Be sure to use this function on any user-generated content that might get displayed on your site. On a forum, for example, you'll need to escape member posts, usernames (yes, someone could stick HTML in there), and even signatures! Basically, anything displayed that originally came from a visitor should be passed through htmlspecialchars.

If you'd rather just remove the visitor's HTML entirely instead of escaping it, you can use the strip_tags function.

Uploading Files

Did you know forms can also be used to upload files? You'll want to read this section if you'd like your visitors to be able to upload images, programs, or any other kind of file to your site.

This part is a little trickier than the rest of the chapter. That said, it's not essential for understanding the rest of the course.

So don't hesitate to come back and read it later, when you actually need it, if you don't feel like diving into something slightly "tougher" just yet.

Once again, we're looking at a two-step process:

  • The visitor arrives on your form and fills it out (choosing a file to upload). A simple HTML page is enough for this.
  • PHP receives the form data and, if a file was uploaded, it "saves" the file in one of the server's folders.

Heads up: uploading can take a while if the file is large. You should let users know not to get impatient while the upload is in progress.

Let's start by creating the form that allows file uploads (just a regular HTML page). We'll then see how to handle the upload on the server using PHP.

The File Upload Form

As soon as your form allows users to upload a file, you need to add the attribute enctype="multipart/form-data" to the <form> tag.

<form action="upload_target.php" method="post" enctype="multipart/form-data">
    <p>File upload form</p>
</form>

Thanks to enctype, the visitor's browser knows it's about to send files.

Now that this is in place, we can add the input field for uploading. It's a basic tag: <input type="file" />. As always, make sure to give the input a name (via the name attribute) so that PHP can recognize it.

<form action="upload_target.php" method="post" enctype="multipart/form-data">
    <p>
        File upload form:<br />
        <input type="file" name="myfile" /><br />
        <input type="submit" value="Upload the file" />
    </p>
</form>

And that's all there is to it! :)

You can of course add other regular form fields (text input, checkboxes, etc.). You can even allow multiple file uploads at once.

For now, we'll keep it simple with just one file field.

Handling the Upload with PHP

As you probably noticed, the form points to a PHP page called upload_target.php. That means the visitor will be redirected there after submitting the form.

Now comes the important part. We need to write the code for upload_target.php to handle the uploaded file.

But wait — if the file's already been uploaded to the server, aren't we done? What does PHP have to do?

When the PHP page runs, the file has indeed been uploaded, but only to a temporary folder. It's up to you to decide whether to accept the file permanently. For example, you might want to check if the file has the right extension — if you asked for an image and got a .txt file, you'll probably want to reject it.

If the file looks good, you can accept it permanently using the move_uploaded_file function.

But how do I know if "the file looks good"?

For each uploaded file, PHP creates a variable $_FILES['field_name']. In our case, that's $_FILES['myfile'].

This is an array containing several pieces of info about the file:

VariableMeaning
$_FILES['myfile']['name']The original name of the uploaded file.
$_FILES['myfile']['type']The file type. For example, an image might be image/gif.
$_FILES['myfile']['size']File size in bytes (1,000 bytes ≈ 1 KB, 1,000,000 bytes ≈ 1 MB).
$_FILES['myfile']['tmp_name']The temporary location where PHP stored the file.
$_FILES['myfile']['error']Error code (0 means no error occurred).

⚠️ Be aware that PHP limits file upload sizes. By default, uploads over 8 MB won't work.

If you added a second file field, you'd get another array like $_FILES['your_other_field'], structured the same way.

Now let's define the checks we'll use to decide whether to accept the uploaded file:

  • Check if a file was actually uploaded (isset($_FILES['myfile'])) and that no upload error occurred.
  • Check that the file doesn't exceed 1 MB (around 1,000,000 bytes) using $_FILES['myfile']['size'].
  • Check that the file extension is allowed (definitely block PHP files to avoid potential server exploits!). For our purposes, we'll allow only image files: .png, .jpg, .jpeg, and .gif.

We'll do all this in upload_target.php.

1. Check if a file was uploaded

We start by checking if $_FILES['myfile'] exists and that the error value is 0 (no error).

<?php
// Check if file was uploaded and there's no error
if (isset($_FILES['myfile']) && $_FILES['myfile']['error'] == 0)
{

} ?>

2. Check the file size

We want to block files over 1 MB. So we check the size property:

<?php
// Check if file was uploaded and there's no error
if (isset($_FILES['myfile']) && $_FILES['myfile']['error'] == 0)
{
    // Check if file size is within the limit
    if ($_FILES['myfile']['size'] <= 1000000)
    {

} } ?>

3. Check the file extension

<?php
$fileInfo = pathinfo($_FILES['myfile']['name']);
$uploadExtension = $fileInfo['extension'];
?>

The pathinfo function gives us an array that includes the file extension, which we store in $uploadExtension.

Then we check if this extension is in our list of allowed types using in_array().

Final result:

<?php
if (isset($_FILES['myfile']) && $_FILES['myfile']['error'] == 0)
{
    if ($_FILES['myfile']['size'] <= 1000000)
    {
        $fileInfo = pathinfo($_FILES['myfile']['name']);
        $uploadExtension = $fileInfo['extension'];
        $allowedExtensions = array('jpg', 'jpeg', 'gif', 'png');
        if (in_array($uploadExtension, $allowedExtensions))
        {

} } } ?>

4. Finalize the upload

If everything checks out, we accept the file with move_uploaded_file().

This function takes two arguments:

  • The temporary filename: $_FILES['myfile']['tmp_name'].
  • The final destination path (you can keep the original name or generate a custom one).

We'll save the file into an uploads subdirectory using the original filename. Since $_FILES['myfile']['name'] might contain the full path (e.g., C:\folder\image.png), we'll use basename() to extract just the file name (image.png).

<?php
if (isset($_FILES['myfile']) && $_FILES['myfile']['error'] == 0)
{
    if ($_FILES['myfile']['size'] <= 1000000)
    {
        $fileInfo = pathinfo($_FILES['myfile']['name']);
        $uploadExtension = $fileInfo['extension'];
        $allowedExtensions = array('jpg', 'jpeg', 'gif', 'png');
        if (in_array($uploadExtension, $allowedExtensions))
        {
            // Validate and permanently store the file
            move_uploaded_file($_FILES['myfile']['tmp_name'], 'uploads/' . basename($_FILES['myfile']['name']));
            echo "Upload completed successfully!";
        }
    }
}
?>

When uploading your script to the server via FTP, make sure the uploads folder exists and is writable. In your FTP client, right-click the folder and choose "File permissions" to edit them (this is called CHMOD). Set the permissions to 733 so PHP can save files there.

This script is a good start, but in practice, you'll likely need to improve it further. For instance, if the filename contains spaces or accented characters, it might cause problems once online. Also, if someone uploads a file with the same name as another user's, the older file will be overwritten!

The solution? Generate your own filenames — maybe something like a counter: 1.png, 2.png, 3.jpg, etc.

Always stay security-conscious. Never allow someone to upload PHP files — they could run malicious code on your server.

And that's a wrap on this chapter about PHP forms!

Now you know how things like forums, chat systems, and login pages are built. The real-world examples might be more complex than our simplified ones, but with what you've learned, you'll be just fine!

How to Build a Website in HTML and CSS

Enjoyed this PHP & MySQL course?

If you liked this lesson, you can find the book "How to Build a Website in HTML and CSS" from the same authors, available on SiteRaw, in bookstores and in online libraries in either digital or paperback format. You will find a complete PHP & MySQL workshop with many exclusive bonus chapters.

More information