75. PHP - Connexion à une base de données

Cet atelier a pour but de permettre de :

75.1. Création de la base de données

Exercice : Dans MySQL, créez une base de donnée, puis une table vous permettant de stocker les informations de votre utilisateur. Vous pourrez utiliser phpmyadmin par exemple.

n.b : cette table contiendra une clé primaire de type numérique avec la propriété "auto_increment".

Bien, histoire de changer d'air, je vais utiliser Postgres pour ce TP. Commençons par l'installer :

[root@CentOS_AdminBDD ~]# yum install postgresql.x86_64 postgresql-server.x86_64

Initialisation de la base et démarrage du service :

[root@CentOS_AdminBDD ~]# service postgresql initdb
[root@CentOS_AdminBDD ~]# /etc/init.d/postgresql start
Starting postgresql service:                               [  OK  ]

Essayons maintenant de se connecter :

[root@CentOS_AdminBDD ~]# su postgres
bash-4.1$ psql
could not change directory to "/root"
psql (8.4.11)
Type "help" for help.
postgres=#

Création d'une nouvelle de données et de la table associée :

postgres=# CREATE DATABASE eof OWNER postgres;
CREATE DATABASE
postgres=# \connect eof;
psql (8.4.11)
You are now connected to database "eof".
eof=# CREATE TABLE users (id_user serial PRIMARY KEY, nom varchar(25) NOT NULL, prenom varchar(25) NOT NULL, login varchar(25) NOT NULL, password varchar(25) NOT NULL, informations text, cv_path varchar(75));
NOTICE:  CREATE TABLE will create implicit sequence "users_id_user_seq" for serial column "users.id_user"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "users_pkey" for table "users"
CREATE TABLE
eof=# \d
                List of relations
 Schema |       Name        |   Type   |  Owner
--------+-------------------+----------+----------
 public | users             | table    | postgres
 public | users_id_user_seq | sequence | postgres
(2 rows)
eof=# \d+ users;
                                                  Table "public.users"
    Column    |         Type          |                        Modifiers                        | Storage  | Description
--------------+-----------------------+---------------------------------------------------------+----------+-------------
 id_user      | integer               | not null default nextval('users_id_user_seq'::regclass) | plain    |
 nom          | character varying(25) | not null                                                | extended |
 prenom       | character varying(25) | not null                                                | extended |
 login        | character varying(25) | not null                                                | extended |
 password     | character varying(25) | not null                                                | extended |
 informations | text                  |                                                         | extended |
 cv_path      | character varying(75) |                                                         | extended |
Indexes:
    "users_pkey" PRIMARY KEY, btree (id_user)
Has OIDs: no

Ajout d'un utilisateur :

[root@CentOS_AdminBDD ~]# createuser cvanvincq
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) n
Shall the new role be allowed to create more new roles? (y/n) n
[root@CentOS_AdminBDD ~]# su postgres
bash-4.1$ psql
postgres=# GRANT ALL PRIVILEGES ON DATABASE eof TO cvanvincq;
postgres=# \q
bash-4.1$ exit
bash-4.1$ exit

Un dernier test pour la route :

[root@CentOS_AdminBDD ~]# su - cvanvincq
[cvanvincq@CentOS_AdminBDD ~]$ psql -d eof
psql (8.4.11)
Type "help" for help.
eof=> \du
            List of roles
 Role name | Attributes  | Member of
-----------+-------------+-----------
 cvanvincq |             | {}
 postgres  | Superuser   | {}
           : Create role
           : Create DB
eof=> \l
                                  List of databases
   Name    |  Owner   | Encoding |  Collation  |    Ctype    |   Access privileges
-----------+----------+----------+-------------+-------------+------------------------
 eof       | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =Tc/postgres
                                                             : postgres=CTc/postgres
                                                             : cvanvincq=CTc/postgres
 postgres  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 template0 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres
                                                             : postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres
                                                             : postgres=CTc/postgres
(4 rows)

75.2. Connexion à la base de données

75.2.1. Quelques explications

Pour créer une connexion Postgres sous PHP, on utilise les fonctions pg_connect ou pg_pconnect.

<?php
        $dbconnect = pg_connect("host='localhost' dbname='eof' user='cvanvincq'");
?>

n.b : pour ceux qui se feraient avoir comme moi, n'oubliez pas de désactiver (ou adapter) le module SELINUX si vous avez une machine du type Redhat-like !.

Pour effectuer une requête, on utilise pg_query.

<?php
	$dbconnect = pg_connect("host='localhost' dbname='eof' user='cvanvincq'");
	$result = pg_query($dbconnect, "SELECT nom, prenom FROM users");
?>

Pour récupérer un résultat, on peut utiliser pg_fetch_row ou autres équivalents (pg_fetch_array, pg_fetch_object, etc.) :

<?php
	$dbconnect = pg_connect("host='localhost' dbname='eof' user='cvanvincq'");
	$result = pg_query($dbconnect, "SELECT nom, prenom FROM users");
		
	while ($row = pg_fetch_row($result)) {
          echo "Nom : ".$row[0]."\n";
          echo "Prémom : ".$row[1]."\n";
	}
?>

75.2.2. Première connexion

Avant de tester quelques reqûetes, il peut être opportun d'alimenter la base préalablement.

eof=> INSERT INTO users (nom, prenom, login, password) VALUES ('Pierre', 'Dupont', 'pdupont', '01011954');
INSERT 0 1
eof=> select * from users;
 id_user |  nom   | prenom |  login  | password | informations | cv_path
---------+--------+--------+---------+----------+--------------+---------
       1 | Pierre | Dupont | pdupont | 01011954 |              |
(1 row)

En reprenant notre exemple précédent :

[root@CentOS_AdminBDD html]# cat index.php
<?php
        $dbconnect = pg_connect("host='localhost' dbname='eof' user='cvanvincq'");
        $result = pg_query($dbconnect, "SELECT nom, prenom FROM users");

        while ($row = pg_fetch_row($result)) {
          echo "Nom : ".$row[0]."\n";
          echo "Prémom : ".$row[1]."\n";
        }
?>
[root@CentOS_AdminBDD html]# php index.php
Nom : Pierre
Prémom : Dupont

75.3. La nouvelle classe UserDb

Créez une classe fille (qui hérite) de la classe User, et ajoutez lui une propriété id, et une méthode doInsert permettant d'insérer les données de votre objet dans la base de données.

Cette méthode ne gérera pas la connexion à la base, mais juste la requête d'insertion.

Transformez maintenant votre page affichage.php en page d'enregistrement en changeant le type d'objet utilisé (classe UserDb à la place de User) et ajoutez un appel à la méthode doInsert.

Testez là avec un jeu d'enregistrement simple.

Nouvelle version du fichier ObjectUser.php :

<?php
	class User {
		public function __construct()
		{}
		
		public function getName()
		{ return $this->mName; }
		public function getSurname()
		{ return $this->mSurname; }
		public function getLogin()
		{ return $this->mLogin; }
		public function getPassword()
		{ return $this->mPassword; }
		public function getAnotherInformations()
		{ return $this->mAnotherInformations; }
		public function getCv()
		{ return $this->mCv; }
		
		public function setName($mName)
		{ $this->mName = $mName; }
		public function setSurname($mSurname)
		{ $this->mSurname = $mSurname; }
		public function setLogin($mLogin)
		{ $this->mLogin = $mLogin; }
		public function setPassword($mPassword)
		{ $this->mPassword = $mPassword; }
		public function setAnotherInformations($mAnotherInformations)
		{ $this->mAnotherInformations = $mAnotherInformations; }
		public function setCv($mCv)
		{ $this->mCv = $mCv; }
		
		public static function printForm() {
			$output = "<form name=\"form\" enctype=\"multipart/form-data\" method=\"POST\" action=\"". $_SERVER['PHP_SELF'] ."\">\n";
				$output .= "<table>\n";
					$output .= "<tr>\n";
						$output .= "<td>Nom : </td>\n";
						$output .= "<td><input type=\"text\" name=\"surname\" /></td>\n";
					$output .= "</tr>\n";
					$output .= "<tr>\n";
						$output .= "<td>Prénom : </td>\n";
						$output .= "<td><input type=\"text\" name=\"name\" /></td>\n";
					$output .= "</tr>\n";
					$output .= "<tr>\n";
						$output .= "<td>Identifiant : </td>\n";
						$output .= "<td><input type=\"text\" name=\"login\" /></td>\n";
					$output .= "</tr>\n";
					$output .= "<tr>\n";
						$output .= "<td>Mot de passe : </td>\n";
						$output .= "<td><input type=\"password\" name=\"password\" /></td>\n";
					$output .= "</tr>\n";
					$output .= "<tr>\n";
						$output .= "<td>Informations complémentaires : </td>\n";
						$output .= "<td><textarea name=\"anotherInformations\" rows=\"5\" cols=\"30\"></textarea></td>\n";
					$output .= "</tr>\n";
					$output .= "<tr>\n";
						$output .= "<input type=\"hidden\" name=\"MAX_FILE_SIZE\" value=\"30000\" />\n";
						$output .= "<td>Curriculum Vitae : </td>\n";
						$output .= "<td><input type=\"file\" name=\"cv\" /></td>\n";
					$output .= "</tr>\n";
					$output .= "<tr>\n";
						$output .= "<td colspan=\"2\"><input type=\"submit\" value=\"Valider\" /></td>";
					$output .= "</tr>\n";
				$output .= "</table>\n";
			$output .= "</form>\n";
			
			echo $output;
		}
		
		public function execForm() {
			if (!empty($_POST['name']))
				$this->mName = $_POST['name'];
			if (!empty($_POST['surname']))
				$this->mSurname = $_POST['surname'];
			if (!empty($_POST['login']))
				$this->mLogin = $_POST['login'];
			if (!empty($_POST['password']))
				$this->mPassword = $_POST['password'];
			if (!empty($_POST['anotherInformations']))
				$this->mAnotherInformations = $_POST['anotherInformations'];
				
			if (!empty($_FILES['cv'])) {
				$uploads_dir = '/uploads';
				if ($_FILES['cv']['error'] == UPLOAD_ERR_OK) {
					$tmp_name = $_FILES['cv']['tmp_name'];
					$name = $_FILES['cv']['name'];
					move_uploaded_file($tmp_name, ".$uploads_dir/$name");
					$this->mCv = $uploads_dir . "/" . $name;
				}
			}	
		}
		
		public function printData() {
			echo "Prénom :" . $this->mName . "<br/>\n";
			echo "Nom :" . $this->mSurname . "<br/>\n";
			echo "Identifiant :" . $this->mLogin . "<br/>\n";
			echo "Mot de passe :" . $this->mPassword . "<br/>\n";
			echo "Informations complémentaires :" . $this->mAnotherInformations . "<br/>\n";
			echo "Fichier uploadé : <a href=\"".$this->mCv."\">lien</a>.";
		}
		
		private $mName;
		private $mSurname;
		private $mLogin;
		private $mPassword;
		private $mAnotherInformations;
		private $mCv;
	}

	class UserDb extends User {
		public function __construct()
		{ parent::__construct(); }

		public function getId()
		{ return $this->mId; }

		public function setId($mId)
		{ $this->mId = $mId; }

		public function connect($host = "localhost", $dbname = "eof", $user = "cvanvincq") {
			if ($this->mConnection = pg_connect("host='".$host."' dbname='".$dbname."' user='".$user."'"))
				return true;
			else
				return false;
		}
		public function disconnect() {
			if (pg_close($this->mConnection))
				return true;
			else
				return false;
		}

		public function doInsert() {
			pg_query("
				INSERT INTO users(nom, prenom, login, password, informations, cv_path) 
				VALUES(
					'".$this->getSurname()."',
					'".$this->getName()."',
					'".$this->getLogin()."',
					'".$this->getPassword()."',
					'".$this->getAnotherInformations()."',
					'".$this->getCv()."'
				)
			");
		}

		private $mConnection;
		private $mId;
	}
?>

Le fichier Formulaire.php :

<?php
	include_once("./ObjectUser.php");
	
	echo "<html>";
		echo "<head><title>Formulaire.php</title></head>";
		echo "<body>";
			if (empty($_POST) && empty($_FILES)) {
				UserDb::printForm();
			} else {
				$monUtilisateur = new UserDb();
				$monUtilisateur->execForm();
				$monUtilisateur->printData();

				$monUtilisateur->connect();
				$monUtilisateur->doInsert();
				$monUtilisateur->disconnect();
			}
		echo "</body>";
	echo "</html>";
?>

75.4. Créez une page de consultation des utilisateurs

Dans un premier temps, ajoutez une méthode de classe à UserDb permettant récupérer une liste d'objets UserDb à partir de la base de données.

Créez une page d'affichage de cette liste (vous utiliserez une boucle foreach et appellerez sur chaque objet, la méthode printData).

Le code de la méthode récupérant la liste des utilisateurs

<?php
// [...]
	public function &getUserDbList() {
		if (!($result = pg_query("SELECT id_user, nom, prenom, login, password, informations, cv_path FROM users;")))
			die("getUserBdList error");

		$cpt =  0;

		while ($row = pg_fetch_assoc($result)) {
			$userTmp = new User();
			$userTmp->setName($row['prenom']);
			$userTmp->setSurname($row['nom']);
			$userTmp->setLogin($row['login']);
			$userTmp->setPassword($row['password']);
			$userTmp->setAnotherInformations($row['informations']);
			$userTmp->setCv($row['cv_path']);
			$userDbList[$cpt++] = $userTmp;
		}
		return $userDbList;
	}
// [...]
?>

Le code de la page ListeUtilisateur.php :

<?php
        include_once("./ObjectUser.php");

	/* Récupération de la liste des utilisateurs */
	$userDbInstance = new UserDb();
	$userDbInstance->connect();
	$userDbList =& $userDbInstance->getUserDbList();
	$userDbInstance->disconnect();

        echo "<html>";
                echo "<head><title>ListeUtilisateur.php</title></head>";
                echo "<body>";
			foreach($userDbList as $monUtilisateur) {
				$monUtilisateur->printData();
				echo "<hr />";
			}
		echo "</body>";
	echo "</html>";
?>

Voici une illustration du rendu :

Figure 68. Affichage des informations utilisateurs

75.5. Sources

Les sources du TP sont disponibles ici-même.