Classe de connexion à la base de données

Eléphant du PHP | 398 Messages

02 avr. 2010, 16:39

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 :)
----------------------------------------------------------------------------------
https://astro-otter.space - Discover wonders and mysteries of Universe

ViPHP
ViPHP | 5462 Messages

02 avr. 2010, 16:43

hello,
c'est un exercice pour toi ? sinon PDO
:wink:

Eléphant du PHP | 398 Messages

02 avr. 2010, 16:48

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 !!
----------------------------------------------------------------------------------
https://astro-otter.space - Discover wonders and mysteries of Universe

ViPHP
ViPHP | 5462 Messages

02 avr. 2010, 16:51

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

Eléphant du PHP | 422 Messages

03 avr. 2010, 07:32

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 ...

++
toujours faire une recherche sur http://www.php.net et/ou sur http://www.google.fr :)
utiliser http://ideone.com/ pour vos codes :)

Eléphanteau du PHP | 27 Messages

03 avr. 2010, 10:44

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 !
Développeur PHP à temps perdu ...
PHP Maximus CMS , un cms plus petit PHP Minimus, un cms minimaliste PHP Nanomus, un pare feu pour votre site PHP Firewall

Mammouth du PHP | 985 Messages

03 avr. 2010, 14:28

é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.
Face à la roche, le ruisseau l'emporte toujours, non pas par la force mais par la persévérance.

Eléphant du PHP | 398 Messages

06 avr. 2010, 11:12

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 :).
----------------------------------------------------------------------------------
https://astro-otter.space - Discover wonders and mysteries of Universe

devlop78
Invité n'ayant pas de compte PHPfrance

06 avr. 2010, 16:29

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);
}

ViPHP
ViPHP | 5462 Messages

06 avr. 2010, 17:06

foreach($donnees as $key=>$value)
{
    $donnees[$key] = mysql_real_escape_string($value);
}
===
$donnees = array_map('mysql_real_escape_string', $donnees);
:wink:

Eléphant du PHP | 398 Messages

06 avr. 2010, 17:27

Je ne connaissais pas du tout la fonction array_map. Tres utile, merci ;).
Je l'ai aussi appliqué pour pg_escape_string.
----------------------------------------------------------------------------------
https://astro-otter.space - Discover wonders and mysteries of Universe

Petit nouveau ! | 1 Messages

13 mai 2010, 10:09

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.

Eléphant du PHP | 398 Messages

07 juin 2010, 17:27

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
----------------------------------------------------------------------------------
https://astro-otter.space - Discover wonders and mysteries of Universe