Creating a CRUD Application With PHP
Short Description
Download Creating a CRUD Application With PHP...
Description
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, VALUES (1, INSERT INTO wishes (wisher_id, 8. VALUES (2, INSERT INTO wishes (wisher_id, VALUES (2,
7.
description) 'Icecream'); description, due_date) 'Cheese', 080501); description) '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 element, if it is not present.
HTML Form in index.php Enter the following code block into the body of index.php:
Show wish list of:
The above piece of code consists of the following elements: •
Enclosing tags
•
The opening 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 project as Main.
on the toolbar if you have set your
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 and tags as the file will contain HTML code too. 2. 3. 4. 11.
12.To display the title, enter the following code block immediately after the opening tag, before the generated
The code now looks like this:
Wish List of
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)
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 tags form rows, the 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 , , and 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?! Create now
Where: •
Still don't have a wish list?! is the text that will be displayed on the page next to
•
is the code that implements a link that opens the
•
Create now is the text that will be displayed as a link.
the link.
createNewWisher.php page.
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: Welcome!
Your name: Password: Please confirm your password:
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. 29. 30. 31. 32.
}
$con = mysql_connect("localhost", "phpuser", "!phpuser"); if (!$con) { die('Could not connect: ' . mysql_error()); } 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. 37. 38.
if ($_POST["user"]=="") { $userIsEmpty = true; }
39. 40. 41. 42. 43.
$con = mysql_connect("localhost", "phpuser", "!phpuser"); if (!$con) { die('Could not connect: ' . mysql_error()); }
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. 50. 51.
if ($_POST["user"]=="") { $userIsEmpty = true; }
52. 53. 54. 55. 56. 57. 58.
$con = mysql_connect("localhost", "phpuser", "!phpuser"); if (!$con) { die('Could not connect: ' . mysql_error()); } mysql_query("SET NAMES 'utf8'");
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. 64. 65.
if ($_POST["user"]=="") { $userIsEmpty = true; }
66. 67. 68. 69. 70.
$con = mysql_connect("localhost", "phpuser", "!phpuser"); if (!$con) { die('Could not connect: ' . mysql_error()); }
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! Your name: 3. 4. 5. 6. 7. 8. 9. 10. 11.
14.Enter the following PHP code block inside the HTML input form below the code for the password input: 15.Password: 16. 17.
22.Enter the following PHP code blocks inside the HTML input form below the code for password confirmation: 23.Please confirm your password: 24. 25. 26. 27.
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 "objectoriented 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:
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 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)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 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 tag: Username: Password
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 block above the HTML block, with the following code:
View more...
Comments