C'est un classique moteur de template. Realise en php4, le code tiens dans un seul fichier a inclure au debut de vos pages pour pouvoir en profiter. Ce n'est pas le code du siecle mais sa peut toujours servir pour une premiere approche dans le cadre d'une utilisation futur d'un moteur plus pousse (commerciale ou gratuit peu importe) genre phplib par exemple...
Pour ceux qui ne le savent pas, un moteur de template est en fait un code permettant la separation de la partie php et html d'une page web garce a des balises specifiques supporte par le moteur.
Voici la liste des fonctions proposees :
- SetImg() pour les images
- SetBlock() pour les blocks
- SetCss() pour les feuilles de styles
- SetVar() pour les variables
- SetFile() pour l'inclusion de fichier
- ReadFile() pour lire et renvoye le contenu d'un fichier
et 2/3 trucs en plus
Source / Exemple :
<?php
/*
Engine Template : V1.0.1
Auteur : IoNAce
E-Mail : ionace@c4.fr
Fonctionnement du moteur :
La creation d'une nouvelle classe passe par le constructeur. Ce constructeur prend en parametre le fichier modele
sur lequel travailler. Un fichier modele est un fichier html (ou autre) comportant des balises specifiques au moteur.
C'est le fichier qui effectue la mise en place des elements sur une page (le plus souvent) de facon generique.
Le deuxieme parametre est le chemin et le nom complet du fichier log. Ce fichier comporte toutes les erreurs internes
du moteur. La date, l'heure, la fonction qui a renvoye l'erreur et le type de l'erreur sont consignes par ecrit. Par
defaut, le constructeur surcharge ce parametre pour eviter d'en avoir a se preocuper. ATTENTION ! Le fichier log est
creer a l'endroit meme ou est le fichier engine.php !!
Une fois le modele charge, toutes les fonctions du moteur agiront sur la copie en memoire. Il est donc important
d'appeller la fonction Display() afin d'affiche le resultat. On peut donc utiliser plusieurs fois la meme fonction,
le resultat ne sera disponible qu'a la fin.
class Template
{
var $ContenuModele;
var $EngineStatus;
var $FichierLog;
var $HandleLog;
var $TableauOfBlock;
var $DelTmpBlock;
/*
Constructeur. Lit le fichier modele est le fichier place en memoire. Le 3e param permet d'effacer les
fichiers temporaires crees par la methode SetBlock()
function Template($Modele='', $ErrorLog='error.log', $DeleteTmpBlock=false)
{
// Initialisation de cette variable pour eviter les surprises
$this->EngineStatus = false;
// Indique a la classe quel est le nom du fichier log
$this->FichierLog = $ErrorLog;
// Indique a la classe qu'elle doit effacer les fichiers temporaires
$this->DelTmpBlock = $DeleteTmpBlock;
// Pour eviter les erreurs inutiles, on verifie que tous les parametres sont transmis
if ( empty($Modele) )
die($this->SetLog('Template->Constructeur', 'Le fichier servant de modele n\'a pas ete indique. Il est impossible de continuer l\'execution sans ce fichier !'));
// On verifie que le fichier existe
if ( !file_exists($Modele) )
die($this->SetLog('Template->Constructeur', 'Le fichier indique servant de modele n\'existe pas !'));
// On charge d'abord le modele puis on le lit integralement
$HandleModele = @fopen($Modele, 'rb')
or die($this->SetLog('Template->Constructeur', 'Erreur lors de l\'ouverture du fichier \''.$Modele.'\'.'));
$this->ContenuModele = @fread($HandleModele, @filesize($Modele))
or die($this->SetLog('Template->Constructeur', 'Erreur lors de la lecture du fichier \''.$Modele.'\'.'));
$this->TableauOfBlock = array();
// Si on en est la c'est bon le chargement est reussi
$this->EngineStatus = true;
}
/*
Gere les variables a partir du fichier modele place en memoire par le contructeur.
Pour definir une variable -> <engine:var name="nom_de la variable" /> (attention aux guillemets !)
function SetVAr($NameOfVar='', $Value='')
{
// Si le moteur n'a pas ete demarre correctement
if ( !$this->EngineStatus )
die($this->SetLog('Template->SetVAr()', 'Le moteur n\'a pas ete demarre avant d\'etre utilise !'));
// Valeur de la balise a rempalcer
$this->ContenuModele = str_replace('<engine:var name="'.$NameOfVar.'" />', $Value, $this->ContenuModele);
}
/*
Gere les blocks. Balise => <engine:block name="nom_du_block">donnees</engine:block:nom_du_block>
"Donnees" correspond au code present entre ces balises. On met les variables a traites dans des crochet []
Le 3e parametre ($MiseEnCache) sert a ecrire dans un fichier le modele du block afin d'eviter de le recharger
et d'aller plus vite.
function SetBlock($NameOfBlock='', $Pointer='', $MiseEnCache=false)
{
// Si le moteur n'a pas ete demarre correctement
if ( !$this->EngineStatus )
die($this->SetLog('Template->SetBlock()', 'Le moteur n\'a pas ete demarre avant d\'etre utilise !'));
// On regarde si le block n'est pas mis en cache
$CachedBlock = md5($NameOfBlock);
// Si on veut mettre le block en cache
if ( $MiseEnCache )
{
// On essaye d'ouvrir le fichier cache
$Handle = @fopen($CachedBlock, 'wb+')
or die($this->SetLog('Template->SetBlock()', 'Le fichier temporaire pour le block "'.$NameOfBlock.'" ayant pour signature numerique '.$CachedBlock.' n\' a pas pu etre creer.'));
$SizeOfFile = @filesize($CachedBlock);
// Si le fichier contient du texte
if ( $SizeOfFile ) {
$ModeleBlock = @fread($Handle, filesize($CacheBlock));
}
// Si le fichier est vide
else
{
// Heu complique a expliquer la... :p On extrait le block du modele
$First = stristr($this->ContenuModele, '<engine:block name="'.$NameOfBlock.'">');
$ModeleBlock = strrev(stristr(strrev($First), strrev('</engine:block:'.$NameOfBlock.'>')));
// On met en cache le block
fputs($Handle, $ModeleBlock, strlen($ModeleBlock))
or die($this->SetLog('Template->SetBlock', 'Impossible d\'ecrire dans le fichier cache.'));
}
fclose($Handle);
}
else {
// Heu complique a expliquer la... :p On extrait le block du modele
$First = stristr($this->ContenuModele, '<engine:block name="'.$NameOfBlock.'">');
$ModeleBlock = strrev(stristr(strrev($First), strrev('</engine:block:'.$NameOfBlock.'>')));
}
// Remplacement
foreach ( $Pointer as $Index => $Value )
$ModeleBlock = str_replace('['.$Index.']', $Value, $ModeleBlock);
// Ajout au tableau general
if ( empty($this->TableauOfBlock[$NameOfBlock]) )
$this->TableauOfBlock[$NameOfBlock] = $ModeleBlock;
else
$this->TableauOfBlock[$NameOfBlock] .= $ModeleBlock;
}
/*
Gere les images. Parametres : 1 - nom de la balise devant etre remplacee
2 - nom de l'image a mettre
3 - nom d'une classe pour eventuellement rajouter une feuille de style a l'image
4 - (FACULTATIF) largeur de l'image
5 - (FACULTATIF) hauteur de l'image
Si les 2 derniers parametres ne sont pas transmis, la fonction va essayer de determiner elle meme la largeur et
la hauteur de l'image. Si seul un des deux parametres est transmis, la fonction va chercher a calculer l'autre
parametre en fonction de celui transmis (calcul du ratio entre les deux)
Type de balise : <engine:img name="nom_de_l_image_a_afficher" />
function SetImg($NameOfBalise='', $Img='', $Class='', $X=0, $Y=0)
{
// Si le moteur n'a pas ete demarre correctement
if ( !$this->EngineStatus )
die($this->SetLog('Template->SetImg()', 'Le moteur n\'a pas ete demarre avant d\'etre utilise !'));
// Verfiie les parametres concernant les dimensiosn de l'images
if ( !$X and !$Y )
$Action = 1; // calcul automatique
else if ( $X and !$Y )
$Action = 2; // on calculera y
else if ( !$X and $Y )
$Action = 3; // on calculera x
else
$Action = 0; // tous les parametres ont ete transmis
// Si un calcul est necessaire, on prepare deja les v aleurs essentielles
if ( $Action )
{
// Recupere la largeur et la ahuteur de l'image
$Values = @getimagesize($Img)
or die($this->SetLog('Template->SetImg()', 'L\'obtention des dimensions de l\'image '.$Img.' a echouee.'));
// X / Y = ratio de l'image
$Ratio = $Values[0] / $Values[1];
// Calcul de tous les ratios
switch ( $Action )
{
case 2: // calcul de y en fonction de x => y = X / Ratio
$Y = @round(($X/$Ratio), 0)
or die($this->SetLog('Template->SetImg()', 'Division par zero ! Instruction : case ratio_x. $X = '.$X.'; $Ratio = '.$Ratio.';'));
break;
case 3: // calcul de x en fonction de y => x = Y * Ratio
$X = @round(($Y*$Ratio), 0)
or die($this->SetLog('Template->SetImg()', 'Division par zero ! Instruction : case ratio_y. $Y = '.$Y.'; $Ratio = '.$Ratio.';'));
break;
case 1: // simple, on recupere les valeurs du tableau renvoye par getimagesize() :p
$X = $Values[0];
$Y = $Values[1];
break;
default:
die($this->SetLog('Template->SetImg()', 'L\'instruction switch( $Action ){} n\'a pas pu aboutir, la variable $Action a une valeur non-prise en charge.'));
}
}
// Travail :p
$this->ContenuModele = str_replace(
'<engine:img name="'.$NameOfBalise.'" />',
'<img src="'.$Img.'" width="'.$X.'" height="'.$Y.'" class="'.$Class.'" />',
$this->ContenuModele
);
}
/*
Gere les feuilles de styles. Balise : <engine:css />
function SetCss()
{
// Si le moteur n'a pas ete demarre correctement
if ( !$this->EngineStatus )
die($this->SetLog('Template->SetCss()', 'Le moteur n\'a pas ete demarre avant d\'etre utilise !'));
// Sinon, on recupere tous ces arguments dans un tableau
$Args = @func_get_args();
// Variable recueillant toues les feuilles de styles pour la mise en cache
$Css = '';
// On parcours le tableau
for ( $i=0; $i<@func_num_args(); $i++ ) {
// Details de l'implantation
$Css .= '<link media="all" rel="stylesheet" type="text/css" href="'.$Args[$i].'" />';
}
// Ajout des feuilles de styles
$this->ContenuModele = str_replace('<engine:css />', $Css, $this->ContenuModele);;
}
/*
Charge un fichier et remplace la balise <engine:file name="nom_du_fichier_a_mettre" /> par le contenu de celui-ci
function SetFile()
{
// Si le moteur n'a pas ete demarre correctement
if ( !$this->EngineStatus )
die($this->SetLog('Template->SetFile()', 'Le moteur n\'a pas ete demarre avant d\'etre utilise !'));
// On cherche les balises FILE
$Regex = '!<engine:file name="(.+)" />!i';
// Recherche des expressions
preg_match($Regex, $this->ContenuModele, $Out);
// Travail
for ( $i=0; $i<count($Out[0]); $i++ )
{
// On nettoie le resultat pour n'obtenir que le nom du fichier demande
$Fichier = str_replace('<engine:file name="', '', $Out[0][$i]);
$Fichier = str_replace('" />', '', $Fichier);
// Probleme : quand il n'y a qu'une seule balise, le deuxieme parametre est toujours egale a 0 donc sa plante.
// Pour eviter ce soucis, on regarde si la valeur n'est pas NULL a un moment
if ( !empty($Fichier) )
{
// On ouvre le fichier demande
$Handle = @fopen($Fichier, 'rb')
or die($this->SetLog('Template->SetFile()', 'Impossible d\'ouvrir le fichier \''.$Fichier.'\'.'));
// On lit tout le fichier et on renvoi son contenu
$Contenu = @fread($Handle, @filesize($Fichier))
or die($this->SetLog('Template->SetFile()', 'Impossible de lire le fichier \''.$Fichier.'\'.'));
// Preparation de la balise
$Balise = '<engine:file name="'.$Fichier.'" />';
// Remplacement
$this->ContenuModele = str_replace($Balise, $Contenu, $this->ContenuModele);
}
}
}
/*
Ecris dans un fichier log les eventuelles erreurs d'execution
function SetLog($NameOfFonction='', $ErrorValue='')
{
// Ouverture du fichier
$HandleLog = @fopen($this->FichierLog, 'ab') or die('Impossible d\'ouvrir le fichier log.<br>');
// Preparation du texte a ecrire (le \r\r\n permet de sauter une ligne dans un fichier sous Windows)
$Date = date('\[\l\e d/m/Y\ \à H\h:i\m:s\s]');
$Log = $Date."\r\r\n".'La fonction '.$NameOfFonction.' a renvoye une erreur : '.$ErrorValue;
$Log .= "\r\r\n".'Adresse IP de la connexion : '.$_SERVER['REMOTE_ADDR']."\r\r\n";
$Log .= '_________________'."\r\r\n\r\r\n";
// Ecriture dans le fichier
@fputs($HandleLog, $Log) or die('Imossible d\'ecrire dans le fichier log.<br>');
// Fermetture du fichier
@fclose($HandleLog);
// On informe l'utilisateur qu'il y a eu une erreur
return '[ERREUR INTERNE] - Il y a eu une erreur. Consultez le fichier log pour en connaître la raison.<br>Date : '.$Date;
}
/*
Lit un fichier et renvoi son contenu. Peut etre utilise pour la fonction SetBloc()
=> SetVar('nom_du_bloc', ReadFile('fichier_a_lire'));
function ReadFile($FileToRead='')
{
// Si le moteur n'a pas ete demarre correctement
if ( !$this->EngineStatus )
die($this->SetLog('Template->ReadFile()', 'Le moteur n\'a pas ete demarre avant d\'etre utilise !'));
// On ouvre le fichier demande
$Handle = @fopen($FileToRead, 'rb')
or die($this->SetLog('Template->ReadFile()', 'Impossible d\'ouvrir le fichier \''.$FileToRead.'\'.'));
// On lit tout le fichier et on renvoi son contenu
$Contenu = @fread($Handle, @filesize($FileToRead))
or die($this->SetLog('Template->ReadFile()', 'Impossible de lire le fichier \''.$FileToRead.'\'.'));
return $Contenu;
}
/*
Fonction gerant le BBCode. Peut etre pas super utile a premiere vue mais peut toujours depanner :-)
Si une variable est transmise, la fonction va activer le bbcode sur le contenu de cette variable sinon, elle le
fera sur le fichier modele.
function SetBBCode($Value='')
{
// Si le moteur n'a pas ete demarre correctement
if ( !$this->EngineStatus )
die($this->SetLog('Template->SetBBCode()', 'Le moteur n\'a pas ete demarre avant d\'etre utilise !'));
// Si une variables n'a pas ete transmise, on considere $Value comme une reference a $ContenuModele
if ( !$Value ) {
$Value = &$this->ContenuModele;
$Reference = true;
}
else {
$Reference = false;
}
/* On remplace toutes les balises pouvant etre enleve sans regex */
// Saut de ligne
$Value = str_replace('[br]', '<br />', $Value);
// Italique
$Value = str_replace('[i]', '<i>', $Value);
$Value = str_replace('
/i', '</i>', $Value);
// Gras
$Value = str_replace('[b]', '<b>', $Value);
$Value = str_replace('
/b', '</b>', $Value);
// Souligne
$Value = str_replace('[u]', '<u>', $Value);
$Value = str_replace('
/u', '</u>', $Value);
// Liste
$Value = str_replace('[list]', '<ul>', $Value);
$Value = str_replace('
/list', '</ul>', $Value);
// Puce dans liste
$Value = str_replace('[li]', '<li>', $Value);
$Value = str_replace('
/li', '</li>', $Value);
// Toutes les balises fermees qui utilisent des regex pour leurs balises ouvertes
$Value = str_replace('
/size', '</span>', $Value);
$Value = str_replace('
/align', '</div>', $Value);
$Value = str_replace('
/color', '</span>', $Value);
$Value = str_replace('
/citation', '</span></fieldset><br>', $Value);
// Tabulation
$Value = str_replace("\t", ' ', $Value);
/* On attaque les regex :p */
// Les images
$Value = preg_replace(
'!\[img\=(http|news|ftp|https){1}(://){1}([a-z0-9]+[a-z0-9/.-]*\.)(gif|bmp|png|jpg|jpeg)\]!i',
'<img src="\\1\\2\\3\\4" />',
$Value
);
// Les liens vers des sites
$Value = preg_replace(
'!(http|news|ftp|https){1}(://){1}([a-z0-9]+[a-z0-9/.-]*[a-z]+)!i',
'<a title="Aller vers \\3" target="_blank" href="\\1\\2\\3">\\1\\2\\3</a>',
$Value
);
// Les mails
$Value = preg_replace(
'!([a-z09][a-z0-9._-]*[a-z09]@{1}[a-z09][a-z0-9._-]*[a-z09]\.{1}[a-z]{2,4})!',
'<a title="Envoyer un email à \\1" href="mailto:\\1">\\1</a>',
$Value
);
// La couleur du texte
$Value = preg_replace(
'!\[color=([a-z#0-9]+)\]!i',
'<span style="color:\\1;">', $Value
);
// Taille du texte
$Value = preg_replace(
'!\[size=([0-9]+)\]!i',
'<span style="font-size:\\1px;">',
$Value
);
// Alignement du texte
$Value = preg_replace(
'!\[align=(center|justify|left|right)\]!i',
'<div align="\\1">',
$Value
);
// Citation
$Value = preg_replace(
'!\[citation=(.+)\]!i',
'<br><fieldset style="background-color:#00CCFF;width:400px;text-align:justify;"><legend><b>\\1 a dit </b></legend><span style="color:#000000;font-size:12px;">',
$Value
);
if ( !$Reference )
return $Value;
}
/*
Cette fonction affiche le modele en memoire. N'appeller cette fonction qu'a la fin du traitement !
function Display()
{
// On affiche les blocks
foreach ( $this->TableauOfBlock as $Indice => $Value )
{
$Regex = '!<engine:block name="'.$Indice.'">.*</engine:block:'.$Indice.'>!iUms';
$this->ContenuModele = @preg_replace($Regex, $Value, $this->ContenuModele)
or die($this->SetLog('Template->Display()', 'Evaluation de l\'expression '.$Regex.' impossible.'));
// On efface les derniers blocks ...
$this->ContenuModele = str_replace('<engine:block name="'.$Indice.'">', '', $this->ContenuModele);
$this->ContenuModele = str_replace('</engine:block:'.$Indice.'>', '', $this->ContenuModele);
// ... ainsi que leurs fichiers temporaire
if ( $this->DelTmpBlock )
@unlink(md5($Indice));
}
// On affiche le contenu du fichier modele
echo $this->ContenuModele;
}
}
?>
Conclusion :
Voila le niveau n'est pas extreme mais il y quelques suptilites, sa sera a vous de juger.
Derniere chose, pour ceux qui se demandent pourquoi j'ai realise une classe en php4 alors que php5 est super, tout simplement parce que mon hebergeur est toujours en php4 ... de toute facon le portage du code en php5 n'est pas d'une difficulte enorme, y a 3 trucs a changer et sa tourne ^^ (mais bon pour ceux qui veulent je peut faire un petit effort et le mettre en zip en php5... ;-) )
En esperant que sa vous plaira
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.