Secured User Interfaces - Learn PHP 7: Object-Oriented Modular Programming using HTML5, CSS3, JavaScript, XML, JSON, and MySQL (2016)

Learn PHP 7: Object-Oriented Modular Programming using HTML5, CSS3, JavaScript, XML, JSON, and MySQL (2016)

Chapter 4. Secured User Interfaces

Steve Prettyman1 

(1)

Georgia, USA

Electronic supplementary material

The online version of this chapter (doi:10.​1007/​978-1-4842-1730-6_​4) contains supplementary material, which is available to authorized users.

“All great ideas look like bad ideas to people who are losers. It’s always good to test a new idea with known losers to make sure they don’t like it.” —Dilbert 11/18/97 ( http://dilbert.com/strips/comic/1997-11-18/ )

Chapter Objectives/Student Learning Outcomes

After completing this chapter, the student will be able to:

·               Explain why user input must be validated in the interface and business rules tiers

·               Explain why user input must be filtered in the business rules tier

·               Use HTML5 code to validate user input

·               Use JavaScript code to validate user input

·               Use PHP if statements (conditional statements) to validate and filter input

·               Use the foreach loop to dynamically create an HTML select box from an XML file

·               Use simple arrays for filtering and validation

·               Pass simple arrays into methods (functions)

·               Understand how to use dependency injection to control code version changes

Secured User Interaction

In Chapter 2, the Hello World examples included user interaction (clicking a Submit button) to call a PHP program. This chapter will use the HTML web form to accept information from the user and then pass this information to a PHP program.

Do not trust your users! You must be prepared for any type of information your users will enter into a web form. You must also make sure that you validate and secure information every time before accepting it into your programs. You must remember that users may elect to not allow JavaScript to run in their browsers. Therefore, your program cannot be dependent on JavaScript code for verification of input. You must be able to handle these three scenarios:

1.

If the user is using an HTML5 capable browser, you can verify all input using HTML5 before sending it to the PHP program on the web server.

2.

If the user is using a browser that does not have HTML5 (or complete HTML5) capability, you can verify all (or some) input using JavaScript. Then you can send the validated information to the PHP program on the web server.

3.

If the user is using a browser that does not have HTML5 capability and has JavaScript disabled, the user input can still be verified by the PHP program on the web server.

It is preferable to handle the initial verification using either of the first two methods. This would verify the correct information before sending it to the server. Method #3 will cause more server calls because the information must be sent to the server for verification, and then any error messages must be sent back to the browser for the user to correct.

Even if you verify the information using method #1 or #2, when the PHP programs receives the information on the web server, you will again evaluate that you have received valid information. Even though the user may have sent valid information, packet sniffing programs can change valid information into harmful information.

HTML5 Form Validation

When building an HTML5 form, you can validate information entered into text boxes. However, browsers that have not implemented the HTML5 techniques (or all of HTML5) will treat the objects (such as text boxes) as if they were normal non-validation objects. The information in the boxes will be accepted without any verification. Therefore, you must also include a JavaScript routine to catch anything not validated by HTML5.

Security and performance —Secure programming is just part of the complete process of protecting your information. The files, directories, servers, networks, and databases must also be properly secured. In addition, any highly important information (such as credit card numbers) must be sent across a secure channel (HTTPS) to additionally protect the information. User IDs and passwords should be encrypted to make it difficult for packet sniffing software.

You will continue with the example from Chapter 3 by updating the Dog class example to accept information from the user for your properties. The Dog class already has security in place, so you will not need to make any additional security updates to the class.

Example 4-1. The lab.html file with some validation

<!DOCTYPE html>

<html lan="en">

<head>

<title>Dog Object</title>

<script src="validator.js"></script>

<style type="text/css">

#JS { display:none; }

</style>

<script>

function checkJS() {

document.getElementById('JS').style.display = "inline";

}

</script>

</head>

<body onload="checkJS();">

<h1>Dog Object Creater</h1>

<div id="JS">

<form method="post" action="lab.php" onSubmit="return validate_input(this)">

<h2>Please complete ALL fields. Please note the required format of information.</h2>

Your Dog's Name (max 20 characters, alphabetic) <input type="text" pattern="[a-zA-Z ]*"  title="Up to 20 Alphabetic Characters" maxlength="20" name="dog_name" id="dog_name" /><br />

Your Dog's Breed (max 35 characters, alphabetic) <input type="text" pattern="[a-zA-Z ]*" title="Up to 35 Alphabetic Characters" maxlength="35" name="dog_breed" id="dog_breed" /><br />

Your Dog's Color (max 15 characters, alphabetic) <input type="text" pattern="[a-zA-Z]*" title="Up to 15 Alphabetic Characters" maxlength="15" name="dog_color" id="dog_color" /><br />

Your Dog's Weight (numeric only) <input type="number" min="1" max="120" name="dog_weight" id="dog_weight" /><br />

<input type="submit" value="Click to create your dog" />

</form>

</div>

<noscript>

<div id="noJS">

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

<h2>Please complete ALL fields. Please note the required format of information.</h2>

Your Dog's Name (max 20 characters, alphabetic) <input type="text" pattern="[a-zA-Z ]*"  title="Up to 20 Alphabetic Characters" maxlength="20" name="dog_name" id="dog_name" /><br />

Your Dog's Breed (max 35 characters, alphabetic) <input type="text" pattern="[a-zA-Z ]*" title="Up to 35 Alphabetic Characters" maxlength="35" name="dog_breed" id="dog_breed" /><br />

Your Dog's Color (max 15 characters, alphabetic) <input type="text" pattern="[a-zA-Z]*" title="Up to 15 Alphabetic Characters" maxlength="15" name="dog_color" id="dog_color" /><br />

Your Dog's Weight (numeric only) <input type="number" min="1" max="120" name="dog_weight" id="dog_weight" /><br />

<input type="submit" value="Click to create your dog" />

</form>

</div>

</noscript>

</body>

</html>

In the head section of Example 4-1, after the validator.js file has been inserted into the program, some CSS has been included that hides (display:none) a division (div) tag with an ID of JS. Just below the CSS code is a small amount of JavaScript code. This code switches the JS division to be visible ($("#JS").show()) and hides the noJS division. There is only one slight difference between the forms in the JS and noJS divisions. You should notice that the noJS form does not call the validate_input JavaScript function.

Why is this?

The answer is simple. If the browser does not have JavaScript enabled, the short JavaScript routine to hide and show the divisions will not run. Thus, the JS division will not be displayed in the browser (because the CSS at the top of the code set its display to none). The noJS division will be visible instead. This allows a browser that does not have JavaScript to send the information entered by the user directly to the PHP program on the web server. Hopefully, the user has an HTML5 browser that will still validate the information before it is sent to the server (#1 in this scenario). However, even if they don’t, the information will be validated on the server (#3 in this scenario, as you will see later in the chapter.

If JavaScript is enabled in the browser, the hide-show routine will “hide” the noJS division and show the JS division. The form that submits the information to the validate_input function will display in the browser. This will allow browsers that have JavaScript enabled to validate information entered by using the validate_input JavaScript function. If the user has an HTML5 browser (#1 in this scenario), this might be overkill, since HTML5 can validate the information. However, you must be prepared for users who have not upgraded their browsers (#2 in this scenario).

A978-1-4842-1730-6_4_Fig1_HTML.jpg

Figure 4-1.

The lab.html file

In Example 4-1, the dog_name, dog_breed, and dog_color text boxes set field lengths to the same maximum values that were validated in the Dog class in Chapter 3. They also use the HTML5 pattern property ([a-zA-Z]) to only allow alphabetic characters. The title property is used to display an error to the user if incorrect information is entered. The dog_weight text box uses an input type of number, which automatically restricts the input. The min and max parameters are also set to restrict the dog’s weight between 1 and 120 lbs. As mentioned, the browser might not interpret these restrictions if it has not fully implemented HTML5 standards. Therefore, you still must also validate the data using the JavaScript validate_input method to be sure that all validation has been completed.

HTML5 capable browsers will validate the information before it is sent to the validate_input function. Thus, if the browser is completely HTML5, all the information will also pass the validation from the JavaScript method. You could check the browser version to determine if the browser is 100% HTML5. However, that would take more JavaScript coding and is unnecessary since the application accomplishes its task without more code.

It is important that all validations are consistent throughout the process of accepting information from the user and passing that information to the application. HTML and JavaScript code are easily viewable by the user (you can “View Source” from within a browser to see the code). Validation of any highly secure format should be done from within a program language that is compiled and secured on a server.

Security and performance —You may be wondering why you should even bother to validate on the user side. Why not just pass all the information to the program on the server and let that program tell you if you need to fix anything? Some programmers actually do this. However, the goal is to have an efficient program. By attempting to validate the information in the user’s browser, you reduce the number of calls to/from the server. This improves the application and web server performance and efficiency. In addition, as you will see, by validating in the browser, the contents in the text boxes will still be available to the user to adjust. If validation is done on the web server, information in the HTML form will be lost because the web page will be reloaded each time you send and receive information from the web server.

The goal of validation in the browser is to make sure that the user provides information that meets the requirements of the program on the server. You may initially cringe that this example displays the format of required information to the user. However, the goal is not to secure the data; the goal is to make sure the data is valid. It is not a security breach to inform the user of the data format requested.

<form method="post" action="lab.php" onSubmit="return validate_input(this)">

The form uses the parameter onSubmit to pass all information that has been entered to the JavaScript method (validate_input). The this keyword indicates that all information from this object (which is the form itself and all the text boxes) is passed to the method. The return keyword indicates that the method will return a TRUE or FALSE status. The HTML code will submit the form to the PHP program (lab.php) on the server if a TRUE status has been returned from the validate_input method.

Do It

1.

Adjust Example 4-1 to include gender information from the Do It in Chapter 3. Use a text box to receive the information from the user. Try to use HTML5 to restrict the type of information the user can enter in the text box. Test your code.

JavaScript Validation

Although this is not a JavaScript book, it will take a brief look at form validation used in the JavaScript method validate_input.

Example 4-2. Form validation via JavaScript—validator.js

function allalphabetic(the_string)

{

   var letters = /^[a-zA-Z ]+$/;

   if (the_string.match(letters))

    {

     return true;

    }

else

    {

    return false;

   }

}

// -------------------------------------------------------------------------------------------

function validate_dog_name(the_string)

{

        if ((the_string.length > 0) && (allalphabetic(the_string)) && (the_string.length < 21))

        {

          return true;

        }

        else

        {

          return false;

        }

}

// -------------------------------------------------------------------------------------------

function validate_dog_breed_color(the_string)

{

    if ((the_string.length > 0) && (allalphabetic(the_string)) && (the_string.length < 35))

        {

           return true;

        }

        else

        {

           return false;

        }

}

function validate_dog_weight(the_string)

{

    if ((the_string > 0 && this_string <= 120) && (!isNaN(the_string)))

        {

           return true;

        }

        else

        {

           return false;

        }

}

// -----------------------------------------------------------------------------------------

function validate_input(form)

{

            var error_message = "";

                    if (!validate_dog_name(form.dog_name.value))

        {

                       error_message += "Invalid dog name. ";

        }

        if (!validate_dog_breed_color(form.dog_breed.value))

        {

            error_message += "Invalid dog breed. ";

        }

        if (!validate_dog_breed_color(form.dog_color.value))

        {

            error_message += "Invalid dog color. ";

                    }

        if (!validate_dog_weight(form.dog_weight.value))

        {

            error_message += "Invalid dog weight. ";

        }

        if (error_message.length > 0)

        {

        alert(error_message);

        return false;

        }

        else

        {

        return true;

        }

}

          if (!validate_dog_breed_color(form.dog_color.value))

        {

            error_message += "Invalid dog color. ";

                    }

        if (!validate_dog_weight(form.dog_weight.value))

        {

            error_message += "Invalid dog weight. ";

        }

        if (error_message.length > 0)

        {

        alert(error_message);

        return false;

        }

        else

        {

        return true;

        }

}

<script src="validator.js"></script>

In Example 4-1, the JavaScript file validator.js is attached to the lab.html file in the head section via an HTML script tag. By placing the JavaScript validation in a separate file, you have simplified the HTML file. The JavaScript file is dependent on the HTML file for display. Error messages are passed to an alert box (alert(error_message);) near the bottom of the method.

Programming suggestion—By passing only a status (error message) back to a calling program, you allow for flexibility. The calling program can then determine how to display the information. This also allows you to easily reuse the method for other HTML forms.

Let’s work backward in reviewing the JavaScript code (Example 4-2). In the HTML file, the onSubmit parameter of the form tag calls the validate_input JavaScript method. This method controls all the validation of each text box on the form. The method uses a series of if statements to call methods that will validate the different types of text boxes. The format of each if statement is very similar.

if (!validate_dog_name(form.dog_name.value))

Each method called will return a true response if the validation passes and a false response if the validation fails. (In JavaScript, the constants true and false are lowercase. In PHP they are uppercase.)

By passingform into the validate_input function, all the parameters and values in the HTML form are passed at the same time. You can select which parameter to use by using dot notation.

In the previous example, form.dog_name.value will pull the value that was entered in the dog_name text box. The value that the user entered in this text box is passed into the validate_dog_name method.

if (!validate_dog_name(form.dog_name.value))

{

    error_message += "Invalid dog name. ";

}

The ! symbol in front of the function name means not. An if statement normally executes if the response from a method (or comparison) is true. However, you want to save an error message in the error_message property if the response returned from the method (validate_dog_name) isfalse (it did not validated correctly). The ! symbol causes the if statement to do the reverse of what’s normal and execute if the function returns a false value.

Each of the other validation methods works in similar ways. The methods check to see if the information entered was in the correct format. If the information was correct, the method returns true. If the information was not correct, the method returns false.

For more information on the JavaScript if conditional statement, visit

https://www.thenewboston.com/videos.php?cat=10&video=16960

For more information on JavaScript functions (methods), visit

https://www.thenewboston.com/videos.php?cat=10&video=16952

function validate_dog_name(the_string)

{

        if ((the_string.length > 0) && (allalphabetic(the_string)) && (the_string.length <= 20))

        {

          return true;

        }

        else

        {

          return false;

        }

}

Each method accepts the value from the particular text box by passing it into the the_string property (function validate_dog_name(the_string)). The if statement in each method does most of the work. In the validate_dog_name method, the if statement attempts to check three requirements for the dog name. The first part of the statement uses the length method to make sure the length of the string is greater than zero. If the length of the string is not greater than zero, the user did not enter anything in the text box. Next, the if statement passes the_string to anallalphabetic method to determine if the text box contains only alphabetic characters (you will look at the function shortly). Finally the if statement checks the string length again to make sure it has not exceeded 20 characters. The && symbol is an AND symbol that requires that all three of these checks be true for the complete if statement to be considered true. If all three are true, the if statement returns true to the validate_input method. If any of the three are false, the if statement returns false to the validate_input method.

Programming note—JavaScript strings include built-in methods that automatically exist once a variable has been created and set with a string value. In the examples in this chapter, you use both the length method and the match method. The length method returns the length of the string. The match method determines if the string contains a set of characters that has been passed into the method (see the next example).

dog_name, dog_breed, and dog_color all require that only alphabetic characters be allowed. So you created the allalphabetic method that can be called by each validation method instead of repeating the same code.

function allalphabetic(the_string)

{

    var letters = /^[a-zA-Z ]+$/;

    if (the_string.match(letters))

    {

      return true;

    }

    else

    {

      return false;

    }

}

The allaphabetic method uses a regular expression to check for alphabetic characters. Most program languages (including PHP) enable the programmer to create a regular expression that will check a string for a required format.

var letters = /^[a-zA-Z ]+$/;

This line sets up the expression to determine if the string only has lowercase and/or uppercase alphabetic characters (a though z, A through Z). You will work more in detail with regular expressions within PHP in a later chapter.

For more information on JavaScript regular expressions, visit

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions

For more information on the JavaScript match method, visit

http://www.w3schools.com/jsref/jsref_match.asp

One of the methods that exists in all JavaScript strings is the match method. This method compares the contents of the string (the_string) to the regular expression (alphabetic characters in this example). If the string meets the requirements of the expression (only contains alphabetic characters), then the method will return true. Otherwise, it will return false. In this example, if the string is alphabetic, true is returned to the if statement in the validate_dog_name (or validate_dog_color or validate_dog_breed) method. If any part of the string contains something other than alphabetic characters, a false is returned to the if statement (which in turn will make the results of the if statement false even if the string size is correct).

Going back to the bottom of the JavaScript code, you determine what to return to the HTML program (lab.html).

if (!validate_dog_weight(form.dog_weight.value))

        {

            error_message += "Invalid dog weight. ";

        }

        if (error_message.length > 0)

        {

        alert(error_message);

        return false;

        }

        else

        {

        return true;

        }

Each if statement at the bottom of the validate_input method will build an error message (such as "Invalid dog weight.") and place it in the error_message property if the validation fails (If a false is returned from the if statement). The += symbol concatenates what is currently in the property with what is being placed into the property (so you don’t overwrite any messages that are already there).

The last if statement (if (error_message.length > 0) checks the length of the error_message property. If it is greater than zero (error messages have been passed into the property), the program will display the messages in an alert box and return false to the HTML program (lab.html). If the length is zero, there were no error messages; true is passed back to the HTML program.

<form method="post" action="lab.php" onSubmit="return validate_input(this)">

In Example 4-1, the format of the form tag will automatically cause a response if a true or false is returned from the validate_input method. If true is returned (there were no validation problems), the HTML program will send the form properties and values to the lab.php program on the web server. If false is returned (there was at least one validation problem), the HTML program will not pass the information and will stay visible in the browser. The alert box will display for the user to see what errors have occurred. When the user closes the alert box, they will still be on the HTML page (with the information they had previously entered). They can correct any incorrect information and click the Submit button (again) to revalidate the information they have entered.

A978-1-4842-1730-6_4_Fig2_HTML.jpg

Figure 4-2.

The lab.html file with incorrect entries

A978-1-4842-1730-6_4_Fig3_HTML.jpg

Figure 4-3.

The lab.html file after failing JavaScript verification

Note

Different browsers react in different ways to JavaScript code. Internet Explorer tries to block JavaScript code by default. If you see no results and are sure your code is correct, yet are receiving error messages about missing methods (such as validate_input) it may be that your browser’s ability to execute JavaScript is turned off. Either turn it on in the settings of the browser or try a different browser that allows JavaScript to run.

Security and performance—Although you have verified input on the HTML page, the data could still cause harm to the system. The user could try to send HTML, JavaScript, and even PHP code that could to cause harm. This could occur from bad information entered in the HTML page, a packet sniffing program intercepting the data transferring to the PHP page, or a program trying to bypass the HTML page altogether. No matter which of these activities produced the harmful information, the PHP program will need to detect it and handle the problem. Therefore, the receiving program ( lab.php ) must try to filter (clean and remove harmful code) the data.

Do It

1.

Adjust Example 4-2 to validate the gender text box from the first Do It. Make sure to include an error message to indicate the problem(s). Also make sure the error message is added to the $error_message property to be displayed with all other error messages. Make sure to test your code for all possible problems with the user entering data. Don’t forget to test if they do not enter any data.

PHP Filtering

It’s time to look at the changes required to the php file (lab.php). You need to be able to accept in the properties and values (dog_name, dog_breed, dog_color, and dog_weight) from the HTML program. However, you need to be concerned that someone might try to send information that could affect the operation of the program or even crash the system in which it is operating.

This section takes two approaches to help reduce the possibility of harmful data. First, you will determine if you have received all required information. If not, you will ask the user to return to the HTML page (lab.html) to enter the information. This will, at least, make sure that you have all data and it meets the validation provided by the HTML5 page and/or JavaScript program (validator.js). Second, you will use some existing PHP methods to filter out HTML, JavaScript, and PHP syntax from the data received. This will reduce the chance that an executable statement will be passed into the program.

Example 4-3. Partial listing of the top of lab.php with the clean_input method

<?php

require_once("dog.php");

function clean_input($value)

{

$bad_chars = array("{", "}", "(", ")", ";", ":", "<", ">", "/", "$");

$value = str_ireplace($bad_chars,"",$value);

// This part below is really overkill because the string replace above removed special characters

$value = htmlentities($value); // Removes any html from the string and turns it into < format

$value = strip_tags($value); // Strips html and PHP tags

        if (get_magic_quotes_gpc())

        {

                $value = stripslashes($value); // Gets rid of unwanted quotes

        }

return $value;

}

if ((isset($_POST['dog_name'])) && (isset($_POST['dog_breed'])) && (isset($_POST['dog_color'])) && (isset($_POST['dog_weight'])))

{

$dog_name = clean_input($_POST['dog_name']);

$dog_breed = clean_input($_POST['dog_breed']);

$dog_color = clean_input($_POST['dog_color']);

$dog_weight = clean_input($_POST['dog_weight']);

$lab = new Dog($dog_name,$dog_breed,$dog_color,$dog_weight);

list($name_error, $breed_error, $color_error, $weight_error) = explode(',', $lab);

...

For more information on the PHP function isset , visit

Examples: http://php.net/manual/en/function.isset.php

Videos: https://www.thenewboston.com/videos.php?cat=11&video=17087

For more information on $_POST, visit

Examples: http://php.net/manual/en/reserved.variables.post.php

Videos: https://www.thenewboston.com/videos.php?cat=11&video=17087

At the top of lab.php, you are adding several items to provide more secure code.

if ((isset($_POST['dog_name'])) && (isset($_POST['dog_breed'])) && (isset($_POST['dog_color'])) && (isset($_POST['dog_weight'])))

This if statement uses the isset method and $_POST to verify that all four properties (dog_name, dog_breed, dog_color, and dog_weight) have been passed into the program with the POST method. If all items have been passed, you then will filter (clean) those items. If any of them have not been passed, an else statement (that you will look at later) will request the user go back to the lab.html page to enter all needed information.

$dog_name = clean_input($_POST['dog_name']);

Each property is passed to the clean_input method (after it has been retrieved using the $_POST method) to remove harmful tags. In this example, the $dog_name property (on the left side of the = sign) will receive the cleaned information.

function clean_input($value)

{

$bad_chars = array("{", "}", "(", ")", ";", ":", "<", ">", "/", "$");

$value = str_ireplace($bad_chars,"",$value);

$value = strip_tags($value); // Strips html and PHP tags

$value = htmlentities($value); // Removes any html from the string and turns it into < format

if (get_magic_quotes_gpc())

        {

                $value = stripslashes($value); // Gets rid of unwanted quotes

        }

return $value;

}

Note

set_magic_quotes_runtime and magic_quotes_runtime has been removed since PHP 5.4. Magic quotes (since PHP 5.4) can no longer be set at runtime.

For more information on the str_ireplace method, visit

http://php.net/manual/en/function.str-ireplace.php

The clean_input method creates an array $bad_chars that contains a list of all special characters you want to remove from the string (you will look at arrays in more detail later in this chapter and future chapters). The str_ireplace method ($value = str_ireplace($bad_chars,"",$value);) will replace all these characters with "" (nothing, it removes them) from the $value property and place what is left into $value. There may be occasions that you do want some of these special characters (for example in an SQL statement). However, you do not need any of these for the input in this example, so you can remove them.

Note

It would be effective and efficient for this example to just remove the characters that are not valid. In a real-world situation, you would not need to also include the stripslashes, htmlentities, and string_tags methods (shown in the method). They are included here to demonstrate their use and why, in other situations, you might use them.

The three PHP methods (stripslashes, htmlentities, and strip_tags) are used to convert harmful code so it cannot be executed. The stripslashes method removes backslashes from quotes (which actually can also done by the str_ireplace method). The htmlentities method converts HTML characters to their equivalent HTML entity (for example a is converted to '). The strip_tags method removes any PHP or HTML tags. If you were using SQL to update a database, you need to add additional functions to disable any harmful SQL statements.

For more information on stripslasheshtmlentities, and strip_tags, visit

Examples – stripslashes: http://php.net/manual/en/function.stripslashes.php

Examples – htmlentities: http://php.net/manual/en/function.htmlentities.php

Examples – strip-tags: http://php.net/manual/en/function.strip-tags.php

Video – magic quotes and stripslashes: https://www.youtube.com/watch?v=NUqkUjbGuPY

Video – htmlentitieshttps://www.thenewboston.com/videos.php?cat=11&video=17058

Video – strip_tagshttps://www.youtube.com/watch?v=rn_dnQFLt3U

Security and performance—It is extremely important that the program filter out any possible harmful information received from outside the application. It is much easier to remove the harmful data initially, or reject the data initially, before it has been used or saved. With major breaches in security today, this is an absolute MUST DO.

You could have also restricted which programs called the PHP program. The $__SERVER global variable can assist you.

if($__SERVER['HTTP_REFERER'] == ' http://www.mysite.com/lab.html ')

{ //  code executed if valid location }

else {exit;}

For more information on the $__SERVER array, visit

Examples: http://php.net/manual/en/reserved.variables.server.php

Video: https://www.thenewboston.com/videos.php?cat=11&video=17047

This example code would reject any program that calls the lab.php program (except for the lab.html program that is located at the site). The exit; command closes the program if it is not called from the correct HTML page.

The filter methods demonstrated will not keep someone from entering “asabsbabsa” as a dog name. However, these methods will keep any entry from being harmful.

Example 4-4. Partial list of the bottom of lab.php with the clean_input method

else

{

print "<p>Missing or invalid parameters. Please go back to the lab.html page to enter valid information.<br />";

print "<a href='lab.html'>Dog Creation Page</a>";

}

The true part of the if statement mentioned includes all the active code in the lab.php file. If one or more parameters is missing, the else section (at the bottom of the lab.php file) will request that the user go back to the lab.html page to properly enter the information.

Do It

Adjust the code in the new lab.php file (download it from the book’s web site). Add code to filter for bad gender code and make sure that gender information has been received from the HTML file. Make sure to pass your property through the clean_input method to remove any harmful data.

Additional HTML Input Security

As you can see from all the code you have seen in this chapter so far, whenever a text box is used on an HTML form, additional code in several areas must be included to validate what the user has typed. Text boxes are necessary when you need to allow the user flexibility in what they can enter (such as a form that includes name and address). However, you can use other form objects when you want to limit the user’s response to a particular list of possible values (such as two-letter abbreviations for states). This would provide more valid data because the user won’t be able to enter a typo or enter invalid data.

HTML5 Select List Box and Radio Buttons

One item that you can change from the original HTML file is the entry of the dog breed. The American Kennel Club currently has over 150 breeds listed on its web site. You can type an option value line for each breed in the HTML file. However, this would be time consuming. Also, if a breed changed, you will have to go back and adjust the list. A better option is to place the breeds in a file and then use that file to populate a select list. If a breed changes or is added, you simply update the one file in one place and all programs that use it will access the new list automatically. If this file is hosted on the web server, you can also use the same file in the dog.php code to verify that a correct breed has been passed to the web server from the user.

Example 4-5. The breeds.xml file

<?xml version="1.0" encoding="UTF-8"?>

<breeds>

<breed>Affenpinscher</breed>

<breed>Afghan Hound</breed>

<breed>Airedale Terrier</breed>

<breed>Akita</breed>

<breed>Alaskan Malamute</breed>

<breed>American English Coonhound</breed>

<breed>American Eskimo Dog</breed>

<breed>American Foxhound</breed>

<breed>American Staffordshire Terrier</breed>

...

</breeds>

Security and performance—Providing the user a list of possible values to choose from on an HTML form provides more validity and security than using text boxes. If the user can only pick from a list, they cannot choose incorrectly, nor enter invalid or harmful information.

The breeds.xml file contains simple XML code (two tags—breeds and breed) listing all breeds. If you were creating a true dog breed site, you probably would want to include more information in this file. You could add more information later without it affecting this program.

You now want to use the XML file (from Example 4-5) to populate a select list box. Since this file will reside on the server, you need to create a program on the server to call and retrieve the information. You will assume that this file has been secured on the server for read-only access. You will not attempt to update or delete any information in the file itself.

You can create a PHP program that will retrieve the information you need with just a few lines of code.

Security and performance—Remember, security is a team effort. Not only does the program need to be secured, but the web server and its file structure must also be properly secured.

Example 4-6. The getbreeds.php file

<?php

$breed_file = simplexml:load_file("breeds.xml");

$xmlText = $breed_file->asXML();

print "<select name='dog_breed' id='dog_breed'>";

print "<option>Select a dog breed</option>";

foreach ($breed_file->children() as $name => $value)

{

print "<option value='$value'>$value</option>";

}

print "</select>";

?>

PHP can complete many powerful tasks with just a few lines of code. The first line of Example 4-6 opens the breeds.xml file, places the contents into a property ($breed_file), and then closes the breeds.xml file.

Skipping to the foreach statement:

foreach ($breed_file->children() as $name => $value)

XML data is treated with a parent-child relationship. The parent can contain children (and the children can have children). In the XML file, the initial parent is breeds. The children that exist under breeds all have the label breed.

<breed>Affenpinscher</breed>

The value in each breed (child) in this example is the text that exists between the breed tags (for example, Affenpinscher).

$breed_file->children() directs the foreach statement to loop through each child (breed in this file). The as $name=> $value part of the statement tells the system to place each child label name (in this example it is always breed, but you can have different children) in $name. It also directs the system to place the value contained in the child (Affenpinscher) in $value.

print "<option value='$value'>$value</option>";

Inside the foreach loop, the print statement places the contents of $value in two places—the value parameter of the option tag and between the option tags. For the first child, it would produce

Option value='Affenpinscher'>Affenpinscher</option>

The foreach loop automatically loops through the file until there are no more records in the file. Similar lines would be created for each of the breeds in the file. These lines, with the other print lines in the file, create an HTML select box dynamically from the contents of the XML file.

For more information on the foreach loop, visit

Examples: http://php.net/manual/en/control-structures.foreach.php

Video: https://www.thenewboston.com/videos.php?cat=11&video=17027

For more information on reading XML files, visit

Video: https://www.thenewboston.com/videos.php?cat=11&video=17090

You need to now call this program from within the HTML file. You can do this using the example JavaScript file from Chapter 2, which uses AJAX. This will allow you to retrieve the select box by only updating the section of the page that will display the box. The only line that needs to be changed from the Chapter 2 example is the line that calls the PHP program.

xmlHttp.open("GET", "get_breeds.php", true);

You simply replace the existing file name with the program that retrieves the select box (get_breeds.php). You can then rename the file (get_breeds.js).You could also pass the name of the program you want to run into the JavaScript method (you will do that later in this chapter).

You now need to make a few changes to the HTML file to use get_breeds.js and to create a div tag for the area that will hold the select box.

Example 4-7. The lab.html file with a dynamic select box

<!DOCTYPE html>

<html lan="en">

<head>

<title>Dog Object</title>

<script src="get_breeds.js"></script>

<script src="validator.js"></script>

<style type="text/css">

#JS { display:none; }

</style>

<script>

function checkJS() {

document.getElementById('JS').style.display = "inline";

}

</script>

</head>

<body onload="checkJS();">

<h1>Dog Object Creater</h1>

<div id="JS">

<form method="post" action="lab.php" onSubmit="return validate_input(this)">

<h2>Please complete ALL fields. Please note the required format of information.</h2>

Enter Your Dog's Name (max 20 characters, alphabetic) <input type="text" pattern="[a-zA-Z]*"  title="Up to 20 Alphabetic Characters" maxlength="20" name="dog_name" id="dog_name" /><br /><br />

Select Your Dog's Color:<br />

<input type="radio" name="dog_color" id="dog_color" value="Brown">Brown<br />

<input type="radio" name="dog_color" id="dog_color" value="Black">Black<br />

<input type="radio" name="dog_color" id="dog_color" value="Yellow">Yellow<br />

<input type="radio" name="dog_color" id="dog_color" value="White">White<br />

<input type="radio" name="dog_color" id="dog_color" value="Mixed">Mixed<br /><br />

Enter Your Dog's Weight (numeric only) <input type="number" min="1" max="120" name="dog_weight" id="dog_weight" /><br /><br />

<script>

AjaxRequest();

</script>

<div id="AjaxResponse"></div><br />

<input type="submit" value="Click to create your dog" />

</form>

</div>

<noscript>

<div id="noJS">

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

<h2>Please complete ALL fields. Please note the required format of information.</h2>

Enter Your Dog's Name (max 20 characters, alphabetic) <input type="text" pattern="[a-zA-Z ]*"  title="Up to 20 Alphabetic Characters" maxlength="20" name="dog_name" id="dog_name" /><br /><br />

Select Your Dog's Color:<br />

<input type="radio" name="dog_color" id="dog_color" value="Brown">Brown<br />

<input type="radio" name="dog_color" id="dog_color" value="Black">Black<br />

<input type="radio" name="dog_color" id="dog_color" value="Yellow">Yellow<br />

<input type="radio" name="dog_color" id="dog_color" value="White">White<br />

<input type="radio" name="dog_color" id="dog_color" value="Mixed">Mixed<br /><br />

Enter Your Dog's Weight (numeric only) <input type="number" min="1" max="120" name="dog_weight" id="dog_weight" /><br /><br />

Enter Your Dog's Breed (max 35 characters, alphabetic) <input type="text" pattern="[a-zA-Z ]*" title="Up to 15 Alphabetic Characters" maxlength="35" name="dog_breed" id="dog_breed" /><br />

<input type="submit" value="Click to create your dog" />

</form>

</div>

</noscript>

</body>

</html>

The only true changes related to creating the dynamic select box are highlighted in bold in Example 4-7.

<script src="get_breeds.js"></script>

The script tag is added near the top of the code to pull in the JavaScript file that contains AJAX to call the PHP program (get_breeds.php) that will display the select box.

<script>

AjaxRequest();

</script>

<div id="AjaxResponse"></div><br />

A script area has been placed in the JS section of the code (the section that will execute if JavaScript is enabled in the browser.) It includes just one line (AjaxRequest();) to execute the AJAX JavaScript code (from the get_breeds.js file). <div id="AjaxResponse"></div> is placed below the closing script tag. This line should look familiar. It is the same line that was included in the Chapter 2 AJAX example. The output of the AjaxRequest() method places the response that is returned from the web server between the div tags with the ID of AjaxResponse. In this example, the dynamically created select box is placed in that location.

A978-1-4842-1730-6_4_Fig4_HTML.jpg

Figure 4-4.

The lab.html file with dynamic select box and radio buttons

You have also replaced the color text box with a static selection of radio buttons. There are just a few possible color combinations for dogs (OK, pretend I am right), and these color combinations are not likely to change, so you don’t need a dynamic list. It makes sense to just hard code the selections in the HTML file.

If the user does not have JavaScript enabled, the original dog breed text box will be displayed (from the NJ section of the code). However, since you did not use JavaScript to create the radio buttons, you include the radio buttons in both sections to provide some better secure coding for non-enabled JavaScript browsers.

The Interface of the program (lab.html) now greatly reduces the possibility of invalid data being entered by reducing the number of text boxes used. The users (assuming they have JavaScript enabled) have no choice but to pick a breed from the select box and to pick a color from the radio buttons.

You can also now use the same XML file to validate that you have received a valid breed name from the users on the server side.

Do It

Adjust the lab.html file from Example 4-7 to include radio buttons (instead of a text box) to accept the gender from the users. Make sure the new lab.html file works with your lab.php file from the previous Do It.

Validating Input with an XML File

You can add just a few lines of code in the dog.php file to validate that the user has not only sent a correctly formatted string, but has also sent a breed listed by the AKC.

Example 4-8. The validator_breed function (in dog.php)

private function validator_breed($value)

{

$breed_file = simplexml:load_file("breeds.xml");

$xmlText = $breed_file->asXML();

if(stristr($xmlText, $value) === FALSE)

{

return FALSE;

}

else

{

return TRUE;

}

}

You can create a private function (only to be used inside the class) to check on the proper breed. This function will accept a value passed into the $value property. The function will then use $breed_file = simplexml:load_file("breeds.xml"); to dump the contents of the XML file into$breed_file. The next line ($xmlText = $breed_file->asXML();) converts the contents of $breed_file into a well formatted string.

if(stristr($xmlText, $value) === FALSE)

The stristr method compares the contents of its second parameter (in this case $value) to see if it exists in the string in the first parameter ($xmlText). If it does not exist, it returns FALSE. If it does exist, it returns the location of the string. For your needs you just need to know if it exists. If it does not, you return FALSE. If it does, you return TRUE.

For more information on the stristr method, visit

http://php.net/manual/en/function.stristr.php

Example 4-9. The complete dog class with validation

<?php

class Dog

{

// ----------------------------------------- Properties ------------------------------------

private $dog_weight = 0;

private $dog_breed = "no breed";

private $dog_color = "no color";

private $dog_name = "no name";

private $error_message = "??";

// ---------------------------------- Constructor -----------------------------------------

function __construct($value1, $value2, $value3, $value4)

{

if (method_exists('dog_container', 'create_dog_app')) {

$name_error = $this->set_dog_name($value1) == TRUE ? 'TRUE,' : 'FALSE,';

$breed_error = $this->set_dog_breed($value2) == TRUE ? 'TRUE,' : 'FALSE,';

$color_error = $this->set_dog_color($value3) == TRUE ? 'TRUE,' : 'FALSE,';

$weight_error= $this->set_dog_weight($value4) == TRUE ? 'TRUE' : 'FALSE';

$this->error_message = $name_error . $breed_error . $color_error . $weight_error;

}

else

{

exit;

}

}

//------------------------------------toString---------------------------------------------

public function __toString()

{

        return $this->error_message;

}

// ---------------------------------- Set Methods -----------------------------------------

function set_dog_name($value)

{

$error_message = TRUE;

(ctype_alpha($value) && strlen($value) <= 20) ? $this->dog_name = $value : $this->error_message = FALSE;

return $this->error_message;

}

function set_dog_weight($value)

{

$error_message = TRUE;

(ctype_digit($value) && ($value > 0 && $value <= 120)) ? $this->dog_weight = $value : $this->error_message = FALSE;

return $this->error_message;

}

function set_dog_breed($value)

{

$error_message = TRUE;

((preg_match("/[a-zA-Z ]+$/", $value)) && ($this->validator_breed($value) === TRUE) && strlen($value) <= 35) ? $this->dog_breed = $value : $this->error_message = FALSE;

return $this->error_message;

}

function set_dog_color($value)

{

$error_message = TRUE;

(ctype_alpha($value) && strlen($value) <= 15) ? $this->dog_color = $value : $this->error_message = FALSE;

return $this->error_message;

}

// ----------------------------------------- Get Methods ----------------------------------

function get_dog_name()

{

return $this->dog_name;

}

function get_dog_weight()

{

return $this->dog_weight;

}

function get_dog_breed()

{

return $this->dog_breed;

}

function get_dog_color()

{

return $this->dog_color;

}

function get_properties()

{

return "$this->dog_weight,$this->dog_breed,$this->dog_color.";

}

// ------------------------------General Method---------------------------------------------

private function validator_breed($value)

{

$breed_file = simplexml:load_file("breeds.xml");

$xmlText = $breed_file->asXML();

if(stristr($xmlText, $value) === FALSE)

{

return FALSE;

}

else

{

return TRUE;

}

}

}

?>

//------------------------------------toString----------------------------------------------

public function __toString()

{

        return $this->error_message;

}

// ---------------------------------- Set Methods ------------------------------------------

function set_dog_name($value)

{

$error_message = TRUE;

(ctype_alpha($value) && strlen($value) <= 20) ? $this->dog_name = $value : $error_message = FALSE;

return $error_message;

}

function set_dog_weight($value)

{

$error_message = TRUE;

(ctype_digit($value) && ($value > 0 && $value <= 120)) ? $this->dog_weight = $value : $error_message = FALSE;

return $error_message;

}

function set_dog_breed($value)

{

$error_message = TRUE;

((ctype_alpha($value)) && ($this->validator_breed($value) === TRUE) && strlen($value) <= 35) ? $this->dog_breed = $value : $error_message = FALSE;

return $error_message;

}

{

$error_message = TRUE;

(ctype_alpha($value) && strlen($value) <= 15) ? $this->dog_color = $value : $error_message = FALSE;

return $error_message;

}

// ----------------------------------------- Get Methods ----------------------------------

function get_dog_name()

{

return $this->dog_name;

}

function get_dog_weight()

{

return $this->dog_weight;

}

function get_dog_breed()

{

return $this->dog_breed;

}

function get_dog_color()

{

return $this->dog_color;

}

function get_properties()

{

return "$this->dog_weight,$this->dog_breed,$this->dog_color.";

}

// ------------------------------General Method---------------------------------------------

private function validator_breed($value)

{

$breed_file = simplexml:load_file("breeds.xml");

$xmlText = $breed_file->asXML();

if(stristr($xmlText, $value) === FALSE)

{

return FALSE;

}

else

{

return TRUE;

}

}

}

?>

function set_dog_color($value)

{

$error_message = TRUE;

(ctype_alpha($value) && strlen($value) <= 15) ? $this->dog_color = $value : $error_message = FALSE;

return $error_message;

}

// ----------------------------------------- Get Methods ----------------------------------

function get_dog_name()

{

return $this->dog_name;

}

function get_dog_weight()

{

return $this->dog_weight;

}

function get_dog_breed()

{

return $this->dog_breed;

}

function get_dog_color()

{

return $this->dog_color;

}

function get_properties()

{

return "$this->dog_weight,$this->dog_breed,$this->dog_color.";

}

// ------------------------------General Method---------------------------------------------

private function validator_breed($value)

{

$breed_file = simplexml:load_file("breeds.xml");

$xmlText = $breed_file->asXML();

if(stristr($xmlText, $value) === FALSE)

{

return FALSE;

}

else

{

return TRUE;

}

}

}

?>

/ -------------------------------General Method---------------------------------------------

private function validator_breed($value)

{

$breed_file = simplexml:load_file("breeds.xml");

$xmlText = $breed_file->asXML();

if(stristr($xmlText, $value) === FALSE)

{

return FALSE;

}

else

{

return TRUE;

}

}

}

?>

You can now make a slight change to the code line that checks the validity of the dog_breed value (see the bold highlighted line in Example 4-9).

((ctype_alpha($value)) && ($this->validator_breed($value) === TRUE) && strlen($value) <= 35) ? $this->dog_breed = $value : $error_message = FALSE;

The statement passes $value into validator_breed ($this->validator_breed($value)). If a TRUE is returned then that part of the if statement would be true. Otherwise it would be false. If the complete if statement is TRUE then the dog_breed property is set to the breed found in the XML file ($this->dog_breed = $value). If it is false, then FALSE is passed into the $error_message property ($error_message = FALSE).

Programming note—When you call a function in the same object, you must use the $this pointer ($this->validator_breed($value) === TRUE)).

You have now completed a program that much more secure. Users cannot enter any invalid information. The only field they can attempt to do so is in the dog_name field. However, even if they try to enter program code, or other code, the server-side program will strip out the special characters so the code becomes harmless. If a packet sniffing program tries to change the data before it is received by the server-side program, the validation and/or filtering methods will either cause the data to be rejected or will, again, make the data harmless.

This program is efficient as it tries to validate the information before it is sent to the server. It reduces the amount of communication back and forth between the server and the user. The completed program has two tiers (interface, business rules) and can be expanded to include a third tier (data) without major changes to the current code.

Programming recommendation—For small web applications that are used infrequently it is not necessary to break the program apart, as is done in this example. However, as mentioned, if it is an application that might expand in the future, or might gain significant users in the future, the program should initially be created with this in mind, by breaking the program into tiers.

Do It

Go to the book’s web site and run the example program. See if you can “break” the security built into the program. Remember, you can only attempt to be as secure as possible, nothing is 100% secure. Were you able to send harmful information to the program that affected the program? If so, what did you do? What might be missing from the program that allowed this to happen? If not, what stopped your harmful data from corrupting the program? What changes might you make to this program that would require you to include a data tier? What inefficiencies still exist in the program? What can you do to fix them?

Dependency Injection

As you have seen, when programs are created, a developer goes through many iterations before the final application has been completed. Along the way, experience programmers will keep different versions of their programs. This allows the programmers to back up to a previous version, quickly, if the version they are working on has too many significant problems. Otherwise, they would have to attempt to strip out the “bad” code without doing harm to the good code. Applications have many files (HTML, JavaScript, CSS, PHP classes, and PHP libraries). Keeping track of which version works with which, or easily changing one part of the program to use a new version of another part, can become confusing. Especially when the file names and class names are coded in the code of the program itself.

Chapter 2 briefly discussed dependency injection. It allows the program (client) that will use a block of code (such as a class) to not know the actual implementation of the block of code it will be using. The client program does not know the actual class name.

You can use this idea to help the development process. The example you are about to look at is not for large-scale applications. However, it does give you a chance to look at the benefits of dependency injection. Large-scale applications should use a MVC (Model-View-Control) model or an established tier (or component) system that provides more efficient communication between components.

Security and performance—Many times there is a trade-off between being as secure as possible and having a program that has the best performance possible. The example that follows will make multiple system calls when it checks to see if a program exists and then uses require_once to load the program. The check for file existence allows the program to handle missing files rather than the program just crashing. In a later chapter, you will look at using try/catch blocks to allow the program to capture any problems without crashing the program. This would reduce the number of system calls (you would no longer need to check for the existence of the files), giving the program better performance.

The dog application uses classes and methods contained in different files. This requires the code to also include require_once statements to pull the files into the program. The current design places the actual file name in the require_once statement. This does not allow you to change different versions of the files, unless you change the code. You will now remove these dependencies to provide more flexibility for future development of the application.

Before you get too bogged down with the code, Figure 4-5 shows the flow of the relationship with the programs.

A978-1-4842-1730-6_4_Fig5_HTML.jpg

Figure 4-5.

Data flow for the dog application

The dog_interface.php program will provide the interface for all parts of the dog application. In addition it provides security and filtering as you have already designed in the previous examples. Along with these other activities, dog_interface creates and uses the dog_container object to contain, create, and pass any other objects needed (without knowing the name of the objects). The dog_container object uses an XML file (not shown) to discover the location and name of files containing the classes it will create (providing dependency injection).

The application will always use the dog_interface program to access the other classes. The dog_interface program will determine what classes are needed to accomplish a particular task. Whenever a class is needed, the dog_interface will use the dog_container to determine the name and location of the class (via the XML file), and to create an instance of the class (object). By using an XML file to list the class file names and locations, changes can be made without causing any code changes to programs in the application.

When the breed select box is requested from the lab.html page, the dog_interface program is called. It will create a dog_container object. The dog_container object will discover the location and file name of the get_breeds class file and the breeds XML file. Once it is discovered, thedog_container object will create a get_breeds object. The get_breeds object will then build the code for the select box; eventually returning the code to the form in lab.html for display to the user. All objects (dog_container and get_breeds) are then destroyed (removed from memory).

When the Submit button is clicked on the lab.html form (assuming all validation is passed), it will call the dog_interface program. This program will create the dog_container object. The dog_container object will then discover the location and file name of the dog.php class file. Once discovered, the dog_container object will create the dog object. The dog object will behave exactly as it has in previous examples (validating properties and displaying properties). Once the dog object has completed, the objects (dog_container and dog) are destroyed (removed from memory). This design allows complete independence of the objects providing both two-tier design (interface and business rules) and dependency injection.

Example 4-10. The dog_applications.xml file

<?xml version="1.0" encoding="UTF-8"?>

<dog_applications>

<application>

<type ID="dog">

<location>dog3.php</location>

</type>

</application>

<application>

<type ID="selectbox">

<location>get_breeds2.php</location>

</type>

</application>

<application>

<type ID="breeds">

<location>breeds.xml</location>

</type>

</application>

</dog_applications>

In Example 4-10, you have created a simple XML file that will be used for version changes of the significant files in the PHP application. Each application tag identifies the type of file (dog, select box, breeds). Each location tag within the application tag provides the file name and location (although in this example you have all files in the same location). Once you adjust the program to use this file, you will have the flexibility to change the file names (such as the example using dog3.php instead of dog.php) and the location without having to change any program code. This can help you to swap versions in/out of the application during the development process.

You will now create a Dog_container class that will contain two methods. get_dog_application will be used to “fetch” the name and location of any of the files listed in the XML file. The create_object method will create an instance of either the dog class or the get_breeds class.

Example 4-11. The dog_container.php file

<?php

class Dog_container

{

private $app;

private $dog_location;

function __construct($value)

{

if (function_exists('clean_input'))

{

$this->app = $value;

}

else

{

exit;

} }

public function set_app($value)

{

$this->app = $value;

}

public function get_dog_application()

{

$xmlDoc = new DOMDocument();

if ( file_exists("dog_applications.xml") )

{

$xmlDoc->load( 'dog_applications.xml' );

$searchNode = $xmlDoc->getElementsByTagName( "type" );

foreach( $searchNode as $searchNode )

{

    $valueID = $searchNode->getAttribute('ID');

    if($valueID == $this->app)

    {

    $xmlLocation = $searchNode->getElementsByTagName( "location" );

    return $xmlLocation->item(0)->nodeValue;

    break;

    }

}

}

    return FALSE;

}

function create_object($properties_array)

{

  $dog_loc = $this->get_dog_application();

  if(($dog_loc == FALSE) || (!file_exists($dog_loc)))

  {

    return FALSE;

  }

  else

  {

    require_once($dog_loc);

    $class_array = get_declared_classes();

        $last_position = count($class_array) - 1;

        $class_name = $class_array[$last_position];

        $dog_object = new $class_name($properties_array);

        return $dog_object;

        }

}

}

?>

First, at the top of the class (dog_container), you declare two private properties—$app and $dog_location. These properties are declared as private, instead of public, to keep their values only known within this class.

In the constructor, $value accepts a name of an application type that you want to find in the XML file (such as selectbox). Later in the code, you will compare $value to the type ID in the XML file to see if you can find the application type and a file associated with it. The constructor places $value into the $app property. However, the method also includes an if statement that uses the method function_exists to determine if the clean_input function exists.

Why? At the beginning of the chapter, you briefly looked at code that allowed you to restrict the use of a program to a specific application that has called it. In this example, you look at another technique to restrict which programs can use this class. The if statement demands that any program that makes an instance of this class must also have a clean_input method. If someone tries to make an instance of the program using another program that does not already contain a clean_input method, the else part of the statement will execute, which will cause the object not to be created and will close the program.

Security and performance—Any time a program is accepting information from the Internet, or across a network, it is a good idea to determine the source of the information. In addition to determining application and function names, PHP programs can also look at the source IP addresses.

public function get_dog_application()

{

$xmlDoc = new DOMDocument();

if ( file_exists("dog_applications.xml") )

{

$xmlDoc->load( 'dog_applications.xml' );

$searchNode = $xmlDoc->getElementsByTagName( "type" );

The first part of the get_dog_application method should look familiar. This code opens the dog_applications.xml file (after making sure it exists). Then it loads the contents into $xmlDoc. The last line calls the PHP method getElementsByTagName. This method searches for all occurrences of “type” in $xmlDoc and places each occurrence in $searchNode.

foreach( $searchNode as $searchNode )

{

    $valueID = $searchNode->getAttribute('ID');

    if($valueID == $this->app)

    {

    $xmlLocation = $searchNode->getElementsByTagName( "location" );

    return $xmlLocation->item(0)->nodeValue;

    break;

    }

}

The foreach loop looks at each line contained in $searchNode. It uses the PHP method getAttribute to place the next line with an ID XML attribute into the property $valueID. Once it is placed in $valueID, the value in this property (dog, selectbox, or breeds) is compared to $this->app. (The property app was loaded with a value in the constructor.) If the ID is found in the XML file, getElementsByTagName will search for the next line that contains a location XML tag. The return line then takes the value in the location tag (the file name and its location) and returns it to the program that called this method. The break statement is used to break out of the loop early because you have already returned the value needed in the previous line of code. The else part of the method (shown in Example 4-11) will return FALSE if the XML file does not exist.

function create_object($properties_array)

The create_object method is used to create the dog and get_breeds objects. The dog object constructor was expecting four values (dog_name, dog_weight, dog_breed, and dog_color) in its constructor. The get_breeds app was not accepting any values in its constructor. In order to provide more efficient code in dog_container, you change the signature of the constructor (the top line of the function) of each class to accept an array, instead of individual values. This will allow you to pass any number of items into either constructor.

function __construct($properties_array)

{ // dog class constructor

if (method_exists('dog_container', 'create_object')) {

$name_error = $this->set_dog_name($properties_array[0]) == TRUE ? 'TRUE,' : 'FALSE,';

$breed_error = $this->set_dog_breed($properties_array[1]) == TRUE ? 'TRUE,' : 'FALSE,';

$color_error = $this->set_dog_color($properties_array[2]) == TRUE ? 'TRUE,' : 'FALSE,';

$weight_error= $this->set_dog_weight($properties_array[3]) == TRUE ? 'TRUE' : 'FALSE';

This requires changing these lines in the dog.php file to accept an array and then use the values in the array to set each property.

Notice that $properties_array in the first line does not have anything that declares it as an array (except the name). Remember that PHP properties determine what data type they are by what is passed in the property. The same is true with arrays. If an array is passed into$properties_array, it becomes an array.

The address of the array is passed into the method. The property that accepts the address ($properties_array) actually points to the location of the array in memory. This is very efficient. If you needed to pass 50 items into a method, you could pass them all one at a time with different properties declared in the methods signature for each of these 50 items. However, instead, you can create an array that holds the 50 items and pass the array. You are only passing one value using this approach, which is the address of the array in memory. Also, as noted with this example, using an array allows you to be flexible in the amount of items you want to pass into a method signature.

$name_error = $this->set_dog_name($properties_array[0]) == TRUE ? 'TRUE,' : 'FALSE,';

To copy an item from an array, you refer to the item using the array’s name ($properties_array) and the position that the item exists in the array ([0]). Notice that you use [] brackets for declaring the position. The position is commonly called the subscript. Arrays subscripts begin with position 0, not position 1.

class GetBreeds {

function __construct($properties_array)

{ //get_breeds constructor

if (!(method_exists('dog_container', 'create_object')))

{

exit;

}

}

You must adjust the get_breeds program. GetBreeds is now a class. You also create the signature of the GetBreeds constructor to accept an array. However, as you can see from this code, you actually will ignore anything that is passed into the array. This allows you to use the same method in dog_container to create an object of either class (or actually of any class that accepts an array). All you need to find is the name of the class (dog or GetBreeds) so you can make an instance of it.

function create_object($properties_array)

{

  $dog_loc = $this->get_dog_application();

  if(($dog_loc == FALSE) || (!file_exists($dog_loc)))

  {

    return FALSE;

  }

The create_object method then calls the get_dog_application method and places the value returned (the location of the file and file name) into $dog_loc. If the value in $dog_loc is FALSE or is not an existing file, the method returns FALSE to the program that called it.

else

  {

    require_once($dog_loc);

    $class_array = get_declared_classes();

        $last_position = count($class_array) - 1;

        $class_name = $class_array[$last_position];

        $dog_object = new $class_name($properties_array);

        return $dog_object;

        } } }

?>

If the path and file name are valid, the else portion of the code will execute. The value in $dog_loc is used in the require_once statement (which pulls the contents of the file into this method).

You must now determine the name of the class that exists in the file (dependence injection requires you to not only discover the file names and file path, but also the class names).

The PHP method get_declared_classes returns an array of all the classes that currently exist in the program. The classes are in order from first to last. Thus, since you just included the file with a class (either the dog or get_breeds class), you can hunt for the last entry in the array created. You have placed the array created by get_declared_classes in $class_array. You can now determine the size of the array. The PHP method count will return the size of an array. Remember the size of an array is the number of items in the array not the last position. If an array has a size of ten, the actual subscripts are 0 through 9, not 1 through 10.

$last_position = count($class_array) - 1;

For more information on get_declared _classes, visit

http://php.net/manual/en/function.get-declared-classes.php

With this in mind, this statement determines the size of $class_array and then subtracts 1 from the size and places that value in $last_position. Thus, if the array had a size of 10, the number 9 would be stored in $last_position (since the array subscripts would be 0 through 9, not 10).

$class_name = $class_array[$last_position];

You can then use the value in $last_position to pull the last class created from the array and place it into $class_name. As you can see, you can actually pass the property $last_position between the [] subscript brackets to indicate to the program you want the value of whatever is in the position located in $last_position. This allows you to be able to pull the information from the last position in any size array (since you have no idea of the size of the $class_array).

You can now create an instance of the class, because you have the class name in $class_name.

$dog_object = new $class_name($properties_array);

This line of code will now create an instance of any class (that accepts an array into the constructor) that has just been included (require_once) in the program. The method will create an instance of either the dog class or getBreeds class.

return $dog_object;

Finally, the object (which is either a dog object or a getBreeds object) is returned to the program that called the method. By returning the object, the calling program has complete access to the object and its properties and methods, even though it did not actually create the object (dog_interface can use the object even though dog_container created it).

The object’s location in memory is returned in a similar way as the array’s location was passed into the constructor in the previous example. You can think of it as the new object is temporarily “contained” within the dog_container object. However, the object is returned (to dog_interface).

Programming note—What? What really happens is that the address in memory of the $dog_object is passed to the calling program ( dog_interface ). This allows the calling program to have access to the object, along with the $dog_container object. Thus, there is only one copy of the$dog_object in memory but two different program blocks can use it. If one of the blocks ( dog_container or dog_interface ) closes, the other object still has access to it, until it also closes. Then the garbage collector will remove the $dog_object from memory.

Example 4-12. The get_breeds class

<?php

class GetBreeds {

function __construct($properties_array)

{ //get_breeds constructor

if (!(method_exists('dog_container', 'create_object')))

{ exit;}}

private $result = "??";

public function get_select($dog_app)

{ if (($dog_app != FALSE) && ( file_exists($dog_app))) {

     $breed_file = simplexml:load_file($dog_app);

     $xmlText = $breed_file->asXML();

     $this->result = "<select name='dog_breed' id='dog_breed'>";

     $this->result = $this->result . "<option value='-1' selected>Select a dog breed</option>";

    foreach ($breed_file->children() as $name => $value)

    {    $this->result = $this->result . "<option value='$value'>$value</option>";  }

      $this->result = $this->result . "</select>";

             return $this->result;

    } else {

             return FALSE;

    }

}

}

?>

As you can see from Example 4-12, only minor changes were needed. As mentioned, a class was declared and a constructor was added. The constructor verifies that this class was created from a program that contains both the dog_container and create_breed_app methods. This security attempts to keep other programs from knowing that the file names and locations for the Dog application that reside in the dog_application.xml file.

Example 4-13. The dog_interface.php file

<?php

function clean_input($value) {

$bad_chars = array( "{", "}", "(", ")", ";", ":", "<", ">", "/", "$" );

$value = str_ireplace($bad_chars,"",$value);

$value = htmlentities($value);

$value = strip_tags($value);

        if (get_magic_quotes_gpc())

        { $value = stripslashes($value); }

$value = htmlentities($value);

return $value;

}

function error_check_dog_app($lab) {

list($name_error, $breed_error, $color_error, $weight_error) = explode(',', $lab);

print $name_error == 'TRUE' ? 'Name update successful<br/>' : 'Name update not successful<br/>';

print $breed_error == 'TRUE' ? 'Breed update successful<br/>' : 'Breed update not successful<br/>';

print $color_error == 'TRUE' ? 'Color update successful<br/>' : 'Color update not successful<br/>';

print $weight_error == 'TRUE' ? 'Weight update successful<br/>' : 'Weight update not successful<br/>';

}

function get_dog_app_properties($lab) {

print "Your dog's name is " . $lab->get_dog_name() . "<br/>";

print "Your dog weights " . $lab->get_dog_weight() . " lbs. <br />";

print "Your dog's breed is " . $lab->get_dog_breed() . "<br />";

print "Your dog's color is " . $lab->get_dog_color() . "<br />";

}

//----------------Main Section-------------------------------------

if ( file_exists("dog_container.php"))

{  require_once("dog_container.php"); }

else { print "System Error #1"; exit; }

if (isset($_POST['dog_app']))

  {

if ((isset($_POST['dog_name'])) && (isset($_POST['dog_breed'])) && (isset($_POST['dog_color'])) && (isset($_POST['dog_weight'])))

{     $container = new dog_container(clean_input($_POST['dog_app']));

     $dog_name = clean_input(filter_input(INPUT_POST, "dog_name"));

     $dog_breed = clean_input($_POST['dog_breed']);

     $dog_color = clean_input($_POST['dog_color']);

     $dog_weight = clean_input($_POST['dog_weight']);

     $properties_array = array($dog_name,$dog_breed,$dog_color,$dog_weight);

     $lab = $container->create_object($properties_array);

         if ($lab != FALSE) {

     error_check_dog_app($lab);

     get_dog_app_properties($lab);  }

         else { print "System Error #2"; }

}

else {

print "<p>Missing or invalid parameters. Please go back to the dog.html page to enter valid information.<br />";

print "<a href='dog.html'>Dog Creation Page</a>";

}

}

else

{

     $container = new dog_container("selectbox");

    $lab = $container->create_breed_app();

if ($lab != FALSE) {

        $container = new dog_container("selectbox");

        $properties_array = array("selectbox");

        $lab = $container->create_object($properties_array);

if ($lab != FALSE) {

        $container->set_app("breeds");

        $dog_app = $container->get_dog_application();

        $method_array = get_class_methods($dog_data);

        $last_position = count($method_array) - 1;

        $method_name = $method_array[$last_position];

        $result = $dog_data->$method_name($dog_app);

                  if ( $result == FALSE) {

            print "System Error #3"; //select box not created

          }

          else

          {

             print $result; //pass back select box

           }

         }

         else

         {

         print "System Error #4";

         }

     }

?>

The dog_interface program is actually the lab.php program with code changes in the main section. None of the methods from lab.php have changed.

if ( file_exists("dog_container.php"))

{  require_once("dog_container.php"); }

else { print "System Error #1"; exit; }

if (isset($_POST['dog_app']))

First the program determines if the dog_container exists by using the PHP file_exists method. If it does, it pulls the code into the program using require_once. If dog_container does not exist, the program prints an error message ("System Error #1") and then closes (exit;).

Next, the program uses isset to determine if a value for $dog_app has been provided by the calling program. If this value has been passed, it is an indication that the calling program wants to create a Dog object.

$container = new dog_container(clean_input($_POST['dog_app']));

$dog_name = clean_input(filter_input(INPUT_POST, "dog_name"));

$dog_breed = clean_input($_POST['dog_breed']);

$dog_color = clean_input($_POST['dog_color']);

$dog_weight = clean_input($_POST['dog_weight']);

$properties_array = array($dog_name,$dog_breed,$dog_color,$dog_weight);

     $lab = $container->create_object($properties_array);

         if ($lab != FALSE)

         {

     error_check_dog_app($lab);

     get_dog_app_properties($lab);

         } else {

         print "System Error #2";

         } else {

print "<p>Missing or invalid parameters. Please go back to the lab.html page to enter valid information.<br />";

print "<a href='lab.html'>Dog Creation Page</a>";

} }

The program then creates an instance of dog_container ($container) that passes the value in $dog_app into the $container object. Each of the properties of the Dog object are filtered using the clean_input method. Then the properties are passed into the $properties_array array. The array is then passed into the create_object method of the dog_container object ($container). If the Dog object ($lab) is created successfully then the error_check_dog_app method is called to verify that each property has valid information. The get_dog_app_properties method is called to display each property.

If any of the properties needed for the Dog object are missing, the user is requested to return to the lab.html page to re-enter the required information.

else

{ //get breeds

     $container = new dog_container("selectbox");

     $properties_array = array("selectbox");

     $lab = $container->create_object($properties_array);

if ($lab != FALSE)

         {

      $container->set_app("breeds");

      $dog_app = $container->get_dog_application();

      $method_array = get_class_methods($lab);

       $last_position = count($method_array) - 1;

       $method_name = $method_array[$last_position];

       $result = $lab->$method_name($dog_app);

          if ( $result == FALSE) // select box not created

          {

            print "System Error #3";

          }

          else

          {

             print $result; // select box created!

           }

         }

         else

         {

         print "System Error #4";

         }

If the $dog_app value is not passed in to the class, the else statement is executed. It is assumed that the user wants to create a getBreeds object. An instance of the dog_container is created ($container) and it passes the value selectbox. (If the object can’t be created, "System Error #4" will display). The words “selectbox” are passed into the array $properties_array (Note: The array keyword must be used or you would be creating a property not an array.) The container object ($container) will then call the create_object (passing the $properties_array to create an instance of the getBreeds class ($lab). If the getBreeds object is successfully created ($lab !=FALSE) you then need to find the location of the get_breeds.xml file (which contains the list of breeds). So you reset the app property (by calling set_app) in the container to “breeds”. This tells the container program you are a getBreeds object, not a dog object. You then use the get_dog_application method of the container to find the location of the breeds XML file.

For more information on arrays, visit

Examples: http://php.net/manual/en/function.array.php

Videos: https://www.thenewboston.com/videos.php?cat=11&video=17024

The PHP method get_class_methods is used to create an array of methods contained in getBreeds. Since the get_select method is the only method (besides the constructor), it is also the last method in the array. Its name is pulled from the array and then it is called using the property$method_name ($result = $dog_data->$method_name($dog_app) ). This allows the getBreed class to be completely independent of the dog_interface. The developer can change the name of the get_select method and everything would still work (as long as it’s the last method in the class). This provides a complete split between the interface tier and the business rules tier.

The location of the XML file is passed into the get_select method of the getBreeds object ($lab), which uses the XML file for the data to create the select list box. The code for the select list box is dropped into $result. If the code did get dropped into $result, the code is displayed (print $result) back into the HTML form for the user to select a breed. If the file name was not valid, an error message (print "System Error #3") will display instead of the select box.

The only other changes required are two slight changes to the lab.html and get_breeds.js files.

function AjaxRequest($value)

In the get_breed.js file, the function header for the AjaxRequest method has been changed to pass the actual file being called (this was not a requirement of this design, but it allows this file to be used for any program that is called via AJAX).

xmlHttp.open("GET", $value, true);

In addition, the open statement has been adjusted to use $value instead of a file name.

In the lab.html program, there are a couple of additional changes.

AjaxRequest('dog_interface.php');

The call to the JavaScript function now passes the file name, which has also been changed to the dog_interface.php file.

<form method="post" action="dog_interface.php" onSubmit="return validate_input(this)">

Finally, the action tag (in both form tag locations) for the HTML form has been changed to call the dog_interface.php program.

Notice that now, whenever you want to use the Dog application you call the interface first. Then the interface determines what you want to accomplish (get the breeds select box or process the properties for the dog you are creating).

You must communicate to all of your classes through the interface. The interface, in turn must create any required objects by using the container (except, of course, for the container itself). This follows the concepts of tier design.

You will not see any different output than previously seen (unless you have some system errors). However, now you can easily change file names and locations (via the XML file) in the application without changing any program code!

Do It

1.

Download the files for this section from the book’s web site. Change the file names for the get_breeds.xml file, the get_breeds.php file, and the dog.php file. Try to run the program via the lab.html file. The select box will not display and the program will not run. Now go to thedog_applications.xml file and change the data in the XML file to the new file names you just created. Go back to your lab.html file (reload it). You should now see the select box. Fill in and select the information and click the Submit button. The application should now work.

Chapter Terms

Validate

validator Method

JavaScript Hide/Show

HTML onSubmit

Form Validation

JavaScript Alert Box

HTML Passing “Form”

JavaScript Dot Notation

JavaScript if Statements

JavaScript length Method

&& AND

|| OR

Regular Expression

JavaScript match Method

Filter/Filtering

isset

$_POST

str_ireplace

Stripslashes

htmlentities

strip_tags

$__SERVER

exit

else

HTML Select List

XML

XML Data format

XML Parent-Child

foreach Loop

HTML Radio Buttons

private Function

stristr

Dependency Injection

function_exists

break Statement

method Signature

getElementsByTagName

getAttribute

array

array subscript

get_declared_classes

Count

Size of an Array

Last Position of an Array

array Keyword

Passing Objects

get_class_methods

 

Chapter Questions and Projects

Multiple Choice

1.

When using form validation, which of the following is true?

a.

The server automatically successfully processes input values with no errors.

b.

A required field is checked to make sure it has content.

c.

A dynamic web page is updated.

d.

All information is sent to the server.

2.

Which of the following can be verified with a validator?

a.

E-mails

b.

IP addresses

c.

Integers

d.

All of the above

3.

Why must you validate your code?

a.

To see if your browser can complete a task.

b.

To make sure your information is correct and secure.

c.

To make sure that your browser can run JavaScript and HTML5.

d.

To verify that your computer can run the latest version of PHP.

4.

The verification code in a PHP file does which of the following?

a.

Compares the information received to an expected standard format

b.

Verifies user program interaction

c.

Checks and eradicates harmful data being entered by the user

d.

Checks for incorrect PHP functions being used

5.

stripslashes do which of the following?

a.

Remove backslashes from quotes.

b.

Convert HTML characters to their equivalent HTML entity.

c.

Remove any PHP or HTML tags.

d.

All of the above.

6.

If the size of an array is 29, what is the subscript range?

a.

1 through 30

b.

1 through 29

c.

0 through 29

d.

None of the above

7.

in_array does which of the following?

a.

Searches for the number of empty spaces in an array.

b.

Searches for the number of characters in an array.

c.

Searches for a value in an array.

d.

None of the above.

8.

The PHP method count will return which of the following of an array?

a.

last_position

b.

subscript

c.

size

d.

None of these

9.

Which method will produce a variable that you can use to refer to the last position of the array?

a.

$last_position=count($class_array) - 1;

b.

$class_array=$last_position(count - 1);

c.

$count=$last_position - 1($class_array);

d.

$last_position=$class_array -1 (count);

10.

The exit command does which of the following?

a.

Automatically directs the user to a new page.

b.

Closes the program if it is not called from the correct HTML page.

c.

Turns off your computer.

d.

None of the above.

11.

What is not true in relation to the foreach command?

a.

Works only with arrays and objects.

b.

Used to parse through each key/value pair in an array.

c.

Can be iterated by reference.

d.

The equivalent to an if/then statement.

12.

The break statement does which of the following?

a.

Ends execution of the for, foreach, do-while, and/or switch structure(s).

b.

Executes the for, foreach, do-while, and/or switch structure(s).

c.

Ensures the execution of for, foreach, do-while, and/or switch structure(s).

d.

Breaks the for, foreach, do-while, and/or switch structure(s) before they are executed.

13.

Using the getAttribute will do which of the following?

a.

Return the value of the attribute.

b.

Print a list of data.

c.

Load a new HTML page.

d.

None of these.

14.

Which function converts HTML tags into their entities versions?

a.

strlen

b.

htmlentities

c.

explode

d.

getAttribute

15.

Which is a commonly used function to find the length of a string?

a.

strlen

b.

getLength

c.

String concatenation

d.

__toString

True/False

1.

The count function returns the number of elements in an array.

2.

When using an array, the index must not exceed the size of the array.

3.

A subscript is the name given to position where the item currently exists in the array and is usually contained in [].

4.

private function is an event in PHP to network for a job.

5.

One purpose of exit is to end the program.

6.

The getElementsByTagName searches for occurrences that correspond to a specific XML tag.

7.

get_declared_classes returns an array of all classes that currently exist in a program in order from first to last.

8.

Dependency injection allows the program client to enter a block of code to know the implementation of the block of code it will be using.

Short Answer/Essay

1.

Why should you validate user input both within the interface tier and business rules tier?

2.

Why should input received in the business rules tier be filtered? What are the different ways you can filter the information?

3.

Explain how you can reduce errors from user input by the type of HTML objects (such as radio buttons) used to accept information.

4.

What causes the example code shown in the dependency injection section of this chapter inefficient? How does this code help a developer with version changes to the application?

Projects

1.

Create an application that registers a runner for the local 5K road race. The interface should accept all necessary personal information (name, address, gender, age, and T-shirt size). Whenever possible, use HTML objects that restrict input (such a select object for T-shirt size and state). Validate all information in the interface tier using both HTML5 and JavaScript. If the information is valid, pass the information to the business rules tier. The business rules tier will validate the information received and filter out any harmful information. Once all information has been accepted, the program will display the cost of entering the race ($25). Any shirts over XL will add an additional charge of $2. Any runner 65 or older will be charged $5 less.

2.

Develop the application described in #1 to use dependency injection to allow the developer to change file name and locations without requiring code changes to the application itself.

Term Project

1.

Update the Chapter 3 Term Project to validate all information as it is entered into an HTML form (via HTML and JavaScript as shown in Chapter 4) in the interface tier. After the information is validated it is passed to the business rules tier. The business rules tier will validate the information received and filter out any harmful information. Once the information is accepted (and stored in the properties) the application will display all fields of the product stored in the warehouse of the ABC Computer Parts Company. The interface tier and the business rules tier must be separated using dependency injection (via an XML file), as shown. Your completed project should use logic similar to the examples shown in this chapter.