Chapters 10 & 11 PHP AND MYSQL
Getting Started The database for a Web app would be created before accessing it from the web. Complete the design and create the tables independently. Use phpmyadmin, for example:
Connecting to a Database PHP offers three different ways to connect to and interact with a MySQL database: 1. Original MySQL extension no longer developed, not recommended 2. MySQL Improved: MySQLi designed specifically for MySQL, so is not easily portable to other databases Procedural implementation (functions) Objects implementation Works for PHP versions < 5.1 3. PHP Data Objects: PDO software neutral, preferable if database flexibility is important. We will focus on PDO
Communicating to the MySQL Database All PHP implementations follow the same sequence: 1. Connect to the MySQL database using the hostname, username, password, and database name. 2. Prepare an SQL query. 3. Execute the query and save the result. 4. Extract the data from the result or confirm the result. 5. Close the connection to the database.
The Connection File <?php /*This file contains the database access information. It should be called pdo_connect.php or something similar*/ // Set the database access information as constants using your DB credentials where indicated: define(dbconnstring,'mysql:host=127.0.0.1;dbname='yourdb'); define(dbuser, 'yourusername'); define(dbpass, 'yoursqlpassword');
Saving the Connection File Important security measure: 1. Place the pdo_connect.php file outside of the public_html directory. 2. Set file permissions on pdo_connect.php to 644.
Connecting to the Database using PDO PDO throws an exception if the connection fails. In development, we need to know the details of the exception In production, we would change the catch block to redirect to a generic error page. Wrap the code in a try catch block and use the constants you defined: try { $conn= new PDO(DBCONNSTRING, DBUSER, DBPASS); } catch (PDOException $e) { } echo $e->getmessage(); //for development only //for deployment (we will learn about the header function soon): // header("location: http://localhost/app/errors.php");
Calling the Connection/Config File Use '../' to go up one level in your folder structure to reference the pdo_connect.php file. Use as many../ as needed. Use the require_once() function, which will halt the script if it is unsuccessful, to connect to the database: <?php require_once ('../pdo_connect.php');?>
The Query Write the SQL query as a PHP string Assign it to a PHP variable. Some things to remember: SQL keywords are not case-sensitive; using all caps is conventional to aid readability Database table names and column names are casesensitive SQL strings must be in quotes (either single or double as long as they match) SQL numeric values are not enclosed in quotes
Creating SQL Queries with PHP Assign the SQL query as a string to a PHP variable. (When possible, test the query first in phpmyadmin to cut down on errors.) $sql = "INSERT INTO JJ_contacts (firstname, lastname, emailaddr, comments, newsletter) VALUES ('$firstname', '$lastname', '$email', '$comments', $howhear)"; Remember that SQL variables are case-sensitive you must reference them exactly as they are in the database (SQL keywords are not case-sensitive.) The semicolon ends the PHP string. It isn't required for the SQL in this case.
Executing Queries with PDO Execute the query by calling the query() method on the connection object (which was assigned in the php_config file) and passing the query string. Assign the result to a new variable: $result = $conn->query($sql); For simple queries like, INSERT, UPDATE, DELETE, etc. (which don't return records), the function will return either TRUE or FALSE. The exec() method can also be used for simple queries. It returns the number of rows affected. For complex queries like SELECT, which return results of the query as a table, $result will be a pointer to the returned table or FALSE if it did not work.
PDO Errors The third element of this array is only created if something went wrong, so that is where to check for errors.
Checking SELECT Queries for Errors To determine if there was a problem with the query, check the third element in the array of error messages from the database which will be in the connection object's errorinfo() method: $errorinfo = $conn->errorinfo(); if (isset($errorinfo[2])) echo $errorinfo[2]; else $numrows = $result->rowcount(); Note that $errorinfo[2] is not necessarily the output you want your users to see. Change it to something more general before deployment.
Processing SELECT Queries It is not necessary to count the number of rows in the result table, but the rowcount() method of the $result object will have it if needed: $numrows = $result->rowcount(); A foreach loop can handle processing for all rows: <?php foreach ($conn->query($sql) as $row) {?> <tr> <td><?php echo $row['image_id'];?></td> <td><?php echo $row['filename'];?></td> <td><?php echo $row['caption'];?></td> </tr> <?php } //endforeach loop?>
Processing SELECT Queries Where do the $row array key values come from? <?php foreach ($conn->query($sql) as $row) {?> <tr> <td><?php echo $row['image_id'];?></td> <td><?php echo $row['filename'];?></td> <td><?php echo $row['caption'];?></td> </tr> <?php } //endforeach loop?>
More Specific SELECT Queries $sql = 'SELECT filename, caption FROM JJ_images WHERE image_id=6'; $sql = 'SELECT filename, caption FROM JJ_images WHERE caption LIKE "%Kyoto%"'; $sql = 'SELECT filename, caption FROM JJ_images WHERE caption LIKE BINARY "%maiko%"'; String search using LIKE comparison operator and wildcard character % Case-sensitive string comparison
SQL Injection SELECT * FROM users WHERE username='abc' AND pw='123' SELECT * FROM users WHERE username='abc' AND pw='123' OR 1=1 When the query is derived from a variable or from user input, it is critical to process the query safely: 1. Check that expected values are the correct type e.g. is_numeric() 2. Escape user input 3. Use prepared statements
Numeric User Input in a Query
Numeric User Input in a Query
Numeric User Input in a Query
User Registration
Inserting User Input to the Database SQL Name Field
Inserting User Input to the Database In the self-processing form, once the user s submission is acceptable, the data can be sent to the database.
Inserting User Input to the Database tinyint Re-work the handling of subscribe $sql = "INSERT into JJ_contacts (firstname, lastname, emailaddr, comments, newsletter) VALUES ('$firstname', '$lastname', '$email', '$comments', $subscribe)"; No quotes for an integer variable
Prepared Statements Important security features A template of an SQL query Uses placeholders for each variable Prevents SQL injection attacks: quotes and other characters are automatically escaped before the query is executed More efficient when the same query is used more than once Binding the results from each column makes output easier to display
Prepared Statements Both MySQLi and PDO use question marks as anonymous placeholders for column values. The execution is the same: 1. Initialize the statement 2. Prepare the statement 3. Bind values to the placeholders 4. Execute the statement 5. Bind the results (optional) 6. Store the results (optional) 7. Fetch the result 8. Close the statement to free the memory used.
Prepared Statements Instead of: Prepare, Bind, Execute:
Prepared Statements An advantage of PDO is that it allows for named placeholders:
Close the existing connection $statement->closecursor(); Optional because PHP will close the connection at the end of the script Makes for good programming form anyway
PDO Connection Crib Sheet
Some methods of the PDO class prepare($sql_statement) lastinsertid() Some methods of the PDOStatement class bindvalue($param, $value) execute() fetchall() fetch() rowcount() closecursor()