Page 1 sur 1

Classe de connexion à la base de données

Posté : 02 avr. 2010, 16:39
par BaLiSTiK
Bonjour,
J'ai créé y a quelques mois une classe pour me connecter à une base de données (MySQL ou PostgreSQL), elle fonctionne nickel (youhou) mais j'aimerai pouvoir l'améliorer, et surtour la sécuriser si elle ne l'est pas assez. Je désirerai donc vos avis divers, nottamment sur des points éventuels à modifier impérativement.

Merci.
Pour se connecter, je stocke les parametres de connexion dans un fichier .ini, qui est protégé en lecture par mon .htacess.

Voila la classe :
<?php
/**
 mail : balistik . fonfon [at] gmail . com
 date : 24/11/2009
 Projet : gestionnaire de blog
 
**/

//Classe de connexion a la base de donnees pour Mysql ou PostgreSQL
//Contient plusieurs methodes
//connexion : realise la connexion a la BD
//preparation donnes : protehes les données avant l insertion avec mysql_real_escape_string et pg_escape_string
//requete : execute une requete SQL
//deconnexion : effectue la deconnexion a la BD


class connexionBD extends appControl{
	
	var $m_nConnect = FALSE;
	
	private $psConnect;
	private $psHost;
	private $psUserName;
	private $psMdp;
	private $psDB;
	
	private $m_nSDB; 
	private $sResult;
	private $messError;
	
	//construction de l objet connexion
	public function __construct(){
		
		/**
			* Declaration du tableau $database
			* connect : 1  (MySQL) ou2(PostgreSQL)
			* host : host de la bd
			* username : login de connexion BD
			* mdp : mot de passe
			* dataBase : nom de la base de donnees
		*/
		$database = array();
		if(file_exists(INC. DS .'app/inc/config/database.ini')){
			$file = INC. DS .'app/inc/config/database.ini';
			$database = parse_ini_file($file);
			$this->psConnect 	= $database['connect']; 	//$psConnect;
			$this->psHost 		= $database['host'];		//$psHost;
			$this->psUserName 	= $database['username'];	//$psUsername;
			$this->psMdp 		= $database['mdpBD'];		//$psMdp;
			$this->psDB 		= $database['dataBase'];	// $psDB;
		}
	}
	
	//destruction de l'instance de classe
	public function __destruct(){
		unset($this);
	}
	
	//Fonction connexion
	public function connexion(){

		//On teste si la connexion a la BD s effectue
		try{
			
			switch($this->psConnect){
				case 1 : 
					$this->m_nConnect 	= mysql_connect($this->psHost,$this->psUserName,$this->psMdp);
					$this->m_nSDB 		= mysql_select_db($this->psDB,$this->m_nConnect);
					break;
				
				case 2 : 
					$conn_string = "host=$this->psHost port=5432 dbname=$this->psDB user=$this->psUserName password=$this->psMdp";
					$this->m_nConnect = pg_connect($conn_string);
					$this->m_nSDB = true;
					break;
			}
			
			if(!$this->m_nConnect){
				throw new MyException ('<div class="msg_err">Probleme de connexion '.$this->psConnect.'<br />Resultat connexion :  '.$this->m_nConnect.'</div>');
			}//fin if
			if(!$this->m_nSDB){
				$mess = '<div class="msg_err">Probleme de connexion &agrave; la database MySQL' ;
			 	$mess .= '&nbsp;'.$this->psDB; 
				$mess .= '</div>';
				throw new MyException($mess);
			}
		}catch(MyException $e){
			echo $e->getError();
		}//fin try/catch*/
	}//fin methode

	/**
	 * Fonction preparant les requetes SQL d insertion et de MAJ (update)
	 *
	 * @param  $donnees au format JSON
	 * @return $donnesOK : tableaux de données protégés
	 */
	function prepareInsertionDonnees($donnees){
	 	//TODO verifier tableau de retour
	 	//TODO 2 : test avec des ' : mise en place des \
		try{
	 		$donnees = json_decode($donnees, true);
	 		switch($this->psConnect){
	 			case 1 :
	 				foreach($donnees as $key=>$value){
	 					$value = mysql_real_escape_string($value);
	 				}
	 				$donnesOK = $donnees;//print_r($donnees);
	 				
	 				break;
	 			case 2 :
	 				foreach($donnees as $key=>$value){
	 					$value = pg_escape_string($value);
	 				}
	 				$donnesOK = $donnees;//print_r($donnees);
	 				break;	
	 		}
	 		if(DEBUG == 2){
	 			echo '<pre>'; print_r($donnesOK); echo '</pre>';
	 		}
	 		if(!$this->psConnect){
	 			throw new MyException('Function prepareInsertionDonnees : probleme de psConnect');
	 		}
	 		return $donnesOK;
	 	}catch(MyException $e){
			echo $e->getError();
		}//fin try/catch
	 }
	
	//Fonction Requete
	public function requete($requete) {
		//On teste l execution d une requete SQL
		try{
			if(empty($requete)){
				throw new MyException('Pas de requete SQL envoye');
			}else{
				$this->confirm = false;	
				switch($this->psConnect){
					case 1 : 
						$this->sResult = mysql_query($requete);
						$this->messError = mysql_error();
						if(DEBUG == 2){ echo '<p>Requete MySQL : ' . $requete . '</p>'; }
						break;
					
					case 2 : 
						$this->sResult = pg_query($requete);
						$this->messError = pg_result_error($requete);
						if(DEBUG == 2){ echo '<p>Requete PostgreSQL : ' . $requete . '</p>'; }
						break;
				}
				
				if(!$this->sResult){
					$this->confirm = false;
					throw new MyException('Probleme d execution de requete SQL :<br>'.$requete.'<br />Message : '.$this->messError);
				}else{
					$this->confirm = true;
				}
			}
		}catch(MyException $e){
			echo $e->getError();
		}//fin try/catch
		return $this->sResult;
	}//fin methode

	/**
	 * Enter description here...
	 *
	 * @param  $resultat :tableau de resultat de la requete SQL
	 * @return $tabResult : tableau de resultat de la requete SQL
	 */
	public function recupDonnesRequete($resultat){
		try{
			$tabResult 	= array();
			$aListe 	= array();
			switch($this->psConnect){
				case 1 :
					while($aListe = mysql_fetch_object($resultat)){
						$tabResult[] = $aListe;
					}
					break;
				case 2 :
					while($aListe = pg_fetch_object($resultat)){
						$tabResult[] = $aListe;
					}
					break;	
			}
			return $tabResult;
		}catch(MyException $e){
			echo $e->getError();
		}//fin try/catch
		
	}
	
	//deconnexion de la base de donnees
	public function deconnexion() {
		switch($this->psConnect){
				case 'mysql' : 
					$this->m_nConnect = mysql_close();
					break;
				
				case 'postgresql' : 
					$this->m_nConnect = pg_close();
					break;
			}
		
	}//fin methode
	
}//fin classe
?>

Et voila à quoi ressemble le fichier database.ini :

Code : Tout sélectionner

;FICHIER contenant les informations de connexion\n;NE PAS EFFACER OU MODIFIER [database] connect = "2" host = "localhost" username = "mon_user" mdpBD = "mon_mdp" dataBase = "nom_db"
Thx d'avance :)

Re: Classe de connexion à la base de données

Posté : 02 avr. 2010, 16:43
par stealth35
hello,
c'est un exercice pour toi ? sinon PDO
:wink:

Re: Classe de connexion à la base de données

Posté : 02 avr. 2010, 16:48
par BaLiSTiK
J'ai pensé un moment à essayer la PDO mais faute de temps pour m'y mettre j ai laissé tomber, je suis allez au plus simple pour moi.

Par contre la question que je me pose, vu que cette classe est intégré dans un outil que je développe et qui sera à disposition de tous, dois-je intégrer des bibliotheques particulières pour utiliser la PDO sans poser de problèmes ou alors la personne qui souhaite utiliser mon outils doit installer lui même sur son serveur ?

EDIT : en cherchant je suis tombé sur ceci :
PDO est fournit avec PHP 5.1 et est disponible en tant qu'extension PECL pour PHP 5.0 ; PDO requiert les nouvelles fonctionnalités OO fournies par PHP 5 et donc, ne fonctionne pas avec les versions antérieures de PHP.
Donc j'en déduis que c est à moi de prévoir !!

Re: Classe de connexion à la base de données

Posté : 02 avr. 2010, 16:51
par stealth35
non la personne dois avoir son serveur configurer pour PDO
PDO étant activer par default depuis la 5.1 avec le driver SQLite, depuis la 5.3 avec le driver mysql par default aussi

Re: Classe de connexion à la base de données

Posté : 03 avr. 2010, 07:32
par telnes
hello

évite les extenions type .ini .inc opte pour .php si c'est du php (en plus ca évitera des souci secu) ou ini.php ...

++

Re: Classe de connexion à la base de données

Posté : 03 avr. 2010, 10:44
par MaximusCMS
hello

évite les extenions type .ini .inc opte pour .php si c'est du php (en plus ca évitera des souci secu) ou ini.php ...

++
+1 je suis de cet avis, les .ini ou .inc ou pire les fichiers type double extension .inc.php sont potentiellement dangereux

rien de tel qu'un fichier PHP avec un contrôle d'accès en début de fichier du type
defined('LOLO') or die('Accès refusé');
Bien évidemment il faudra définir LOL dans le fichier qui inclura le fichier de config comme ceci par exemple
define('LOLO', true );
dès lors il sera plus difficile pour une personne mal intentionnée d'obtenir le contenu de ce fichier de configuration
D'ailleurs l'expérience m'a prouvée à maintes fois qu'il ne faut pas reposer sa confiance et la sécurité d'un projet sur un fichier .htaccess, PHP est maitre à bord et il ne faut pas hésiter à y recourir !

Re: Classe de connexion à la base de données

Posté : 03 avr. 2010, 14:28
par Dr@ke
évite les extenions type .ini .inc opte pour .php si c'est du php (en plus ca évitera des souci secu) ou ini.php ...
Je ne suis pas d'accord du tout.
Car:
Si tu interdis l'accès direct aux fichiers possédant l'extension .inc dans un .htaccess à la racine de ton site, et bien tout accès extérieur sera interdit et ce quelque soit ou se trouve le fichier ensuite...
Cela permet aussi de bien distinguer les fichiers include et require.
C'est justement l'avantage d'une extension .inc, la combinaison des deux éléments cités plus haut.

Re: Classe de connexion à la base de données

Posté : 06 avr. 2010, 11:12
par BaLiSTiK
J ai opté pour le stockage dans un fichier INI tout simplement car lorsque qu'on dézippe l'application et qu'on l'utilise la premiere fois, y a 3 formulaires de pré-installation avant de pouvoir accéder au reste de l'appli :
- On indique les données de connexion à la base de données
- Création de l'administrateur
- Divers renseignements (choix du charset, du titre du site, texte de présentation...)

Pour l'heure actuelle, j ai encore pas mal de modifications à faire avant de proposer l'appli en test :).

Re: Classe de connexion à la base de données

Posté : 06 avr. 2010, 16:29
par devlop78
foreach($donnees as $key=>$value){
$value = mysql_real_escape_string($value);
}


Sauf erreur de ma part, là tu modifie $value, pas $donnees. Un exemple de la documentation php pour cette utilisation (passage en référence) :

foreach ($arr as &$value) {
$value = $value * 2;
}

et moi je fais toujours (mais en fait ça fonctionne peut-être ta façon ... mais je trouverais pas ça très logique) :

foreach($donnees as $key=>$value){
$donnees[$key] = mysql_real_escape_string($value);
}

Re: Classe de connexion à la base de données

Posté : 06 avr. 2010, 17:06
par stealth35
foreach($donnees as $key=>$value)
{
    $donnees[$key] = mysql_real_escape_string($value);
}
===
$donnees = array_map('mysql_real_escape_string', $donnees);
:wink:

Re: Classe de connexion à la base de données

Posté : 06 avr. 2010, 17:27
par BaLiSTiK
Je ne connaissais pas du tout la fonction array_map. Tres utile, merci ;).
Je l'ai aussi appliqué pour pg_escape_string.

Re: Classe de connexion à la base de données

Posté : 13 mai 2010, 10:09
par zorglub
Il existe également ADODB, qui présente l'avantage d'être particulièrement riche en terme de bases de données supportées. C'est un standard, que PDO mettra des années à remplacer...

Son usage est assez simple. On peut également le compléter en utilisant OBJETBDD, (http://objetbdd.sourceforge.net), qui permet de ne pas avoir à coder les requêtes classiques de lecture, d'écriture et de suppression.

Re: Classe de connexion à la base de données

Posté : 07 juin 2010, 17:27
par BaLiSTiK
J'ai deux améliorations à proposer :
- Mettre des transactions pour l'éxécution des requêtes SQL
- Faire une fonction retournant le dernier ID inséré (car j en ai besoin comme exprimé ici : sql-bases-donnees/insertion-dans-tables ... 53782.html)

Pour les transactions, n'en ayant fait que rapidement en cours (donc ça remonte à loin ^^) je ne sais aps trop vmt m'y prendre. Je pense que ceci devrait le faire :
Si on reprend ma fonction requete() :

	//Fonction Requete
	public function requete($requete) {
		//On teste l execution d une requete SQL
		try{
			if(empty($requete)){
				throw new MyException('Pas de requete SQL envoye');
			}else{
				$this->confirm = false;	
				switch($this->psConnect){
					case 1 : 
						mysql_query("BEGIN;");
						$this->sResult = mysql_query($requete);
						mysql_query("COMMIT;");
						$this->messError = mysql_error();
						if(DEBUG == 2){ echo '<p>Requete MySQL : ' . $requete . '</p>'; }
						break;
					
					case 2 : 
						pg_query("BEGIN;");
						$this->sResult = pg_query($requete);
						pg_query("COMMIT;");
						$this->messError = pg_result_error($requete);
						if(DEBUG == 2){ echo '<p>Requete PostgreSQL : ' . $requete . '</p>'; }
						break;
				}
				
				if(!$this->sResult){
					$this->confirm = false;
					throw new MyException('Probleme d execution de requete SQL :<br>'.$requete.'<br />Message : '.$this->messError);
				}else{
					$this->confirm = true;
				}
			}
		}catch(MyException $e){
			echo $e->getError();
		}//fin try/catch
		return $this->sResult;
	}//fin methode