You are on page 1of 46

Creating a CRUD Application with PHP

Lesson 1: Creating a MySQL Database


This lesson describes the last preliminary step in developing the Wish List application, that of creating a
sample database with test data. To complete the steps in this tutorial, you will need a database in which to
store data of wishers. With the NetBeans IDE you can perform all these activities through the IDE interface.
Before starting, see the tutorial requirements described in Creating a CRUD Application with PHP - Main
page.
Creating the User of the Database
Before you create a database you need to create its User who will be granted the right to perform any
operations on the database. Creating a database User involves:
• Connecting to the MySQL server as the root user.
• Connecting to the MySQL system database as a root user. This step is necessary to enable running an
SQL command for creating a user because you cannot run an SQL command without being
connected to any database.
• Executing a user creation MySQL statement.
1. Start the IDE, switch to the Services window, and expand the Databases node.
2. To connect to the MySQL database server, navigate to the MySQL Server node and from the context
menu choose Connect.

The MySQL Server Properties dialog box appears.


3. If you have not previously configured MySQL, a dialog opens in which you fill in the fields:
○ In the Server host name field, type localhost.
○ In the Server port number field, type 3306.
○ In the Administrator user name field, type root.
○ In the Administrator password field, type the root user's password that you set during the
installation of the MySQL server.
○ Switch on the Save password checkbox and click OK.
The NetBeans IDE connects to the MySQL server, checks for the databases available through the
server, detects the system mysql database, and adds the corresponding new node mysql to the
Databases tree.

4. To execute an SQL command, you need to be connected to a database. Because only the MySQL
system is available, you need to connect to it. To connect to the system database, navigate to the
mysql node and from the context menu choose Connect. If a connection does not already exist, the
New Database Connection dialog box appears. The User Name field is by default filled in with root.
In the Password field, enter the root user's password.
The New Database Connection dialog box shows the message "Connection established." Click OK.
A new node named jdbc:mysql://localhost:3306/mysql is added to the Databases tree.
5. Navigate to the jdbc:mysql://localhost:3306/mysql node and from the context menu choose
Execute Command.

An SQL Command window opens. In the SQL Command window, use syntax similar to the
following statement:
6. CREATE USER 'phpuser'@'localhost'
IDENTIFIED BY '!phpuser'
From the context menu, choose Run Statement. If the command is executed successfully, the Status
bar shows the message: "SQL Statement(s) executed successfully". If another message is displayed,
check the syntax and follow the message hints.
Creating the Sample Database
To create the database:
1. Navigate to the MySQL Server at localhost:3306 node and from the context menu choose Create
Database. The Create MySQL Database dialog box appears. Fill in the fields:
○ In the Database Name field, enter wishlist.
○ Switch on the Grant full access to user checkbox and from the drop down list select
phpuser@localhost phpuser @ localhost Click OK.

The "Grant full access to user" function does not always work. If it does not work, connect to
the database as the root user and send the SQL query GRANT ALL ON wishlist.* TO
phpuser@localhost phpuser @ localhost .
2. The New Database Connection dialog box appears.
Establishing Connection to the Sample Database
In the New Database Connection dialog box, fill in the fields:
1. From the Name drop down list, choose MySQL (Connector/J driver)
2. In the Database URL edit box, specify the host, the port, and the database as follows:
jdbc:mysql://localhost:3306/wishlist
3. In the User Name and Password edit boxes, enter the name and the password specified in section
Creating the Owner (User) of the Database (in our example phpuser and !phpuser respectively).
Click OK. The corresponding new connection node is displayed in the Databases tree.

4. (Optional) Now you can delete the default mysql connection by navigating to the
jdbc:mysql://localhost:3306/ node and choosing Disconnect and then Delete from the context
menu.
Designing the Structure of the Sample Database
To arrange and store all the necessary data you need two tables:
• A wishers table for storing names and passwords of registered users
• A wishes table for storing descriptions of wishes
The wishers table contains three fields:
1. id - the unique ID of a wisher. This field is used as the Primary Key
2. name
3. password

The wishes table contains four fields:


1. id - the unique ID of a wish. The field is used as the Primary Key
2. wisher_id - the ID of the wisher to whom the wish belongs. The field is used as the Foreign Key.
3. description
4. due_date - the date by when the wish is requested
The tables are related through the wisher's ID. All the fields are mandatory except due_date in wishes.
Creating the Tables
1. To connect to the database, on the jdbc:mysql://localhost:3306/wishlist connection, click the
right mouse button and choose Connect from the context menu.
Note: If the menu item is disabled, you are already connected. Continue with step 2.
2. From the same context menu, choose Execute Command. An empty SQL Command window opens.
3. To create the wishers table,
a. Type the following SQL query (note that you need to explicitly set character sets to UTF-8
for internationalization):
b. CREATE TABLE wishers(
c. id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
d. name CHAR(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL
UNIQUE,
password CHAR(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT
NULL
)
Note: You can get a unique auto generated number from MySQL by specifying the
AUTO_INCREMENT property for a field. MySQL will generate a unique number by
incrementing the last number of the table and will automatically add to the auto incremented
field. In our example the ID field is auto incremented.
e. Click the right mouse button on the query and then choose Run Statement from the context
menu.
Note: The default storage engine for MySQL is MyISAM, which does not support foreign
keys. If you want to use foreign keys, consider using InnoDB as the storage engine.
To create the wishes table:
a. Type the following SQL query:
b. CREATE TABLE wishes(
c. id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
d. wisher_id INT NOT NULL,
e. description CHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT
NULL,
f. due_date DATE,
FOREIGN KEY (wisher_id) REFERENCES wishers(id)
)
g. Click the right mouse button on the query and then choose Run Statement from the context menu.
To verify that the new tables are added to the database, switch to the Services window and then navigate to the
jdbc:mysql://localhost:3306/wishlist connection node.
Click the right mouse button and choose Refresh. The nodes wishers and wishes appear in the tree.
Entering the Test Data
To test your application you will need some data in the database. The example below shows how to add two
wishers and four wishes.
1. On the jdbc:mysql://localhost:3306/wishlist connection, click the right mouse button and choose
Execute Command. An empty SQL Command window opens.
2. To add a wisher, use syntax similar to the example below:
3. INSERT INTO wishers (name, password)
VALUES ('Tom', 'tomcat');
Click the right mouse button on the query and from the context menu choose Run Statement.
Note: The statement does not contain a value for the id field. The values are entered automatically
because the field type is specified as AUTO_INCREMENT.
Enter another test wisher:
INSERT INTO wishers (name, password)
VALUES ('Jerry', 'jerrymouse');
4. To add the wishes, use syntax similar to the example below:
5. INSERT INTO wishes (wisher_id, description, due_date)
6. VALUES (1, 'Sausage', 080401);
INSERT INTO wishes (wisher_id, description)
7. VALUES (1, 'Icecream');
INSERT INTO wishes (wisher_id, description, due_date)
8. VALUES (2, 'Cheese', 080501);
INSERT INTO wishes (wisher_id, description)
VALUES (2, 'Candle');
Select the queries, click the right mouse button on each query and from the context menu choose Run
Selection.
Note: You can also execute the queries one after another as described in item 2.
9. To view the test data, click the right mouse button on the relevant table and from the context menu
choose View Data.

Lesson 2: Designing the Application. Reading from the Database


In this lesson you create and configure the PHP project to develop your application, create a list of pages in
the application, and define the relations between them. You will also develop a piece of the basic application
functionality and test it against the data you entered in the sample database in lesson 1.
Creating a PHP Project
For information on creating and configuring a PHP project, see Setting Up a PHP Project.
Defining a Page Flow Diagram
The scope of your application covers the following use cases:

1. The user views the wish list of a person.


2. The user registers as a new wisher.
3. The user logs in and creates her/his wish list.
4. The user logs in and edits his/her wish list.
To cover this basic functionality, you will need to implement the following pages:
1. The "front" page index.php for logging in, registering, and switching to wish lists of
other users.
2. The wishlist.php page for viewing the wish list of a particular wisher.
3. The createNewWisher.php for registering as a wisher.
4. The editWishList.php page for editing a wish list by its owner.
5. The editWish.php page for creating and editing wishes.
Basic Functionality: Viewing the Wish List of a Person
Now that you have finished the preliminary steps, you can start implementing the basic functionality of your
application. Start with viewing the wish list of a wisher. This feature does not involve any validations and
can be easily tested as you have already entered the test data into the database. The feature's functionality
will be implemented on two pages, index.php and wishlist.php.
Create the wishlist.php File
1. Start the NetBeans IDE.
2. Click the right mouse button on the Source files node and from the context menu
choose New > PHP File.
3. On the New PHP File panel, in the File Name: edit box, type wishlist and press Finish.

4. According to your project setup, the index.php file is already created. If not, create it as
described above.
5. Switch to the Projects window, expand your project node, and double click the
index.php file. The index.php file opens in the main IDE editor area. The file contains a
template for entering HTML and PHP code.
Note: You can ignore warnings from the HTML validator.

Transferring Data from index.php to wishlist.php


The index.php file will not contain any PHP code so you can easily remove the following block:

This file is used for two purposes:


• Displaying a page with controls for entering data.
• Transferring the entered data to another page.
These actions are performed using HTML forms. Each form contains:
• A set of fields that correspond to the controls on the page with their types specified
• The destination URL address that corresponds to the page where the entered data must
be transferred.
The data is received and processed on the destination page. In our example, the data is entered on the index
page (index.php) and transferred to the wishlist.php page. You need to implement data transferring in
index.php and data reception in wishlist.php.
Internationalizing the Form
To use international UTF-8 characters, insert the following element inside the <head> element, if it is not
present.
<meta http-equiv="content-type" content="text/html; charset=UTF-8">

HTML Form in index.php


Enter the following code block into the body of index.php:
<form action="wishlist.php" method="GET" name="wishList">
Show wish list of: <input type="text" name="user"/>
<input type="submit" value="Go" />
</form>
The above piece of code consists of the following elements:
• Enclosing tags <form></form>
• The opening <form> tag that contains the action field for entering the name of the file
where the data must be transferred (wishlist.php) and the method to be applied to
transferring data (GET). PHP creates a special array $_GET and populate there values of
the fields from the original form.
• The text that appears on the page: Show wish list of:
• A text input field for entering the name of the user whose wish list one wants to view.
The name ("user") is the key to pick the data on the destination form.
• An input field of the "submit" type with the text "Go". The type "submit" means that the
input field appears on the page as a button and the data is transferred when exactly
this control is affected.

Testing index.php
To test the front index.php page of your application:

1. Click the right mouse button on the Sources node and choose Run Project from the

context menu or click the Run Main Project icon on the toolbar if you have set your
project as Main.
2. In the Show wish list of: edit box, enter Tom and click Go. An empty page with the
following URL appears: http://localhost:90/Lesson2/wishlist.php?user=tom. This URL
indicates that your main page works properly.

Receiving and Processing Data in wishlist.php


1. Double click the wishlist.php file. The template that opens is different from index.php.
Begin and end the file with <html></html> and <body></body> tags as the file will
contain HTML code too.
2. <html>
3. <body>
4. <?php
5. /*
6. * To change this template, choose Tools | Templates
7. * and open the template in the editor.
8. */
9.
10. ?>
11. </body>
</html>
12.To display the title, enter the following code block immediately after the opening
<body> tag, before the generated <?php tag:
Wish List of <?php echo $_GET["user"]."<br/>";?>
The code now looks like this:
<html>
<body>Wish List of <?php echo $_GET["user"]."<br/>";?>

<?php

/*

* To change this template, choose Tools | Templates

* and open the template in the editor.

*/
?>

</body>
</html>
The PHP code block displays the data that is received through the method GET in the field "user".
This data is transferred from index.php where the name of the wish list owner Tom was entered in
the text field "user". Repeat the steps from Testing index.php to see that wishlist.php works properly.

13.Delete the commented section in the template PHP block. Paste the following code
block where the comments were. This code opens the connection to the database.
14.$con = mysql_connect("localhost", "phpuser", "!phpuser");
15.if (!$con) {
16. die('Could not connect: ' . mysql_error());
17.}
mysql_query("SET NAMES 'utf8'");
The code attempts to open a connection to the database and gives an error message if
there is a failure.

18.Beneath the code to open the connection to the database, in the same PHP block, type
or paste the following code. This code retrieves the ID of the wisher whose wish list was
requested:
19.mysql_select_db("wishlist", $con);
20.$wisher = mysql_query("SELECT ID FROM wishers WHERE
name='".mysql_real_escape_string($_GET["user"])."'");
$wisherID = mysql_result($wisher, 0);
The data is selected from the wishlist database through the $con connection. The
selection criterion is the name received from the index.php as "user".
The syntax of a SELECT SQL statement can be briefly described as follows:

○ After SELECT, specify the fields from which you want to get data. An asterisk (*)
stands for all fields.
○ After FROM clause, specify the name of the table from which the data must be
retrieved.
○ The WHERE clause is optional. Specify the filter conditions in it.
Security Note: The $_GET["user"] parameter is escaped in order to prevent SQL injection attacks.
See Wikipedia on SQL injections and the mysql_real_escape_string documentation. Although in
the context of this tutorial you are not at risk of harmful SQL injections, it is best practice to escape
strings in MySQL queries that would be at risk of such an attack.
21.Above the code to retrieve the ID of the wisher, type or paste the following code. This
code kills the process and displays an error message if the requested wisher is not
found in the database:
22.if (mysql_num_rows($wisher)<1) {
23. die("The person " .$_GET["user"]. " is not found. Please check the spelling
and try again" );
}
This PHP block is now complete. The wishlist.php file now looks like this:
<html>

<body>Wish List of <?php echo $_GET["user"]."<br/>";?>

<?php

$con = mysql_connect("localhost", "phpuser", "!phpuser");

if (!$con) {

die('Could not connect: ' . mysql_error());

mysql_query("SET NAMES 'utf8'");

mysql_select_db("wishlist", $con);

$wisher = mysql_query("SELECT ID FROM wishers WHERE


name='".mysql_real_escape_string($_GET["user"])."'");

if (mysql_num_rows($wisher)<1) {

die("The person " .$_GET["user"]. " is not found. Please check the
spelling and try again" );

}
$wisherID = mysql_result($wisher, 0);

?>

</body>

</html>
If you test the application and enter an invalid user, the following message appears.

24.Beneath the PHP block, type or paste the following HTML code block. This code opens a
table, specifies the color of its borders (black), and "draws" the table header with the
columns "Item" and "Due Date."
25.<table border="black">
26. <tr>
27. <th>Item</th>
28. <th>Due Date</th>
29. </tr>
</table>
The </table> tag closes the table.

30.Enter the following PHP code block above the closing </table> tag:
31.<?php
$result = mysql_query("SELECT * FROM wishes WHERE wisher_id=". $wisherID);
while($row = mysql_fetch_array($result)) {
32. $desc = $row["description"];
$dueDate = $row["due_date"];
echo "<tr><td>" . strip_tags($desc,'<br><p><h1>')."</td>";
echo "<td>". strip_tags($dueDate)."</td></tr>\n";
}
mysql_close($con);
?>
Within the code:

○ The SELECT query retrieves the wishes with their due dates for the specified
wisher by his ID, which was retrieved in step 4, and stores the wishes and due
dates in an array $result.
○ A loop displays the items of the $result array as rows in the table while the array
is not empty.
○ The <tr></tr> tags form rows, the <td></td> tags form cells within rows,
and \n starts a new line.
○ The strip_tags function removes any html tags from the displayed description
and date. Note that <br>, <p>, and <h1> tags are allowed in the description.
The strip_tags function cannot accept a variable passed as a reference, which is
why the variables $desc and $dueDate are created.
○ The $con connection to the database is closed.
Note: By default, MySQL is configured to be case sensitive. Make sure you type the names of
database fields exactly as they are specified during the database table creation.
Security note: Strip tags from database entries before displaying them in order to prevent cross-site
scripting. Although this is not a risk in the context of this tutorial, it is best practise to always write
code that is free of vulnerabilities.
33.To test the application, run the project as described in section Testing index.php.

Lesson 3: Creating a New Application User


In this lesson you expand the application with the Create a New Wisher functionality.
The implementation will affect the index.php file and two new files will be created named
createNewWisher.php and editWishList.php.
Adding a Link to Start Creating a New Wisher
Enter the following code block into the body of index.php:

Still don't have a wish list?! <a href="createNewWisher.php">Create now</a>


Where:
• Still don't have a wish list?! is the text that will be displayed on the page next to
the link.
• <a href="createNewWisher.php"></a> is the code that implements a link that opens the
createNewWisher.php page.
• Create now is the text that will be displayed as a link.
Creating New PHP Files
Create two new PHP files in your project's Source Files, as described in Lesson 2.
• createNewWisher.php
• editWishList.php
Leave editWishList.php with its default content. You will modify this file in later lessons, but you need it
to exist now because createNewWisher.php references it. For the remainder of this lesson, you modify
createNewWisher.php.
Adding an HTML Form for Entering the Data of a New Wisher
Type or paste the following HTML block into createNewWisher.php, beneath the PHP block:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
Welcome!<br>
<form action="createNewWisher.php" method="POST">
Your name: <input type="text" name="user"/><br/>
Password: <input type="password" name="password"/><br/>
Please confirm your password: <input type="password"
name="password2"/><br/>
<input type="submit" value="Register"/>
</form>
</body>
</html>
Note: The password type is a special type of a text field where characters are replaced with asterisks. The
code presents an HTML form for a user to enter the name and password of the new wisher in the text fields.
When the user clicks the "Register" button, the entered data is transferred for validation to the same page,
createNewWisher.php.
Note: You can ignore warnings from the HTML validator.
Validating Data and Adding It to the Database
The PHP block must be above all HTML code, empty lines, or whitespace. The position of the PHP code
block is important to enable correct functioning of the redirection statement. Within the PHP block, type or
paste the code blocks described below in this section, in the order they are written.
Add the following code to validate data:
1. Initialize variables. The first variables pass database credentials and the others are the
variables that will be used in the PHP operations.
2. /** database connection credentials */
$dbHost="localhost";
$dbUsername="phpuser";
$dbPasswd="!phpuser";
3.
4. /** other variables */
5. $userNameIsUnique = true;
6. $passwordIsValid = true;
7. $userIsEmpty = false;
8. $passwordIsEmpty = false;
9. $password2IsEmpty = false;
10.

11.Below the variables, add an if clause. The parameter of the if clause checks that the
page was requested from itself via the POST method. If not, the further validations are
not performed and the page is shown with empty fields as described above.
12.if ($_SERVER["REQUEST_METHOD"] == "POST") {
13.
}
14.Within the curly braces of the if clause, add another if clause that checks whether
the user has filled in the wisher's name. If the text field "user" is empty, the value of
$userIsEmpty is changed to true.
15.if ($_SERVER["REQUEST_METHOD"] == "POST") {
16.
17.
18. if ($_POST["user"]=="")
19. $userIsEmpty = true;
}
20.Add code that establishes a database connection. If the connection cannot be
established, the MySQL error is sent to the output.
21.if ($_SERVER["REQUEST_METHOD"] == "POST") {
22.
23.
24. if ($_POST["user"]=="") {
25. $userIsEmpty = true;
26. }
27.
28. $con = mysql_connect("localhost", "phpuser", "!phpuser");
29. if (!$con) {
30. die('Could not connect: ' . mysql_error());
31. }
32. mysql_query("SET NAMES 'utf8'");
}
33.Add code that checks whether a user whose name matches the "user" field already
exists. The code does this by trying to find a wisher ID number for a name matching the
name in the "user" field. If such an ID number exists, the value of $userNameIsUnique is
changed to "false."
34.if ($_SERVER["REQUEST_METHOD"] == "POST") {
35.

36. if ($_POST["user"]=="") {
37. $userIsEmpty = true;
38. }

39.

40. $con = mysql_connect("localhost", "phpuser", "!phpuser");


41. if (!$con) {
42. die('Could not connect: ' . mysql_error());
43. }

44. mysql_query("SET NAMES 'utf8'");

45. mysql_select_db("wishlist", $con);


$wisher = mysql_query("SELECT id FROM wishers WHERE name='".
$_POST["user"]."'");
$wisherIDnum=mysql_num_rows($wisher);
if ($wisherIDnum) {
$userNameIsUnique = false;
}
}
46.Add an if clause that checks whether the user entered and confirmed a password
correctly. The code checks that the Password ("password") and Confirm Password
('password2) fields are not empty in the form and that they are identical. Otherwise the
values of the corresponding boolean variables are changed accordingly.
47.if ($_SERVER["REQUEST_METHOD"] == "POST") {
48.

49. if ($_POST["user"]=="") {
50. $userIsEmpty = true;
51. }

52.

53. $con = mysql_connect("localhost", "phpuser", "!phpuser");


54. if (!$con) {
55. die('Could not connect: ' . mysql_error());
56. }
57. mysql_query("SET NAMES 'utf8'");
58.

59. mysql_select_db("wishlist", $con);


$wisher = mysql_query("SELECT id FROM wishers WHERE name='".
$_POST["user"]."'");
$wisherIDnum=mysql_num_rows($wisher);
if ($wisherIDnum) {
$userNameIsUnique = false;
}

if ($_POST["password"]=="")
$passwordIsEmpty = true;
if ($_POST["password2"]=="")
$password2IsEmpty = true;
if ($_POST["password"]!=$_POST["password2"]) {
$passwordIsValid = false;
}

}
60. Complete the if clause by adding code that inserts a new entry into the "wishers" database. The
code checks that the name of the wisher is specified uniquely and that the password is entered and
confirmed validly. If the conditions are met, the code takes the "user" and "password" values from
the HTML form and inserts them into the Name and Password columns, respectively, of a new row
in the wishers database. After creating the row, the code closes the database connection and redirects
the application to the page editWishList.php.
61.if ($_SERVER["REQUEST_METHOD"] == "POST") {
62.

63. if ($_POST["user"]=="") {
64. $userIsEmpty = true;
65. }

66.

67. $con = mysql_connect("localhost", "phpuser", "!phpuser");


68. if (!$con) {
69. die('Could not connect: ' . mysql_error());
70. }

71. mysql_query("SET NAMES 'utf8'");

72.

73. mysql_select_db("wishlist", $con);


$wisher = mysql_query("SELECT id FROM wishers WHERE name='".
$_POST["user"]."'");
$wisherIDnum=mysql_num_rows($wisher);
if ($wisherIDnum) {
$userNameIsUnique = false;
}

if ($_POST["password"]=="")
$passwordIsEmpty = true;
if ($_POST["password2"]=="")
$password2IsEmpty = true;
if ($_POST["password"]!=$_POST["password2"]) {
$passwordIsValid = false;
}

74. if (!$userIsEmpty && $userNameIsUnique && !$passwordIsEmpty && !


$password2IsEmpty && $passwordIsValid) {

mysql_select_db("wishlist", $con);
mysql_query("INSERT wishers (name, password) VALUES ('".
$_POST["user"]."', '".$_POST["password"]."')");
mysql_close($con);
header('Location: editWishList.php' );
exit;
}
}
Displaying Error Messages in the Input Form
Now you implement the display of error messages when the entered data is invalid. The implementation is
based on the validations and changes to the values of the boolean variables described in Validating Data and
Adding It to the Database.
1. Enter the following PHP code block inside the HTML input form, below the wisher's
name input:
2. Welcome!<br>
<form action="createNewWisher.php" method="POST">
Your name: <input type="text" name="user"/><br/>
3.
4.

5. <?php
6. if ($userIsEmpty) {
7. echo ("Enter your name, please!");
8. echo ("<br/>");
9. }
10. if (!$userNameIsUnique) {
11. echo ("The person already exists. Please check the spelling and try
again");
12. echo ("<br/");
13. }
?>
14.Enter the following PHP code block inside the HTML input form below the code for the
password input:
15.Password: <input type="password" name="password"/><br/>
16.

17.<?php
18. if ($passwordIsEmpty) {
19. echo ("Enter the password, please!");
20. echo ("<br/>");
21. }
?>
22.Enter the following PHP code blocks inside the HTML input form below the code for
password confirmation:
23.Please confirm your password: <input type="password" name="password2"/><br/>
24.
25.
26.

27.<?php
28. if ($password2IsEmpty) {
29. echo ("Confirm your password, please");
30. echo ("<br/>");
31. }
32. if (!$password2IsEmpty && !$passwordIsValid) {
33. echo ("The passwords do not match!");
34. echo ("<br/");
35. }
?>

Testing the Create New Wisher Functionality


1. Run the application. The index page opens.
2. On the index page, click the link next to the text Still don't have a wish list? The
following form opens:

3. Leave only the Your name field empty and click Register. An error message displays.

4. Enter the name of a registered wisher, for example, Tom in the Your name field, fill in
the other fields correctly, and click Register. An error message displays.
5. Fill in the Password and Please confirm your password fields with different values and
click Register. An error message displays.
6. Enter Bob in the Your name field, specify the same password in both password fields
and click Register. The page that opens is empty but the redirection passed correctly as
the URL ends with editWishList.php:
7. To check that the data is stored in the database, navigate to wishers on the Services
window below the wislist1 node and from the context menu choose View Data

Lesson 4: Optimizing the Code with Classes and Objects


In this lesson you optimize the code to facilitate maintaining it in the future. This affects the files
createNewWisher.php and wishlist.php. Additionally, a new file called db.php is created.
Your application's code contains several similar blocks with queries to the database. To make the code easier
to read and maintain in the future, you can extract these blocks, implement them as functions of a separate
class called WishDB, and place WishDB in db.php. Afterwards you can include the db.php file in any PHP
file and use any function from WishDB without code duplication. Such an approach ensures that any
changes to queries or functions will be made in one place and you will not have to parse the entire
application code.
When you use a function from WishDB, you do not change the value of any of WishDB's variables. Instead,
you use the WishDB class as a blueprint for creating an object of WishDB, and you change the values of
variables in that object. When you finish working with that object, it is destroyed. Because the values of the
WishDB class itself are never changed, you can reuse the class an unlimited number of times. In some cases
you may want to have multiple instances of a class in existance at the same time, and in other cases you may
prefer a "singleton" class, where you only have one instance in existance at any one time. WishDB in this
tutorial is a singleton class.
Note that the term for creating an object of a class is "instantiating" that class, and that another word for an
object is an "instance" of a class. The general term for programming with classes and objects is "object-
oriented programming," or OOP. PHP 5 uses a sophisticated OOP model. See php.net for more information.
Creating the db.php File
Create a new subfolder in the Source Files folder. Name the folder Includes. Create a new file named db.php
and place it in Includes. Later you can add more files to this folder that will be included in other PHP files.
To create db.php in a new folder:
1. Click the right mouse button on the Source files node and choose New > Folder from
the context menu. The New Folder dialog opens.
2. In the Folder Name field, type Includes. Then click Finish.
3. Click the right mouse button on the Includes node and choose New > PHP File from the
context menu. The New PHP File dialog opens.
4. In the File Name field, type db. Then click Finish.
Creating the WishDB Class
To create the WishDB class, you need to initialize the variables of the class and implement a constructor of
the class.
Open the file db.php and type the following code in it:

<?php
class WishDB {

// single instance of self shared among all instances


private static $instance = null;

// db connection config vars


private $user = "phpuser";
private $pass = "!phpuser";
private $dbName = "wishlist";
private $dbHost = "localhost";
private $con = null;

}
?>
The object (or "instance") of the WishDB class is stored in the $instance variable. In the code above, it is
declared null. You also declare database configuration variables for storing the name and password of the
database owner (user), the name of the database, and the database host. All these variable declarations are
"private," meaning that the initial values in the declarations cannot be accessed from outside the WishDB
class (See php.net).
Instantiating the WishDB class
For other PHP files to use functions in the WishDB class, these PHP files need to call a function that creates
an object of ("instantiates") the WishDB class. WishDB is designed as a singleton class, meaning that only
one instance of the class is in existance at any one time. It is therefore useful to prevent any external
instantiation of WishDB, which could create duplicate instances.
Inside the WishDB class, type or paste the following code:
//This method must be static, and must return an instance of the object if the object
//does not already exist.
public static function getInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}

// The clone and wakeup methods prevents external instantiation of copies of the
Singleton class,
// thus eliminating the possibility of duplicate objects.
public function __clone() {
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
public function __wakeup() {
trigger_error('Deserializing is not allowed.', E_USER_ERROR);
}
The getInstance function is "public" and "static." "Public" means that it can be freely accessed from
outside the class. "Static" means that the function is available even when the class has not been instantiated.
As the getInstance function is called to instantiate the class, it must be static.
The double-colon (::), called the Scope Resolution Operator, and the self keyword are used to access static
functions. Self is used from within the class definition to refer to the class itself. When the double-colon is
used from outside the class definition, the name of the class is used instead of self. See php.net on the
Scope Resolution Operator.
Adding a Constructor to the WishDB Class
A class can contain a special method known as a 'constructor' which is automatically processed whenever an
instance of that class is created. In this tutorial, you add a constructor to WishDB that connects to the
database whenever WishDB is instantiated.
Add the following code to WishDB:
// private constructor
private function __construct() {
$this->con = mysql_connect($this->dbHost, $this->user, $this->pass)
or die ("Could not connect to db: " . mysql_error());
mysql_query("SET NAMES 'utf8'");
mysql_select_db($this->dbName, $this->con)
or die ("Could not select db: " . mysql_error());
}
Note the use of the pseudovariable $this instead of the variables $con, $dbHost, $user, or $pass. The
pseudovariable $this is used when a method is called from within an object context. It refers to the value of
a variable within that object.
Functions in the WishDB Class
In this lesson you will implement the following functions of the WishDB class:
• get_wisher_id_by_name for retrieving the id of a wisher based on the wisher's name
• get_wishes_by_wisher_id for retrieving a list of wishes of the wisher with a specific id
• create_wisher for adding a new wisher record to the table wishers

Function get_wisher_id_by_name
The function requires the name of a wisher as the input parameter and returns the wisher's id.

Type or paste the following function into the WishDB class, after the WishDB function:

public function get_wisher_id_by_name ($name) {


$name = mysql_real_escape_string($name);
$result = mysql_query("SELECT id FROM wishers WHERE name = '" . $name . "'");
if (mysql_num_rows($result) > 0)
return mysql_result($result, 0);
else
return null;
}
The code block executes the query "SELECT ID FROM wishers WHERE Name = '" . $name . "'",
where $name is the name of the wisher. The query result is an array of id's from the records
that meet the query. If the array is not empty this automatically means that it contains one
element because the field name is specified as UNIQUE during the table creation. In this case
the function returns the first element of the $result array (the element with the zero
numbered). If the array is empty the function returns null.

Security Note: The $name string is escaped in order to prevent SQL injection attacks. See Wikipedia on
SQL injections and the mysql_real_escape_string documentation. Although in the context of this tutorial
you are not at risk of harmful SQL injections, it is best practice to escape strings in MySQL queries that
would be at risk of such an attack.
Function get_wishes_by_wisher_id
The function requires the id of a wisher as the input parameter and returns the wishes registered for the
wisher.
Enter the following code block:

public function get_wishes_by_wisher_id($id) {


return mysql_query("SELECT * FROM wishes WHERE wisher_id=" . $id);
}
The code block executes the query "SELECT * FROM wishes WHERE wisher_id=" . $id and
returns a resultset which is an array of records that meet the query. The selection is
performed by the wisher_id, which is the foreign key for the table wishes.

Function create_wisher
The function creates a new record in the wishers table. The function requires the name and password of a
new wisher as the input parameters and does not return any data.
Enter the following code block:

public function create_wisher ($name, $password){


$name = mysql_real_escape_string($name);
$password = mysql_real_escape_string($password);
mysql_query("INSERT INTO wishers (name, password) VALUES ('" . $name . "', '" .
$password . "')");
}
The code block executes the query "INSERT wishers (Name, Password) VALUES ('".$name."',
'".$password."')", where $name is the name of the new wisher and $password is the wisher's
password. The query adds a new record to the "wishers" table with the fields "name" and
"password" filled in with the values of $name and $password respectively.

Refactoring Your Application Code


Now that you have a separate class for working with the database, you can replace duplicated blocks with
calls to the relevant functions from this class. This will help avoid misspelling and inconsistency in the
future. Code optimization that does not affect the functionality is called refactoring.
Refactoring the wishlist.php File
Start with the wishlist.php file because it is short and the improvements will be more
illustrative.

1. At the top of the <?php ?> block, enter the following line to enable the use of the
db.php file:
require_once("Includes/db.php");
2. Replace the following code block:
3. $con = mysql_connect("localhost", "phpuser", "!phpuser");
4. if (!$con) {
5. die('Could not connect: ' . mysql_error());
6. }
7.
8. mysql_query("SET NAMES 'utf8'");
9. mysql_select_db("wishlist", $con);
10.$wisher = mysql_query("SELECT ID FROM wishers WHERE
name='".mysql_real_escape_string($_GET["user"])."'");
11.if (mysql_num_rows($wisher)<1) {
12. die("The person " .$_GET["user"]. " is not found. Please check the spelling
and try again" );
13.}
$wisherID = mysql_result($wisher, 0);
with the following lines of code:
$wisherID = WishDB::getInstance()->get_wisher_id_by_name($_GET["user"]);
if (!$wisherID) {
die("The person " .$_GET["user"]. " is not found. Please check the spelling
and try again" );
}
This code first calls the getInstance function in WishDB. getInstance returns an instance of
WishDB, and the code calls the get_wisher_id_by_name function within that instance. If the
requested wisher is not found in the database, the code kills the process and displays an error
message.
No code is necessary here for opening a connection to the database. The connection is opened by the
constructor of the WishDB class. If the name and/or password changes, you need to update only the
relevant variables of the WishDB class.
14.Replace the following code:
$result = mysql_query("SELECT * FROM wishes WHERE Wisherid=". $wisherID);
with a call of the function get_wishes_by_wisher_id:

$result = WishDB::getInstance()->get_wishes_by_wisher_id($wisherID);

15.Remove the following line:


mysql_close($con);
The code is not necessary because the connection to the database is automatically
closed as soon as the WishDB object is destroyed.

Refactoring the createNewWisher.php File


Refactoring will not affect the HTML input form or the code for displaying the related error messages.
1. At the top of the <?php?> block, enter the following code to enable the use of the
db.php file:
require_once("Includes/db.php");
2. Replace the following code block:
3. $con = mysql_connect($dbHost, $dbUsername, $dbPasswd);
4. if (!$con) {
5. die('Could not connect: ' . mysql_error());
6. }
7. mysql_query("SET NAMES 'utf8'");
8.
9. mysql_select_db("wishlist", $con);
10.$wisher = mysql_query("SELECT id FROM wishers WHERE name='".$_POST["user"]."'");
11.$wisherIDnum=mysql_num_rows($wisher);
12.if ($wisherIDnum) {
13. $userNameIsUnique = false;
14.}

with code that calls that gets an instance of WishDB and calls the
get_wisher_id_by_name function from that instance:

$wisherID = WishDB::getInstance()->get_wisher_id_by_name($_POST["user"]);
if ($wisherID) {
$userNameIsUnique = false;
}
The WishDB object exists as long as the current page is being processed. It is destroyed
after the processing is completed or interrupted. The code for opening a connection to
the database is not necessary because this is done by the WishDB function. The code
for closing the connection is not necessary because the connection is closed as soon as
the WishDB object is destroyed.

15.Replace the following code block:


16.if (!$userIsEmpty && $userNameIsUnique && !$passwordIsEmpty && !$password2IsEmpty
&& $passwordIsValid) {
17. mysql_select_db("wishlist", $con);
18. mysql_query("INSERT wishers (name, password) VALUES ('".$_POST["user"]."',
'".$_POST["password"]."')");
19. mysql_close($con);
20. header('Location: editWishList.php' );
21. exit;
}
with:

if (!$userIsEmpty && $userNameIsUnique && !$passwordIsEmpty && !$password2IsEmpty


&& $passwordIsValid) {
WishDB::getInstance()->create_wisher($_POST["user"], $_POST["password"]);
header('Location: editWishList.php' );
exit;
}

Lesson 5: Adding Security. Implementing Application User Logon


In this lesson you implement the logon functionality for a wisher. This affects the following files:
• index.php
• createNewWisher.php
• editWishlist.php
• db.php
Implementing the Logon functionality consists of the following steps:
• Saving the wisher's ID in the Session upon the creation of a wisher
• Validating that the user who attempts to edit a wish list is logged in
• Logging on wisher from the index.php page
Saving the Wisher's ID in the Session Upon Creation
A Session is a persistent storage for transferring information from one page to another without using an
HTML input form. This functionality is supported through a predefined PHP array $_SESSION.
For the sake of security, after a new wisher is created he should be logged on automatically without filling in
a form. Therefore you need to modify the createNewWisher.php file to implement the following
functionality:
• Add a new wisher to the database.
• Open a session.
• Store the wisher's name in the session.
• Transfer the wisher's name in the session when the wisher is redirected to the
editWishList.php page.
In the createNewWisher.php file, locate the line:
WishDB::getInstance()->create_wisher($_POST["user"], $_POST["password"]);
and enter the following code block right below:

session_start();
$_SESSION["user"] = $_POST["user"];
The code block starts a session, which means opening the $_SESSION array for entering or
retrieving data. Then the code adds an element to the $_SESSION array. The added element
contains a value and an identifier (key). The value is the name of the newly created wishers
and the identifier is "user". Then the program redirects the wisher to the editWishList.php
page.

Validating User Logon


When a user reaches the editWishList.php page the application should confirm that the page is accessed
by the same person who was just registered on the createNewWisher.php page.
Implementing this functionality consists of two steps:
• Retrieving the wisher's name from the Session
• Redirecting the user to the index.php if retrieving the wisher's name from the Session
failed

Retrieving the Wisher's Name from the Session


Replace the default code in the PHP block of editWishList.php with the following:

session_start();
if (array_key_exists("user", $_SESSION)) {
echo "Hello " . $_SESSION["user"];
}
The code block opens the $_SESSION array for retrieving data and verifies that $_SESSION contains an
element with the identifier "user". If the check is successful, the code prints a welcome message.
To check that the session is implemented correctly:

1. Run the createNewWisher.php file and create a new wisher, for example Jack.
The editWishList.php opens with Hello Jack.
2. Clear session cookies in your browser or end the session and run editWishList.php from
the IDE.
The editWishList.php file opens with Hello because no user has been transferred
through a session. This is not correct because it enables someone who is not logged in
and not registered to create or edit a wish list. In order to avoid this, the user needs to
be redirected to the index.php page.

Redirecting a User Who Is Not Logged In


Add the following code block to editWishList.php, below the if clause:

else {
header('Location: index.php');
exit;
}
The code redirects the user to the index.php page and cancels PHP code execution.
To check that the functionality is implemented correctly, run the editWishList.php file. The
expected result is that the index.php page opens.

Logging In from the index.php Page


The logon from the index.php page consists of two steps:
• Entering the user's name and password in an HTML input form and submitting the data
for validation to the index.php page.
• Validating the logon

HTML Form for Logon on index.php


In the index.php file, enter the following code before the closing </body> tag:

<form name="logon" action="index.php" method="POST" >


Username: <input type="text" name="user"/>
Password <input type="password" name="userpassword"/>
<input type="submit" value="Edit My Wish List"/>
</form>
Note: You can ignore warnings from the HTML validator.
The code presents an HTML form that enables entering the name and password of the user in
the text fields. When the user clicks Edit My Wish List, the data is transferred to the same
page, index.php.
Logon Validation
Logon validation involves:
• Checking where the user was redirected from.
• Verifying the user's name and password.
• Saving the user name to the Session and redirecting the user to the editWishList.php
page or Displaying an error message.

Source of Redirection
A user may access the index.php page on starting the application, or from the editWishList.php page, or
when redirected from the index.php page after entering name and password.
Because only in the last case is the HTML request method POST used, you can always learn where the user
was located when they accessed index.php.
In the index.php file, create a <?php ?> block above the HTML block, with the following code:

<?php

require_once("Includes/db.php");

$logonSuccess = true;

// verify user's credentials


?>
The code block enables the use of the db.php file and initializes the $logonSuccess variable,
which will be used later to display error messages.

Verifying the User's Credentials


Replace the comment // verify user's credentials with the following code block:

if ($_SERVER["REQUEST_METHOD"] == "POST"){

if (WishDB::getInstance()->verify_wisher_credentials($_POST["user"],
$_POST["userpassword"]) == 1) {
session_start();
$_SESSION["user"] = $_POST["user"];
header('Location: editWishList.php');
} else {
$logonSuccess = false;
}
}
If the request method is POST, which means that the user was redirected from the index.php page, the code
block calls the verify_wisher_credentials function with the name and password entered during logon.
If the verify_wisher_credentials function returns 1, which means that a wisher with the specified
combination of name and password is registered in the database, the $_SESSION array is opened for entering
data. Then a new element is added to the $_SESSION array. The element contains a value and an identifier
(key). The value is the name of the wisher and the identifier is "user". Then the user is redirected to the
editWishList.php page in order to edit the wish list.
If the verify_wisher_credentials function does not return 1, the value of the $logonSuccess variable is
changed to false. The value of the variable is used in displaying an error message.
Function verify_wisher_credentials
In order to implement verification of the wisher's credentials, you need to add a new function to the WishDB
class in the db.php file. The function requires a name and a password as the input parameters and returns 0
or 1.
Enter the following code block:
public function verify_wisher_credentials ($name, $password){
return mysql_num_rows(mysql_query("SELECT * FROM wishers
WHERE name = '" . $name . "' AND password = '" . $password . "'"));
}
The code block executes the query "SELECT * FROM wishers WHERE Name = '" . $name . "'
AND Password = '" . $password . "'" and returns the number of records that meet the
specified query. 1 is returned if such record is found and 0 is returned if there is no such
record in the database.

Displaying Error Messages


In order to enable the application to display error messages, enter the following <? php ?>
code block into the logon form in index.php, below the input fields but above the button:

<?php
if (!$logonSuccess)
echo "Invalid name and/or password";
?>
The code block checks the value of the $logonSuccess variable and if it is false, displays an
error message.

Testing the Logon from the index.php Page


To check that the logon functionality works correctly on the index.php front page:

1. Run the application.


2. On the index.php page, enter Tom in the Username edit box and Tim in the Password
edit box.
3. Press Edit My Wish List. An error message is displayed:

4. Enter Tom in the Username edit box and tomcat in the Password edit box.
5. Press Edit My Wish list. The editWishList.php page is displayed:

Lesson 6: Writing a New Entry into the Database


In this lesson you expand the application functionality with two features:
• Adding a new wish
• Returning to the front index.php page
The implementation affects the editWishList.php file and a new file editWish.php is created.
Submitting a New Wish
The user submits a new wish in the following steps:
1. The user logs in, switches to the editWishList.php page, and presses the Add Wish
button. The editWish.php page opens, displaying an HTML form.
2. In the HTML form, the user enters a description of a wish and possibly the date by when
he/she wants it and presses the Save Changes button.
3. If a form is submitted without a description of the wish, the user is returned to the form
to try again. If the user submitted a due date but no description, that date is
redisplayed when the form reloads.
To enable this procedure for the user, you add the following functionality to the application:
• User interface components, consisting of an HTML form for adding wishes and a button
in editWishList.php that redirects the user to the form.
• Code for redisplaying the due date if an incomplete form is submitted.

Adding the User Interface Components


To add functionality for adding a new wish:
1. Implement the Add Wish button. In the editWishList.php file, enter the following HTML
form below the PHP block:
2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
3. <html>
4. <head>
5.
6. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
7. </head>
8. <body>
9. <form name="addNewWish" action="editWish.php">
10. <input type="submit" value="Add Wish"/>
11. </form>
12. </body>
</html>
Note: You can ignore warnings from the HTML validator.
The form contains an "Add Wish" input field of the submit type. This field implements the "Add
Wish" button. When the user clicks Add Wish, they are redirected to the editWish.php page.
Because no data is transferred through this form, no Server Request method is used.
13.Add a table above the Add Wish button that displays the existing wishes for the wisher.
Type or paste the following code (similar to wishlist.php):
<table border="black">
<tr><th>Item</th><th>Due Date</th></tr>
<?php
require_once("Includes/db.php");
$wisherID = WishDB::getInstance()-
>get_wisher_id_by_name(mysql_real_escape_string($_SESSION["user"]));
$result = WishDB::getInstance()->get_wishes_by_wisher_id($wisherID);
while($row = mysql_fetch_array($result)) {
strip_tags($row["description"],'<br><p><h1>');
echo "<tr><td>" . $row["description"]."</td>";
strip_tags($row["due_date"],'<br><p><h1>');
echo "<td>".$row["due_date"]."</td>";
echo "</tr>\n";
}
?>
</table>
14.Create the editWish.php file in the Source Files folder.
15.In editWish.php, implement the Add Wish form. Type or paste the following code below
the <? php ?> block:
16.<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
17.
18.<html>
19. <head>
20.
21. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
22. </head>
23. <body>
24. <form name="editWish" action="editWish.php" method="POST">
Describe your wish: <input type="text" name="wish" value="" /><br/>
When do you want to get it? <input type="text" name="dueDate"
value=""/><br/>
<input type="submit" name="saveWish" value="Save Changes"/>
<input type="submit" name="back" value="Back to the List"/>
25. </form>
26. </body>
</html>
The Add Wish form contains:
• Two empty text fields for entering the wish description and due date.
• The texts to be printed next to the input fields.
• A submit field that represents a Save Changes button
• A submit field that represents a Back to the List button for returning to the
editWishList.php page
Upon pressing the Add Wish button, the form submits the entered data to the same page, editWish.php,
through the Request method POST.
Redisplaying the Due Date after an Unsuccessful Submission
If the user does not fill in a description in the Add Wish form, an error message is displayed and the user
returns to the editWish.php page. When the user returns to editWish.php, the Add Wish form should
show the value of dueDate if it was entered. In the current implementation of the form, both fields are
always empty. To keep entered values, you need to save the data of the new wish in an array. The array will
consist of two elements named description and due-date. You then need to change the Add Wish form so
it retrieves the value of the dueDate field from the array.
Note: The code that reloads the input form if no description is entered is included in the code that validates
the data and enters it to the database. This code is not described in this section. The code in this section only
preserves the value of dueDate so that it is displayed if the form is reloaded .
To redisplay the input form after the user submits it unsuccessfully:
1. Type or paste the following code block inside the HTML <body> element of
editWish.php, directly above the input form:
2. <?php
3. if ($_SERVER["REQUEST_METHOD"] == "POST")
$wish = array("description" => $_POST["wish"],
"due_date" => $_POST["dueDate"]);
else
$wish = array("description" => "",
"due_date" => "");
?>
The code checks which Request Server method was used for transferring the data and creates an
array named $wish. If the method is POST, which means that the input form is displayed after an
unsuccessful attempt to save a wish with an empty description, the elements description and
due_date accept the values transferred through POST.
If the method is not POST, which means that the input form is displayed for the first time after
redirection form the editWishList.php page, the elements description and due_date are empty.
Note: In either case the description is empty. The difference is only in the dueDate.
4. Update the Add Wish form so that the values of its input fields are retrieved from the
$wish array. Replace the lines in the Add Wish form:
5. Describe your wish: <input type="text" name="wish" value="" /><br/>
When do you want to get it? <input type="text" name="dueDate" value=""/><br/>
with:

Describe your wish: <input type="text" name="wish" value="<?php echo


$wish['description'];?>" /><br/>
When do you want to get it? <input type="text" name="dueDate" value="<?php echo
$wish['due_date']; ?>"/><br/>
Verifying the Wisher's Logon
In the editWish.php file, enter the following session handling code inside the <? php ?> block
at the top of the file:

session_start();
if (!array_key_exists("user", $_SESSION)) {
header('Location: index.php');
exit;
}
The code:

• Opens the $_SESSION array for retrieving data..


• Verifies that the array $_SESSION contains an element with the identifier "user".
• If the check fails, which means that the user is not logged on, redirects the application
to the front index.php page and cancels the PHP processing.
To check that session handling works correctly, run the editWish.php file from the IDE. The index.php page
opens, because no user has been transferred to the editWish.page through a session.
Inserting the New Wish to the Database
After the user submits a new wish, the application needs to add the wish to the "wishes" database. To enable
this functionality, add the following code to the application:
• Add two more auxiliary functions to the WishDB class in db.php.
○ One function adds a new record to the wishes table.
○ The other function converts dates into the format that the MySQL databases
server supports.
• Add code to editWish.php that will use the new auxilliary functions in WishDB to enter
the new wish into the database.

Adding the insert_wish Function to WishDB


This function requires the wisher's id, a description of the new wish, and the due date of the wish as the
input parameters and enters this data to the database in a new record. The function does not return any
values.
Open db.php and type or paste the following code into the WishDB class:
function insert_wish($wisherId, $description, $duedate){
$description = mysql_real_escape_string($description);
return mysql_query("INSERT INTO wishes (wisher_id, description, due_date)" .
" VALUES (" . $wisherId . ", '" . $description . "', "
. $this->format_date_for_sql($duedate) . ")");
}
The code calls the function format_date_for_sql to convert the entered due date into a format
that can be processed by the MySQL server. Then the query INSERT INTO wishes (wisher_id,
description, due_date)is executed to enter the new wish to the database.
Adding the format_date_for_sql Function to WishDB
The function requires a string with a date as the input parameter. The function returns a date in the format
that can be processed by the MySQL database server or null if the input string is empty.
Type or paste the following code into the WishDB class:

function format_date_for_sql($date){
if ($date == "")
return "NULL";
else {
$dateParts = date_parse($date);
return $dateParts["year"]*10000 + $dateParts["month"]*100 + $dateParts["day"];
}

}
If the input string is empty, the code returns NULL. Otherwise, the internal date_parse function
is called with the $date as the input parameter. The date_parse function returns an array that
consists of three elements named $dateParts["year"], $dateParts["month"], and
$dateParts["day"]. The final output string is constructed of the elements of the $dateParts
array.

Entering the New Wish Record in the Database


Now that you have developed the auxiliary functions, add code to validate the new wish data and enter the
data to the database if it is valid. If the data is not valid, the code must reload the Add Wish form. If the data
is invalid because no description has been entered but there is a due date, the due date is saved and
redisplayed when the form reloads, thanks to code you developed earlier.
Enter the following code inside the <? php?> block of editWish.php, below the session
handling code:

require_once("Includes/db.php");
$wisherId = WishDB::getInstance()->get_wisher_id_by_name($_SESSION["user"]);

$wishDescriptionIsEmpty = false;
if ($_SERVER["REQUEST_METHOD"] == "POST"){
if (array_key_exists("back", $_POST)) {
header('Location: editWishList.php' );
exit;
} else
if ($_POST["wish"] == "") {
$wishDescriptionIsEmpty = true;
}
else {
WishDB::getInstance()->insert_wish($wisherId, $_POST["wish"],
$_POST["dueDate"]);
header('Location: editWishList.php' );
exit;
}
}

The code performs the following functions:


• Enables the use of the db.php file
• Gets or creates an instance of the class WishDB
• Retrieves the id of the wisher who is attempting to add a wish by calling the function
get_wisher_id_by_name
• Initializes the $wishDescriptionIsEmpty flag, which will be used later for showing error
messages.
• Checks that the Request method is POST, which means that the data was submitted
from the form for entering the wish data on the editWish.php page itself.
• Checks whether the $_POST array contains an element with the "back" key
If the $_POST array contains an element with the "back" key, the Back to the List button was pressed before
submitting the form. In this case the code redirects the user to the editWishList.php without saving any
data that was entered in the fields and stops PHP processing.
If the $_POST array does not contain an element with the "back" key, the data was submitted by pressing
the Save Changes button. In this case the code validates whether the wish description is filled in. The code
does it by checking whether the element with the "wish" key in the $_POST array is empty and, if the key is
empty, changes the $wishDescriptionIsEmpty flag to true. Note that with no further code executed in the
PHP block, the Add Wish form reloads.
If the Back to the List button was not pressed and the wish description is filled in, the code calls the function
insert_wish with the wisher's id, the description, and the due date for the wish as the input parameters. The
code then redirects the user to the editWishList.php page and stops the PHP processing.
Displaying Error Messages
If the user attempts to save a wish but has not entered a description for it, an error message
must be displayed.
Enter the following <? php?> block inside the HTML input form, below the "Describe your
wish" input field:

<?php
if ($wishDescriptionIsEmpty) echo "Please enter description<br/>";
?>
The error message is displayed if the $wishDescriptionIsEmpty flag is true. The flag is
processed during the input form validation.

Returning to the Front index.php Page


The user should be able to return to the front page of the application at any time by pressing
a button.
To implement this functionality, enter the following HTML input form in the editWishList.php
file, before the closing </body> tag:

<form name="backToMainPage" action="index.php">


<input type="submit" value="Back To Main Page"/>
</form>
The form redirects the user to the front index.php page upon pressing the Back to Main Page
button.

Testing the Add Wish Functionality


1. Run the application. On the index.php page, fill in the fields: in the Username field,
enter "Tom", in the Password field, enter "tomcat".
2. Press the Edit My Wish List button. The editWishList.php page opens.

3. Press the Back to Main Page button. The index.php page opens.
4. Logon as Tom and press the Edit My Wish List button again. The editWishList.php page
opens.
5. Press the Add Wish button. The editWish.php page opens. Fill in the form.

Press the Back to the List button. The editWishList.php page opens but the entered
wish is not added.
6. Press the Add Wish button again. The editWish.php page opens. Fill in the due date and
leave the description empty. Press the Save Changes button. The editWish.php page
displays the input form with an error message and filled in due date.
7. Press the Add Wish button again. The editWish.php page opens. Fill in the form and
press the Save Changes button. The editWishList.php page shows an updated list of
wishes.

Lesson 7: Updating and Deleting Entries in the Database


In this lesson you will expand the application's functionality with two features:
• Editing a wish
• Deleting a wish
The implementation of these two features will affect the editWishList.php and editWish.php files. A
new file deleteWish.php will be created.
The current document is a part of the Creating a CRUD Application in the NetBeans IDE for PHP tutorial.
Editing a Wish
The functionality supports the following use case:

• On the editWishList.php page, the user presses the Edit button to the right of a wish.
The editWish.php page with the data of the selected wish opens.
• The user changes the description and/or the due date of the wish and presses the Save
Changes button.
• If the description is not filled in, an error message is displayed and the user returns to
the editWish.php page.
• If the description is filled in, the application returns to the editWishList.php page,
where the wish is updated.
The implementation consists of the following steps:
• Adding an Edit button on the editWishList page
• On the editWish.php page, updating the array $wish for storing wish data
• Updating the input form on the editWish.php page..
• Validation of the submitted data and updating the wish in the database..

Implementing the Edit Button


In editWishList.php, a table with the wishes of a wisher is implemented by a loop (a while statement)
that displays rows with wishes while the wishes are selected from the database. Add an Edit button as the
extreme right cell in a row.
1. To transfer the ID of a wish through the HTML input form, store it in a variable. Enter
the following code line at the end of the while loop:
2. $wishID = $row["id"];

?>
3. To implement the Edit button, add a table inside the "while" loop. To put an HTML table
inside the loop, first delete the closing curly braket from the loop, then type or paste
the following code beneath the PHP block. The while loop is now closed by the bracket
in the PHP block you added after the table, after the echo "</tr>\n"; operation.
4. <td>
5. <form name="editWish" action="editWish.php" method="GET">
6. <input type="hidden" name="wishID" value="<?php echo $wishID; ?>"/>
7. <input type="submit" name="editWish" value="Edit"/>
8. </form>
9. </td>
10.<?php
11. echo "</tr>\n";
12.}
?>
The entire table, including the form with the Edit button inside the while loop, now looks like this:
<table border="black">
<tr><th>Item</th><th>Due Date</th></tr>
<?php
require_once("Includes/db.php");
$wisherID = WishDB::getInstance()-
>get_wisher_id_by_name(mysql_real_escape_string($_SESSION["user"]));
$result = WishDB::getInstance()->get_wishes_by_wisher_id($wisherID);
while($row = mysql_fetch_array($result)) {
strip_tags($row["description"],'<br><p><h1>');
echo "<tr><td>" . $row["description"]."</td>";
strip_tags($row["due_date"],'<br><p><h1>');
echo "<td>".$row["due_date"]."</td>";
echo "</tr>\n";
$wishID = $row["id"];

?>
<td>
<form name="editWish" action="editWish.php" method="GET">
<input type="hidden" name="wishID" value="<?php echo $wishID; ?
>"/>
<input type="submit" name="editWish" value="Edit"/>
</form>
</td>
<?php
echo "</tr>\n";
}
?>
</table>
The form contains a submit field, which implements the Edit button, and a hidden field wishID for
transferring the ID of the wish displayed to left of the Edit button. The ID of the wish is stored in the
$wishID variable.
13.Remove the first echo "</tr>\n"; operation, the one above $wishID = $row["id"].
Otherwise you close the row before the last </td> and your table will not display
correctly.

Expanding the $wish Array


Upon pressing the Edit button on the editWishList.php page, the ID of the selected wish is transferred to
the editWish.php page through the Server Request method GET. To store the id of the wish, you need to
add a new element to the $wish array.
As when adding a new wish, the input form can be accessed both from the editWishList.php page and
from the editWish.php page after an unsuccessful attempt to save. The cases are distinguished by the
Server Request method through which the data is transferred. GET indicates that the form is displayed when
the user first gets to the page by pressing Edit Wish. POST indicates that the user is redirected to the form
after attempting to save a wish without a description.
Replace the PHP block in the HTML <body> above the EditWish input form with the following:
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST")
$wish = array("id" => $_POST["wishID"], "description" => $_POST["wish"], "due_date" =>
$_POST["dueDate"]);
else
if (array_key_exists("wishID", $_GET))
$wish = mysql_fetch_array(WishDB::getInstance()->get_wish_by_wish_id($_GET["wishID"]));
else
$wish = array("id" => "", "description" => "", "due_date" => "");
?>
The code initializes the $wish array with three elements: id, description, and due_date. The values of
these elements depend on the Server Request method. If the Server Request method is POST, the values are
received from the input form. Otherwise, if the Server Request method is GET and the $_GET array
contains an element with the key "wishID", the values are retrieved from the database by the function
get_wish_by_wish_id. Finally, if the Server Request method is neither POST nor GET, which means the
Add New Wish use case takes place, the elements are empty.
The preceding code covers the cases for creation and editing wishes. Now you need to update the input form
so that it can be also used for both cases.
Updating the HTML Input Form - Unifying the Implementation of Creation and
Editing
Currently the input form works for creation of a new wish when the wish has no id. To unify
the tasks of creating and editing wishes, you need to add a hidden field for transferring the ID
of a wish. The value of the hidden field must be retrieved from the $wish array. The value
must be an empty string during the creation of a new wish. If the wish is edited, the value of
the hidden field must change to the ID of the wish. To create this hidden field, add the
following line to the top of the EditWish input form:

<input type="hidden" name="wishID" value="<?php echo $wish["id"];?>" />

Updating the Wish in the Database


Now you need to update the code that verifies the input data and inserts the wish to the database. The current
code does not distinguish between creating a new wish case and updating an existing one. In the current
implementation, a new record is always added to the database because the code does not verify the value of
the wish ID transferred from the input form.
You need to add the following functions:
• If the transferred element "wishID" is an empty string, create a new wish.
• Otherwise, if the element "wishID" is not an empty string, update the wish.
To update editWish.php so that it verifies if a wish is new and updates it if it is not new:
1. Add the update_wish function to db.php.
2. public function update_wish($wishID, $description, $duedate){
3. $description = mysql_real_escape_string($description);
return mysql_query("UPDATE wishes SET description = '" . $description . "',
due_date = " . $this->format_date_for_sql($duedate)
. " WHERE id =" . $wishID);
}
4. Add the get_wish_by_wish_id function to db.php.
5. public function get_wish_by_wish_id ($wishID) {
return mysql_query("SELECT * FROM wishes WHERE id = " . $wishID);
}

6. In the main PHP block of editWish.php, add a condition to the else statement that
inserts the wish to the database, changing it to an else if statement:
else if ($_POST["wishID"]=="") {
WishDB::getInstance()->insert_wish($wisherId, $_POST["wish"],
$_POST["dueDate"]);
header('Location: editWishList.php' );
exit;
}
7. Type or paste another else if statement below the one you just edited:
8. else if ($_POST["wishID"]!="") {
WishDB::getInstance()->update_wish($_POST["wishID"], $_POST["wish"],
$_POST["dueDate"]);
header('Location: editWishList.php' );
exit;
}
The code checks that the wishID element in the $_POST array is not an empty string, which means that the
user was redirected from the editWishList.php page by pressing the Edit button and that the user has filled
in the description of the wish. If the check is successful, the code calls the function update_wish with the
input parameters wishID, description, and dueDate. These parameters are received from the HTML
input form through the POST method. After update_wish is called, the application is redirected to the
editWishList.php page and the PHP processing is canceled.
Testing the Edit Wish Functionality
1. Run the application. On the index.php page, fill in the fields: in the Username field,
enter "Tom", in the Password field, enter "tomcat".
2. Press the Edit My Wish List button. The editWishList.php page opens.

3. Click Edit next to Icecream. The editWish.php page opens.

4. Edit the fields and press Back to the List. The editWishList.php page opens but the
changes are not saved.
5. Press Edit next to Icecream. Clear the Describe your wish field and press Save Changes.
An error message is displayed.

6. Enter Chocolate icecream in the Describe your wish field and press Save Changes. The
editWishList.php page opens with the updated list.

Deleting a Wish
Now that you can create, read, and update wishes, add functionality for deleting a wish.
To enable the user to delete wishes:
1. Add a delete_wish function to db.php.
2. function delete_wish ($wishID){
return mysql_query("DELETE FROM wishes WHERE id = " . $wishID);
}
3. Create a new PHP file named deleteWish.php and enter the following code into the <?
php ?> block:
require_once("Includes/db.php");
WishDB::getInstance()->delete_wish ($_POST["wishID"]);
header('Location: editWishList.php' );
The code enables the use of the db.php file. It then calls the function delete_wish from
an instance of WishDB, with the wishID as the input parameter. Finally, the application
is redirected to the editWishList.php page.

4. To implement the Delete button, enter the following code block inside the while loop in
editWishList.php, directly below the code block for the editWish button:
5. <td>
6. <form name="deleteWish" action="deleteWish.php" method="POST">
7. <input type="hidden" name="wishID" value="<?php echo $wishID; ?>"/>
8. <input type="submit" name="deleteWish" value="Delete"/>
9. </form>
</td>
The HTML input form contains a hidden field for the wishID and a submit button labelled
Delete.

Testing the Delete Wish Functionality


To check that the functionality is implemented correctly, press Delete next to any item on the
editWishList.php page. The item is no longer on the list.

Lesson 8: Making the Application Look Better Using the CSS Technology
In this lesson you learn how to do the following:
• Hide input forms when they are not used by implementing JavaScript functions
• Improve the appearance of tables with empty cells.
• Define the styles and positioning of page elements by applying Cascading Style Sheet
• Implement the application design using divs.
The current document is a part of the Creating a CRUD Application in the NetBeans IDE for PHP tutorial.
Hiding Forms
Presently, the main index.php page of your application always displays the entire logon and showWishList
forms. To improve the appearance of your application, you can hide the forms and replace them with
buttons. When the user presses a button the corresponding hidden form expands.
To implement this behavior:
1. Add a <script></script> block to the index.php file right above the closing </body>
tag.
2. Develop two JavaScript functions inside the tags.
3. Make some minor changes to the index.php file
JavaScript Functions
JavaScript functions do not require any input parameters and do not return any result. The following code
checks the visibility status of the corresponding form and changes it to the opposite status. It also changes
the text on the button. To accomplish these changes, enter the following code inside the <script></scrip>
tags:
function showHideLogonForm() {
if (document.all.logon.style.visibility == "visible"){
document.all.logon.style.visibility = "hidden";
document.all.myWishList.value = "My Wishlist >>";
}
else {
document.all.logon.style.visibility = "visible";
document.all.myWishList.value = "<< My Wishlist";
}
}
function showHideShowWishListForm() {
if (document.all.wishList.style.visibility == "visible") {
document.all.wishList.style.visibility = "hidden";
document.all.showWishList.value = "Show Wish List of >>";
}
else {
document.all.wishList.style.visibility = "visible";
document.all.showWishList.value = "<< Show Wish List of";
}
}

Updating index.php
1. Add a style attribute to the logon form:
<form name="logon" action="index.php" method="POST" style="visibility:<?php if
($logonSuccess) echo "hidden";
else echo
"visible";?>">
The style attribute defines whether the form is hidden or visible. The <?php ?> block is
used to keep the form visible until the user logs on successfully.

2. Enter the following code above the logon input form code:
<input type="submit" name="myWishList" value="My Wishlist >>"
onclick="javascript:showHideLogonForm()"/>
The code implements a button with the text "My Wishlist >>". The button stands in
place of the logon form. Pressing the button calls the showHideLogonForm function.

3. Add a style attribute to the showWishList form:


4. <form name="wishList" action="wishlist.php" method="GET"
style="visibility:hidden">
Show wish list of: <input type="text" name="user"/>
<input type="submit" value="Go" />
</form>
5. Enter the following code above the showWishList form:
<input type="submit" name="showWishList" value="Show Wish List of >>"
onclick="javascript:showHideShowWishListForm()"/>
6. Remove the following code from the form because it is already placed on the button:
Show wishlist of:
Improving the Appearance of Tables
To make empty cells in tables look better, use the &nbsp; special character. Below is an
example of this method from the wishlist.php file. You can apply it to the table in the
editWishList.php file.

<div class="table">
<table border="black">
<tr><th>Item</th><th>Due Date</th></tr>
<?php
$result = WishDB::getInstance()->get_wishes_by_wisher_id($wisherID);
while($row = mysql_fetch_array($result)) {
echo "<tr><td>&nbsp;" . $row["description"]."</td>";
echo "<td>&nbsp;".$row["due_date"]."</td></tr>\n";
}
?>
</table>
</div>
Defining Styles Using the Cascading Style Sheet
Presently the controls in your application "stick" to each other and are usually placed in the upper left-hand
corner of the screen. To improve the appearance of you application's pages, specify the size, position, color,
font, and other parameters of controls by defining styles and assigning these styles to particular controls.
Styles are defined in a separate Cascading Style Sheet (CSS) file.
All the recommendations and suggestions concerning the application design are optional. The style
definitions below are intended just to give you an example of improving the application appearance. The
settings are appropriate for screen resolution 1024x768 pixel or higher.
Creating a CSS File
1. Click the right mouse button on the Source Files node and from the context menu
choose New > Cascading Style Sheet.
2. On the Cascading Style Sheet panel, in the File Name edit box enter wishlist. Click
Finish.

The new file wishlist.css is shown in the project tree.


Defining CSS Styles
The NetBeans IDE provides a friendly Style Builder code generation tool that enables you to define styles .
Just choose the appropriate setting from a list and evaluate the presentation of the sample text in the Preview
area. The code to implement the style is generated automatically. All the changes you make to a style are
immediately reflected so you can tune the appearance of your application to your taste and habits.
Open the wishlist.css file. The file already contains a "root" class, which you can remove.
Please, find the CSS styles for the application in the wishlist.css file that you can download
here. The code is intuitively clear and contains:

• Two styles: "body" and "input" - that are automatically applied inside any
<body></body> or <input/> tag.
• CSS classes that are applied when explicitly specified. The names of classes have dots
in preposition, for example,.createWishList. Some classes are used several times, for
example, the ".error" class is applied to all error messages in the application. Other
classes are used only once, for example, ".showWishList", ".logon".
Implementing the Design Using HTML Divs
All the recommendations and suggestions concerning the application design are optional. Like the style
definitions above they are intended just to give you an example of how to improve the application's
appearance.
The example below shows how you can improve the appearance of the index.php page.
index.php
1. To enable using the CSS classes that you defined, enter the following code inside the
<head></head> block:
<link href="wishlist.css" type="text/css" rel="stylesheet" media="all" />
The styles "body" and "input" are automatically applied inside the corresponding tags
so you do need to indicate them explicitly.

2. To apply any other style (class) to an area, enclose the code that implements the area
in the <div class=""></div> tags:
<div class="showWishList">
<input type="submit" name="showWishList" value="Show Wish List of >>"
onclick="javascript:showHideShowWishListForm()"/>

<form name="wishList" action="wishlist.php" method="GET"


style="visibility:hidden">
<input type="text" name="user"/>
<input type="submit" value="Go" />
</form>
</div>
Note: When a class is specified within a

tag, no dot is required in preposition.

3. You can use embedded <div> tags:


<div class="logon">
<input type="submit" name="myWishList" value="My Wishlist >>"
onclick="javascript:showHideLogonForm()"/>
<form name="logon" action="index.php" method="POST"
style="visibility:<?php if ($logonSuccess) echo "hidden";
else echo "visible";?>">
Username: <input type="text" name="user"/>
Password: <input type="password" name="userpassword"/><br/>
<div class="error">
<?php
if (!$logonSuccess) echo "Invalid name and/or password";
?>
</div>
<input type="submit" value="Edit My Wish List"/>
</form>
</div>
The class "logon" is applied to the entire form, and the class "error" is applied to an
error message within the form.

Lesson 9: Deploying the Application on a Remote Web Server


Normally, a real-life PHP application is run on a remote server and is accessed through a File Transfer
Protocol (FTP). To deploy your CRUD application on a remote server, you will need to register an account
on a hosting provider, register an FTP account, and create a remote database.
You can use any hosting you like. The current document describes the deployment procedure on the
X10HOSTING free hosting.
All the user names, passwords, and email addresses are fake and used as examples only. The administration
of the hosting blocks an account if the user does not show up on the forum fore more than a week. So you
may fail to apply exactly the same user names, passwords, email addresses, and other credentials from the
tutorial.
In this lesson you learn how to do the following:
• Register a hosting account
• Register an FTP account
• Create a remote MySQL database
• Set up your project to use the registered remote web hosting
• Change your database connection settings to use the remote database
Registering an Email Account
Create an email account, if you have not created it before. In this example the email address is
phpuser65@googlemail.com. phpuser65 @ googlemail.com.
Registering a Hosting Account
To create a hosting account on the X10HOSTING free hosting, follow the steps in their wizard, entering the
following settings. You will enter similar information on any other hosting site.
Account Setting Value
Email Address phpuser65@gmail.com phpuser65 @ gmail.com
Domain name x10Hosting.com
Subdomain phpuser
Hosting Account Username (also for login
phpuser
to cPanel)
Hosting Account Password (also for login
qwerty1234
to cPanel)
Forum Username phpuser
Forum Password qwerty
FTP Account name uploader
uploader@phpuser.x10hosting.com uploader @
FTP User Name
phpuser.x10hosting.com
FTP Server ftp.phpuser.x10hosting.com
Remote Database Host Name phpuser
Remote Database wishlist
Remote Database Username phpuser
Remote Database User Password !phpuser
Registering an FTP Account
Now that you have a hosting account, you need an FTP account where you will transfer your PHP source
and other related files for executing them on the server. For x10Hosting, you opent the cPanel and select
New FTP Account, then follow their wizard.
Creating a Remote Database
Because the CRUD application uses a database you will also need to deploy the wishlist MySQL database
on the remote server where you have a hosting account.
Setting Up a PHP Project with Existing Sources and Remote Web Site Run Configuration
1. Download the source files that correspond to the state of the application after the previous lesson is
completed. Extract the files.
2. Save the source files in the htdocs folder.
3. Create a PHP project with existing sources:
○ Specify the location of the downloaded sources in the Source folder
○ Choose the Remote Web Site run configuration and configure the FTP connection
4. Complete the project creation.
Updating the Class WishDB
So far you have developed and run the Wish List application on the local web server and used a local
MySQL database server. To make your application work with the remote database, you need to update the
connection settings specified through the variables of the class WishDB.
1. Open the file db.php.
2. Change the variables of the class WishDB:
3. var $user = "<the name of the remote database user>";
4. var $pass = "<the password of the remote database user>";
5. var $dbName = "<the name of the remote database>";
6. var $dbHost = "<the account username specified during the hosting account
creation>";
In this example the variables will be updated as follows:
var $user = "phpuser";
var $pass = "!phpuser";
var $dbName = "wishlist";
var $dbHost = "phpuser";

You might also like