Thursday 21 November 2019

Web Tutorial: The Contact Us Page (Part 4/4)

For this, you could take the easy way out and simply insert an image, but that's no fun and oh, so retro. However, the considerably more modern method requires us to use Google Maps. And for greater effect, you'll need a Google Account. No sweat if you don't, you just won't be able to use certain features!

Let's say, for example, I want the map to showcase a location on Cecil Street, which was the address I specified in the Card.

Go to Google Maps, and search for the place.


Click on it, and you'll see a descriptive bar on the left side of your screen.


Click on Share or Embed Map. This should bring up a popup on-screen.


Click on Embed a Map. Here, there's a HTML snippet you can copy. This snippet will change according to the size you select, but don't bother with that right now. Just copy the HTML snippet.


The code should be pasted into the div that is being styled by mapContainer.
<div class="mapContainer">
    <iframe src="https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d1994.410947080802!2d103.8475582!3d1.2805386!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x31da190d9688e047%3A0x51dfe23cf3f6846d!2sCecil%20Court!5e0!3m2!1sen!2ssg!4v1568307144640!5m2!1sen!2ssg" width="600" height="450" frameborder="0" style="border:0;" allowfullscreen=""></iframe>
</div>


Remove the width and height specification totally.
<div class="mapContainer">
    <iframe src="https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d1994.410947080802!2d103.8475582!3d1.2805386!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x31da190d9688e047%3A0x51dfe23cf3f6846d!2sCecil%20Court!5e0!3m2!1sen!2ssg!4v1568307144640!5m2!1sen!2ssg" frameborder="0" style="border:0;" allowfullscreen=""></iframe>
</div>


And then style iframes within mapContainer, setting width and height to 100%. This ensures that if you ever need to adjust the size of your content, you won't need to do it again for the map!
.mapContainer
{
    width: 100%;
    height: 300px;
    float: left;
    margin-top: 1em;
}

.mapContainer iframe
{
    width: 100%;
    height: 100%;
}


And there you have a Map!

But this just isn't cool enough...

What if you could customize the map? Yeah well, you'll need a Google Account for that, so if you don't have one and can't be arsed to create one, we can stop here. If not, read on!

Click on Your Places. You'll be asked to sign in if you haven't already.


Then click on the Maps tab.


View all your maps...


Here, you'll see your saved Maps. There should be none. Create one.


Here, click on the box on the left.


It's time to name your Map by entering a title and description. Click Save.


Navigate to the area where your desired location is, and click on this icon to add a marker.


Add a title and description for the marker. Click Save.


Here's your marker! You can click on this icon to add a picture.


You can add any picture you want. I simply added a logo in this case.


Click on this link to share the map. This is important; if you skip this step, you won't be able to embed the map.


Click on the "change" link.


Set it to "public", then Save.


Access the menu and select "embed on my site".


Copy the provided HTML.


Paste into the div.
<div class="mapContainer">
    <iframe src="https://www.google.com/maps/d/embed?mid=1tY75QTSZ5HF9XzEWNN6-UbeAVgDLlMmY" width="640" height="480"></iframe>
</div>


Again, you should remove the width and height specification.
<div class="mapContainer">
    <iframe src="https://www.google.com/maps/d/embed?mid=1tY75QTSZ5HF9XzEWNN6-UbeAVgDLlMmY"></iframe>
</div>


And now you have a map! A customized map, even! Try clicking on it, and you will see the details we entered earlier, pop up.


There's more, of course...

...but I'm not going to go in depth regarding Google's full suite of map features. You should feel free to explore on your own after the head start I've given you. There's a lot of cool stuff in there.

For your information,
T___T

Monday 18 November 2019

Web Tutorial: The Contact Us Page (Part 3/4)

This is where we will be making things look good. Or, well, less ugly.

Colors and layout are a huge part of UX, and while we won't be performing any astounding feats of wizardry today, we will at least be cleaning stuff up. It helps that the markup is already done, and all we really need to do is supply the CSS.

So let's begin by giving all divs a red outline for better clarity, and putting in some margin and padding resets for the html and body tags. Here, let's specify a black background and font properties.
<style>
    html, body
    {
        padding: 0;
        margin: 0;
        font-size: 14px;
        font-family: arial;
        background-color: #000000;
        height: 100%;
    }

    div
    {
        outline: 1px solid #FF0000;
    }

    .hide
    {
        display: none;
    }
</style>


Seeing a change already.


Next, we style contentContainer. This places all content in the middle of the screen via the margin property. Width is set to 800 pixels which will be wide enough for most screens, and height at 100%. The background has been set to white.
div
{
    outline: 1px solid #FF0000;
}

.contentContainer
{
    width: 800px;
    height: 100%;
    margin: 0 auto 0 auto;
    background-color: #FFFFFF;
}

.hide
{
    display: none;
}


Yes, that's it...


contactContainer is styled next. It's the style for the div that goes inside contentContainer. Width is 90%, with some padding at the top, and the margin property sets it to the middle of its parent.
.contentContainer
{
    width: 800px;
    height: 100%;
    margin: 0 auto 0 auto;
    background-color: #FFFFFF;
}

.contactContainer
{
    width: 90%;
    padding-top: 10px;
    margin: 0 auto 0 auto;
}

.hide
{
    display: none;
}


See it taking shape!


The next thing we style is innerContainer, which comes after messageContainer (which we won't style yet) within contactContainer. The width is 100%, but that's about it. There will be no visible changes in your display, so don't bother refreshing. It's just a layout div to hold everything together.
.contactContainer
{
    width: 90%;
    padding-top: 10px;
    margin: 0 auto 0 auto;
}

.innerContainer
{
    width: 100%;
}

.hide
{
    display: none;
}


Now for something more visually substantial. The Form, the Card and the Map are three visual components of the Contact Us page. The Map will take up the bottom of the page, while the Form and the Card will fill the top of the page.

For formContainer, we're going with 50% of its parent's width, a bit of padding, and rounded corners. Background color and border have been set to a light grey. Then we set the float property to left.
.hide
{
    display: none;
}

.formContainer
{
    width: 50%;
    float: left;
    padding: 0.5em;
    background-color: #DDDDDD;
    border: 1px solid #DDDDDD;
    border-radius: 10px;
}


Isn't that nice?


cardContainer takes up 40% width. We'll float it right, give it rounded corners and padding, and a light grey border.
.formContainer
{
    width: 50%;
    float: left;
    padding: 0.5em;
    background-color: #DDDDDD;
    border: 1px solid #DDDDDD;
    border-radius: 10px;
}

.cardContainer
{
    width: 40%;
    float: right;
    padding: 0.5em;
    border: 1px solid #DDDDDD;
    border-radius: 10px;
}


You'll see it's looking a little flat at the moment. That's because that div is empty with no defined height.



mapContainer will take up full width, and we'll define the height as well. A top margin gives it some space between the first two divs.
.formContainer
{
    width: 50%;
    float: left;
    padding: 0.5em;
    background-color: #DDDDDD;
    border: 1px solid #DDDDDD;
    border-radius: 10px;
}

.cardContainer
{
    width: 40%;
    float: right;
    padding: 0.5em;
    border: 1px solid #DDDDDD;
    border-radius: 10px;
}

.mapContainer
{
    width: 100%;
    height: 300px;
    float: left;
    margin-top: 1em;
}


This should give you a better idea about the general layout.


The Form

Let's work on the form some more. Here's some styling for the labels.
.formContainer
{
    width: 50%;
    float: left;
    padding: 0.5em;
    background-color: #DDDDDD;
    border: 1px solid #DDDDDD;
    border-radius: 10px;
}

label
{
    font-weight: bold;
    font-size: 0.75em;
    color: #444444;
}

.cardContainer
{
    width: 40%;
    float: right;
    padding: 0.5em;
    border: 1px solid #DDDDDD;
    border-radius: 10px;
}


You won't see much change yet, but trust me that it will look amazing once we're finished.


Now we style all input textboxes with a width, height, wounded corners and a bit of padding. Set the border to zero thickness!
label
{
    font-weight: bold;
    font-size: 0.75em;
    color: #444444;
}

input[type = text]
{
    width: 25em;
    height: 1.5em;
    padding: 0.25em;
    border-radius: 5px;
    border: 0px solid #000000;
}

.cardContainer
{
    width: 40%;
    float: right;
    padding: 0.5em;
    border: 1px solid #DDDDDD;
    border-radius: 10px;
}


Sweet!


This is the styling for the button, and it's really up to taste. I recommend that you float it right, and maybe add a hover pseudoselector so it changes color upon a mouseover.
input[type = text]
{
    width: 25em;
    height: 1.5em;
    padding: 0.25em;
    border-radius: 5px;
    border: 0px solid #000000;
}

input[type = submit]
{
    display: inline-block;
    float: right;
    width: 5em;
    height: 2em;
    border-radius: 5px;
    border: 0px solid #000000;
    background-color: #999999;
    font-weight: bold;
    cursor: pointer;
}

input[type = submit]:hover
{
    background-color: #FFFFFF;
    cursor: pointer;
}

.cardContainer
{
    width: 40%;
    float: right;
    padding: 0.5em;
    border: 1px solid #DDDDDD;
    border-radius: 10px;
}


So now you have a pretty button!


The styling for the textarea tag is pretty much the same as for the input textboxes, except that this element doesn't inherit font settings from the body and you have to explicitly specify them.
input[type = submit]:hover
{
    background-color: #FFFFFF;
    cursor: pointer;
}

textarea
{
    width: 25em;
    padding: 0.25em;
    border-radius: 5px;
    border: 0px solid #000000;
    font-family: arial;
}

.cardContainer
{
    width: 40%;
    float: right;
    padding: 0.5em;
    border: 1px solid #DDDDDD;
    border-radius: 10px;
}


Great!


Let's style formrow so that there'll be a decent amount of padding. Specifying the font size here will also change the labels.
textarea
{
    width: 25em;
    padding: 0.25em;
    border-radius: 5px;
    border: 0px solid #000000;
    font-family: arial;
}

.formrow
{
    margin-top: 1em;
    font-size: 1.5em;
}

.cardContainer
{
    width: 40%;
    float: right;
    padding: 0.5em;
    border: 1px solid #DDDDDD;
    border-radius: 10px;
}

There you go.


Let's not forget the error messages. Let's make them red to really hammer home the point. The font size should be a teeny bit smaller, and in bold. Any span tags within that CSS class should have height specified, and maybe some padding. In order to specify height for an inline element like span, though, you'll need to set the display property to inline-block.
.formrow
{
    margin-top: 1em;
    font-size: 1.5em;
}

.error
{
    color: #FF0000;
    font-size: 0.8em;
    font-weight: bold;
}

.error span
{
    display: inline-block;
    height: 1.5em;
    padding-top: 0.25em;
}

.cardContainer
{
    width: 40%;
    float: right;
    padding: 0.5em;
    border: 1px solid #DDDDDD;
    border-radius: 10px;
}


This should be what you see if you click the Send button without filling in anything!


The Card

The purpose of the Card is to show contact details. And that's what we'll do. In this div, add three divs and style each one using the CSS class cardrow.
<div class="cardContainer">
    <div class="cardrow">
       
    </div>

    <div class="cardrow">

    </div>

    <div class="cardrow">

    </div>
</div>


Then fill in some details.
<div class="cardContainer">
    <div class="cardrow">
        +65 1234567
    </div>

    <div class="cardrow">
        mail@teochewthunder.com
    </div>

    <div class="cardrow">
        140 Cecil Street<br />
        12-34a<br />
        Singapore 069543
    </div>
</div>


Kind of cramped and plain, isn't it?


As with the formrow CSS class, styling cardrow this way affects font size and row spacing.
.cardContainer
{
    width: 40%;
    float: right;
    padding: 0.5em;
    border: 1px solid #DDDDDD;
    border-radius: 10px;
}

.cardrow
{
    margin-bottom: 1em;
    font-size: 1.2em;
}

.mapContainer
{
    width: 100%;
    height: 300px;
    float: left;
    margin-top: 1em;
}


Much better! But let's improve things further. Add more styles to each div that you've styled using the CSS class cardrow.


<div class="cardContainer">
    <div class="cardrow icon_phone">
        +65 1234567
    </div>

    <div class="cardrow icon_email">
        mail@teochewthunder.com
    </div>

    <div class="cardrow icon_address">
        123 South Dakota Avenue<br />
        12-34a<br />
        Singapore 112113
    </div>
</div>


And then let's write the classes icon_phone, icon_email and icon_address. Each of these uses the after pseudoselector. Set the display property to block, with width to 2em. Height is variable - for the phone number and email, they take up only one line, so the height should be 1em. But for the address, it should be 3em. All this is floated left because they will be to the left of the content., and the text is aligned center. For the content property, we'll use HTML symbols.
.cardrow
{
    margin-bottom: 1em;
    font-size: 1.2em;
}   

.icon_phone:before
{
    display: block;
    content: "\260F";
    width: 2em;
    height: 1em;
    float: left;
    text-align: center;
}

.icon_email:before
{
    display: block;
    content: "\2709";
    width: 2em;
    height: 1em;
    float: left;
    text-align: center;
}

.icon_address:before
{
    display: block;
    content: "\2616";
    width: 2em;
    height: 3em;
    float: left;
    text-align: center;
}

.mapContainer
{
    width: 100%;
    height: 300px;
    float: left;
    margin-top: 1em;
}


Beautiful!


Just one final touch! The card is significantly shorter than the form. While it would take effort to make them exactly equal in height, all we're really trying to do is achieve a little visual balance. So let's add a logo. I'm gonna go with my personal logo for this.


Use the after pseudoselector, float it right with a width and height of 3em, then set the background size to contain. The margin-top property has been set to a negative value so that it will overlap the last row just a bit!
.cardContainer
{
    width: 40%;
    float: right;
    padding: 0.5em;
    border: 1px solid #DDDDDD;
    border-radius: 10px;
}

.cardContainer:after
{
    content: "";
    display: block;
    width: 3em;
    height: 3em;
    float: right;
    margin-top: -2em;
    background: url(logo.png) right top no-repeat;
    background-size: contain;
}

.cardrow
{
    margin-bottom: 1em;
    font-size: 1.2em;
}


We're done for the Card!


Styling the message

There's one more thing - the message at the top of the page. It's currently in black and white, and while there's nothing wrong with that, it helps to use color for context.

First, we set sizes, padding, round corners, all the purely aesthetic stuff. We'll use the before pseudoselector to add a 2em space at the start of the block.
.contactContainer
{
    width: 90%;
    padding-top: 10px;
    margin: 0 auto 0 auto;
}

.messageContainer
{
    width: 100%;
    height: 2.5em;
    padding-top: 1em;
    font-weight: bold;
    margin-bottom: 0.5em;
    border-radius: 10px;
    color: #FFFFFF;
}

.messageContainer:before
{
    content: "";
    display: block;
    width: 2em;
    height: 2em;
    float: left;
    font-size: 2em;
    margin-top: -0.5em;
    text-align: center;
}

.innerContainer
{
    width: 100%;
}


Then in the PHP, after declaring the variable message, declare the variable messageclass and set it to "message_error".
<?php
session_start();

$message = "";
$messageclass = "message_error";

$errors = array();


At these points, set messageclass. On any successful case, messageclass should be set to message_success. And message_error on any unsuccessful case.
        if (!$mailsent)
        {
            $form_email = "";
            $form_name = "";
            $form_comments = "";

            $message = "Email sent. Thank you!";
            $messageclass = "message_success";
        }
        else
        {
            $message = "An error occured while trying to send your mail. Please try again.";
            $messageclass = "message_error";
        }
    }       
}
else
{
    $message = "CSRF attack foiled!";
    $messageclass = "message_error";
}


In the HTML, set the div to be styled using not only messageContainer, but also hide if there is no message, and either message_error or message_success if there is a message.
<div class="messageContainer <?php echo ($message == "" ? "hide" : $messageclass); ?>">
    <?php echo $message; ?>
</div>


Back to the CSS, we will write styles for message_error and message_success. The background color for message_error is a light red, and light blue for message_success. And we will use the before pseudoselector to set the content property in both cases - a tick for message_success and a cross for message_error.
.messageContainer
{
    width: 100%;
    height: 2.5em;
    padding-top: 1em;
    font-weight: bold;
    margin-bottom: 0.5em;
    border-radius: 10px;
    color: #FFFFFF;
}

.messageContainer:before
{
    content: "";
    display: block;
    width: 2em;
    height: 2em;
    float: left;
    font-size: 2em;
    margin-top: -0.5em;
    text-align: center;
}

.message_error
{
    background-color: #FF9999;
}

.message_success
{
    background-color: #9999FF;
}

.message_error:before
{
    content: "\02718";
}

.message_success:before
{
    content: "\02714";
}

.innerContainer
{
    width: 100%;
}


Now let's see what happens when we submit successfully.


An unsuccessful case!


And finally, remove the red outlines.
div
{
    outline: 0px solid #FF0000;
}


Yep, that's how it should look.


Next

Stay tuned for the final piece of the puzzle. I'm gonna show you how to insert a map widget into your page.

Thursday 14 November 2019

Web Tutorial: The Contact Us Page (Part 2/4)

In the last part, the form working as intended hinges upon users entering valid data. What if they didn't enter valid data? What if they missed stuff out? Worse, what if they entered stuff that breaks your HTML?

In this part, we implement controls to prevent that from happening. At the very basic level, we have server-side validation. For this, whatever data the user sends to the PHP server will be validated, and error messages will be displayed if data is not valid.

First, we put in placeholders for error messages. For Name, the only thing we need to worry about is missing data. So let's have a div, styled using the error CSS class. And within it, have a span tag with the error message within.
<div class="formrow">
    <label for="txtName">Name</label><br />
    <input type="text" id="txtName" name="txtName" maxlength="50" placeholder="e.g, Jose D'Cruz" />
</div>
<div class="error" id="name_required">
    <span>Name is required.</span>
</div>


For Email, you have two things to worry about - missing data and invalid data. You generally want there to be an email, and you want the email to be an actual email. So let's have two divs and two error messages.
<div class="formrow">
    <label for="txtEmail">Email</label><br />
    <input type="text" id="txtEmail" name="txtEmail" maxlength="50" placeholder="e.g, j_dcruz208@youremail.com" />
</div>
<div class="error" id="email_required">
    <span>Email is required.</span>
</div>
<div class="error" id="email_format_incorrect">
    <span>Email is in an incorrect format.</span>
</div>


And let's have one for Comments.
<div class="formrow">
    <label for="txtComments">Comments</label><br />
    <textarea type="text" id="txtComments" name="txtComments" rows="5" maxlength="500" wrap="hard" placeholder="e.g, You're awesome!"></textarea>
</div>
<div class="error" id="comments_required">
    <span>Comments are required.</span>
</div>


See your results!


In the PHP code, create the associative array, errors. Then fill in the array with key-value pairs as shown, setting all values to false.
$message = "";

$errors = array();
$errors["name_required"] = false;
$errors["email_required"] = false;
$errors["comments_required"] = false;
$errors["email_format_incorrect"] = false;

$mailsent = false;


Under the part where the form values are obtained, run a str_replace() function on each one, removing all spaces. If the result is an empty string, then the user tried to be funny somewhere. Either way, the string is blank and thus invalid.
$form_name = trim($_POST["txtName"]);
$form_email = trim($_POST["txtEmail"]);
$form_comments = trim($_POST["txtComments"]);

if (str_replace(" ", "", $form_name) == "")
{

}

if (str_replace(" ", "", $form_email) == "")
{

}

if (str_replace(" ", "", $form_comments) == "")
{

}   


Set the respective values of the key-value pairs in errors, to true.
$form_name = trim($_POST["txtName"]);
$form_email = trim($_POST["txtEmail"]);
$form_comments = trim($_POST["txtComments"]);

if (str_replace(" ", "", $form_name) == "")
{
    $errors["name_required"] = true;
}

if (str_replace(" ", "", $form_email) == "")
{
    $errors["email_required"] = true;
}

if (str_replace(" ", "", $form_comments) == "")
{
    $errors["comments_required"] = true;
}   


For Email, include an Else block. We only want to check for a valid email if there is an email. Run the string through the validateEmail() function, then set the key-value pair in errors if the function returns false.
if (str_replace(" ", "", $form_email) == "")
{
    $errors["email_required"] = true;
}
else
{
    if (!validateEmail($form_email))
    {
        $errors["email_format_incorrect"] = true;
    }           
}


And there we have the validateEmail() function. The parameter in this function is a string, str. It returns true by default.
    else
    {
        $message = "CSRF attack foiled!";
        $messageclass = "message_error";
    }
}

function validateEmail($str)
{
    return true;
}


Generally, there is no such thing as an email with less than 5 characters, so return false if that is true.
function validateEmail($str)
{
    if (strlen($str) < 5) return false;

    return true;
}


Obviously, if there is no "@" character in the string, it can't be an email.
function validateEmail($str)
{
    if (strlen($str) < 5) return false;
    if (strstr($str, "@") === false) return false;

    return true;
}


If the first or last letter of str is "@", it's also wrong.
function validateEmail($str)
{
    if (strlen($str) < 5) return false;
    if (strstr($str, "@") === false) return false;
    if (strpos($str, "@") == 0 || strpos($str, "@") == strlen($str) - 1) return false;

    return true;
}


Hold up.... why not use Regular Expressions?

Good question. Regular Expressions are really powerful. They're also a pain in the ass when dealing with email strings. These days, there are just too many ways a string can qualify as an actual email address. So stick with the basics.

There are ways to verify an email address by sending and receiving of course... but I really don't want to go there today.

Next, we declare an If block around the emailing portion.
if ()
{
    $headers = "MIME-Version: 1.0\r\n";
    $headers .= "Content-type:text/html;charset=UTF-8\r\n";
    $headers .= "From: " . $form_email . "\r\n";
    $headers .= "X-Mailer: PHP/" . phpversion();

    $subject = "Contact request from " . $form_name;
    $body = nl2br($form_comments);

    $mailsent = mail("teochewthunder@gmail.com", $subject, $body, $headers);

    if (!$mailsent)
    {
        $form_email = "";
        $form_name = "";
        $form_comments = "";

        $message = "Email sent. Thank you!";
        $messageclass = "message_success";
    }
    else
    {
        $message = "An error occured while trying to send your mail. Please try again.";
        $messageclass = "message_error";
    }
}   


This code should only fire off if the size of the array returned by running errors through an array_filter() function, is 0, which means there are no errors. That's because array_filter(), in its simplest form, filters out all values that are false.

More on array_filter() if you're interested!
if (sizeof(array_filter($errors)) == 0)
{
    $headers = "MIME-Version: 1.0\r\n";
    $headers .= "Content-type:text/html;charset=UTF-8\r\n";
    $headers .= "From: " . $form_email . "\r\n";
    $headers .= "X-Mailer: PHP/" . phpversion();

    $subject = "Contact request from " . $form_name;
    $body = nl2br($form_comments);

    $mailsent = mail("teochewthunder@gmail.com", $subject, $body, $headers);

    if (!$mailsent)
    {
        $form_email = "";
        $form_name = "";
        $form_comments = "";

        $message = "Email sent. Thank you!";
        $messageclass = "message_success";
    }
    else
    {
        $message = "An error occured while trying to send your mail. Please try again.";
        $messageclass = "message_error";
    }
}   


Now, we only want error messages to appear when input is invalid (duh), so let's add this to each div that's styled with error. This basically means that if that particular key-value pair in errors is not true, then style that div using hide as well.
<div class="formrow">
    <label for="txtName">Name</label><br />
    <input type="text" id="txtName" name="txtName" maxlength="50" placeholder="e.g, Jose D'Cruz" />
</div>
<div class="error <?php echo $errors["name_required"] ? "" : "hide" ?>" id="name_required">
    <span>Name is required.</span>
</div>

<div class="formrow">
    <label for="txtEmail">Email</label><br />
    <input type="text" id="txtEmail" name="txtEmail" maxlength="50" placeholder="e.g, j_dcruz208@youremail.com" />
</div>
<div class="error <?php echo $errors["email_required"] ? "" : "hide" ?>" id="email_required">
    <span>Email is required.</span>
</div>
<div class="error <?php echo $errors["email_format_incorrect"] ? "" : "hide" ?>" id="email_format_incorrect">
    <span>Email is in an incorrect format.</span>
</div>

<div class="formrow">
    <label for="txtComments">Comments</label><br />
    <textarea type="text" id="txtComments" name="txtComments" rows="5" maxlength="500" wrap="hard" placeholder="e.g, You're awesome!"></textarea>
</div>
<div class="error <?php echo $errors["comments_required"] ? "" : "hide" ?>" id="comments_required">
    <span>Comments are required.</span>
</div>


In the CSS, let's create the CSS class hide. It basically sets the display property to none.
<style>
    .hide
    {
        display: none;
    }
</style>


Refresh and test. Try entering no value, or all spaces for some. Try an obviously invalid email. See what happens?


Yep!


We're missing something...

You'll notice that the inputs in the form go blank when the error messages are displayed. This is not helpful. What if Name and Email were valid but only Comments had an error? Then the user would have to fill all these in again.

So add the appropriate value in these inputs. If the form hasn't been submitted, the variables will be empty strings anyway.
<div class="formrow">
    <label for="txtName">Name</label><br />
    <input type="text" id="txtName" name="txtName" maxlength="50" value="<?php echo $form_name; ?>" placeholder="e.g, Jose D'Cruz" />
</div>
<div class="error <?php echo $errors["name_required"] ? "" : "hide" ?>" id="name_required">
    <span>Name is required.</span>
</div>

<div class="formrow">
    <label for="txtEmail">Email</label><br />
    <input type="text" id="txtEmail" name="txtEmail" maxlength="50" value="<?php echo $form_email; ?>" placeholder="e.g, j_dcruz208@youremail.com" />
</div>
<div class="error <?php echo $errors["email_required"] ? "" : "hide" ?>" id="email_required">
    <span>Email is required.</span>
</div>
<div class="error <?php echo $errors["email_format_incorrect"] ? "" : "hide" ?>" id="email_format_incorrect">
    <span>Email is in an incorrect format.</span>
</div>

<div class="formrow">
    <label for="txtComments">Comments</label><br />
    <textarea type="text" id="txtComments" name="txtComments" rows="5" maxlength="500" wrap="hard" placeholder="e.g, You're awesome!"><?php echo $form_comments; ?></textarea>
</div>
<div class="error <?php echo $errors["comments_required"] ? "" : "hide" ?>" id="comments_required">
    <span>Comments are required.</span>
</div>


There you go!


But wait...

The fact that you're displaying user-input to screen not only puts you at risk of a XSS attack, but also, what if the input broke the HTML?

Try this as a name and submit.


Uh-oh!


What we should do here is sanitize the input. Create a function, sanitize(), in the PHP. Set it to run the argument, str, through the htmlentities() function, and add in other arguments to handle quotes, special characters and other HTML entities. That way, even if the user enters markup, it will not break your HTML when displayed as part of your form.
    else
    {
        $message = "CSRF attack foiled!";
        $messageclass = "message_error";
    }
}

function sanitize ($str)
{
    return htmlentities($str, ENT_COMPAT|ENT_QUOTES, "UTF-8", true);
}

function validateEmail($str)
{
    if (strlen($str) < 5) return false;
    if (strstr($str, "@") === false) return false;
    if (strpos($str, "@") == 0 || strpos($str, "@") == strlen($str) - 1) return false;

    return true;
}


And then ensure that your displayed output is sanitized.
<div class="formrow">
    <label for="txtName">Name</label><br />
    <input type="text" id="txtName" name="txtName" maxlength="50" value="<?php echo sanitize($form_name); ?>" placeholder="e.g, Jose D'Cruz" />
</div>
<div class="error <?php echo $errors["name_required"] ? "" : "hide" ?>" id="name_required">
    <span>Name is required.</span>
</div>

<div class="formrow">
    <label for="txtEmail">Email</label><br />
    <input type="text" id="txtEmail" name="txtEmail" maxlength="50" value="<?php echo sanitize($form_email); ?>" placeholder="e.g, j_dcruz208@youremail.com" />
</div>
<div class="error <?php echo $errors["email_required"] ? "" : "hide" ?>" id="email_required">
    <span>Email is required.</span>
</div>
<div class="error <?php echo $errors["email_format_incorrect"] ? "" : "hide" ?>" id="email_format_incorrect">
    <span>Email is in an incorrect format.</span>
</div>

<div class="formrow">
    <label for="txtComments">Comments</label><br />
    <textarea type="text" id="txtComments" name="txtComments" rows="5" maxlength="500" wrap="hard" placeholder="e.g, You're awesome!"><?php echo sanitize($form_comments); ?></textarea>
</div>
<div class="error <?php echo $errors["comments_required"] ? "" : "hide" ?>" id="comments_required">
    <span>Comments are required.</span>
</div>


There you are, it works!


It even works with accented and foreign characters!



Client-side validation

I know what you're thinking - why client-side validation when server-side validation is perfectly fine? Well, for starters, it's always faster than validating the data after it's been sent.

The task of client-side validation is to validate the data before it is submitted to the server. And because JavaScript can be turned off (not that I'd recommend doing so), the server-side validation, while slower, is a very dependable fallback.

So, long story short... you have server-side validation, and it's time for client-side validation.

In the form tag, add an onsubmit attribute. This is an event handler that triggers whenever the form is submitted. If the value is true, then it submits. If it is false, execution halts there. The function triggered is validateForm().
<form action="" method="POST" onsubmit="return validateForm();">


In the JavaScript, create the validateForm() function. First, get the placholders by declaring the variable placehlders and setting it to the array returned by the getElementsByClassName() method, and passing in "error" as an argument. This will get all elements with the CSS class of error.
<script>
    function validateForm()
    {
        var placeholders = document.getElementsByClassName("error");
    }
</script>


Iterate through the placeholders array. For every element whose class is "error", set it to "error hide". This means to hide all placeholders.
var placeholders = document.getElementsByClassName("error");

for (var i = 0; i < placeholders.length; i++)
{
    placeholders[i].className = "error hide";
}


Create an array, errors. Declare variables txtName, txtEmail and txtComments, and get the appropriate value from the DOM.
var placeholders = document.getElementsByClassName("error");

for (var i = 0; i < placeholders.length; i++)
{
    placeholders[i].className = "error hide";
}

var errors = [];

var txtName = document.getElementById("txtName");
var txtEmail = document.getElementById("txtEmail");
var txtComments = document.getElementById("txtComments");


Now, we're going to replicate in JavaScript what we did in the PHP. The JavaScript equivalent of replacing spaces with empty strings is the replace() method using a Regular Expression and an empty string as arguments.
var txtName = document.getElementById("txtName");
var txtEmail = document.getElementById("txtEmail");
var txtComments = document.getElementById("txtComments");

if (txtName.value.replace(/\s/g, "").length == 0)
{

}

if (txtEmail.value.replace(/\s/g, "").length == 0)
{

}
else
{
    if (!validateEmail(txtEmail.value))
    {

    }                   
}

if (txtComments.value.replace(/\s/g, "").length == 0)
{

}


For each error that is triggered, push the appropriate string into the errors array.
if (txtName.value.replace(/\s/g, "").length == 0)
{
    errors.push("name_required");
}

if (txtEmail.value.replace(/\s/g, "").length == 0)
{
    errors.push("email_required");
}
else
{
    if (!validateEmail(txtEmail.value))
    {
        errors.push("email_format_incorrect");
    }                   
}

if (txtComments.value.replace(/\s/g, "").length == 0)
{
    errors.push("comments_required");
}


And then let's create the validateEmail() function in JavaScript. It's just using equivalent functions of the ones we used in the PHP function we created.
function validateForm()
{
    var placeholders = document.getElementsByClassName("error");

    for (var i = 0; i < placeholders.length; i++)
    {
        placeholders[i].className = "error hide";
    }

    var errors = [];

    var txtName = document.getElementById("txtName");
    var txtEmail = document.getElementById("txtEmail");
    var txtComments = document.getElementById("txtComments");

    if (txtName.value.replace(/\s/g, "").length == 0)
    {
        errors.push("name_required");
    }

    if (txtEmail.value.replace(/\s/g, "").length == 0)
    {
        errors.push("email_required");
    }
    else
    {
        if (!validateEmail(txtEmail.value))
        {
            errors.push("email_format_incorrect");
        }                   
    }

    if (txtComments.value.replace(/\s/g, "").length == 0)
    {
        errors.push("comments_required");
    }
}

function validateEmail(str)
{
    if (str.length < 5) return false;
    if (str.indexOf("@") == -1) return false;
    if (str.indexOf("@") == 0 || str.indexOf("@") == str,length - 1) return false;

    return true;
}


Now, if the errors array is not empty, return true. This basically means that the form will submit.
if (txtComments.value.replace(/\s/g, "").length == 0)
{
    errors.push("comments_required");
}

if (errors.length == 0)
{
    return true;
}


If not, iterate through the errors array using a For loop and display the appropriate placeholders using the getElementById() method. And, of course, return false.
if (errors.length == 0)
{
    return true;
}
else
{               
    for (var i = 0; i < errors.length; i++)
    {
        document.getElementById(errors[i]).className = "error";
    }

    return false;
}


This should appear exactly like the PHP validation that we wrote in the first part of this tutorial, except that the form will not submit if there are errors! And if you turn JavaScript off, it should submit, then validate via the PHP code.


Yep!


Next

We will be beautifying this form somewhat and making it visually less confusing.