Abstraction SQL en PHP
<?php
/*******
*
* Classe d'acces simplifié SQL
* Last modified: march 28, 2014
* ©The P'tit Prince
* source : http://codes-sources.commentcamarche.net/source/100478-class-sql
*
* v2 pifou25 pour interface SQL - dec 2014
********/
class mypdo implements sql {
private $config; // Configuration de connection SQL
private $connect; // Connection a la base
private $debug = false;
private $dateformat = '%d-%m-%y à %H:%i:%s'; /* Mettre ça dans les tpl */
private $dbdecal = '00:00:00';
private $prebdd = '';
private $query = null; // Requete en cours
private $stmt = null; // PDO::statement en cours
private $log = false; // objet log.class.php
private $errno = ''; // Enregistre la derniere erreur
private $err = 0; // Enregistre la derniere erreur
private $records; // Enregistre le nombre d'enregistrements de la dernière requête
private $vars;
public $queries = array(); // infos pour debug
/*******
*
* Constructeur
*
********/
function __construct($host,$login,$pass,$base){
try{
$this->connect = new PDO(
"mysql:host=$host; dbname=$base",
$login,
$pass
);
$this->connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}catch(PDOException $error){
// Faire class debug
$this->err = 'Échec lors de la connexion : ' . $error->getMessage();
echo $this->err;
die($this->err);
}
$this->connect->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$this->connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$this->connect->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING);
//$this->connect->exec("SET NAMES utf8");
}
/**
* mode debug
* @param $debug booleen
* @return void
*/
function set_debug($debug)
{
$this->debug = $debug;
}
/**
* décalage horaire pour les dates
* @param $decal String au format HH:mm:ss (ex: '00:00:00')
* @return void
*/
function set_dbdecal($var)
{
$this->dbdecal = $var;
}
/**
* ajouter un préfixe à toutes les tables
* @param $var String
* @return void
*/
function set_prebdd($var)
{
$this->prebdd = $var;
}
/**
* selon les BDD l'échappement de caractère est spécifique
* PDO->quote ajoute les quote en début et fin aussi = ne convient pas.
* addslashes = faute de mieux
*
* @param $string String à échapper
* @return String
*/
function escape_string($string)
{
return addslashes($string);
}
/**
* 'analyser' une requête SQL. permet des remplacements (format date ou décalage, préfixe...)
* @param $req String
* @return String
*/
function parse_query($req)
{
/* le DATE_FORMAT c'était long a écrire */
if($this->dbdecal != '00:00:00'){
$req = preg_replace("/_UDATE_FORMAT\((.*?)\)/i","DATE_FORMAT(FROM_UNIXTIME($1) + INTERVAL '".$this->dbdecal."' HOUR_SECOND,'".$this->dateformat."')",$req);
$req = preg_replace("/_DATE_FORMAT\((.*?)\)/i","DATE_FORMAT($1 + INTERVAL '".$this->dbdecal."' HOUR_SECOND,'".$this->dateformat."')",$req);
}else{
$req = preg_replace("/_UDATE_FORMAT\((.*?)\)/i","FROM_UNIXTIME($1,'".$this->dateformat."')",$req);
$req = preg_replace("/_DATE_FORMAT\((.*?)\)/i","DATE_FORMAT($1,'".$this->dateformat."')",$req);
}
/* TODO ? ajouter le parse pour le préfixe des tables */
if(!empty($this->prebdd))
$req = preg_replace('/(INTO|FROM|UPDATE)\s+`?(\w+)/ig', '$1 `'.$this->prebdd.'$2`', $req);
return $req;
}
/**
* dernier code erreur (ou zéro si la dernière requête est OK)
* @return Int
*/
function errno()
{
return $this->errno;
}
/**
* dernier message d'erreur
* @return String
*/
function error()
{
return $this->err;
}
/**
* dernier id inséré
* @return Int
*/
function insert_id()
{
if($this->stmt != null)
return $this->stmt->lastInsertId();
}
/**
* nb de lignes modifiées par la dernière requête
* @return Int
*/
function affected_rows()
{
if($this->stmt != null)
return $this->stmt->rowCount();
}
/**
* rechercher la n'ième ligne et le n'ième champs
* @param $res : un objet ''PDO::statement''
* @param $row Int : la ligne à chercher
* @param $field String ou Int : indice du champs à chercher. Si omis, renvoie la ligne complète
* @return mixed (String ou Array)
*/
function result($res, $row, $field = NULL)
{
$ret = $res->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_ABS, $row);
if($field != null && isset($ret[$field]))
return $ret[$field];
else
return $ret;
}
/**
* compter le nb de lignes de la ressource
* @param $res : objet ''result''
* @return Int
*/
function num_rows($res)
{
return $this->records;
}
/**
* exécuter la requête
* @param $req : requête SQL
* @param $explain : ajouter les explications SQL (requête EXPLAIN)
* @return mixed (booleen, objet recordset, ''result'' ...)
*/
function query($req, $explain = true)
{
return $this->prepareQuery($req, null, $explain);
}
/**
* libérer un objet
* @param $res : objet ''result''
* @return booleen
*/
function free_result($res)
{
return $res->closeCursor();
}
/**
* log une erreur SQL (dans un fichier ou...)
* @param $req String
* @return String
*/
function log_error($req)
{
$text = '**** '.date("H:i:s d/m/Y")." ***\n";
$text .= $this->errno." | ".print_r( $this->err, true) ."\n";
$text .= $this->errno." | ".$req."\n\n";
$this->log($text);
return $text;
}
/**
* log du texte (dans un fichier ou...)
* @param $text String
* @return void
*/
function log($text) {
if($this->log === false)
$this->log = new log(SITE_DIR."cache/log/mysql_".date("d_m_Y").".log", false, false);
$this->log->text($text);
}
/**
* exécuter la requête + renvoyer la 1ère ligne uniquement, sous forme d'un tableau
* @param $req String
* @return Array
*/
function make_array_result($req)
{
if($res = $this->query($req))
return $res->fetch();
else
return false;
}
/**
* exécuter la requête + renvoyer sous forme d'un tableau
* @param $req String
* @param $explain : ajouter les explications SQL (requête EXPLAIN)
* @return Array
*/
function make_array($req, $explain = true)
{
if($stmt = $this->query($req)){
$res = $stmt->fetchAll();
$this->records = count($res);
return $res;
}
else
return false;
}
/**
* exécuter la requête + renvoyer sous forme d'un tableau indexé, la clé du tableau est le champ $idx
* @param $req String
* @param $idx String : champs à utiliser comme index du tableau
* @param $explain : ajouter les explications SQL (requête EXPLAIN)
* @return Array
*/
function index_array($req, $idx = false, $explain = true)
{
if($idx === false)
return $this->make_array($req, $explain);
$var = array();
if($stmt = $this->query($req))
while($row = $stmt->fetch())
$var[$row[$idx]] = $row;
$this->records = count($var);
return $var;
}
/**
* exécuter la requête + renvoyer la valeur de la 1ère ligne
* remarque : idem que result($sql, 0, $field);
* @param $req String
* @param $field String : le nom du champs à rendre
* @return mixed (String ou Int)
*/
function get_result($sql, $field)
{
if($stmt = $this->query($sql))
{
$res = $stmt->fetch();
return isset($res[$field]) ? $res[$field] : false;
}
return false;
}
/**
* fermeture de la connexion : inutile en PDO
* @return booleen
*/
function close(){
unset($this->connect);
return true;
}
/*******
*
* Autres Fonctions Publiques - spécifique mypdo, hors interface SQL
*
********/
// prépare et execute une requette SQL avec des paramètres - ou pas
// rend un objet PDOStatement
// spécifique PDO
public function prepareQuery($query,$vars=NULL,$explain=true){
$this->query = $this->parse_query($query);
$this->stmt = $this->connect->prepare($this->query);
try{
$res = $this->stmt->execute($vars);
}catch(Exception $error){
$this->err = $error->getMessage();
echo $this->err;
return false;
}
$this->err = $this->stmt->errorInfo();
$this->errno = $this->stmt->errorCode();
// si debug ajouter des infos
if($this->debug && $explain) {
$this->queries[] = array('req' => $this->query,
'errno'=>$this->errno,
'err' => $this->err,
'time'=> 0, // $this->getmicrotime()-$debut,
// 'infos' => mysql_info(),
'num' => 0
);
}
if ($res)
return $this->stmt;
else {
$this->log_error($this->query . "\n" . print_r($vars, true));
return false;
}
}
// utilité des fonctions suivantes ??
// Permet d'insérer une nouvelle entrée dans la base
public function Insert($table, $vars){
$this->query = "INSERT INTO $table SET ";
$this->vars = array();
foreach($vars as $key => $value){
$this->query .= "$key = :$key, ";
$this->vars[$key] = $value;
}
$this->query = substr($this->query, 0, -2);
return $this->ExecuteSQL($this->query, $this->vars);
}
// Permet de supprimer une ou des entrée SQL
public function Delete($table, $where = NULL){
$this->query = "DELETE FROM $table WHERE ";
if(!is_array($where)){
return false;
}else{
$this->vars = array();
foreach($where as $key => $value){
$this->query .= "$key = :$key AND ";
$this->vars[$key] = $value;
}
$this->query = substr($this->query, 0, -5);
return $this->ExecuteSQL($this->query, $this->vars);
}
}
//Permet de selectionner des données dans la base
public function Select($table, $value='*', $where = NULL, $param = NULL){
$this->query = "SELECT $value FROM $table WHERE ";
if(!isset($param['operand'])){
$param['operand'] = 'AND';
}
if(!isset($param['like'])){
$param['like'] = false;
}
if(is_array($where)){
foreach($where as $key => $value){
if($param['like']){
$this->query .= "$key LIKE %:$key% $param[operand] ";
}else{
$this->query .= "$key = :$key $param[operand] ";
}
$this->vars[$key] = $value;
}
$this->query = substr($this->query, 0, -(strlen($param['operand'])+2));
}else{
$this->query = substr($this->query, 0, -6);
}
if(isset($param['orderby'])){
$this->query .= " ORDER BY $param[orderby]";
}
if(isset($param['limit'])){
$this->query .= " LIMIT $param[limit]";
}
return $this->ExecuteSQL($this->query, $this->vars);
}
//Permet de mettre à jour des données dans la base
public function Update($table, $value, $where){
$this->query = "UPDATE $table SET ";
foreach($value as $key => $value){
$this->query .= "$key = :$key, ";
$this->vars[$key] = $value;
}
$this->query = substr($this->query, 0, -2);
$this->query .= " WHERE ";
foreach($where as $key=> $value){
$this->query .= " $key = :$key AND ";
$this->vars[$key] = $value;
}
$this->query = substr($this->query, 0, -5);
return $this->ExecuteSQL($this->query, $this->vars);
}
// Retourne le nombre d'entrées
public function CountRows($table, $where = NULL){
$param = array('like' => false);
$result = $this->Select($table,'count(*)',$where,$param);
return $result["count(*)"];
}
}