Je viens aujourd'hui proposer ma réalisation (la première version potable
Alors je présente le basard, c'est une classe permettant de gérer des données à la manière de sgdb actuels...
C'est à dire que les champ peuvent avoir des types (int,string,time -bientôt-), des valeurs par défaut sont possibles, un champ auto_increment est possible également, une option null/not_null est possible également... bref le basique...
Seuelement je vous arrête tout de suite, les possibilitée s'arrête là, en effet il n'est pas prévu de faire fonctionner le tout pour structure de données compliquée c'est à dire avec relation entre bases....
Cet outil peut donc servir pour la gestion de logs sur un site, ou encore pour un calendrier "simple", une liste de taches etc...
bref, voici la classe:
<?php
/**
* Classe dataTxt
* Permet de gérer des données simplement
* Dans des fichiers textes
*
* Attention, cette classe ne se veux pas une alternative
* aux sgbd actuels (mysql,pgsql,...)
* Car les actions possible sont restreintes...
* En effet, l'optique est "mono-base", c'est à dire
* pas de structure incluant plusieurs base de données
* et des liens entre elles...
*
* Exemple d'utilisation :
* <code><?php
*
* //création d'une base de donnée
*
* include('dataTxt.classe.php');
* $data=new dataTxt();
*
* $data->newDataFile(
* 'bdd.txt',
* array(
* array(
* 'col_name'=>'id',
* 'col_type'=>'int',
* 'col_default_value'=>null,
* 'col_notnull'=>true,
* 'col_autoinc'=>true
* ),
* array(
* 'col_name'=>'nom',
* 'col_type'=>'string',
* 'col_default_value'=>'dup#ond',
* 'col_notnull'=>true,
* 'col_autoinc'=>false
* ),
* array(
* 'col_name'=>'prenom',
* 'col_type'=>'string',
* 'col_default_value'=>'jean',
* 'col_notnull'=>true,
* 'col_autoinc'=>false
* ),
* )
* );
* ?></code>
* <code><?php
*
* //connection à une bdd
* //actions diverses
*
* include('dataTxt.classe.php');
* $data=new dataTxt('bdd.txt');
*
*
* //insertion de données
* if($data->insert(array('id'=>null,'nom'=>'dupond','prenom'=>'paul')))
* echo "Enregistrement effectué";
* else
* echo "Erreur à l'enregistrement";
*
*
* //récupération de données
*
* $results=$data->select(array('nom','prenom'),'all');
* echo '<pre>';
* print_r($res);
* echo '</pre>';
* ?></code>
*
* @author Joris Mulliez <[email protected]>
* @version 0.0.2
* @since PHP5.x.x
* @package dataTxt
*/
class dataTxt {
/**
* chemin vers le fichier de données
*/
private $file=null;
/**
* séparateur de champs
*/
private $separator="#";
/**
* séparateur de champs
*/
private $separatorProtected="#";
/**
* séparateur entre le nom et le type d'un champ
*/
private $typeSeparator="|";
/**
* séparateur entre le nom et le type d'un champ
*/
private $typeSeparatorProtected="\|";
/**
* structure du fichier
*/
private $structure=null;
/**
* Pas de gestion des erreurs
*/
const NO_ERROR=0;
/**
* Gestion des erreurs haute
*/
const ALL_ERROR=1;
/**
* Contient le niveau de gestion d'erreurs
*/
private $errorLevel=ALL_ERROR;
/**
* dataTxt::__construct.
*
* Méthode qui initialise les paramètres: le fichier sur lequel on travail
* Et la gestion des erreurs
*
* Les paramètres sont facultatifs
* @access public
* @param string $file chemin du fichier de données
* @param string $errolevel Type of source : NULL, FILE, CURL.
* @return bool
*/
public function __construct($file=false,$errorLevel=null){
if($errorLevel!==null)
$this->errorLevel=$errorLevel;
if($file!==false)
return $this->selectFile($file);
return true;
}
/**
* dataTxt::insert.
*
* Méthode d'insertion de données dans le fichier texte
*
* Le paramètres à entrer est un tableau de cette forme
* array(
* 'colonne1'=> null,
* 'colonne2'=>'value2',
* 'colonne3'=>'value3'
* )
*
* @access public
* @param array $donnees données à insérer
* @return bool
*/
public function insert($donnees){
if($this->structure==null)
$this->getStructure();
if(@$fp=fopen($this->file,'a')){
$content='';
$i=0;
foreach($this->structure as $key=>$value){
if($key==='autoinc')
continue;
if($i>0)
$content.=$this->separator;
if(!empty($donnees[$value['col_name']])){
$content.=$this->escape($donnees[$value['col_name']]);
} else {
if($value['col_autoinc']){
$this->structure['autoinc']=$this->structure['autoinc']+1;
$content.=$this->structure['autoinc'];
} elseif($value['col_notnull'] && !empty($value['col_default_value'])){
$content.=$value['col_default_value'];
} else {
$this->error("Une valeur doit être spécifiée pour la colonne <b>".$value['col_name']."</b>");
}
}
$i++;
}
if(@fwrite($fp,"\r\n".$content)===false){
if($this->errorLevel==self::ALL_ERROR){
$this->error("Impossible d'écrire dans le fichier ".$this->file);
} else {
return false;
}
} else {
fclose($fp);
$this->change_id();
return true;
}
} else {
if($this->errorLevel==self::ALL_ERROR){
$this->error("Impossible d'ouvrir le fichier ".$this->file);
} else {
return false;
}
}
}
/**
* dataTxt::newDataFile
*
* Méthode de création de fichier de donnée
*
* Le paramètres $structure est un tableau de cette forme
* array(
* array(
* 'col_name'=>'name',
* 'col_type'=>'type', // int|string|time
* 'col_default_value'=>'default_value', // string|null
* 'col_notnull'=>true or false,
* 'col_autoinc'=>true or false
* ),
* etc...
* )
*
* @access public
* @param string $filename chemin du fichier à créer
* @param array $structure tableau de structure
* @return bool
*/
public function newDataFile($filename,$structure){
$structure=$this->escape_array($structure);
$flag_autoinc=0;
$content="##Struct##";
$temp=array();
for($i=0;$i<count($structure);$i++){
$temp[$i]=$structure[$i]['col_name'].$this->typeSeparator;
$temp[$i].=$structure[$i]['col_type'].$this->typeSeparator;
$temp[$i].=$structure[$i]['col_default_value'].$this->typeSeparator;
$temp[$i].=($structure[$i]['col_notnull'] ? '1' :'0').$this->typeSeparator;
if($structure[$i]['col_autoinc']){
$temp[$i].='1';
$flag_autoinc++;
if($flag_autoinc>1)
$this->error("Un seul champ de type auto increment est autorisé");
} else {
$temp[$i].='0';
}
}
$content.=implode($this->separator,$temp);
$content.='##autoInc##'.($flag_autoinc==1 ? '0' : 'false');
echo $content.'<br />';
if(@$fp=fopen($filename,'w')){
if(@fwrite($fp,$content)===false){
fclose($fp);
if($this->errorLevel==self::ALL_ERROR){
$this->error("Impossible d'écrire dans le fichier ".$filename);
} else {
return false;
}
} else {
$this->selectFile($filename);
return true;
}
} else {
if($this->errorLevel==self::ALL_ERROR){
$this->error("Impossible de créer le fichier ".$filename);
} else {
return false;
}
}
}
/**
* dataTxt::select
*
* Méthode de selection de données dans le fichier texte
*
* @access public
* @param mixed $what ce qu'on veut récupérer
* @param mixed $where filtre de selection
* @return array
*/
public function select($what='all',$where='all'){
if($this->structure==null) $this->getStructure();
$lines=file($this->file);
$result=array();
for($i=1;$i<count($lines);$i++){
if($where!=='all' && is_array($where)){
foreach($where as $key=>$value){
$tab=$this->explode_reg($this->separator,$lines[$i]);
$j=0;
foreach($this->structure as $key2=>$value2){
if($key2!=='autoinc')
$tab[$value2['col_name']]=$tab[$j++];
}
if(is_array($value)){
foreach($value as $bleuh){
if(isset($tab[$key]) && $tab[$key]==$bleuh){
if($what!=='all' && is_array($what)){
foreach($tab as $keypsi=>$psi){
if(in_array($keypsi,$what,true)!==false){
$temp[$keypsi]=$psi;
}
}
$result[]=$temp;
} else {
$result[]=$tab;
}
}
}
} else {
if(isset($tab[$key]) && $tab[$key]==$value)
$result[]=$tab;
}
}
} else {
$tab=$this->explode_reg($this->separator,$lines[$i]);
$j=0;
foreach($this->structure as $key2=>$value2){
if($key2!=='autoinc'){
$tab[$value2['col_name']]=$this->unescape($tab[$j]);
$j++;
}
}
if($what!=='all' && is_array($what)){
foreach($tab as $keypsi=>$psi){
if(in_array($keypsi,$what,true)!==false){
$temp[$keypsi]=$this->unescape($psi);
}
}
$result[]=$temp;
} else {
$result[]=$tab;
}
}
}
return $result;
}
/**
* dataTxt::delete
*
* Méthode de supression de données dans le fichier texte
*
* @access public
* @param mixed $what ce qu'on veut supprimer
* @return bool
*/
public function delete($what='all'){
if($this->structure==null)
$this->getStructure();
$content='';
$lines=file($this->file);
if($what==='all'){
if(file_put_contents($this->file,str_replace("\r\n",'',$lines[0]))){
$this->change_id(0);
return true;
} else {
return false;
}
} else {
$k=0;
for($i=1;$i<count($lines);$i++){
$j=0;
foreach($this->structure as $key=>$value){
$tab=$this->explode_reg($this->separator,$lines[$i]);
if($key!=='autoinc')
$tab2[$value['col_name']]=$tab[$j++];
}
foreach($tab2 as $key=>$value){
foreach($what as $key2=>$value2){
if($key2===$key){
if($value2!=$value){
$temp[]=$tab2;
}
}
}
}
}
$content="##Struct##";
foreach($this->structure as $key=>$value){
if($key!=='autoinc'){
$content.=$value['col_name'].$this->typeSeparator;
$content.=$value['col_type'].$this->typeSeparator;
$content.=$value['col_default_value'].$this->typeSeparator;
$content.=($value['col_notnull'] ? '1' :'0').$this->typeSeparator;
$content.=($value['col_autoinc'] ? '1' :'0').$this->typeSeparator;
}
}
$content.="##autoInc##".$this->structure['autoinc'];
foreach($temp as $value)
$content.="\r\n".implode($this->separator,$value);
if(file_put_contents($this->file,$content)){
return true;
} else {
return false;
}
}
}
/**
* dataTxt::selectFile.
*
* Méthode qui vérifie si le fichier existe
* Si oui, initialise la variable $this->file avec ce chemin
*
* prend en paramètres le chemin du fichier à tester
* @access private
* @param string $filename chemin du fichier de données
* @return bool
*/
private function selectFile($filename){
if(file_exists($filename)){
$this->file=$filename;
return true;
} else {
if($errorLevel==self::NO_ERROR){
return false;
} else {
$this->error("Le fichier <b>".$file."</b> n'éxiste pas!");
}
}
}
/**
* dataTxt::explode_reg.
*
* Méthode similaire à explode, mais qui gère la protection
* de caractères
*
* prend en paramètres $char (le caractère protégé) et $str
* la chaine à éclater
* retourne un tableau contenant les "éclats"
*
* @access private
* @param string $char caractère protégé
* @param string $str chaine à eclater
* @return array
*/
private function explode_reg($char,$str){
$res=array();
$j=0;
for($i=0;$i<strlen($str);$i++){
if($str{$i}==$char && $str{$i-1}!='\\'){
$j++;
}
$res[$j].=(($str{$i}==$char && $str{$i-1}!='\\') || $str{$i}=="\n" || $str{$i}=="\r") ? '' : $str{$i};
}
return $res;
}
/**
* dataTxt::getStructure.
*
* Méthode qui initialise la variable $this->structure, en parsant
* le fichier txt
*
* @access private
* @param none
* @return none
*/
private function getStructure(){
$lines=file($this->file);
$temp=explode('##Struct##',$lines[0]);
$temp=explode('##autoInc##',$temp[1]);
if(count($lines)>1){
$autoinc=explode("\r\n",$temp[1]);
if($autoinc=='false')
$struct['autoinc']=false;
else
$struct['autoinc']=(int)$autoinc[0];
} else {
if($temp[1]=='false')
$struct['autoinc']=false;
else
$struct['autoinc']=$temp[1];
}
$temp=$this->explode_reg($this->separator,$temp[0]);
foreach($temp as $value){
$tab=$this->explode_reg($this->typeSeparator,$value);
$struct[]=array(
'col_name'=>$tab[0],
'col_type'=>$tab[1],
'col_default_value'=>$tab[2],
'col_notnull'=>$tab[3],
'col_autoinc'=>$tab[4]
);
}
$this->structure=$struct;
}
/**
* dataTxt::escape_array
*
* Méthode de protecion des données d'un tableau
*
* @access private
* @param array $array données à protéger
* @return array
*/
private function escape_array($array){
$temp=array();
for($i=0;$i<count($array);$i++){
if(is_array($array[$i])){
foreach($array[$i] as $key=>$value){
$temp[$i][$key]=$this->escape($value);
}
}
}
return $temp;
}
/**
* dataTxt::error
*
* Affiche l'erreur et indique l'endroit où elle s'est produite
*
* @access private
* @param string $message message d'erreur
* @return none
*/
private function error($message){
$errors=debug_backtrace();
echo "<br />Erreur à la ligne <b>".$errors[1]['line']."</b> du fichier <b>".$errors[1]['file'];
echo "</b><br />Message:<br />".$message;
exit();
}
/**
* dataTxt::escape
*
* Méthode de protecion de donnée
*
* @access private
* @param string $var donnée à protéger
* @return string
*/
private function escape($var){
$var=preg_replace("'([^\\\\])".$this->separatorProtected."'U","$1\\".$this->separator,$var);
return preg_replace("'([^\\\\])".$this->typeSeparatorProtected."'U","$1\\".$this->typeSeparator,$var);
}
/**
* dataTxt::escape
*
* Méthode de déprotecion de donnée
*
* @access private
* @param string $var donnée à protéger
* @return string
*/
private function unescape($var){
$var=preg_replace("'\\\\".$this->separatorProtected."'U",$this->separator,$var);
return preg_replace("'\\\\".$this->typeSeparatorProtected."'U",$this->typeSeparator,$var);
}
/**
* dataTxt::escape
*
* Mise à jour de la structure du fichier pour l'id
*
* @access private
* @param none
* @return bool
*/
private function change_id($id=null){
if($this->structure==null) $this->getStructure();
if(file_exists($this->file)){
$content=file_get_contents($this->file);
$id=($id===null ? $this->structure['autoinc'] : $id);
$content=preg_replace("'##autoInc##[0-9]+'","##autoInc##".$id,$content);
echo $content;
if(file_put_contents($this->file,$content)){
return true;
} else {
$this->error("Erreur de mise à jour de l'id");
}
} else {
$this->error("Erreur de mise à jour de l'id");
}
}
}
?>
et quelques exemples d'utilisations,création d'un fichier de données:
<?php
include('dataTxt.classe.php');
$essai=new dataTxt();
$essai->newDataFile(
'db.txt',
array(
array(
'col_name'=>'id',
'col_type'=>'int',
'col_default_value'=>null,
'col_notnull'=>true,
'col_autoinc'=>true
),
array(
'col_name'=>'nom',
'col_type'=>'string',
'col_default_value'=>'dup#ond',
'col_notnull'=>true,
'col_autoinc'=>false
),
array(
'col_name'=>'prenom',
'col_type'=>'string',
'col_default_value'=>'jean',
'col_notnull'=>true,
'col_autoinc'=>false
),
)
);
?>
insertion/récupération de données:<?php
include('dataTxt.classe.php');
$essai=new dataTxt('db.txt');
if($essai->insert('id'=>null,'nom'=>'mulliez','prenom'=>'joris'))
echo 'enregistrement effectué';
$res=$essai->select(array('nom','prenom'),'all');
echo '<pre>';
print_r($res);
echo '</pre>';
?>
Voilà il reste tout de même beaucoup de choses à faire, notammentsur la gestion d'erreur, peut-être lever des exeptions plutôt que planter le programme...
Ensuite, il faut que je fasse toute la vérifications des paramètres passés... (si les tableaux ont la bonne structure, etc)
et bien d'autres choses
s'ajoute à celà ce que vous allez me proposer ci-dessous
voili voilou,
j'attend vos remarques!