Access to a database
Create site11 by copying site10.
- /cms
- ...
- site10
- site11
In this chapter, we are going to program the access to a database, the configuration of the connector and the initialization of the connection when the program starts, then a set of functions for registering variables in the DB.
To test the result online, enter http://www.frasq.org/cms/site11 in the address bar of your navigator.
Create a user called frasqdb2
in the table user
of the database mysql
:
(Host, `User`, Password, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv, Reload_priv, Shutdown_priv, Process_priv, File_priv, Grant_priv, References_priv, Index_priv, Alter_priv, Show_db_priv, Super_priv, Create_tmp_table_priv, Lock_tables_priv, Execute_priv, Repl_slave_priv, Repl_client_priv, Create_view_priv, Show_view_priv, Create_routine_priv, Alter_routine_priv, Create_user_priv, Event_priv, Trigger_priv, ssl_type, max_questions, max_updates, max_connections, max_user_connections)
VALUES ('localhost', 'frasqdb2', PASSWORD('Fch9Xw4k'), 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', '', '0', '0', '0', '0')
IMPORTANT: Choose a random password and write it down. Remember to select the PASSWORD function for the field Password
or the value will not be encrypted and the password transmitted by PHP, which will be encrypted, will not match.
Add the access rights for the user frasqdb2
to the DB frasqdb2
in the db
table:
(Host, Db, USER, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv, Grant_priv, References_priv, Index_priv, Alter_priv, Create_tmp_table_priv, Lock_tables_priv, Create_view_priv, Show_view_priv, Create_routine_priv, Alter_routine_priv, Execute_priv, Event_priv, Trigger_priv)
VALUES ('localhost', 'frasqdb2', 'frasqdb2', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'N', 'N', 'Y', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N')
Quit MySQL:
mysql> quit
Read the article The web developer tools to learn how to install MySQL and more generally a LAMP environment.
A connector to a DB has 4 parameters: the name of the user of the DB and its password, the name or the IP address of the server and the name of the DB.
Add the configuration file db.inc in the folder includes with the following content:
- /cms/site11
- includes
- db.inc
- includes
- $db_url = 'mysql://username:password@localhost/databasename';
- $db_prefix = false;
- $db_debug = false;
$db_url
defines the connector the DB. Replace databasename and username by frasqdb2, password by the password you wrote down when you created the user of the DB.
$db_prefix
allows changing the names of all the tables in order to avoid conflicts with other components of the DB.
$db_debug
set to true
traces all the SQL orders.
IMPORTANT: Make sure this file is protected from an external access and yet readable by Apache:
$ chmod 600 db.inc
$ sudo chown www-data db.inc
Initialize the connection to the DB when the program starts in the bootstrap
function defined in the file bootstrap.php in the folder library:
- @include 'db.inc';
Loads the configuration of the connexion to the database.
- if (isset($db_url) && $db_url == 'mysql://username:password@localhost/databasename') {
- $db_url = false;
- }
- if ($db_url) {
- require_once 'pdo.php';
- db_connect($db_url);
- }
Sets $db_url
to false
if $db_url
has the value which hints to the parameters in a connector.
If $db_url
isn't false
, loads the file with the functions for accessing a DB then opens the connection.
Add the file pdo.php in the folder library with the following content:
- /cms/site11
- library
- pdo.php
- library
- $db_conn=false;
- $db_scheme=false;
- function db_connect($url, $persistent=true) {
- global $db_conn, $db_scheme;
- $url = parse_url($url);
- $scheme = $url['scheme'];
- $host = urldecode($url['host']);
- if (isset($url['port'])) {
- $host = $host . ':' . $url['port'];
- }
- $user = urldecode($url['user']);
- $pass = isset($url['pass']) ? urldecode($url['pass']) : '';
- $path = urldecode($url['path']);
- if ($path[0] == '/') {
- $path = substr($path, 1);
- }
- $dsn = "$scheme:host=$host;dbname=$path";
- $options = array(PDO::ATTR_PERSISTENT => $persistent ? true : false);
- try {
- $db_conn = new PDO($dsn, $user, $pass, $options);
- $db_conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
- $db_conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
- $db_conn->exec("SET NAMES 'utf8'");
- if ($scheme == 'mysql') {
- $db_conn->exec("SET SQL_MODE='ANSI_QUOTES'");
- }
- $db_scheme=$scheme;
- }
- catch (PDOException $e) {
- die($e->getMessage());
- }
- return $db_conn;
- }
db_connect
parses $url
to extract the parameters for the connection to the DB then opens a permanent connection with the server and selects the requested DB.
In case of a problem, db_connect
pulls up the MySQL error and triggers a PHP error.
Before returning the connector, db_connect
forces the character encoding to UTF-8.
Note that $db_conn
is a global variable.
- function db_query($sql) {
- global $db_debug;
- global $db_conn;
- if ($db_debug) {
- dump($sql);
- }
- try {
- $r = $db_conn->query($sql);
- }
- catch (PDOException $e) {
- die($e->getMessage());
- }
- $rows = $r->fetchAll(PDO::FETCH_ASSOC);
- if (!$rows) {
- return false;
- }
- return $rows;
- }
db_query
executes the request $sql
by calling the private function _db_sql_query
and returns all the response lines in an array or false
if the request didn't return anything.
- function db_query($sql) {
- global $db_debug;
- global $db_conn;
- if ($db_debug) {
- dump($sql);
- }
- try {
- $r = $db_conn->query($sql);
- }
- catch (PDOException $e) {
- die($e->getMessage());
- }
- $rows = $r->fetchAll(PDO::FETCH_ASSOC);
- if (!$rows) {
- return false;
- }
- if (get_magic_quotes_runtime()) {
- foreach ($rows as $row) {
- foreach ($row as $k => &$v) {
- $v = stripslashes($v);
- }
- }
- }
- return $rows;
- }
In this version used before PHP 7, db_query
removes all the \ (BACKSLASH) from all the values which are automatically added by PHP if the configuration parameter magic_quotes_gpc
is true
.
- function db_insert($sql) {
- return _db_sql_exec($sql);
- }
- function db_update($sql) {
- return _db_sql_exec($sql);
- }
- function db_delete($sql) {
- return _db_sql_exec($sql);
- }
- function db_exec($sql) {
- return _db_sql_exec($sql);
- }
- function db_insert_id($id=null) {
- global $db_conn;
- $r = $db_conn->lastInsertId($id);
- return $r;
- }
db_insert
, db_update
and db_delete
return the result of the execution of the request $sql
by the private function _db_sql_query
.
db_insert_id
returns the primary key created by the last call to db_insert
.
- function db_sql_arg($s, $escape=true, $optional=false) {
- global $db_conn;
- if ($s === NULL or $s === false or $s === '') {
- return $optional ? 'NULL' : "''";
- }
- return $escape ? $db_conn->quote($s) : "'$s'";
- }
db_sql_arg
prepares an argument for an SQL request by adding a ' (QUOTE) before and after a literal value.
Set $escape
to false
only if $s
cannot contain characters which are special to SQL.
Set $optional
to true
for a field whose value can be optional.
IMPORTANT: PHP must be connected to a DB for the mysql_real_escape_string
to function.
- function db_prefix_table($table) {
- global $db_prefix;
- return $db_prefix ? $db_prefix . $table : $table;
- }
db_prefix_table
adds $db_prefix
at the beginning of a table name.
$db_prefix
is defined in db.inc.
IMPORTANT: Systematically use db_prefix_table
and db_sql_arg
to build table names and argument values in an SQL request. EXAMPLE:
- $sqlname=db_sql_arg($name, false);
- $tabregistry=db_prefix_table('registry');
- db_delete("DELETE FROM $tabregistry WHERE name=$sqlname LIMIT 1");
$sqlname
contains the value of $name
surrounded by quotes, without escape characters. If $db_prefix
is set to fq_
, $tabregistry
will be set to fq_registry
.
- function _db_sql_exec($sql) {
- global $db_debug;
- global $db_conn;
- if ($db_debug) {
- dump($sql);
- }
- try {
- $r = $db_conn->exec($sql);
- }
- catch (PDOException $e) {
- die($e->getMessage());
- }
- return $r;
- }
_db_sql_exec
traces the request $sql
if $db_debug
is true
then executes it.
In case of error, PHP is stopped.
_db_sql_exec
is a private function called by all the functions which execute an SQL request. It allows centralizing all the calls to the exec
method of the PDO class.
$db_debug
is defined in db.inc.
Modify the home page, in English and in French, to display the version numbers of PHP, MySQL and the web server's system:
- /cms/site11
- views
- en
- home.phtml
- fr
- home.phtml
- en
- views
- <h3>Welcome</h3>
- <p>PHP <?php echo phpversion(); ?><br />
- MySQL <?php echo db_version(); ?><br />
- <?php echo php_uname('s'); ?> <?php echo php_uname('r'); ?></p>
- <h3>Bienvenue</h3>
- <p>PHP <?php echo phpversion(); ?><br />
- MySQL <?php echo db_version(); ?><br />
- <?php echo php_uname('s'); ?> <?php echo php_uname('r'); ?></p>
Enter http://localhost/cms/site11 in the address bar of your navigator to check that the site is connected to the DB.
Set $db_url
to false
in the file includes/db.inc to not connect the program to the DB. Reload the home page. An error is generated.
The function db_version
isn't defined. The file pdo.php hasn't been loaded by the function bootstrap
.
To illustrate the access functions to a DB, we will program a permanent register for saving variables and their values:
$ mysql -u root -p
Enter in the BD of the site which you have just created:
mysql> USE frasqdb2;
Create the table registry
with the fields name
and value
:
mysql> CREATE TABLE registry (
name varchar(100) NOT NULL,
value longtext NOT NULL,
PRIMARY KEY (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Add the file registry.php in the folder library with the following content:
- /cms/site11
- library
- registry.php
- library
- function registry_get($name, $default=false) {
- $sqlname=db_sql_arg($name, false);
- $tabregistry=db_prefix_table('registry');
- $r = db_query("SELECT value FROM $tabregistry WHERE name=$sqlname LIMIT 1");
- return $r ? unserialize($r[0]['value']) : $default;
- }
registry_get
returns the value of the variable whose name is given by $name
.
Values registered in the DB are serialized.
registry_get
builds an SQL order which extracts the value of the requested variable and deserialize it before returning it.
Note how the functions db_sql_arg
and db_prefix_table
are used.
If the variable $name
doesn't exist, registry_get
returns the value given by $default
which is false
by default.
- function registry_set($name, $value) {
- $sqlname=db_sql_arg($name, false);
- $sqlvalue=db_sql_arg(serialize($value), true);
- $tabregistry=db_prefix_table('registry');
- db_insert("INSERT $tabregistry SET name=$sqlname, value=$sqlvalue ON DUPLICATE KEY UPDATE name=VALUES(name), value=VALUES(value)");
- }
registry_set
registers the variable whose name is given by $name
with the value given by $value
.
Values registered in the DB are serialized.
If the variable is already registered, its value is replaced.
- function registry_delete($name) {
- $sqlname=db_sql_arg($name, false);
- $tabregistry=db_prefix_table('registry');
- db_delete("DELETE FROM $tabregistry WHERE name=$sqlname LIMIT 1");
- }
registry_delete
deletes the variable whose named is given by $name
.
Comments