Subversion Repositories Applications.framework

Compare Revisions

No changes between revisions

Ignore whitespace Rev 302 → Rev 303

/tags/v0.3-aleaume/framework/Debug.php
New file
0,0 → 1,186
<?php
// declare(encoding='UTF-8');
/**
* Classe fournissant des fonctions de débogage équivalante à var_dump et print_r.
* L'affichage et l'utilisation de ces fonctions sont améliorés via cette classe.
* Cette classe est inspirée de la classe Zend_Debug.
*
* @category PHP 5.2
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2009, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL-v3
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL-v2
* @version $Id$
* @link /doc/framework/
*/
class Debug {
/** Paramètrer le fichier de config avec "php:Debug::MODE_ECHO" : les messages sont affichés en utilisant echo au moment
* où ils sont déclenchés dans le code.*/
const MODE_ECHO = 'echo';
/** Paramètrer le fichier de config avec "php:Debug::MODE_NOTICE" : les message sont stockés par le gestionnaire
* d'exception sous forme d'erreur de type E_USER_NOTICE et sont renvoyés sur la sortie standard à la fin de l'execution
* du programme (via echo).*/
const MODE_NOTICE = 'e_user_notice';
/** Paramètrer le fichier de config avec "php:Debug::MODE_ENTETE_HTTP" : les message sont stockés par le gestionnaire
* d'exception sous forme d'erreur de type E_USER_NOTICE et sont renvoyés dans un entête HTTP (X_REST_DEBOGAGE_MESSAGES)
* à la fin de l'execution du programme.
* Surtout utile pour le Serveur REST. */
const MODE_ENTETE_HTTP = 'entete_http';
/** Mode de php (cli ou sapi) */
protected static $mode = null;
/** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
private static $parametres_obligatoires = array('debogage', 'debogage_mode');
/**
* Accesseur pour le mode
* @return string le mode de php
*/
public static function getMode() {
if (self::$mode === null) {
self::$mode = PHP_SAPI;
}
return self::$mode;
}
 
/**
* Equivalent de var_dump
* @param mixed $variable la variable à dumper
* @param string $mot_cle le mot cle à associer à la variable
* @param boolean $echo si true on affiche le résultat, si false on ne renvoie que la chaine sans l'afficher
* @return string la chaine à afficher representant le dump ou null si echo
*/
public static function dump($variable, $mot_cle = null, $echo = false) {
// var_dump de la variable dans un buffer et récupération de la sortie
ob_start();
var_dump($variable);
$sortie = ob_get_clean();
 
// Pré-traitement de la sortie
$sortie = preg_replace("/\]\=\>\n(\s+)/m", "] => ", $sortie);
 
// Traitement général du débogage
return self::traiterDebogage($mot_cle, $sortie, $echo);
}
 
/**
* Equivalent de print_r.
* @param mixed $variable la variable à afficher
* @param string $mot_cle le mot cle à associer
* @param boolean $echo faire un echo ou non
* @return string la chaine contenant la variable printée ou null si echo
*/
public static function printr($variable, $mot_cle = null, $echo = false) {
// Récupération de la sortie
$sortie = print_r($variable, true);
 
// Traitement général du débogage
return self::traiterDebogage($mot_cle, $sortie, $echo);
}
/**
* Affichage d'informations sur l'espace mémoire occupé par une variable
*
* @link http://forum.webmaster-rank.info/developpement-site/code-taille-memoire-d-une-variable-en-php-t1344.html
* @since 0.3
*
* @param mixed $var la variable dont on veut connaître l'empreinte mémoire.
* @param string $mot_cle le mot cle à associer
* @param boolean $echo faire un echo ou non
*
* @return string la chaine d'information sur l'espace mémoire occupé ou bien null si echo
*/
public static function tailleMemoireVar($var, $mot_cle = null, $echo = false) {
$memoire_depart = memory_get_usage();
$temp = unserialize(serialize($var));
$taille = memory_get_usage() - $memoire_depart;
$sortie = Fichier::convertirTaille($taille);
return self::traiterDebogage($mot_cle, $sortie, $echo);
}
 
/**
* Affichage d'informations sur l'espace mémoire occupé par le script PHP
*
* @link http://forum.webmaster-rank.info/developpement-site/code-taille-memoire-d-une-variable-en-php-t1344.html
* @since 0.3
*
* @param string $mot_cle le mot cle à associer
* @param boolean $echo faire un echo ou non
*
* @return string la chaine d'information sur l'espace mémoire occupé ou bien null si echo
*/
public static function tailleMemoireScript($mot_cle = null, $echo = false) {
$sortie = 'Mémoire -- Utilisé : '.Fichier::convertirTaille(memory_get_usage(false)).
' || Alloué : '.
Fichier::convertirTaille(memory_get_usage(true)) .
' || MAX Utilisé : '.
Fichier::convertirTaille(memory_get_peak_usage(false)).
' || MAX Alloué : '.
Fichier::convertirTaille(memory_get_peak_usage(true)).
' || MAX autorisé : '.
ini_get('memory_limit');
// Traitement général du débogage
return self::traiterDebogage($mot_cle, $sortie, $echo);
}
/**
* Traite une chaine de débogage et les mots clés associés
* @param string $mot_cle le mot à associer à la chaine
* @param string $sortie le chaine de debogage
* @param boolean $echo faire un echo du resultat ou non
* @return string la chaine de debogage formatée ou bien null si echo
*/
private static function traiterDebogage($mot_cle, $sortie, $echo) {
Config::verifierPresenceParametres(self::$parametres_obligatoires);
$debogage = Config::get('debogage');
$mode = Config::get('debogage_mode');
$mot_cle = self::formaterMotCle($mot_cle);
$sortie = self::traiterSortieSuivantMode($mot_cle, $sortie);
 
// Affichage et/ou retour
if ($debogage == true) {
if ($echo === true || $mode == self::MODE_ECHO) {
echo $sortie;
return null;
} else if ($mode == self::MODE_NOTICE || $mode == self::MODE_ENTETE_HTTP) {
trigger_error($sortie, E_USER_NOTICE);
return null;
} else {
return $sortie;
}
}
}
 
/**
* formate un mot clé donné
* @param string $mot_cle le mot clé à formaté
* @return string le mot clé formaté ou bien un chaine vide le mot clé est null ou vide
*/
private static function formaterMotCle($mot_cle) {
return ($mot_cle === null) ? '' : rtrim($mot_cle).' ';
}
 
/**
* traite la sortie de la chaine de débogage suivant le mode de php
* @param string $mot_cle le mot clé associé à la chaine
* @param string $sortie la chaine de débogage
* @return string la sortie formatée pour le mode en cours
*/
private static function traiterSortieSuivantMode($mot_cle, $sortie) {
$corps = $mot_cle.PHP_EOL.$sortie;
if (self::getMode() == 'cli') {
$sortie = PHP_EOL.$corps.PHP_EOL;
} else {
$sortie = '<pre>'.$corps.'</pre>';
}
return $sortie;
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/Bdd.php
New file
0,0 → 1,412
<?php
// declare(encoding='UTF-8');
/**
* Classe Bdd, d'accés au base de données.
* Elle fait office d'abstraction légère de base de données en utilisant diverses possibilités d'accès aux
* bases de données (PDO, mysql, mysqli, SQLite3).
* Les valeurs pour le paramètre 'bdd_abstraction' du fichier config.ini sont : pdo, mysql, mysqli, sqlite3
* Vous pouvez aussi utiliser : "php:Bdd::ABSTRACTION_PDO","php:Bdd::ABSTRACTION_MYSQL", "php:Bdd::ABSTRACTION_MYSQLI",
* "php:Bdd::ABSTRACTION_SQLITE3".
* Elle peut être étendue, pour ajouter le support d'autres bases de données où prendre en compte des méthodes spécifique à
* un type d'abstraction.
*
* @category php 5.2
* @package Framework
* @author Aurélien PERONNET <aurelien@tela-botanica.org>
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
* @version $Id$
* @link /doc/framework/
*/
class Bdd {
/** Constante stockant le squelette du message en cas d'erreur de requête sql. */
const ERREUR_REQUETE_TPL = 'Requête echec.\nFichier : %s.\nLigne : %s.\nMessage : %s.\nRequête : %s';
/** Constante stockant le squelette du message en cas d'erreur de connexion à la base de données. */
const ERREUR_CONNEXION_TPL = 'Erreur de connexion à la base de données, vérifiez les paramètres du fichier de configuration.\nMessage : %S.';
/** Constante stockant le squelette du message en cas d'erreur de sélection de la base de données. */
const ERREUR_SELECTION_BDD_TPL = 'Erreur de sélection de la base de données, vérifiez les paramètres du fichier de configuration.\nMessage : %S.';
/** Constante stockant le code pour l'abstraction de PDO. */
const ABSTRACTION_PDO = 'pdo';
/** Constante stockant le code pour l'abstraction de mysql. */
const ABSTRACTION_MYSQL = 'mysql';
/** Constante stockant le code pour l'abstraction de mysqli. */
const ABSTRACTION_MYSQLI = 'mysqli';
/** Constante stockant le code pour l'abstraction de SQLite3. */
const ABSTRACTION_SQLITE3 = 'sqlite3';
/** Constante stockant le code pour le mode tableau associatif des résultats des requêtes. */
const MODE_ASSOC = 'ASSOC';
/** Constante stockant le code pour le mode objet des résultats des requêtes. */
const MODE_OBJET = 'OBJECT';
/** Mode de fetch associatif */
protected $ASSOC = '';
/** Mode de fetch objet */
protected $OBJECT = '';
 
/** abstraction de base de données utilisée */
protected $abstraction;
/** DSN pour accéder à la base de données */
protected $dsn;
/** Type de base de données (mysql, mysqli, etc ...) */
protected $type;
/** Hote herbergeant la base de données */
protected $hote;
/** Nom de la base de données à laquelle le modèle doit se connecter */
protected $bdd_nom;
/** Nom d'utilisateur */
protected $utilisateur;
/** Mot de passe */
protected $pass;
 
/** Encodage de la base de données */
protected $encodage = null;
/** Connexion à la base de données */
protected $connexion = null;
 
/** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
protected $parametres_obligatoires = array('bdd_abstraction', 'bdd_protocole', 'bdd_serveur', 'bdd_nom',
'bdd_utilisateur', 'bdd_mot_de_passe', 'bdd_encodage');
/** Constructeur par défaut, appelé à l'initialisation. */
public function __construct() {
Config::verifierPresenceParametres($this->parametres_obligatoires);
$this->abstraction = strtolower(Config::get('bdd_abstraction'));
$this->type = Config::get('bdd_protocole');
$this->hote = Config::get('bdd_serveur');
$this->bdd_nom = Config::get('bdd_nom');
$this->utilisateur = Config::get('bdd_utilisateur');
$this->pass = Config::get('bdd_mot_de_passe');
$this->encodage = Config::get('bdd_encodage');
 
$this->dsn = $this->type.':dbname='.$this->bdd_nom.';host='.$this->hote;
$this->initialiserProtocole();
}
 
/** Initialise les constantes de classe à leur bonne valeur et déclenche une erreur si le protocole n'est pas bien défini. */
protected function initialiserProtocole() {
switch ($this->abstraction) {
case self::ABSTRACTION_PDO :
$this->ASSOC = PDO::FETCH_ASSOC;
$this->OBJECT = PDO::FETCH_CLASS;
break;
case self::ABSTRACTION_MYSQL :
$this->ASSOC = 'mysql_fetch_assoc';
$this->OBJECT = 'mysql_fetch_object';
break;
case self::ABSTRACTION_MYSQLI :
$this->ASSOC = 'fetch_assoc';
$this->OBJECT = 'fetch_object';
break;
case self::ABSTRACTION_SQLITE3 :
$this->ASSOC = 'SQLITE3_ASSOC';
$this->OBJECT = 'SQLITE3_OBJECT';
break;
default:
$m = "Erreur : l'abstraction '{$this->abstraction}' n'est pas prise en charge";
trigger_error($m, E_USER_WARNING);
}
}
/**
* Connection à la base de données en utilisant les informations fournies par
* le fichier de configuration.
* Cette méthode est private et final car elle n'a pas vocation a être appelée par l'utilisateur.
*/
protected function connecter() {
if ($this->connexion == null) {
switch ($this->abstraction) {
case self::ABSTRACTION_PDO :
try {
$this->connexion = new PDO($this->dsn, $this->utilisateur, $this->pass);
} catch (PDOException $e) {
$e = sprintf(self::ERREUR_CONNEXION_TPL, $e->getMessage());
trigger_error($e, E_USER_WARNING);
}
break;
case self::ABSTRACTION_MYSQL :
$this->connexion = mysql_connect($this->hote, $this->utilisateur, $this->pass);
if ($this->connexion !== false) {
$selection = mysql_select_db($this->bdd_nom, $this->connexion);
if ($selection === false) {
$e = sprintf(self::ERREUR_SELECTION_BDD_TPL, mysql_error());
trigger_error($e, E_USER_WARNING);
}
} else {
$e = sprintf(self::ERREUR_CONNEXION_TPL, mysql_error());
trigger_error($e, E_USER_WARNING);
}
break;
case self::ABSTRACTION_MYSQLI :
$this->connexion = @new mysqli($this->hote, $this->utilisateur, $this->pass, $this->bdd_nom);
if ($this->connexion->connect_errno) {
$e = sprintf(self::ERREUR_CONNEXION_TPL, $this->connexion->connect_error);
trigger_error($e, E_USER_WARNING);
}
break;
case self::ABSTRACTION_SQLITE3 :
// cas particulier de sqllite, on considère que le nom de la base de données correspond au fichier à ouvrir
$this->connexion = new SQLite3($this->bdd_nom);
if (!$this->connexion) {
$e = sprintf(self::ERREUR_CONNEXION_TPL, '');
trigger_error($e, E_USER_WARNING);
}
break;
default:
$this->connexion = null;
}
if ($this->encodage != null) {
$this->requete("SET names '".$this->encodage."'");
}
}
}
/**
* @deprecated changement de nom. Disparaîtra dans la version 0.4. Utiliser à la place : @see requeter
*/
final protected function requete($requete) {
return $this->requeter($requete, $mode);
}
/**
* Execute une requête et retourne le résultat tel que renvoyé par l'abstraction courante.
*
* @param string la requête à effectuer
* @return mixed un objet contenant le résultat de la requête
*/
public function requeter($requete) {
$this->connecter();
 
$retour = null;
switch ($this->abstraction) {
case self::ABSTRACTION_PDO :
try {
$retour = $this->connexion->query($requete);
} catch (PDOException $e) {
$m = sprintf(self::ERREUR_REQUETE_TPL, $e->getFile(), $e->getLine(), $e->getMessage(), $requete);
trigger_error($m, E_USER_WARNING);
}
break;
case self::ABSTRACTION_MYSQL :
$retour = mysql_query($requete, $this->connexion);
break;
case self::ABSTRACTION_MYSQLI :
$retour = $this->connexion->query($requete);
break;
case self::ABSTRACTION_SQLITE3 :
$retour = $this->connexion->exec($requete);
break;
}
return $retour;
}
/**
* @deprecated changement de nom. Disparaîtra dans la version 0.4. Utiliser à la place : @see recuperer
*/
final protected function requeteUn($requete, $mode = self::MODE_ASSOC) {
return $this->recuperer($requete, $mode);
}
/**
* Execute une requête et retourne le premier résultat sous forme de tableau (par défaut) ou d'objet.
* Les noms des champs de la base de données correspondent aux noms des clés du tableau ou aux noms des attributs de l'objet.
*
* @param string la requête à effectuer
* @param string le mode de retour ASSOC (Bdd::MODE_ASSOC) pour un tableau ou OBJECT (Bdd::MODE_OBJET) pour un objet.
* @return mixed un objet ou un tableau contenant le résultat de la requête
*/
public function recuperer($requete, $mode = self::MODE_ASSOC) {
$this->connecter();
 
$retour = null;
switch ($this->abstraction) {
case self::ABSTRACTION_PDO :
try {
$resultat = $this->connexion->query($requete);
$retour = $resultat->fetch($this->$mode);
} catch (PDOException $e) {
$m = sprintf(self::ERREUR_REQUETE_TPL, $e->getFile(), $e->getLine(), $e->getMessage(), $requete);
trigger_error($m, E_USER_WARNING);
}
break;
case self::ABSTRACTION_MYSQL :
$res = mysql_query($requete, $this->connexion);
$fonction_fetch = $this->$mode;
$retour = $fonction_fetch($res);
break;
case self::ABSTRACTION_MYSQLI :
$res = $this->connexion->query($requete);
$fonction_fetch = $this->$mode;
$retour = $res->$fonction_fetch();
break;
case self::ABSTRACTION_SQLITE3 :
$retour = $this->connexion->querySingle($requete);
break;
}
return $retour;
}
/**
* @deprecated changement de nom. Disparaîtra dans la version 0.4. Utiliser à la place : @see recupererTous
*/
final protected function requeteTous($requete, $mode = self::MODE_ASSOC) {
return $this->recupererTous($requete, $mode);
}
/**
* Execute une requête et retourne un tableau de résultats. Un résultat peut être présentés sous forme
* de tableau (par défaut) ou d'objet.
* Les noms des champs de la base de données correspondent aux noms des clés du tableau résultat ou
* aux noms des attributs de l'objet résultat.
*
* @param string la requête à effectuer
* @param string le mode de retour des résultats : ASSOC (Bdd::MODE_ASSOC) pour un tableau ou OBJECT (Bdd::MODE_OBJET) pour un objet.
* @return array un tableau contenant les résultats sous forme d'objets ou de tableau (par défaut).
*/
public function recupererTous($requete, $mode = self::MODE_ASSOC) {
$this->connecter();
$retour = null;
switch ($this->abstraction) {
case self::ABSTRACTION_PDO :
try {
$resultat = $this->connexion->query($requete);
if ($resultat !== false) {
$retour = $resultat->fetchAll($this->$mode);
} else {
$retour = false;
}
} catch (PDOException $e) {
$m = sprintf(self::ERREUR_REQUETE_TPL, $e->getFile(), $e->getLine(), $e->getMessage(), $requete);
trigger_error($m, E_USER_WARNING);
}
break;
case self::ABSTRACTION_MYSQL :
$resultat = mysql_query($requete, $this->connexion);
$fonction_fetch = $this->$mode;
while ($ligne = $fonction_fetch($resultat)) {
$retour[] = $ligne;
}
break;
case self::ABSTRACTION_MYSQLI :
$resultat = $this->connexion->query($requete);
$function_fetch = $this->$mode;
while ($ligne = $resultat->$function_fetch()) {
$retour[] = $ligne;
}
break;
case self::ABSTRACTION_SQLITE3 :
$resultat = $this->connexion->query($requete);
while ($ligne = $resultat->fetch_array($this->ASSOC)) {
if ($mode == self::MODE_OBJET) {
// Cas particulier de sqllite qui n'a pas de fonction fetch_object
$ligneObjet = new stdClass();
foreach ($ligne as $colonne => $valeur) {
$ligneObjet->$colonne = $valeur;
}
$ligne = $ligneObjet;
}
$retour[] = $ligne;
}
break;
}
return $retour;
}
 
/**
* Protège une chaine de caractères avant l'insertion dans la base de données (ajout de quotes ou guillemets).
* @param string la chaine à protéger
* @return string la chaine protégée
*/
public function proteger($chaine) {
$this->connecter();
 
$retour = $chaine;
switch ($this->abstraction) {
case self::ABSTRACTION_PDO :
$retour = $this->connexion->quote($chaine);
break;
case self::ABSTRACTION_MYSQL :
$retour = '"'.mysql_real_escape_string($chaine, $this->connexion).'"';
break;
case self::ABSTRACTION_MYSQLI :
$retour = '"'.$this->connexion->real_escape_string($chaine).'"';
break;
case self::ABSTRACTION_SQLITE3 :
$retour = $this->connexion->escapeString($chaine);
break;
}
return $retour;
}
 
/**
* Retourne l'identifiant de la dernière ligne insérée, ou la dernière valeur d'une séquence d'objets, dépendamment, dans
* le cas de PDO, du driver utilisé. Les méthodes utilisées pour retourner l'identifiant peuvent avoir des comportements
* différent. Consulter la documentation PHP correspondant à l'abstraction choisie avant de l'utiliser :
* @link(http://fr.php.net/manual/fr/pdo.lastinsertid.php, PDO::lastInsertId([ string $name = NULL ]))
* @link(http://php.net/manual/en/mysqli.insert-id.php, mysqli->insert_id())
* @link(http://fr.php.net/manual/fr/function.mysql-insert-id.php, mysql_insert_id())
* @link(http://fr.php.net/manual/fr/sqlite3.lastinsertrowid.php, SQLite3::lastInsertRowID())
* @param mixed un paramètre éventuel à transmettre (en fonction de l'abstraction de BDD utilisée).
* @return mixed le dernier identifiant de clé primaire ajouté dans la base de données (string ou int).
*/
public function recupererIdDernierAjout($parametres = null) {
$this->connecter();
 
$retour = $chaine;
switch ($this->abstraction) {
case self::ABSTRACTION_PDO :
$retour = $this->connexion->lastInsertId($parametres);
break;
case self::ABSTRACTION_MYSQL :
$retour = mysql_insert_id($this->connexion);
break;
case self::ABSTRACTION_MYSQLI :
$retour = $this->connexion->insert_id();
break;
case self::ABSTRACTION_SQLITE3 :
$retour = $this->connexion->lastInsertRowID();
break;
}
return $retour;
}
/**
* Destructeur de classe, se contente de fermer explicitement la connexion à la base de donnée.
*/
public function __destruct() {
switch ($this->abstraction) {
case self::ABSTRACTION_PDO :
$this->connexion = null;
break;
case self::ABSTRACTION_MYSQL :
return mysql_close($this->connexion);
break;
case self::ABSTRACTION_MYSQLI :
$this->connexion->close();
break;
case self::ABSTRACTION_SQLITE3 :
$this->connexion->close();
break;
}
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/RestServeur.php
New file
0,0 → 1,488
<?php
/**
* Classe principale gérant les services web de type (@link(REST, http://fr.wikipedia.org/wiki/Rest).
*
* Elle contient :
* - les constantes indiquant les différentes (@link(méthode HTTP, http://fr.wikipedia.org/wiki/Http) prises en compte.
* - les @link(codes HTTP des réponses, http://fr.wikipedia.org/wiki/Liste_des_codes_HTTP)
*
* Ce serveur REST accepte 4 types de méthodes HTTP : GET, PUT, POST, DELETE.
* GET et POST ne pose généralement pas de problème pour les clients HTTP mais ce n'est pas forcément le cas pour PUT et DELETE.
* Vous pouvez donc pour réaliser :
* - DELETE : utiliser la méthode POST avec action=DELETE dans le corps de la requête.
* - PUT : utiliser la méthode POST avec une url ne contenant aucune indication de ressource.
* Une autre solution consiste à utiliser n'importe quelle méthode et à ajouter l'entête "X_HTTP_METHOD_OVERRIDE" avec pour
* valeur le nom de la méthode que vous souhaitez utiliser. Exemple d'entête : "X_HTTP_METHOD_OVERRIDE: PUT".
* Exemple : <code>curl -v -v -H "X_HTTP_METHOD_OVERRIDE: DELETE" "http://www.mondomaine.org/services/apiVersion/[mon-service]/"</code>
* Cela fonctionne avec Apache.
*
* Les classes des services web doivent avoir un nom au format ChatMot "MonService" et être appelée dans l'url par le même nom
* en minuscule où les mots sont séparés par des tirets "mon-service".
*
* Paramètres liés dans config.ini :
* - serveur.baseURL : morceau de l'url pour appeler le serveur relative au domaine. Exemple : pour http://www.tela-botanica.org/mon_serveur/
* mettre : "/mon_serveur/"
* - serveur.baseAlternativeURL : sur le même principe que ci-dessus permet d'affecter une deuxième url (pour gérer des raccourci via htaccess)
*
* Encodage en entrée : utf8
* Encodage en sortie : utf8
*
* @category Php 5.2
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @since 0.3
* @version $Id$
* @link /doc/framework/
*/
// TODO : gerer les retours : dans ce controleur : code retour et envoi ...
class RestServeur {
/** Nom de la méthode appelée dans un service pour éxécuter une requête de type GET. */
const METHODE_GET = 'consulter';
/** Nom de la méthode appelée dans un service pour éxécuter une requête de type POST. */
const METHODE_POST = 'modifier';
/** Nom de la méthode appelée dans un service pour éxécuter une requête de type DELETE. */
const METHODE_DELETE = 'supprimer';
/** Nom de la méthode appelée dans un service pour éxécuter une requête de type PUT. */
const METHODE_PUT = 'ajouter';
/** Code HTTP 200 indiquant le succès de l'accès à un service web par la méthode GET.
* L'utiliser lors d'une requète de type GET (consulter) pour indiquer le succès de l'opération.
* Sera renvoyée par défaut par PHP. */
const HTTP_CODE_OK = '200';
/** Code HTTP 201 indiquant que l'accès à un service web est un succès et que la ressource a été créée ou modifié.
* L'utiliser lors d'une requète de type PUT (ajouter) ou POST (modifier) pour indiquer le succès de l'opération. */
const HTTP_CODE_CREATION_OK = '201';
/** Code HTTP 204 indique que l'accès à un service web est un succès et qu'il n'y a pas de contenu à renvoyer.
* L'utiliser lors d'une requète de type DELETE (supprimer) pour indiquer le succès de l'opération. */
const HTTP_CODE_SUPPRESSION_OK = '204';
/** Code HTTP 400 indique que les paramètres envoyés au service contiennent des erreurs.
* L'utiliser pour indiquer l'échec de l'accès au service. La réponse pourra contenir un message expliquant la source
* de l'erreur. */
const HTTP_CODE_MAUVAISE_REQUETE = '400';
/** Code HTTP 401 indiquant que l'accès à un service web est refusé car l'authentification (obligatoire) a échoué pour
* accéder à la ressource. */
const HTTP_CODE_ACCES_NON_AUTORISE = '401';
/** Code HTTP 404 indiquant que la ressource indiquée par l'url est introuvable. */
const HTTP_CODE_RESSOURCE_INTROUVABLE = '404';
/** Code HTTP 405 indiquant soit :
* - que le service web ne possède pas d'accès la ressource correspondant à la méthode HTTP employée.
* - que la méthode HTTP enployée n'est pas en accord avec la ressource indiquée par l'url. */
const HTTP_CODE_METHODE_NON_AUTORISE = '405';
/** Code d'erreur HTTP 409 indiquant qu'un conflit est survenu vis à vis de la ressource.
* Par exemple, essayer de créer deux fois la même ressource ou bien tenter de modifier une ressource qui a été modifiée par
* ailleurs. */
const HTTP_CODE_CONFLIT = '409';
/** Code HTTP 411 indiquant que des paramètres passés dans le contenu de la requête sont nécessaires au service. */
const HTTP_CODE_CONTENU_REQUIS = '411';
/** Code d'erreur HTTP 500 Internal Server Error.
* L'utiliser quand le serveur ou un service soulève une erreur ou une exception. */
const HTTP_CODE_ERREUR = '500';
/** Mettre à true pour activer l'affichage des messages d'erreurs et de débogage.
* @var boolean */
private static $debogageActivation = false;
/** Indiquer le mode de débogage à utiliser (@see Debug).
* @var string */
private static $debogageMode = '';
/** La méthode de la requête HTTP utilisée.
* @var string */
private $methode = 'GET';
 
/** Le contenu brut du corps de la requête HTTP (s'il y en a).
* @var array */
private $requeteDonnees = null;
/** Le contenu sous forme de tableau de paires clés-valeurs du corps de la requête HTTP (s'il y en a).
* @var array */
private $requeteDonneesParsees = null;
 
/** Version de l'API demandée.
* Ex. http://www.mondomaine.org/services/[apiVersion]/mon-service/
* @var mixed Généralement deux nombres séparés par un point. Ex. : 1.0
*/
private $apiVersion = null;
 
/** Nom du service demandé.
* Ex. http://www.mondomaine.org/services/apiVersion/[mon-service]/
* @var string par défaut vaut null.
*/
private $service = null;
/** Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
* Ex. http://www.mondomaine.org/services/apiVersion/mon-service/[maRessource/maSousResource...]
* @var array
*/
private $ressources = array();
/** Partie de l'url situé après le '?' servant à paramétrer le service demandé.
* Ex. http://www.mondomaine.org/services/apiVersion/mon-service?monParametre1=maValeur1&monParametre2=maValeur2
* @var array
*/
private $parametres = array();
/** Tableau contenant les paramètres de configuration du serveur.
* @var array
*/
private static $config = array();
/** Codes HTTP. */
private static $http10 = array(
self::HTTP_CODE_OK => 'OK',
self::HTTP_CODE_CREATION_OK => 'Created',
self::HTTP_CODE_SUPPRESSION_OK => 'No Content',
self::HTTP_CODE_MAUVAISE_REQUETE => 'Bad Request',
self::HTTP_CODE_ACCES_NON_AUTORISE => 'Unauthorized',
self::HTTP_CODE_RESSOURCE_INTROUVABLE => 'Not Found',
self::HTTP_CODE_METHODE_NON_AUTORISE => 'Method Not Allowed',
self::HTTP_CODE_CONFLIT => 'Conflict',
self::HTTP_CODE_CONTENU_REQUIS => 'Length Required',
self::HTTP_CODE_ERREUR => 'Internal Server Error'
);
/** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
private $parametres_obligatoires = array('debogage', 'debogage_mode', 'serveur.baseURL', 'chemin_modules');
 
/**
* Analyse les données envoyées au serveur, enregistre la méthode HTTP utilisée pour appeler le serveur et parse
* l'url appelée pour trouver le service demandé.
*/
public function __construct() {
Config::verifierPresenceParametres($this->parametres_obligatoires);
self::$debogageActivation = Config::get('debogage');
self::$debogageMode = Config::get('debogage_mode');
 
if (isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && isset($_SERVER['QUERY_STRING'])) {
$this->initialiserMethode();
$this->initialiserRequeteDonnees();
$urlParts = $this->decouperUrlChemin();
$this->initialiserApiVersion(array_shift($urlParts));
$this->initialiserServiceNom(array_shift($urlParts));
$this->initialiserRessource($urlParts);
$this->initialiserParametres();
Debug::printr($this);
// Enregistrement en première position des autoload de la méthode gérant les classes des services
spl_autoload_register(array(get_class(), 'chargerClasse'));
} else {
$e = "La classe Serveur du TBFRamework nécessite, pour fonctionner, l'accès aux variables serveurs REQUEST_URI, REQUEST_METHOD et QUERY_STRING.";
trigger_error($e, E_USER_ERROR);
}
}
private function initialiserMethode() {
if (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']) && count(trim($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) > 0) {
$this->methode = trim($_SERVER['X_HTTP_METHOD_OVERRIDE']);
} else {
$this->methode = $_SERVER['REQUEST_METHOD'];
}
}
private function initialiserRequeteDonnees() {
if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 0) {
$this->requeteDonnees = '';
$httpContent = fopen('php://input', 'r');
while ($data = fread($httpContent, 1024)) {
$this->requeteDonnees .= $data;
}
fclose($httpContent);
}
}
private function decouperUrlChemin() {
if (strlen($_SERVER['QUERY_STRING']) == 0) {
$tailleURL = strlen($_SERVER['REQUEST_URI']);
} else {
$tailleURL = -(strlen($_SERVER['QUERY_STRING']) + 1);
}
$urlChaine = '';
if (strpos($_SERVER['REQUEST_URI'], Config::get('serveur.baseURL')) !== false) {
$urlChaine = substr($_SERVER['REQUEST_URI'], strlen(Config::get('serveur.baseURL')), $tailleURL);
} else if (strpos($_SERVER['REQUEST_URI'], Config::get('serveur.baseAlternativeURL')) !== false) {
$urlChaine = substr($_SERVER['REQUEST_URI'], strlen(Config::get('serveur.baseAlternativeURL')), $tailleURL);
}
return explode('/', $urlChaine);
}
private function initialiserApiVersion($apiVersion) {
if (isset($apiVersion) && !empty($apiVersion)) {
$this->apiVersion = $apiVersion;
self::$config['chemins']['api'] = Config::get('chemin_modules').$this->apiVersion.DS;
} else {
$e = "Aucune version d'API n'a été spécifié dans l'url qui doit avoir la forme suivante http://www.mondomaine.org/services/apiVersion/monService/";
trigger_error($e, E_USER_ERROR);
}
}
private function initialiserServiceNom($serviceNom) {
if (isset($serviceNom) && !empty($serviceNom)) {
$this->service = $this->traiterNomService($serviceNom);
} else {
$e = "Aucun service n'a été spécifié dans l'url qui doit avoir la forme suivante http://www.mondomaine.org/services/apiVersion/monService/";
trigger_error($e, E_USER_ERROR);
}
}
private function traiterNomService($serviceNom) {
return str_replace(' ', '', ucwords(str_replace('-', ' ', strtolower($serviceNom))));
}
private function initialiserRessource($urlParts) {
if (is_array($urlParts) && count($urlParts) > 0) {
foreach ($urlParts as $ressource) {
// Ne pas utiliser empty() car valeur 0 acceptée
if ($ressource != '') {
$this->ressources[] = urldecode($ressource);
}
}
}
}
private function initialiserParametres() {
$this->nettoyerGet();
$this->parametres = $_GET;
}
private function nettoyerGet() {
// Pas besoin d'utiliser urldecode car déjà fait par php pour les clés et valeur de $_GET
if (isset($_GET) && count($_GET) > 0) {
foreach ($_GET as $cle => $valeur) {
$verifier = array('NULL', "\n", "\r", "\\", "'", '"', "\x00", "\x1a", ';');
$_GET[$cle] = strip_tags(str_replace($verifier, '', $valeur));
}
}
}
/**
* La méthode __autoload() charge dynamiquement les classes trouvées dans le code.
* Cette fonction est appelée par php5 quand il trouve une instanciation de classe dans le code.
*
*@param string le nom de la classe appelée.
*@return void le fichier contenant la classe doit être inclu par la fonction.
*/
public static function chargerClasse($classe) {
if (class_exists($classe)) {
return null;
}
 
$chemins = array('', self::$config['chemins']['api']);
foreach ($chemins as $chemin) {
$chemin = $chemin.$classe.'.php';
if (file_exists($chemin)) {
require_once $chemin;
}
}
}
/**
* Execute la requête.
*/
function executer() {
switch ($this->methode) {
case 'GET':
$this->get();
break;
case 'POST':
$this->post();
break;
case 'DELETE':
$this->delete();
break;
case 'PUT':
$this->put();
break;
default :
$e = "La méthode HTTP '{$this->methode}' n'est pas prise en compte par ce serveur REST.";
trigger_error($e, E_USER_WARNING);
}
// Affichage des exceptions et erreurs générées par les services
$this->gererErreurs();
}
 
/**
* Execute a GET request. A GET request fetches a list of resource when no resource name is given, a list of element
* when a resource name is given, or a resource element when a resource and resource unique identifier are given. It does not change the
* database contents.
*/
private function get() {
if ($this->service != null) {
$Service = new $this->service(self::$config);
if (method_exists($Service, self::METHODE_GET)) {
$methodeGet = self::METHODE_GET;
$Service->$methodeGet($this->ressources, $this->parametres);
} else {
$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_GET."' nécessaire ".
"lors de l'appel du service via la méthode HTTP GET.";
trigger_error($e, E_USER_ERROR);
}
}
}
 
private function post() {
$paires = $this->parserDonneesRequete();
 
if (count($paires) != 0) {
if (isset($paires['action']) && $paires['action'] == 'DELETE') {// Altnative à l'utilisation de DELETE
$this->delete();
} else if (count($this->ressources) == 0) {// Altnative à l'utilisation de PUT
$this->add();
} else {
if ($this->service != null) {
$Service = new $this->service(self::$config);
if (method_exists($Service, self::METHODE_POST)) {
$methodePost = self::METHODE_POST;
if ($Service->$methodePost($this->ressources, $paires)) {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CREATION_OK);
}
} else {
$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_POST."' nécessaire ".
"lors de l'appel du service via la méthode HTTP POST.";
trigger_error($e, E_USER_ERROR);
}
}
}
} else {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CONTENU_REQUIS);
}
}
 
private function put() {
$paires = $this->parserDonneesRequete();
 
if (count($paires) != 0) {
if ($this->service != null) {
$Service = new $this->service(self::$config);
if (method_exists($Service, self::METHODE_PUT)) {
$methodePut = self::METHODE_PUT;
if ($Service->$methodePut($this->ressources, $paires)) {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CREATION_OK);
}
} else {
$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_PUT."' nécessaire ".
"lors de l'appel du service via la méthode HTTP PUT (ou équivalant).";
trigger_error($e, E_USER_ERROR);
}
}
} else {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CONTENU_REQUIS);
}
}
 
private function delete() {
if (count($this->ressources) != 0) {
if ($this->service != null) {
$Service = new $this->service(self::$config);
if (method_exists($Service, self::METHODE_DELETE)) {
$methodeDelete = self::METHODE_DELETE;
if ($Service->$methodeDelete($this->ressources, $paires)) {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_SUPPRESSION_OK);
} else {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
}
} else {
$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_DELETE."' nécessaire ".
"lors de l'appel du service via la méthode HTTP DELETE (ou équivalant).";
trigger_error($e, E_USER_ERROR);
}
}
} else {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
}
}
/**
* Parse les données contenu dans le corps de la requête HTTP (= POST) en :
* - décodant les clés et valeurs.
* - supprimant les espaces en début et fin des clés et des valeurs.
*
* @return array Tableau de paires clé et valeur.
*/
private function parserDonneesRequete() {
$donnees = array();
if ($this->$requeteDonneesParsees != null) {
$donnees = $this->$requeteDonneesParsees;
} else if ($this->requeteDonnees != null) {
$paires = explode('&', $this->requeteDonnees);
foreach ($paires as $paire) {
list($cle, $valeur) = explode('=', $paire);
$cle = (isset($cle)) ? trim(urldecode($cle)) : '';
$valeur = (isset($valeur)) ? trim(urldecode($valeur)) : '';
$donnees[$cle] = $valeur;
}
$this->$requeteDonneesParsees = $donnees;
}
return $donnees;
}
/**
* Envoyer un entête HTTP (version 1.0) de statut.
* Il remplacera systématiquement tout entête HTTP de statut précédement envoyé.
* @param int $code entier indiquant le code du statut de l'entête HTTP à envoyer.
*/
public static function envoyerEnteteStatutHttp($code) {
if (isset(self::$http10[$code])) {
$txt = self::$http10[$code];
header("HTTP/1.0 $code $txt", true);
}
}
/**
* Si des exceptions ou des erreurs sont soulevées par le serveur ou les services, elles sont gérées par cette méthode.
* Si nous avec des erreurs d'un type différent d'E_USER_NOTICE (réservé au débogage), elle sont renvoyées sur la sortie
* standard (via echo).
* Si seulement des erreurs de type E_USER_NOTICE, sont présentes, elle sont envoyées en fonction du contenu du paramètre de
* config "debogage_mode" :
* - Debug::MODE_ECHO : les messages sont affichés en utilisant echo au moment où ils sont déclenchés dans le code.
* - Debug::MODE_NOTICE : les message sont stockés par le gestionnaire d'exception sous forme d'erreur de type
* E_USER_NOTICE et sont renvoyés sur la sortie standard à la fin de l'execution du programme (via echo).
* - Debug::MODE_ENTETE_HTTP : les message sont stockés par le gestionnaire d'exception sous forme d'erreur de type
* E_USER_NOTICE et sont renvoyés dans un entête HTTP (X_REST_DEBOGAGE_MESSAGES) à la fin de l'execution du programme.
* - Autre valeur : les messages sont formatés puis retournés par la fonction de débogage (à vous de les afficher).
*/
public static function gererErreurs() {
if (self::$debogageActivation && GestionnaireException::getExceptionsNbre() > 0) {
$exceptionsTriees = GestionnaireException::getExceptionsTriees();
reset($exceptionsTriees);
$debogageSeulement = true;
if (! (count($exceptionsTriees) == 1 && key($exceptionsTriees) == E_USER_NOTICE)) {
self::envoyerEnteteStatutHttp(self::HTTP_CODE_ERREUR);
$debogageSeulement = false;
}
$exceptionsFormatees = array();
foreach ($exceptionsTriees as $exceptions) {
foreach ($exceptions as $e) {
if ($debogageSeulement && self::$debogageMode == Debug::MODE_ENTETE_HTTP) {
$exceptionsFormatees[] = GestionnaireException::formaterExceptionTxt($e);
} else {
echo GestionnaireException::formaterExceptionXhtml($e);
}
}
}
if ($debogageSeulement && self::$debogageMode == Debug::MODE_ENTETE_HTTP) {
header('X_REST_DEBOGAGE_MESSAGES: '.json_encode($exceptionsFormatees));
}
}
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/Controleur.php
New file
0,0 → 1,122
<?php
// declare(encoding='UTF-8');
/**
* Classe Controleur, coeur d'une application, c'est normalement la seule classe d'une application
* qui devrait être appelée de l'extérieur.
* Elle est abstraite donc doit obligatoirement être étendue.
*
* @category php 5.2
* @package Framework
* @author Aurélien PERONNET <aurelien@tela-botanica.org>
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2009, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
* @version $Id$
* @link /doc/framework/
*
*/
abstract class Controleur {
/** Variable statique indiquant que les tableaux _GET et _POST ont déjà été encodé au format de l'appli. */
private static $encodage = false;
 
/** Chemin de base vers les classes métiers de la partie Modèle de l'application. */
private $base_chemin_modele = null;
/** Chemin de base vers les fichiers squelette de la partie Vue de l'application. */
private $base_chemin_squelette = null;
/** Chemin de base vers les classes controleurs de la partie Controleur de l'application. */
private $base_chemin_controleur = null;
/** Objet URL contant l'url de la base de l'application. */
private $base_url_applicaton = null;
 
/** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
protected $parametres_obligatoires = array('chemin_modeles', 'chemin_squelettes', 'chemin_controleurs', 'base_url_application');
/**
* Constructeur par défaut
*/
public function __construct() {
Config::verifierPresenceParametres($this->parametres_obligatoires);
$this->base_chemin_modele = Config::get('chemin_modeles');
$this->base_chemin_squelette = Config::get('chemin_squelettes');
$this->base_chemin_controleur = Config::get('chemin_controleurs');
$this->base_url_application = new Url(Config::get('base_url_application'));
}
 
/**
* Charge un modele donné et le rend disponible sous la forme $this->nom_modele
*
* @param string $nom_modele le nom du modèle à  charger
*
* @return boolean false si le chargement a échoué, sinon true.
*/
final public function chargerModele($nom_modele) {
$sortie = true;
if (!isset($this->$nom_modele)) {
$modele = $this->getModele($nom_modele);
if ($modele !== false) {
$this->$nom_modele = new $nom_modele;
} else {
$sortie = false;
}
}
return $sortie;
}
 
/**
* Retourne un modele donné
*
* @param string $nom_modele le nom du fichier modèle à charger sans son extension
* @param String $ext l'extension du fichier du modèel (par défaut : ".php"
*
* @return mixed false si le chargement a échoué, sinon l'objet du modèle demandé.
*/
final protected function getModele($nom_modele, $ext = '.php') {
$sortie = false;
$chemin_modele = $this->registre->get('base_chemin_modele').$nom_modele.$ext;
if (file_exists($chemin_modele)) {
include_once $chemin_modele;
if (class_exists($nom_modele)) {
$sortie = new $nom_modele;
}
}
return $sortie;
}
 
/**
* Fonction prenant en paramètre le nom d'un squelette et un tableau associatif de données,
* en extrait les variables, charge le squelette et retourne le résultat des deux combinés.
*
* @param String $nom_squelette le nom du squelette sans son extension
* @param Array $donnees un tableau associatif contenant les variables a injecter dans la vue
* @param String $ext l'extension du fichier du squelette (par défaut : ".tpl.html"
*
* @return boolean false si la vue n'existe pas, sinon la chaine résultat.
*/
final protected function getVue($nom_squelette, &$donnees = array(), $ext = '.tpl.html') {
$donnees = $this->preTraiterDonnees($donnees);
$chemin_squelette = $this->base_chemin_squelette.$nom_squelette.$ext;
$sortie = SquelettePhp::analyser($chemin_squelette, $donnees);
 
return $sortie;
}
 
/**
* Fonction prenant en paramètre un tableau de données et effectuant un traitement dessus.
* Cette fonction est à surcharger dans les classes filles pour automatiser un traitement
* avant chaque chargement de vue.
*
* @param Array $donnees Le tableau de données à traiter
*
* @return Array $donnees Le tableau de données traité
*/
protected function preTraiterDonnees(&$donnees) {
return $donnees;
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/Framework.php
New file
0,0 → 1,241
<?php
// declare(encoding='UTF-8');
/**
* Classe de base du Framework :
* - fournissant des infos sur l'application,
* - paramétrant l'environnement de l'appli et du framework,
* - réalisant des traitements sur les variables globales ($_GET, $_POST, $_COOKIE...)
*
* Cette classe contient la fonction de chargement automatique de classes.
* Ce fichier doit toujours rester à la racine du framework car il initialise le chemin
* de l'application en se basant sur son propre emplacement.
*
* @category PHP 5.2
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL-v3
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL-v2
* @version $Id$
* @since 0.3
* @link /doc/framework/
*/
class Framework {
 
/** Variable statique indiquant que les tableaux _GET et _POST ont déjà été encodé au format de l'appli. */
private static $encodage = false;
/** Tableau d'informations sur l'application */
private static $info = null;
/** Chemin de base de l'application */
private static $chemin = null;
 
/** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
private static $parametres_obligatoires = array('chemin_controleurs', 'chemin_modeles', 'chemin_bibliotheque',
'url_arg_separateur_entree', 'url_arg_separateur_sortie',
'encodage_sortie', 'encodage_appli');
/**
* Initialise l'environnement nécessaire au Framework : constantes globales, méthodeles autoload, séparateur d'arguments
* d'url.
* Cette méthode est appelée automatiquement suite à la définition du chemin de l'application via Application::setChemin().
*/
private static function initialiserEnvironnement() {
self::enregistrerMethodesAutoload();
self::initialiserUrl();
}
/**
* Initialise différentes classes du Framework nécessaires pour le fonctionnement de l'application.
* Ces classes sont ensuites controlées via les fichiers de config.ini.
* Elle est appelée automatiquement suite à la définition du chemin de l'application via Application::setChemin().
*/
private static function initialiserFramework() {
GestionnaireException::configurer();
//Log::configurer();
self::verifierEtReencoderTableauRequete();
}
/**
* Redéfinit des constantes globales utiles pour le Framework et les applis.
*/
private static function definirConstantesGlobales() {
/** Redéfinition de la constante DIRECTORY_SEPARATOR en version abrégée DS */
if (!defined('DS')) {
define('DS', DIRECTORY_SEPARATOR);
}
/** Redéfinition de la constante PATH_SEPARATOR en version abrégée PS */
if (!defined('PS')) {
define('PS', PATH_SEPARATOR);
}
}
private static function enregistrerMethodesAutoload() {
spl_autoload_register(array(get_class(), 'autoloadFw'));
// Vérification des paramètres de configuration obligatoire pour assurer le fonctionnement du Framework
Config::verifierPresenceParametres(self::$parametres_obligatoires);
// Initialisation du gestionnaire d'erreur avant toute chose
GestionnaireException::initialiser();
spl_autoload_register(array(get_class(), 'autoloadAppliDefaut'));
// Autoload défini par l'application
if (function_exists('__autoload')) {
spl_autoload_register('__autoload');
}
}
/**
* Autoload pour le Framework.
*/
private static function autoloadFw($nom_classe_fw) {
$dossiers_classes = array( dirname(__FILE__).DS,
dirname(__FILE__).DS.'utilitaires'.DS);
foreach ($dossiers_classes as $chemin) {
$fichier_a_tester = $chemin.$nom_classe_fw.'.php';
if (file_exists($fichier_a_tester)) {
include_once $fichier_a_tester;
return null;
}
}
}
/**
* Autoload par défaut pour l'application
*/
private static function autoloadAppliDefaut($nom_classe) {
$dossiers_classes = array( Config::get('chemin_controleurs'),
Config::get('chemin_modeles'),
Config::get('chemin_bibliotheque'));
foreach ($dossiers_classes as $chemin) {
$fichier_a_tester = $chemin.$nom_classe.'.php';
if (file_exists($fichier_a_tester)) {
include_once $fichier_a_tester;
return null;
}
}
}
/**
* Initialise le format des urls.
*/
private static function initialiserUrl() {
ini_set('arg_separator.input', Config::get('furl_arg_separateur_entree'));
ini_set('arg_separator.output', Config::get('url_arg_separateur_sortie'));
}
/**
* Permet d'indiquer le chemin de base de l'Application.
* Cette méthode doit obligatoirement être utilisée par l'application pour que le Framework fonctionne correctement.
* @param string $chemin_fichier_principal chemin de base
*/
public static function setCheminAppli($chemin_fichier_principal) {
if (self::$chemin === null) {
if (!file_exists($chemin_fichier_principal)) {
trigger_error("Le fichier indiqué n'existe pas. Utilisez __FILE__ dans la méthode setCheminAppli().", E_USER_ERROR);
} else {
self::definirConstantesGlobales();
self::$chemin = dirname($chemin_fichier_principal).DS;
self::initialiserEnvironnement();
self::initialiserFramework();
}
} else {
trigger_error("Le chemin de l'application a déjà été enregistré auprès du Framework", E_USER_WARNING);
}
}
 
/**
* accesseur pour le chemin
* @return string le chemin
*/
public static function getCheminAppli() {
return self::$chemin;
}
 
/** Le tableau des informations sur l'application possède les clés suivantes :
* - nom : nom de l'application
* - abr : abréviation de l'application
* - encodage : encodage de l'application (ISO-8859-15, UTF-8...)
*
* @param array $info tableau fournissant des informations sur l'application
* @return void
*/
public static function setInfoAppli($info) {
if (self::$info === null) {
self::$info = $info;
} else {
trigger_error("Le informations de l'application ont déjà été enregistrées auprès du Framework", E_USER_WARNING);
}
}
 
/**
* Accesseur pour le tableau d'infos sur l'application.
* @param string $cle la clé à laquelle on veut accéder
*/
public static function getInfoAppli($cle = null) {
if ($cle !== null) {
if (isset(self::$info[$cle])) {
return self::$info[$cle];
}
} else {
return self::$info;
}
}
/**
* Procédure vérifiant l'encodage des tableaux $_GET et $_POST et les transcodant dans l'encodage de l'application
*/
protected static function verifierEtReencoderTableauRequete() {
if (self::$encodage == false && Config::get('encodage_sortie') != Config::get('encodage_appli')) {
$_POST = self::encoderTableau($_POST, Config::get('encodage_appli'), Config::get('encodage_sortie'));
$_GET = self::encoderTableau($_GET, Config::get('encodage_appli'), Config::get('encodage_sortie'));
// Traitement des magic quotes
self::verifierEtTraiterSlashTableauRequete();
self::$encodage = true;
}
}
/**
* Procédure vérifiant l'activation des magic quotes et remplacant les slash dans les tableaux de requete
*/
private static function verifierEtTraiterSlashTableauRequete() {
if (get_magic_quotes_gpc()) {
if (!function_exists('nettoyerSlashProfond')) {
function nettoyerSlashProfond($valeur) {
return ( is_array($valeur) ) ? array_map('nettoyerSlashProfond', $valeur) : stripslashes($valeur);
}
}
$_GET = array_map('nettoyerSlashProfond', $_GET);
$_POST = array_map('nettoyerSlashProfond', $_POST);
$_COOKIE = array_map('nettoyerSlashProfond', $_COOKIE);
}
}
 
/**
* Fonction récursive transcodant toutes les valeurs d'un tableau de leur encodage d'entrée vers un encodage de sortie donné
* @param $tableau Array Un tableau de données à encoder
* @param $encodage_sortie String l'encodage vers lequel on doit transcoder
* @param $encodage_entree String l'encodage original des chaines du tableau (optionnel)
* @return Array Le tableau encodé dans l'encodage de sortie
*
*/
final static protected function encoderTableau($tableau, $encodage_sortie, $encodage_entree = null) {
if (is_array($tableau)) {
foreach ($tableau as $cle => $valeur) {
if (is_array($valeur)) {
$tableau[$cle] = self::encoderTableau($valeur, $encodage_sortie, $encodage_entree);
} else {
$tableau[$cle] = mb_convert_encoding($valeur, $encodage_sortie, $encodage_entree);
}
}
}
return $tableau;
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/CacheFichier.php
New file
0,0 → 1,871
<?php
class CacheFichier {
/**
* Options disponibles
*
* ====> (string) stockage_chemin :
* Chemin vers le dossier devant contenir l'arborescence du cache.
*
* =====> (boolean) fichier_verrou :
* - Active / Désactive le verrouillage des fichiers
* - Peut éviter la corruption du cache dans de mauvaises circonstances, mais cela ne fonctionne pas sur des serveur
* multithread et sur les systèmes de fichiers NFS par exemple.
*
* =====> (boolean) controle_lecture :
* - Activer / désactiver le contrôle de lecture
* - S'il est activé, une clé de contrôle est ajoutée dans le fichier de cache et cette clé est comparée avec celle calculée
* après la lecture.
*
* =====> (string) controle_lecture_type :
* Type de contrôle de lecture (seulement si le contrôle de lecture est activé).
* Les valeurs disponibles sont:
* - «md5» pour un contrôle md5 (le meilleur mais le plus lent)
* - «crc32» pour un contrôle de hachage crc32 (un peu moins sécurisé, mais plus rapide, un meilleur choix)
* - «adler32» pour un contrôle de hachage adler32 (excellent choix aussi, plus rapide que crc32)
* - «strlen» pour un test de longueur uniquement (le plus rapide)
*
* =====> (int) dossier_niveau :
* - Permet de réglez le nombre de niveau de sous-dossier que contiendra l'arborescence des dossiers du cache.
* 0 signifie "pas de sous-dossier pour le cache",
* 1 signifie "un niveau de sous-dossier",
* 2 signifie "deux niveaux" ...
* Cette option peut accélérer le cache seulement lorsque vous avez plusieurs centaines de fichiers de cache.
* Seuls des tests spécifiques peuvent vous aider à choisir la meilleure valeur possible pour vous.
* 1 ou 2 peut être est un bon début.
*
* =====> (int) dossier_umask :
* - Umask pour les sous-dossiers de l'arborescence du cache.
*
* =====> (string) fichier_prefixe :
* - préfixe pour les fichiers du cache
* - ATTENTION : faite vraiment attention avec cette option, car une valeur trop générique dans le dossier cache du système
* (comme /tmp) peut provoquer des catastrophes lors du nettoyage du cache.
*
* =====> (int) fichier_umask :
* - Umask pour les fichiers de cache
*
* =====> (int) metadonnees_max_taille :
* - taille maximum pour le tableau de métadonnées du cache (ne changer pas cette valeur sauf si vous savez ce que vous faite)
*
* @var array options disponibles
*/
protected $options = array(
'stockage_chemin' => null,
'fichier_verrou' => true,
'controle_lecture' => true,
'controle_lecture_type' => 'crc32',
'dossier_niveau' => 0,
'dossier_umask' => 0700,
'fichier_prefixe' => 'tbf',
'fichier_umask' => 0600,
'metadonnees_max_taille' => 100
);
 
/**
* Array of metadatas (each item is an associative array)
*
* @var array
*/
protected $metadonnees = array();
 
private $Cache = null;
/**
* Constructor
*
* @param array $options associative array of options
* @throws Zend_Cache_Exception
* @return void
*/
public function __construct(array $options = array(), Cache $cache) {
$this->Cache = $cache;
$this->initialiserOptionsParConfig();
$this->setOptions($options);
 
if (isset($this->options['prefixe_fichier'])) {
if (!preg_match('~^[a-zA-Z0-9_]+$~D', $this->options['prefixe_fichier'])) {
trigger_error("Préfixe de nom de fichier invalide : doit contenir seulement [a-zA-Z0-9_]", E_USER_WARNING);
}
}
if ($this->options['metadonnees_max_taille'] < 10) {
trigger_error("Taille du tableau des méta-données invalide, elle doit être > 10", E_USER_WARNING);
}
if (isset($options['dossier_umask']) && is_string($options['dossier_umask'])) {
// See #ZF-4422
$this->options['dossier_umask'] = octdec($this->options['dossier_umask']);
}
if (isset($options['fichier_umask']) && is_string($options['fichier_umask'])) {
// See #ZF-4422
$this->options['fichier_umask'] = octdec($this->options['fichier_umask']);
}
}
private function initialiserOptionsParConfig() {
while (list($nom, $valeur) = each($this->options)) {
if (Config::existe($nom)) {
$this->options[$nom] = Config::get($nom);
}
}
}
private function setOptions($options) {
while (list($nom, $valeur) = each($options)) {
if (!is_string($nom)) {
trigger_error("Nom d'option incorecte : $nom", E_USER_WARNING);
}
$nom = strtolower($nom);
if (array_key_exists($nom, $this->options)) {
$this->options[$nom] = $valeur;
}
}
}
 
public function setEmplacement($emplacement) {
if (!is_dir($emplacement)) {
trigger_error("L'emplacement doit être un dossier.", E_USER_WARNING);
}
if (!is_writable($emplacement)) {
trigger_error("Le dossier de stockage du cache n'est pas accessible en écriture", E_USER_WARNING);
}
$emplacement = rtrim(realpath($emplacement), '\\/').DS;
$this->options['stockage_chemin'] = $emplacement;
}
 
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* @param string $id cache id
* @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
* @return string|false cached datas
*/
public function charger($id, $ne_pas_tester_validiter_du_cache = false) {
$donnees = false;
if ($this->tester($id, $ne_pas_tester_validiter_du_cache)) {
$metadonnees = $this->getMetadonneesFichier($id);
$fichier = $this->getFichierNom($id);
$donnees = $this->getContenuFichier($fichier);
if ($this->options['controle_lecture']) {
$cle_secu_donnees = $this->genererCleSecu($donnees, $this->options['controle_lecture_type']);
$cle_secu_controle = $metadonnees['hash'];
if ($cle_secu_donnees != $cle_secu_controle) {
// Probléme détecté par le contrôle de lecture !
// TODO : loguer le pb de sécu
$this->supprimer($id);
$donnees = false;
}
}
}
return $donnees;
}
 
/**
* Teste si un enregistrement en cache est disponible ou pas (pour l'id passé en paramètre).
*
* @param string $id identifiant de cache.
* @return mixed false (le cache n'est pas disponible) ou timestamp (int) "de dernière modification" de l'enregistrement en cache
*/
public function tester($id) {
clearstatcache();
return $this->testerExistenceCache($id, false);
}
 
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data Datas to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @return boolean true if no problem
*/
public function sauver($donnees, $id, $tags = array(), $duree_vie_specifique = false) {
clearstatcache();
$fichier = $this->getFichierNom($id);
$chemin = $this->getChemin($id);
$resultat = true;
if ($this->options['dossier_niveau'] > 0) {
if (!is_writable($chemin)) {
// maybe, we just have to build the directory structure
$this->lancerMkdirEtChmodRecursif($id);
}
if (!is_writable($chemin)) {
$resultat = false;
}
}
if ($resultat === true) {
if ($this->options['controle_lecture']) {
$cle_secu = $this->genererCleSecu($donnees, $this->options['controle_lecture_type']);
} else {
$cle_secu = '';
}
$metadonnees = array(
'hash' => $cle_secu,
'mtime' => time(),
'expiration' => $this->Cache->getTimestampExpiration($duree_vie_specifique),
'tags' => $tags
);
 
if (! $resultat = $this->setMetadonnees($id, $metadonnees)) {
// TODO : ajouter un log
} else {
$resultat = $this->setContenuFichier($fichier, $donnees);
}
}
return $resultat;
}
 
/**
* Remove a cache record
*
* @param string $id cache id
* @return boolean true if no problem
*/
public function supprimer($id) {
$fichier = $this->getFichierNom($id);
$suppression_fichier = $this->supprimerFichier($fichier);
$suppression_metadonnees = $this->supprimerMetadonnees($id);
return $suppression_metadonnees && $suppression_fichier;
}
 
/**
* Clean some cache records
*
* Available modes are :
* 'all' (default) => remove all cache entries ($tags is not used)
* 'old' => remove too old cache entries ($tags is not used)
* 'matchingTag' => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* 'notMatchingTag' => remove cache entries not matching one of the given tags
* ($tags can be an array of strings or a single string)
* 'matchingAnyTag' => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode clean mode
* @param tags array $tags array of tags
* @return boolean true if no problem
*/
public function nettoyer($mode = Cache::NETTOYAGE_MODE_TOUS, $tags = array()) {
// We use this protected method to hide the recursive stuff
clearstatcache();
return $this->nettoyerFichiers($this->options['stockage_chemin'], $mode, $tags);
}
 
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds() {
return $this->analyserCache($this->options['stockage_chemin'], 'ids', array());
}
 
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags() {
return $this->analyserCache($this->options['stockage_chemin'], 'tags', array());
}
 
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsAvecLesTags($tags = array()) {
return $this->analyserCache($this->options['stockage_chemin'], 'matching', $tags);
}
 
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsSansLesTags($tags = array()) {
return $this->analyserCache($this->options['stockage_chemin'], 'notMatching', $tags);
}
 
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of any matching cache ids (string)
*/
public function getIdsAvecUnTag($tags = array()) {
return $this->analyserCache($this->options['stockage_chemin'], 'matchingAny', $tags);
}
 
/**
* Return the filling percentage of the backend storage
*
* @throws Zend_Cache_Exception
* @return int integer between 0 and 100
*/
public function getPourcentageRemplissage() {
$libre = disk_free_space($this->options['stockage_chemin']);
$total = disk_total_space($this->options['stockage_chemin']);
$pourcentage = 0;
if ($total == 0) {
trigger_error("Impossible d'utiliser la fonction disk_total_space", E_USER_WARNING);
} else {
$pourcentage = ($libre >= $total) ? 100 : ((int) (100. * ($total - $libre) / $total));
}
return $pourcentage;
}
 
/**
* Return an array of metadatas for the given cache id
*
* The array must include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadonnees($id) {
if ($metadonnees = $this->getMetadonneesFichier($id)) {
if (time() > $metadonnees['expiration']) {
$metadonnees = false;
} else {
$metadonnees = array(
'expiration' => $metadonnees['expiration'],
'tags' => $metadonnees['tags'],
'mtime' => $metadonnees['mtime']
);
}
}
return $metadonnees;
}
 
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function ajouterSupplementDureeDeVie($id, $supplement_duree_de_vie) {
$augmentation = true;
if ($metadonnees = $this->getMetadonneesFichier($id)) {
if (time() > $metadonnees['expiration']) {
$augmentation = false;
} else {
$metadonnees_nouvelle = array(
'hash' => $metadonnees['hash'],
'mtime' => time(),
'expiration' => $metadonnees['expiration'] + $supplement_duree_de_vie,
'tags' => $metadonnees['tags']
);
$augmentation = $this->setMetadonnees($id, $metadonnees_nouvelle);
}
}
return $augmentation;
}
 
/**
* Get a metadatas record
*
* @param string $id Cache id
* @return array|false Associative array of metadatas
*/
protected function getMetadonneesFichier($id) {
$metadonnees = false;
if (isset($this->metadonnees[$id])) {
$metadonnees = $this->metadonnees[$id];
} else {
if ($metadonnees = $this->chargerMetadonnees($id)) {
$this->setMetadonnees($id, $metadonnees, false);
}
}
return $metadonnees;
}
 
/**
* Set a metadatas record
*
* @param string $id Cache id
* @param array $metadatas Associative array of metadatas
* @param boolean $save optional pass false to disable saving to file
* @return boolean True if no problem
*/
protected function setMetadonnees($id, $metadonnees, $sauvegarde = true) {
if (count($this->metadonnees) >= $this->options['metadonnees_max_taille']) {
$n = (int) ($this->options['metadonnees_max_taille'] / 10);
$this->metadonnees = array_slice($this->metadonnees, $n);
}
$resultat = true;
if ($sauvegarde) {
$resultat = $this->sauverMetadonnees($id, $metadonnees);
}
if ($resultat == true) {
$this->metadonnees[$id] = $metadonnees;
}
return $resultat;
}
 
/**
* Drop a metadata record
*
* @param string $id Cache id
* @return boolean True if no problem
*/
protected function supprimerMetadonnees($id) {
if (isset($this->metadonnees[$id])) {
unset($this->metadonnees[$id]);
}
$fichier_meta = $this->getNomFichierMeta($id);
return $this->supprimerFichier($fichier_meta);
}
 
/**
* Clear the metadatas array
*
* @return void
*/
protected function nettoyerMetadonnees() {
$this->metadonnees = array();
}
 
/**
* Load metadatas from disk
*
* @param string $id Cache id
* @return array|false Metadatas associative array
*/
protected function chargerMetadonnees($id) {
$fichier = $this->getNomFichierMeta($id);
if ($resultat = $this->getContenuFichier($fichier)) {
$resultat = @unserialize($resultat);
}
return $resultat;
}
 
/**
* Save metadatas to disk
*
* @param string $id Cache id
* @param array $metadatas Associative array
* @return boolean True if no problem
*/
protected function sauverMetadonnees($id, $metadonnees) {
$fichier = $this->getNomFichierMeta($id);
$resultat = $this->setContenuFichier($fichier, serialize($metadonnees));
return $resultat;
}
 
/**
* Make and return a file name (with path) for metadatas
*
* @param string $id Cache id
* @return string Metadatas file name (with path)
*/
protected function getNomFichierMeta($id) {
$chemin = $this->getChemin($id);
$fichier_nom = $this->transformaterIdEnNomFichier('interne-meta---'.$id);
return $chemin.$fichier_nom;
}
 
/**
* Check if the given filename is a metadatas one
*
* @param string $fileName File name
* @return boolean True if it's a metadatas one
*/
protected function etreFichierMeta($fichier_nom) {
$id = $this->transformerNomFichierEnId($fichier_nom);
return (substr($id, 0, 21) == 'interne-meta---') ? true : false;
}
 
/**
* Remove a file
*
* If we can't remove the file (because of locks or any problem), we will touch
* the file to invalidate it
*
* @param string $file Complete file path
* @return boolean True if ok
*/
protected function supprimerFichier($fichier) {
$resultat = false;
if (is_file($fichier)) {
if ($resultat = @unlink($fichier)) {
// TODO : ajouter un log
}
}
return $resultat;
}
 
/**
* Clean some cache records (protected method used for recursive stuff)
*
* Available modes are :
* Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $dir Directory to clean
* @param string $mode Clean mode
* @param array $tags Array of tags
* @throws Zend_Cache_Exception
* @return boolean True if no problem
*/
protected function nettoyerFichiers($dossier, $mode = Cache::NETTOYAGE_MODE_TOUS, $tags = array()) {
if (!is_dir($dossier)) {
return false;
}
$resultat = true;
$prefixe = $this->options['fichier_prefixe'];
$glob = @glob($dossier.$prefixe.'--*');
if ($glob === false) {
// On some systems it is impossible to distinguish between empty match and an error.
return true;
}
foreach ($glob as $fichier) {
if (is_file($fichier)) {
$fichier_nom = basename($fichier);
if ($this->etreFichierMeta($fichier_nom)) {
// Pour le mode Cache::NETTOYAGE_MODE_TOUS, nous essayons de tous supprimer même les vieux fichiers méta
if ($mode != Cache::NETTOYAGE_MODE_TOUS) {
continue;
}
}
$id = $this->transformerNomFichierEnId($fichier_nom);
$metadonnees = $this->getMetadonneesFichier($id);
if ($metadonnees === FALSE) {
$metadonnees = array('expiration' => 1, 'tags' => array());
}
switch ($mode) {
case Cache::NETTOYAGE_MODE_TOUS :
if ($resultat_suppression = $this->supprimer($id)) {
// Dans ce cas seulement, nous acception qu'il y ait un problème avec la suppresssion du fichier meta
$resultat_suppression = $this->supprimerFichier($fichier);
}
$resultat = $resultat && $resultat_suppression;
break;
case Cache::NETTOYAGE_MODE_EXPIRATION :
if (time() > $metadonnees['expiration']) {
$resultat = $this->supprimer($id) && $resultat;
}
break;
case Cache::NETTOYAGE_MODE_AVEC_LES_TAGS :
$correspondance = true;
foreach ($tags as $tag) {
if (!in_array($tag, $metadonnees['tags'])) {
$correspondance = false;
break;
}
}
if ($correspondance) {
$resultat = $this->supprimer($id) && $resultat;
}
break;
case Cache::NETTOYAGE_MODE_SANS_LES_TAGS :
$correspondance = false;
foreach ($tags as $tag) {
if (in_array($tag, $metadonnees['tags'])) {
$correspondance = true;
break;
}
}
if (!$correspondance) {
$resultat = $this->supprimer($id) && $resultat;
}
break;
case Cache::NETTOYAGE_MODE_AVEC_UN_TAG :
$correspondance = false;
foreach ($tags as $tag) {
if (in_array($tag, $metadonnees['tags'])) {
$correspondance = true;
break;
}
}
if ($correspondance) {
$resultat = $this->supprimer($id) && $resultat;
}
break;
default:
trigger_error("Mode de nettoyage invalide pour la méthode nettoyer()", E_USER_WARNING);
break;
}
}
if ((is_dir($fichier)) and ($this->options['dossier_niveau'] > 0)) {
// Appel récursif
$resultat = $this->nettoyerFichiers($fichier.DS, $mode, $tags) && $resultat;
if ($mode == Cache::NETTOYAGE_MODE_TOUS) {
// Si mode == Cache::NETTOYAGE_MODE_TOUS, nous essayons de supprimer la structure aussi
@rmdir($fichier);
}
}
}
return $resultat;
}
 
protected function analyserCache($dossier, $mode, $tags = array()) {
if (!is_dir($dossier)) {
return false;
}
$resultat = array();
$prefixe = $this->options['fichier_prefixe'];
$glob = @glob($dossier.$prefixe.'--*');
if ($glob === false) {
// On some systems it is impossible to distinguish between empty match and an error.
return array();
}
foreach ($glob as $fichier) {
if (is_file($fichier)) {
$nom_fichier = basename($fichier);
$id = $this->transformerNomFichierEnId($nom_fichier);
$metadonnees = $this->getMetadonneesFichier($id);
if ($metadonnees === FALSE) {
continue;
}
if (time() > $metadonnees['expiration']) {
continue;
}
switch ($mode) {
case 'ids':
$resultat[] = $id;
break;
case 'tags':
$resultat = array_unique(array_merge($resultat, $metadonnees['tags']));
break;
case 'matching':
$correspondance = true;
foreach ($tags as $tag) {
if (!in_array($tag, $metadonnees['tags'])) {
$correspondance = false;
break;
}
}
if ($correspondance) {
$resultat[] = $id;
}
break;
case 'notMatching':
$correspondance = false;
foreach ($tags as $tag) {
if (in_array($tag, $metadonnees['tags'])) {
$correspondance = true;
break;
}
}
if (!$correspondance) {
$resultat[] = $id;
}
break;
case 'matchingAny':
$correspondance = false;
foreach ($tags as $tag) {
if (in_array($tag, $metadonnees['tags'])) {
$correspondance = true;
break;
}
}
if ($correspondance) {
$resultat[] = $id;
}
break;
default:
trigger_error("Mode invalide pour la méthode analyserCache()", E_USER_WARNING);
break;
}
}
if ((is_dir($fichier)) and ($this->options['dossier_niveau'] > 0)) {
// Appel récursif
$resultat_analyse_recursive = $this->analyserCache($fichier.DS, $mode, $tags);
if ($resultat_analyse_recursive === false) {
// TODO : ajoute un log
} else {
$resultat = array_unique(array_merge($resultat, $resultat_analyse_recursive));
}
}
}
return array_unique($resultat);
}
 
/**
* Make a control key with the string containing datas
*
* @param string $data Data
* @param string $controlType Type of control 'md5', 'crc32' or 'strlen'
* @throws Zend_Cache_Exception
* @return string Control key
*/
protected function genererCleSecu($donnees, $type_de_controle) {
switch ($type_de_controle) {
case 'md5':
return md5($donnees);
case 'crc32':
return crc32($donnees);
case 'strlen':
return strlen($donnees);
case 'adler32':
return hash('adler32', $donnees);
default:
trigger_error("Fonction de génération de clé de sécurité introuvable : $type_de_controle", E_USER_WARNING);
}
}
 
/**
* Transform a cache id into a file name and return it
*
* @param string $id Cache id
* @return string File name
*/
protected function transformaterIdEnNomFichier($id) {
$prefixe = $this->options['fichier_prefixe'];
$resultat = $prefixe.'---'.$id;
return $resultat;
}
 
/**
* Make and return a file name (with path)
*
* @param string $id Cache id
* @return string File name (with path)
*/
protected function getFichierNom($id) {
$path = $this->getChemin($id);
$fileName = $this->transformaterIdEnNomFichier($id);
return $path . $fileName;
}
 
/**
* Return the complete directory path of a filename (including hashedDirectoryStructure)
*
* @param string $id Cache id
* @param boolean $decoupage if true, returns array of directory parts instead of single string
* @return string Complete directory path
*/
protected function getChemin($id, $decoupage = false) {
$morceaux = array();
$chemin = $this->options['stockage_chemin'];
$prefixe = $this->options['fichier_prefixe'];
if ($this->options['dossier_niveau'] > 0) {
$hash = hash('adler32', $id);
for ($i = 0 ; $i < $this->options['dossier_niveau'] ; $i++) {
$chemin .= $prefixe.'--'.substr($hash, 0, $i + 1).DS;
$morceaux[] = $chemin;
}
}
return ($decoupage) ? $morceaux : $chemin;
}
 
/**
* Make the directory strucuture for the given id
*
* @param string $id cache id
* @return boolean true
*/
protected function lancerMkdirEtChmodRecursif($id) {
$resultat = true;
if ($this->options['dossier_niveau'] > 0) {
$chemins = $this->getChemin($id, true);
foreach ($chemins as $chemin) {
if (!is_dir($chemin)) {
@mkdir($chemin, $this->options['dossier_umask']);
@chmod($chemin, $this->options['dossier_umask']); // see #ZF-320 (this line is required in some configurations)
}
}
}
return $resultat;
}
 
/**
* Test if the given cache id is available (and still valid as a cache record)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @return boolean|mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
protected function testerExistenceCache($id, $ne_pas_tester_validiter_du_cache) {
$resultat = false;
if ($metadonnees = $this->getMetadonnees($id)) {
if ($ne_pas_tester_validiter_du_cache || (time() <= $metadonnees['expiration'])) {
$resultat = $metadonnees['mtime'];
}
}
return $resultat;
}
 
/**
* Return the file content of the given file
*
* @param string $file File complete path
* @return string File content (or false if problem)
*/
protected function getContenuFichier($fichier) {
$resultat = false;
if (is_file($fichier)) {
$f = @fopen($fichier, 'rb');
if ($f) {
if ($this->options['fichier_verrou']) @flock($f, LOCK_SH);
$resultat = stream_get_contents($f);
if ($this->options['fichier_verrou']) @flock($f, LOCK_UN);
@fclose($f);
}
}
return $resultat;
}
 
/**
* Put the given string into the given file
*
* @param string $file File complete path
* @param string $string String to put in file
* @return boolean true if no problem
*/
protected function setContenuFichier($fichier, $chaine) {
$resultat = false;
$f = @fopen($fichier, 'ab+');
if ($f) {
if ($this->options['fichier_verrou']) @flock($f, LOCK_EX);
fseek($f, 0);
ftruncate($f, 0);
$tmp = @fwrite($f, $chaine);
if (!($tmp === FALSE)) {
$resultat = true;
}
@fclose($f);
}
@chmod($fichier, $this->options['fichier_umask']);
return $resultat;
}
 
/**
* Transform a file name into cache id and return it
*
* @param string $fileName File name
* @return string Cache id
*/
protected function transformerNomFichierEnId($nom_de_fichier) {
$prefixe = $this->options['fichier_prefixe'];
return preg_replace('~^' . $prefixe . '---(.*)$~', '$1', $nom_de_fichier);
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/RestService.php
New file
0,0 → 1,91
<?php
/**
* Classe principale gérant les services.
* Paramètres liés dans config.ini :
* - serveur.baseURL
*
* Encodage en entrée : utf8
* Encodage en sortie : utf8
*
* @category Php 5.2
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @since 0.3
* @version $Id$
* @link /doc/framework/
*/
abstract class RestService {
/** Objet de connection à la base de données. */
protected $bdd;
public function __construct($config) {
$this->config = $config;
// Connection à la base de données
$this->bdd = new Bdd();
}
/**
* Méthode appelée lors d'une requête HTTP de type GET.
*
* Si la consultation est un succès, le code statut HTTP retourné devrait être 200.
*
* @param array Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
* @param array Partie de l'url situé après le '?' servant à paramétrer le service demandé.
* @return string une chaine indiquant le succès de l'opération et les données demandées.
*/
public function consulter($ressources, $parametres) {
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_METHODE_NON_AUTORISE);
echo "Le service '".get_class($this)."' n'autorise pas la consultation.";
}
/**
* Méthode appelée lors d'une requête HTTP de type POST.
*
* La ressource à modifier est indiquée via l'url. Les données devant servir à la mise à jours sont passées dans le corps
* de la requête.
* Si la modification est un succès, le code statut HTTP retourné devrait être 201.
*
* @param array Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
* @param array les données transférées dans le corps de la requête devant servir à la modification.
* @return mixed une chaine indiquant le succès de l'opération ou rien.
*/
public function modifier($ressources, $requeteDonnees) {
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_METHODE_NON_AUTORISE);
echo "Le service '".get_class($this)."' n'autorise pas la modification.";
}
/**
* Méthode appelée lors d'une requête HTTP de type PUT.
*
* L'identifiant de la ressource à ajouter est indiqué via l'url si on le connait par avance. Sinon, il doit être créé par
* le service. Dans ce dernier cas, le nouvel identifiant devrait être renvoyé dans le corps de la réponse.
* Si l'ajout est un succès, le code statut HTTP retourné devrait être 201.
*
* @param array Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
* @param array les données transférées dans le corps de la requête devant servir à l'ajout.
* @return string l'identifiant créé.
*/
public function ajouter($ressources, $requeteDonnees) {
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_METHODE_NON_AUTORISE);
echo "Le service '".get_class($this)."' n'autorise pas la création.";
}
/**
* Méthode appelée lors d'une requête HTTP de type DELETE (ou POST avec action=DELETE dans le corps de la requete).
*
* Si la suppression est un succès, le code statut HTTP retourné devrait être 204.
*
* @param array Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
* @return mixed une chaine indiquant le succès de l'opération ou rien.
*/
public function supprimer($ressources) {
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_METHODE_NON_AUTORISE);
echo "Le service '".get_class($this)."' n'autorise pas la suppression.";
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/Url.php
New file
0,0 → 1,416
<?php
// declare(encoding='UTF-8');
/**
* Classe Url, gérant le découpage des paramètres, leurs modification etc...
* Traduction et conversion d'une classe (NET_Url2) issue de Pear
*
* @category Php 5.2
* @package Framework
* @author Christian SCHMIDT <schmidt@php.net> (Auteur classe originale)
* @author Aurélien PERONNET <aurelien@tela-botanica.org>
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
* @version SVN: $Id$
* @link /doc/framework/
*/
class Url {
 
/**
* Répresenter les tableaux dans les requêtes en utilisant la notation php []. Par défaut à true.
*/
const OPTION_UTILISER_CROCHETS = 'utiliser_crochets';
 
/**
* URL-encoder les clés des variables dans les requêtes. Par défaut à true.
*/
const OPTION_ENCODER_CLES = 'encoder_cles';
 
/**
* Séparateurs de variables lors du parsing de la requête. Chaque caractère
* est considéré comme un séparateur. Par défaut, spécifié par le paramêtre
* arg_separator.input dans php.ini (par défaut "&").
*/
const OPTION_SEPARATEUR_ENTREE = 'separateur_entree';
 
/**
* Séparateur de variables lors de la génération de la requête. Par défaut, spécifié
* par le paramètre arg_separator.output dans php.ini (par défaut "&").
*/
const OPTION_SEPARATEUR_SORTIE = 'separateur_sortie';
 
/**
* Options par défaut correspondant au comportement de php
* vis à vis de $_GET
*/
private $options = array(
self::OPTION_UTILISER_CROCHETS => true,
self::OPTION_ENCODER_CLES => true,
self::OPTION_SEPARATEUR_ENTREE => '&',
self::OPTION_SEPARATEUR_SORTIE => '&');
 
/**
* @var string|bool
*/
private $schema = false;
 
/**
* @var string|bool
*/
private $infoUtilisateur = false;
 
/**
* @var string|bool
*/
private $hote = false;
 
/**
* @var int|bool
*/
private $port = false;
 
/**
* @var string
*/
private $chemin = '';
 
/**
* @var string|bool
*/
private $requete = false;
 
/**
* @var string|bool
*/
private $fragment = false;
 
/** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
private $parametres_obligatoires = array('url_arg_separateur_entree', 'url_arg_separateur_sortie');
/**
* @param string $url une URL relative ou absolue
* @param array $options
*/
public function __construct($url, $options = null) {
Config::verifierPresenceParametres($this->parametres_obligatoires);
$this->setOption(self::OPTION_SEPARATEUR_ENTREE, Config::get('url_arg_separateur_entree'));
$this->setOption(self::OPTION_SEPARATEUR_SORTIE, Config::get('url_arg_separateur_sortie'));
if (is_array($options)) {
foreach ($options as $nomOption => $valeur) {
$this->setOption($nomOption);
}
}
 
if (preg_match('@^([a-z][a-z0-9.+-]*):@i', $url, $reg)) {
$this->schema = $reg[1];
$url = substr($url, strlen($reg[0]));
}
 
if (preg_match('@^//([^/#?]+)@', $url, $reg)) {
$this->setAutorite($reg[1]);
$url = substr($url, strlen($reg[0]));
}
 
$i = strcspn($url, '?#');
$this->chemin = substr($url, 0, $i);
$url = substr($url, $i);
 
if (preg_match('@^\?([^#]*)@', $url, $reg)) {
$this->requete = $reg[1];
$url = substr($url, strlen($reg[0]));
}
 
if ($url) {
$this->fragment = substr($url, 1);
}
}
/**
* Renvoie la valeur de l'option specifiée.
*
* @param string $nomOption Nom de l'option demandée
*
* @return mixed
*/
public function getOption($nomOption) {
return isset($this->options[$nomOption]) ? $this->options[$nomOption] : false;
}
 
/**
* Met à jour la valeur de l'option spécifiée.
*
* @param string $nomOption une des constantes commençant par self::OPTION_
* @param mixed $valeur valeur de l'option
*
* @return void
* @see self::OPTION_STRICTE
* @see self::OPTION_UTILISER_CROCHETS
* @see self::OPTION_ENCODER_CLES
*/
public function setOption($nomOption, $valeur) {
if (!array_key_exists($nomOption, $this->options)) {
return false;
}
$this->options[$nomOption] = $valeur;
}
 
/**
* Renvoie la partie autorité, i.e. [ infoUtilisateur "@" ] hote [ ":" port ], ou
* false si celle-ci est absente.
*
* @return string|bool
*/
private function getAutorite() {
if (!$this->hote) {
return false;
}
 
$autorite = '';
 
if ($this->infoUtilisateur !== false) {
$autorite .= $this->infoUtilisateur . '@';
}
 
$autorite .= $this->hote;
 
if ($this->port !== false) {
$autorite .= ':' . $this->port;
}
 
return $autorite;
}
 
/**
* @param string|false $autorite
*
* @return void
*/
private function setAutorite($autorite) {
$this->user = false;
$this->pass = false;
$this->hote = false;
$this->port = false;
if (preg_match('@^(([^\@]+)\@)?([^:]+)(:(\d*))?$@', $autorite, $reg)) {
if ($reg[1]) {
$this->infoUtilisateur = $reg[2];
}
 
$this->hote = $reg[3];
if (isset($reg[5])) {
$this->port = intval($reg[5]);
}
}
}
 
/**
* Renvoie vrai ou faux suivant que l'instance en cours représente une URL relative ou absolue.
*
* @return bool
*/
private function etreAbsolue() {
return (bool) $this->schema;
}
/**
* La suppression des segments à points est décrite dans la RFC 3986, section 5.2.4, e.g.
* "/foo/../bar/baz" => "/bar/baz"
*
* @param string $chemin un chemin
*
* @return string un chemin
*/
private static function supprimerSegmentsAPoints($chemin) {
$sortie = '';
 
// Assurons nous de ne pas nous retrouver piégés dans une boucle infinie due à un bug de cette méthode
$j = 0;
while ($chemin && $j++ < 100) {
if (substr($chemin, 0, 2) == './') {// Étape A
$chemin = substr($chemin, 2);
} else if (substr($chemin, 0, 3) == '../') {
$chemin = substr($chemin, 3);
} else if (substr($chemin, 0, 3) == '/./' || $chemin == '/.') {// Étape B
$chemin = '/' . substr($chemin, 3);
} else if (substr($chemin, 0, 4) == '/../' || $chemin == '/..') {// Étape C
$chemin = '/' . substr($chemin, 4);
$i = strrpos($sortie, '/');
$sortie = $i === false ? '' : substr($sortie, 0, $i);
} else if ($chemin == '.' || $chemin == '..') {// Étape D
$chemin = '';
} else {// Étape E
$i = strpos($chemin, '/');
if ($i === 0) {
$i = strpos($chemin, '/', 1);
}
if ($i === false) {
$i = strlen($chemin);
}
$sortie .= substr($chemin, 0, $i);
$chemin = substr($chemin, $i);
}
}
 
return $sortie;
}
/**
* (Re-)Création de la partie requête de l'URL à partir des données du tableau (passé en paramètre).
*
* @param array (nom => valeur) tableau de clés & valeurs pour la partie requête de l'url.
* @return void (Re-)Création de la partie requête.
*/
public function setRequete(Array $parametres) {
if (!$parametres) {
$this->requete = false;
} else {
foreach ($parametres as $nom => $valeur) {
if ($this->getOption(self::OPTION_ENCODER_CLES)) {
$nom = rawurlencode($nom);
}
 
if (is_array($valeur)) {
foreach ($valeur as $k => $v) {
if ($this->getOption(self::OPTION_UTILISER_CROCHETS)) {
$parties[] = sprintf('%s[%s]=%s', $nom, $k, $v);
} else {
$parties[] = $nom.'='.$v;
}
}
} else if (!is_null($valeur)) {
$parties[] = $nom . '=' . $valeur;
} else {
$parties[] = $nom;
}
}
$this->requete = implode($this->getOption(self::OPTION_SEPARATEUR_SORTIE), $parties);
}
}
/**
* (Re-)Création de la partie requête de l'URL à partir de la fusion du tableau (passé en paramètre) et
* les valeurs présentes dans $_GET.
*
* @param array (nom => valeur) tableau de clés & valeurs pour la partie requête de l'url.
* @return void (Re-)Création de la partie requête.
*/
public function fusionnerRequete(Array $parametres) {
if ($parametres) {
$requete = $parametres + $_GET;
$this->setRequete($requete);
}
}
 
/**
* Normalise les données de l'instance d'Url faisant appel à cette méthode.
*
* @return void l'instance d'Url courrante est normalisée.
*/
public function normaliser() {
// Voir RFC 3886, section 6
 
// les cchémas sont insesibles à la casse
if ($this->schema) {
$this->schema = strtolower($this->schema);
}
 
// les noms d'hotes sont insensibles à la casse
if ($this->hote) {
$this->hote = strtolower($this->hote);
}
 
// Supprimer le numéro de port par défaut pour les schemas connus (RFC 3986, section 6.2.3)
if ($this->port && $this->schema && $this->port == getservbyname($this->schema, 'tcp')) {
$this->port = false;
}
 
// normalisation dans le cas d'un encodage avec %XX pourcentage (RFC 3986, section 6.2.2.1)
foreach (array('infoUtilisateur', 'hote', 'chemin') as $partie) {
if ($this->$partie) {
$this->$partie = preg_replace('/%[0-9a-f]{2}/ie', 'strtoupper("\0")', $this->$partie);
}
}
 
// normalisation des segments du chemin (RFC 3986, section 6.2.2.3)
$this->chemin = self::supprimerSegmentsAPoints($this->chemin);
 
// normalisation basée sur le schéma (RFC 3986, section 6.2.3)
if ($this->hote && !$this->chemin) {
$this->chemin = '/';
}
}
 
/**
* Renvoie une instance d'objet Url representant l'URL canonique du script PHP en cours d'éxécution.
*
* @return Url retourne un objet Url ou null en cas d'erreur.
*/
public static function getCanonique() {
$url = null;
if (!isset($_SERVER['REQUEST_METHOD'])) {
trigger_error("Le script n'a pas été appellé à travers un serveur web", E_USER_WARNING);
} else {
// À partir d'une URL relative
$url = new self($_SERVER['PHP_SELF']);
$url->schema = isset($_SERVER['HTTPS']) ? 'https' : 'http';
$url->hote = $_SERVER['SERVER_NAME'];
$port = intval($_SERVER['SERVER_PORT']);
if ($url->schema == 'http' && $port != 80 || $url->schema == 'https' && $port != 443) {
$url->port = $port;
}
}
return $url;
}
 
/**
* Renvoie une instance d'objet Url representant l'URL utilisée pour récupérer la requête en cours.
*
* @return Url retourne un objet Url ou null en cas d'erreur.
*/
public static function getDemande() {
$url = null;
if (!isset($_SERVER['REQUEST_METHOD'])) {
trigger_error("Le script n'a pas été appellé à travers un serveur web", E_USER_WARNING);
} else {
// On part d'une URL relative
$url = new self($_SERVER['REQUEST_URI']);
$url->schema = isset($_SERVER['HTTPS']) ? 'https' : 'http';
// On met à jour les valeurs de l'hôte et si possible du port
$url->setAutorite($_SERVER['HTTP_hote']);
}
return $url;
}
 
/**
* Renvoie un représentation sous forme de chaine de l'URL.
*
* @return string l'url
*/
public function getURL() {
// Voir RFC 3986, section 5.3
$url = '';
if ($this->schema !== false) {
$url .= $this->schema . ':';
}
 
$autorite = $this->getAutorite();
if ($autorite !== false) {
$url .= '//' . $autorite;
}
$url .= $this->chemin;
 
if ($this->requete !== false) {
$url .= '?' . $this->requete;
}
 
if ($this->fragment !== false) {
$url .= '#' . $this->fragment;
}
 
return $url;
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/Cache.php
New file
0,0 → 1,507
<?php
// declare(encoding='UTF-8');
/**
* Classe Cache permettant de mettre en cache des données.
* Basée sur les principes de Zend_Cache (Copyright (c) 2005-2010, Zend Technologies USA, Inc. All rights reserved.)
*
* @category php 5.2
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license http://framework.zend.com/license/new-bsd Licence New BSD
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
* @version $Id$
* @link /doc/framework/
*/
class Cache {
/** Socke les enregistrements du cache dans des fichiers textes de façon extremement simple. */
const STOCKAGE_MODE_SIMPLE = "FichierSimple";
/** Socke les enregistrements du cache dans des fichiers textes. */
const STOCKAGE_MODE_FICHIER = "Fichier";
/** Socke les enregistrements du cache dans une base de données SQLite. */
const STOCKAGE_MODE_SQLITE = "Sqlite";
/** 'tous' (par défaut) : supprime tous les enregistrements. */
const NETTOYAGE_MODE_TOUS = "tous";
/** 'expiration' : supprime tous les enregistrements dont la date d'expériration est dépassée. */
const NETTOYAGE_MODE_EXPIRATION = "expiration";
/** 'avecLesTags' : supprime tous les enregistrements contenant tous les tags indiqués. */
const NETTOYAGE_MODE_AVEC_LES_TAGS = "avecLesTags";
/** 'sansLesTags' : supprime tous les enregistrements contenant aucun des tags indiqués. */
const NETTOYAGE_MODE_SANS_LES_TAGS = "sansLesTags";
/** 'avecUnTag' : supprime tous les enregistrements contenant au moins un des tags indiqués. */
const NETTOYAGE_MODE_AVEC_UN_TAG = "avecUnTag";
/**
* Dernier identifiant de cache utilisé.
*
* @var string $dernier_id
*/
private $dernier_id = null;
/**
* Les options disponibles pour le cache :
* ====> (string) stockage_mode :
* Indique le mode de stockage du cache à utiliser parmis :
* - Cache::STOCKAGE_MODE_FICHIER : sous forme d'une arborescence de fichiers et dossier
* - Cache::STOCKAGE_MODE_SQLITE : sous forme d'une base de données SQLite
*
* ====> (string) stockage_chemin :
* Chemin vers :
* - Cache::STOCKAGE_MODE_FICHIER : le dossier devant contenir l'arborescence.
* - Cache::STOCKAGE_MODE_SQLITE : le fichier contenant la base SQLite.
*
* ====> (boolean) controle_ecriture :
* - Active / Désactive le controle d'écriture (le cache est lue jute après l'écriture du fichier pour détecter sa corruption)
* - Activer le controle d'écriture ralentira légèrement l'écriture du fichier de cache mais pas sa lecture
* Le controle d'écriture peut détecter la corruption de fichier mais ce n'est pas un système de controle parfait.
*
* ====> (boolean) mise_en_cache :
* - Active / Désactive la mise en cache
* (peut être très utile pour le débogage des scripts utilisant le cache
*
* =====> (string) cache_id_prefixe :
* - préfixe pour les identifiant de cache ( = espace de nom)
*
* ====> (boolean) serialisation_auto :
* - Active / Désactive la sérialisation automatique
* - Peut être utilisé pour sauver directement des données qui ne sont pas des chaines (mais c'est plus lent)
*
* ====> (int) nettoyage_auto :
* - Désactive / Régler le processus de nettoyage automatique
* - Le processus de nettoyage automatiques détruit les fichier trop vieux (pour la durée de vie donnée)
* quand un nouveau fichier de cache est écrit :
* 0 => pas de nettoyage automatique
* 1 => nettoyage automatique systématique
* x (integer) > 1 => nettoyage automatique toutes les 1 fois (au hasard) sur x écriture de fichier de cache
*
* ====> (int) duree_de_vie :
* - Durée de vie du cache (en secondes)
* - Si null, le cache est valide indéfiniment.
*
* @var array $options les options disponibles pour le cache .
*/
protected $options = array(
'stockage_mode' => self::STOCKAGE_MODE_FICHIER,
'stockage_chemin' => null,
'controle_ecriture' => true,
'mise_en_cache' => true,
'cache_id_prefixe' => null,
'serialisation_auto' => false,
'nettoyage_auto' => 10,
'duree_de_vie' => 3600,
);
protected $stockage = null;
public function __construct($options = array(), $options_stockage = array()) {
$this->initialiserOptionsParConfig();
$this->setOptions($options);
if ($this->options['stockage_mode'] == self::STOCKAGE_MODE_FICHIER) {
$this->stockage = new CacheFichier($options_stockage, $this);
$this->stockage->setEmplacement($this->options['stockage_chemin']);
} else if ($this->options['stockage_mode'] == self::STOCKAGE_MODE_SQLITE) {
$this->stockage = new CacheSqlite($options_stockage, $this);
$this->stockage->setEmplacement($this->options['stockage_chemin']);
} else {
trigger_error("Ce mode de stockage n'existe pas ou ne supporte pas la création par le constructeur", E_USER_WARNING);
}
}
private function initialiserOptionsParConfig() {
while (list($nom, $valeur) = each($this->options)) {
if (Config::existe($nom)) {
$this->options[$nom] = Config::get($nom);
}
}
}
private function setOptions($options) {
while (list($nom, $valeur) = each($options)) {
if (!is_string($nom)) {
trigger_error("Nom d'option incorecte : $nom", E_USER_WARNING);
}
$nom = strtolower($nom);
if (array_key_exists($nom, $this->options)) {
$this->options[$nom] = $valeur;
}
}
}
/**
* Permet de (re-)définir l'emplacement pour le stockage du cache.
* En fonction du mode de stockage utilisé , l'emplacement indiqué correspondra au chemin du :
* - dossier où stocker les fichiers pour le mode "fichier".
* - fichier de la base de données pour le mode "sqlite".
* @param string $emplacement chemin vers dossier (Cache::STOCKAGE_MODE_FICHIER) ou fichier base Sqlite (Cache::STOCKAGE_MODE_SQLITE)
* @return void
*/
public function setEmplacement($emplacement) {
if ($emplacement != null) {
$this->executerMethodeStockage('setEmplacement', array($emplacement));
} else {
trigger_error("L'emplacement ne peut pas être null.", E_USER_WARNING);
}
}
public static function fabriquer($mode, $options = array()) {
if ($mode == self::STOCKAGE_MODE_SIMPLE) {
return new CacheSimple($options);
} else {
trigger_error("Le mode '$mode' de stockage n'existe pas ou ne supporte pas la création par fabrique", E_USER_WARNING);
}
return false;
}
/**
* Teste si un cache est disponible pour l'identifiant donné et (si oui) le retourne (false dans le cas contraire)
*
* @param string $id Identifiant de cache.
* @param boolean $ne_pas_tester_validiter_du_cache Si mis à true, la validité du cache n'est pas testée
* @return mixed|false Cached datas
*/
public function charger($id, $ne_pas_tester_validiter_du_cache = false) {
$donnees = false;
if ($this->options['mise_en_cache'] === true) {
$id = $this->prefixerId($id);
$this->dernier_id = $id;
self::validerIdOuTag($id);
$donnees = $this->executerMethodeStockage('charger', array($id, $ne_pas_tester_validiter_du_cache));
$donnees = $this->deserialiserAutomatiquement($donnees);
}
return $donnees;
}
/**
* Test if a cache is available for the given id
*
* @param string $id Cache id
* @return int|false Last modified time of cache entry if it is available, false otherwise
*/
public function tester($id) {
$resultat = false;
if ($this->options['mise_en_cache'] === true) {
$id = $this->prefixerId($id);
self::validerIdOuTag($id);
$this->dernier_id = $id;
$resultat = $this->executerMethodeStockage('tester', array($id));
}
return $resultat;
}
/**
* Sauvegarde en cache les données passées en paramètre.
*
* @param mixed $donnees Données à mettre en cache (peut être différent d'une chaine si serialisation_auto vaut true).
* @param string $id Identifiant du cache (s'il n'est pas définit, le dernier identifiant sera utilisé).
* @param array $tags Mots-clés du cache.
* @param int $duree_de_vie_specifique Si != false, indique une durée de vie spécifique pour cet enregistrement en cache (null => durée de vie infinie)
* @return boolean True si aucun problème n'est survenu.
*/
public function sauver($donnees, $id = null, $tags = array(), $duree_de_vie_specifique = false) {
$resultat = true;
if ($this->options['mise_en_cache'] === true) {
$id = ($id === null) ? $this->dernier_id : $this->prefixerId($id);
self::validerIdOuTag($id);
self::validerTableauDeTags($tags);
$donnees = $this->serialiserAutomatiquement($donnees);
$this->nettoyerAutomatiquement();
$resultat = $this->executerMethodeStockage('sauver', array($donnees, $id, $tags, $duree_de_vie_specifique));
if ($resultat == false) {
// Le cache étant peut être corrompu, nous le supprimons
$this->supprimer($id);
} else {
$resultat = $this->controlerEcriture($id, $donnees);
}
}
return $resultat;
}
/**
* Supprime un enregistrement en cache.
*
* @param string $id Identificant du cache à supprimer.
* @return boolean True si ok
*/
public function supprimer($id) {
$resultat = true;
if ($this->options['mise_en_cache'] === true) {
$id = $this->prefixerId($id);
self::validerIdOuTag($id);
$resultat = $this->executerMethodeStockage('supprimer', array($id));
}
return $resultat;
}
/**
* Nettoyage des enregistrements en cache
*
* Mode de nettoyage disponibles :
* 'tous' (défaut) => supprime tous les enregistrements ($tags n'est pas utilisé)
* 'expiration' => supprime tous les enregistrements dont la date d'expériration est dépassée ($tags n'est pas utilisé)
* 'avecLesTag' => supprime tous les enregistrements contenant tous les tags indiqués
* 'sansLesTag' => supprime tous les enregistrements contenant aucun des tags indiqués
* 'avecUnTag' => supprime tous les enregistrements contenant au moins un des tags indiqués
*
* @param string $mode mode de nettoyage
* @param array|string $tags peut être un tableau de chaîne ou une simple chaine.
* @return boolean True si ok
*/
public function nettoyer($mode = self::NETTOYAGE_MODE_TOUS, $tags = array()) {
$resultat = true;
if ($this->options['mise_en_cache'] === true) {
if (!in_array($mode, array(Cache::NETTOYAGE_MODE_TOUS,
Cache::NETTOYAGE_MODE_EXPIRATION,
Cache::NETTOYAGE_MODE_AVEC_LES_TAGS,
Cache::NETTOYAGE_MODE_SANS_LES_TAGS,
Cache::NETTOYAGE_MODE_AVEC_UN_TAG))) {
trigger_error("Le mode de nettoyage du cache indiqué n'est pas valide", E_USER_WARNING);
}
self::validerTableauDeTags($tags);
$resultat = $this->executerMethodeStockage('nettoyer', array($mode, $tags));
}
return $resultat;
}
 
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds() {
$ids = $this->executerMethodeStockage('getIds');
$ids = $this->supprimerPrefixe($ids);
return $ids;
}
 
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags() {
return $this->executerMethodeStockage('getTags');
}
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsAvecLesTags($tags = array()) {
$ids = $this->executerMethodeStockage('getIdsAvecLesTags', array($tags));
$ids = $this->supprimerPrefixe($ids);
return $ids;
}
 
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsSansLesTags($tags = array()) {
$ids = $this->executerMethodeStockage('getIdsSansLesTags', array($tags));
$ids = $this->supprimerPrefixe($ids);
return $ids;
}
 
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of matching any cache ids (string)
*/
public function getIdsAvecUnTag($tags = array()) {
$ids = $this->executerMethodeStockage('getIdsAvecUnTag', array($tags));
$ids = $this->supprimerPrefixe($ids);
return $ids;
}
 
/**
* Return the filling percentage of the backend storage
*
* @return int integer between 0 and 100
*/
public function getPourcentageRemplissage() {
return $this->executerMethodeStockage('getPourcentageRemplissage');
}
 
/**
* Return an array of metadatas for the given cache id
*
* The array will include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadonnees($id) {
$id = $this->prefixerId($id);
return $this->executerMethodeStockage('getMetadonnees', array($id));
}
 
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function ajouterSupplementDureeDeVie($id, $supplement_duree_de_vie) {
$id = $this->prefixerId($id);
return $this->executerMethodeStockage('ajouterSupplementDureeDeVie', array($id, $supplement_duree_de_vie));
}
 
/**
* Fabrique et retourne l'identifiant du cache avec son préfixe.
*
* Vérifie l'option 'cache_id_prefixe' et retourne le nouvel id avec préfixe ou simplement l'id lui même si elle vaut null.
*
* @param string $id Identifiant du cache.
* @return string Identifiant du cache avec ou sans préfixe.
*/
private function prefixerId($id) {
$nouvel_id = $id;
if (($id !== null) && isset($this->options['cache_id_prefixe'])) {
$nouvel_id = $this->options['cache_id_prefixe'].$id;
}
return $nouvel_id;
}
private function executerMethodeStockage($methode, $params = null) {
if (method_exists($this->stockage, $methode)) {
if ($params == null) {
$resultat = call_user_func(array($this->stockage, $methode));
} else {
$resultat = call_user_func_array(array($this->stockage, $methode), $params);
}
} else {
$resultat = false;
trigger_error("La méthode '$methode' n'existe pas dans la classe '".get_class($this)."'.", E_USER_WARNING);
}
return $resultat;
}
private function supprimerPrefixe($ids) {
// Il est nécessaire de retirer les cache_id_prefixe des ids (voir #ZF-6178, #ZF-7600)
if (isset($this->options['cache_id_prefixe']) && $this->options['cache_id_prefixe'] !== '') {
$prefixe =& $this->options['cache_id_prefixe'];
$prefixe_longueur = strlen($prefixe);
foreach ($ids as &$id) {
if (strpos($id, $prefixe) === 0) {
$id = substr($id, $prefixe_longueur);
}
}
}
return $ids;
}
private function controlerEcriture($id, $donnees_avant_ecriture) {
$resultat = true;
if ($this->options['controle_ecriture']) {
$donnees_apres_ecriture = $this->executerMethodeStockage('charger', array($id, true));
if ($donnees_avant_ecriture != $donnees_apres_ecriture) {
$this->executerMethodeStockage('supprimer', array($id));
$resultat = false;
}
}
return $resultat;
}
private function deserialiserAutomatiquement($donnees) {
if ($donnees !== false && $this->options['serialisation_auto']) {
// we need to unserialize before sending the result
$donnees = unserialize($donnees);
}
return $donnees;
}
private function serialiserAutomatiquement($donnees) {
if ($this->options['serialisation_auto']) {
// we need to serialize datas before storing them
$donnees = serialize($donnees);
} else {
if (!is_string($donnees)) {
trigger_error("Les données doivent être une chaîne de caractères ou vous devez activez l'option serialisation_auto = true", E_USER_WARNING);
}
}
return $donnees;
}
private function nettoyerAutomatiquement() {
if ($this->options['nettoyage_auto'] > 0) {
$rand = rand(1, $this->options['nettoyage_auto']);
if ($rand == 1) {
$this->nettoyer(self::NETTOYAGE_MODE_EXPIRATION);
}
}
}
/**
* Valide un identifiant de cache ou un tag (securité, nom de fichiers fiables, préfixes réservés...)
*
* @param string $chaine Identificant de cache ou tag
* @return void
*/
protected static function validerIdOuTag($chaine) {
if (!is_string($chaine)) {
trigger_error('Id ou tag invalide : doit être une chaîne de caractères', E_USER_ERROR);
}
if (substr($chaine, 0, 9) == 'internal-') {
trigger_error('"internal-*" identifiants ou tags sont réservés', E_USER_WARNING);
}
if (!preg_match('~^[a-zA-Z0-9_]+$~D', $chaine)) {
trigger_error("Id ou tag invalide '$chaine' : doit contenir seulement [a-zA-Z0-9_]", E_USER_WARNING);
}
}
 
/**
* Valide un tableau de tags (securité, nom de fichiers fiables, préfixes réservés...)
*
* @param array $tags tableau de tags
* @return void
*/
protected static function validerTableauDeTags($tags) {
if (!is_array($tags)) {
trigger_error("Tableau de tags invalide : doit être un tableau 'array'", E_USER_WARNING);
}
foreach ($tags as $tag) {
self::validerIdOuTag($tag);
}
reset($tags);
}
/**
* Calcule et retourne le timestamp d'expiration
*
* @return int timestamp d'expiration (unix timestamp)
*/
public function getTimestampExpiration($duree_de_vie) {
if ($duree_de_vie === false) {
if (isset($this->options['duree_de_vie']) && is_int($this->options['duree_de_vie'])) {
$duree_de_vie = (int) $this->options['duree_de_vie'];
} else {
$duree_de_vie = 3600;
}
}
$timestamp = ($duree_de_vie === null) ? 9999999999 : (time() + $duree_de_vie);
return $timestamp;
}
}
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/config.defaut.ini
New file
0,0 → 1,261
; Encodage : UTF-8
; Attention : Renommer ce fichier en config.ini
 
; +------------------------------------------------------------------------------------------------------+
; Général
; ds : Séparateur de dossier
; ps : Séparateur de chemin
; eol : Fin de ligne de fichier
 
ds = DIRECTORY_SEPARATOR
ps = PATH_SEPARATOR
eol = PHP_EOL
 
; +------------------------------------------------------------------------------------------------------+
; URLs
; url_arg_separateur_entree : Le séparateur des arguments d'une url à parser (par défaut, utiliser : "php:ini_get('arg_separator.input')")
; url_arg_separateur_sortie : Le séparateur utilisé pour séparer les arguments d'une URL générée (défaut, utiliser : "php:ini_get('arg_separator.output')")
; url_base : URL de base de l'application. Si vide : fonctionnement Stand-alone
; Peut utiliser un objet Net_URL comme ceci : "php:$mon_objet_net_url->getUrl()"
 
url_arg_separateur_entree = "&amp;"
url_arg_separateur_sortie = "&amp;"
url_base = ""
 
; +------------------------------------------------------------------------------------------------------+
; Débogage
; fw_debogage : Indique si oui ou non on veut afficher le débogage.
; Indique sous quelle forme les méssages de débogage doivent s'afficher :
; - "php:Debug::MODE_ECHO" : le message est affiché en utilisant echo
; - "php:Debug::MODE_NOTICE" : le message est affiché en utilisant une erreur de type notice
; - "php:Debug::MODE_ENTETE_HTTP" : les messages sont envoyés dans un entête HTTP "X_REST_DEBOGAGE".
; - "Autre valeur" : les messages sont formatés puis retournés par la méthode de débogage utilisée.
; fw_debogage_contexte : Indique si oui ou non on veut afficher le contexte de débogage.
; fw_debogage_niveau : Niveau d'erreur à employer pour le code PHP. Voir le manuel de PHP pour les différents niveaux disponibles.
 
 
debogage = true
debogage_mode = "php:Debug::MODE_ECHO"
debogage_contexte = false
debogage_niveau = 30719
 
; +------------------------------------------------------------------------------------------------------+
; Benchmark
; fw_benchmark_chrono : Indique si oui ou nom on veut afficher le tableau de chronométrage de l'application. (BENCHMARK)
benchmark_chrono = true
 
; +------------------------------------------------------------------------------------------------------+
; Log
; log_debogage : Indique si oui ou non on veut activer la journalisation des erreurs.
; log_script : Indique si oui (true) ou non (false) les scripts doivent loguer les messages
; log_taille_max : Indique la taille max d'un fichier log (en octets)
 
log_debogage = false
log_script = true
log_taille_max = 1000000
 
; +------------------------------------------------------------------------------------------------------+
; Chemins, dossiers et fichiers
; fichier_config : Nom des fichiers de config recherché. Défini par défaut dans la classe Config
; chemin_framework : Chemin vers le dossier du framework. Défini par défaut dans la classe Config
; dossier_bibliotheque : Nom du dossier de la bibliotheque de codes de l'application.
; dossier_composants : Nom du dossier des composants graphiques de l'application.
; dossier_configurations : Nom du dossier des controleurs de l'application.
; dossier_controleurs : Nom du dossier des controleurs de l'application.
; dossier_i18n : Nom du dossier des traductions de l'application.
; dossier_modeles : Nom du dossier des modèles de l'application.
; dossier_squelettes :Nom du dossier des squelettes de l'application.
; dossier_logs : Nom du dossier des logs de l'application.
; dossier_modules : Nom du dossier contenant les modules (sous partie d'une application, scripts ou services web).
 
; fichier_config = "config%s.ini"
; chemin_framework = "php:dirname(__FILE__).DS"
 
dossier_bibliotheque = bibliotheque
dossier_composants = composants
dossier_configurations = configurations
dossier_controleurs = controleurs
dossier_i18n = i18n
dossier_modeles = modeles
dossier_squelettes = squelettes
dossier_logs = logs
dossier_modules = modules
 
; chemin_appli :Chemin vers le dossier de l'appli.
; chemin_bibliotheque : Chemin vers le dossier de la bibliotheque de codes de l'application.
; chemin_composants : Chemin vers le dossier des composants graphiques de l'application.
; chemin_configurations : Chemin vers le dossier des configurations de l'application.
; chemin_controleurs : Chemin vers le dossier des controleurs de l'application.
; chemin_i18n : Chemin vers le dossier des traductions de l'application.
; chemin_modeles : chemin vers le dossier des modèles de l'application.
; chemin_squelettes : Chemin vers le dossier des squelettes de l'application.
; chemin_logs : Chemin vers le dossier des logs de l'application.
; chemin_modules : Chemin vers les dossiers spécifiques aux scripts CLI.
 
chemin_appli = "php:Framework::getCheminAppli()"
chemin_bibliotheque = "{ref:chemin_appli}{ref:dossier_bibliotheque}{ref:ds}"
chemin_composants = "{ref:chemin_appli}{ref:dossier_composants}{ref:ds}"
chemin_configurations = "{ref:chemin_appli}{ref:dossier_configurations}{ref:ds}"
chemin_controleurs = "{ref:chemin_appli}{ref:dossier_controleurs}{ref:ds}"
chemin_i18n = "{ref:chemin_appli}{ref:dossier_i18n}{ref:ds}"
chemin_modeles = "{ref:chemin_appli}{ref:dossier_modeles}{ref:ds}"
chemin_squelettes = "{ref:chemin_appli}{ref:dossier_squelettes}{ref:ds}"
chemin_logs = "{ref:chemin_appli}{ref:dossier_logs}{ref:ds}"
chemin_modules = "{ref:chemin_appli}{ref:dossier_modules}{ref:ds}"
 
; +------------------------------------------------------------------------------------------------------+
; Paramètrage de la base de données.
; bdd_abstraction : abstraction de la base de données.
; bdd_protocole : Protocole de la base de données.
; bdd_serveur : Nom du serveur de bases de données.
; bdd_utilisateur : Nom de l'utilisateur de la base de données.
; bdd_mot_de_passe : Mot de passe de l'utilisateur de la base de données.
; bdd_nom : Nom de la base de données principale.
; bdd_encodage : Encodage de la base de données principale. Normalement le même que l'application mais au format base de
; données : voir ici : http://dev.mysql.com/doc/refman/5.0/en/charset-charsets.html
; et là: http://www.postgresql.org/docs/8.1/static/multibyte.html pour les correspondances
bdd_abstraction = pdo
bdd_protocole = mysql
bdd_serveur = localhost
bdd_utilisateur = ""
bdd_mot_de_passe = ""
bdd_nom = ""
bdd_encodage = "utf8"
 
; +------------------------------------------------------------------------------------------------------+
; Encodage
; encodage_appli : encodage de l'application, des fichiers php, squelettes de l'application
; encodage_sortie : Encodage des donnés renvoyées au navigateur
; (faire attention à la correspondane avec les .htaccess et les balises meta du html des squelettes)
 
encodage_appli = "UTF-8"
encodage_sortie = "UTF-8"
 
; +------------------------------------------------------------------------------------------------------+
; I18n
; i18n_url_parametre : nom du paramètre GET contenant la langue demandée
; i18n_langue_defaut : Indique la langue par défaut
; i18n_locale : Indique la locale à utiliser pour le système (alphabet, date, nombre...)
; i18n_systeme_locale : Paramètres indiquant à PHP qu'elle est la locale à utiliser (par défaut français UTF-8).
; i18n_timezone : Indique la zone horaire
; i18n_systeme_timezone : Définit la zone horaire pour le framework et son application
 
i18n_url_parametre = "langue"
i18n_langue_defaut = "fr"
i18n_locale = "fr_FR.UTF-8"
i18n_systeme_locale = "php:setlocale(LC_ALL, '{ref:i18n_locale}')"
i18n_timezone = "Europe/Paris"
i18n_systeme_timezone = "php:date_default_timezone_set('{ref:i18n_timezone}');"
 
; +------------------------------------------------------------------------------------------------------+
; Cache
; ====> (string) stockage_mode :
; Indique le mode de stockage du cache à utiliser parmis :
; - Cache::STOCKAGE_MODE_FICHIER : sous forme d'une arborescence de fichiers et dossier
; - Cache::STOCKAGE_MODE_SQLITE : sous forme d'une base de données SQLite
; ====> (string) stockage_chemin :
; Chemin vers :
; - Cache::STOCKAGE_MODE_FICHIER : le dossier devant contenir l'arborescence.
; - Cache::STOCKAGE_MODE_SQLITE : le fichier contenant la base SQLite.
; ====> (boolean) controle_ecriture :
; - Active / Désactive le controle d'écriture (le cache est lue jute après l'écriture du fichier pour détecter sa corruption)
; - Activer le controle d'écriture ralentira légèrement l'écriture du fichier de cache mais pas sa lecture
; Le controle d'écriture peut détecter la corruption de fichier mais ce n'est pas un système de controle parfait.
; ====> (boolean) mise_en_cache :
; - Active / Désactive la mise en cache
; (peut être très utile pour le débogage des scripts utilisant le cache
; ====> (string) cache_id_prefixe :
; - préfixe pour les identifiant de cache ( = espace de nom)
; ====> (boolean) serialisation_auto :
; - Active / Désactive la sérialisation automatique
; - Peut être utilisé pour sauver directement des données qui ne sont pas des chaines (mais c'est plus lent)
; ====> (int) nettoyage_auto :
; - Désactive / Régler le processus de nettoyage automatique
; - Le processus de nettoyage automatiques détruit les fichier trop vieux (pour la durée de vie donnée)
; quand un nouveau fichier de cache est écrit :
; 0 => pas de nettoyage automatique
; 1 => nettoyage automatique systématique
; x (integer) > 1 => nettoyage automatique toutes les 1 fois (au hasard) sur x écriture de fichier de cache
; ====> (int) duree_de_vie :
; - Durée de vie du cache (en secondes)
; - Si null, le cache est valide indéfiniment.
 
stockage_mode = "php:Cache::STOCKAGE_MODE_SQLITE"
stockage_chemin = "php:Fichier::getDossierTmp().DS.'cache.sqlite'"
controle_ecriture = "php:TRUE"
mise_en_cache = "php:TRUE"
cache_id_prefixe = "php:NULL"
serialisation_auto = "php:FALSE"
nettoyage_auto = 10
duree_de_vie = 3600
 
; Si cache de type FICHIER, paramètres supplémentaires :
; =====> (boolean) fichier_verrou :
; - Active / Désactive le verrouillage des fichiers
; - Peut éviter la corruption du cache dans de mauvaises circonstances, mais cela ne fonctionne pas sur des serveur
; multithread et sur les systèmes de fichiers NFS par exemple.
; =====> (boolean) controle_lecture :
; - Activer / désactiver le contrôle de lecture
; - S'il est activé, une clé de contrôle est ajoutée dans le fichier de cache et cette clé est comparée avec celle calculée
; après la lecture.
; =====> (string) controle_lecture_type :
; Type de contrôle de lecture (seulement si le contrôle de lecture est activé).
; Les valeurs disponibles sont:
; - «md5» pour un contrôle md5 (le meilleur mais le plus lent)
; - «crc32» pour un contrôle de hachage crc32 (un peu moins sécurisé, mais plus rapide, un meilleur choix)
; - «adler32» pour un contrôle de hachage adler32 (excellent choix aussi, plus rapide que crc32)
; - «strlen» pour un test de longueur uniquement (le plus rapide)
; =====> (int) dossier_niveau :
; - Permet de réglez le nombre de niveau de sous-dossier que contiendra l'arborescence des dossiers du cache.
; 0 signifie "pas de sous-dossier pour le cache",
; 1 signifie "un niveau de sous-dossier",
; 2 signifie "deux niveaux" ...
; Cette option peut accélérer le cache seulement lorsque vous avez plusieurs centaines de fichiers de cache.
; Seuls des tests spécifiques peuvent vous aider à choisir la meilleure valeur possible pour vous.
; 1 ou 2 peut être est un bon début.
; =====> (int) dossier_umask :
; - Umask pour les sous-dossiers de l'arborescence du cache.
; =====> (string) fichier_prefixe :
; - préfixe pour les fichiers du cache
; - ATTENTION : faite vraiment attention avec cette option, car une valeur trop générique dans le dossier cache du système
; (comme /tmp) peut provoquer des catastrophes lors du nettoyage du cache.
; =====> (int) fichier_umask :
; - Umask pour les fichiers de cache
; =====> (int) metadonnees_max_taille :
; - taille maximum pour le tableau de métadonnées du cache (ne changer pas cette valeur sauf si vous savez ce que vous faite)
fichier_verrou = "php:TRUE"
controle_lecture = "php:TRUE"
controle_lecture_type = "crc32"
dossier_niveau = 2
dossier_umask = 0707
fichier_prefixe = "tbf"
fichier_umask = 0606
metadonnees_max_taille = 100
 
; Si cache de type SQLITE, paramètres supplémentaires :
; ====> (int) defragmentation_auto :
; - Désactive / Régler le processus de défragmentation automatique
; - Le processus de défragmentation automatiques réduit la taille du fichier contenant la base de données
; quand un ajout ou une suppression de cache est réalisée :
; 0 => pas de défragmentation automatique
; 1 => défragmentation automatique systématique
; x (integer) > 1 => défragmentation automatique toutes les 1 fois (au hasard) sur x ajout ou suppression de cache
 
defragmentation_auto = 10
 
; +------------------------------------------------------------------------------------------------------+
; Identifications
; identification : Indiquer ici si l'utilisateur est identifié ou pas.
; Peut utiliser un objet Auth comme ceci : "php:$mon_objet_auth->getAuth()"
 
identification = true
 
; +------------------------------------------------------------------------------------------------------+
; Serveur REST
; Les paramètres ci-dessous sont à définir obligatoirement dans votre dossier de services web REST.
; serveur.baseURL : morceau de l'url pour appeler le serveur relative au domaine.
; Exemple : pour http://www.tela-botanica.org/mon_serveur/ mettre : "/mon_serveur/"
; serveur.baseAlternativeURL : (optionnel) sur le même principe que ci-dessus permet d'affecter une deuxième base relative d'url
; (pour gérer des raccourci via htaccess par exemple)
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/Script.php
New file
0,0 → 1,289
<?php
// declare(encoding='UTF-8');
/**
* Script est une classe abstraite qui doit être implémenté par les classes éxecutant des scripts en ligne de commande.
*
* @category PHP 5.2
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @author Delphine CAUQUIL <delphine@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL-v3
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL-v2
* @since 0.3
* @version $Id$
* @link /doc/framework/
*/
 
abstract class Script {
/** Niveau de message de type LOG */
const MSG_LOG = 0;
/** Niveau de message de type ERREUR */
const MSG_ERREUR = 1;
/** Niveau de message de type AVERTISSEMENT */
const MSG_AVERTISSEMENT = 2;
/** Niveau de message de type INFORMATION */
const MSG_INFO = 3;
 
/** Inititulé des différents types de message. */
private static $msg_niveaux_txt = array('LOG', 'ERREUR','AVERTISSEMENT', 'INFO');
/**
* Le nom du script tel que passé dans la ligne de commande.
* @var string
*/
private $script_nom = null;
/**
* Paramêtres par défaut disponibles pour la ligne de commande
* le tableau se construit de la forme suivante :
* - clé = nom du paramêtre '-foo'
* - value = contient un nouveau tableau composé de cette façon :
* - booléen: true si le paramêtre est obligatoire
* - booléen ou var : true si le paramêtre nécessite un valeur à sa suite ou la valeur par défaut
* - string: description du contenu du paramêtre
* Les paramêtres optionels devraient être déclaré à la fin du tableau.
* Le dernier parametre du tableau peut avoir la valeur '...',
* il contiendra alors l'ensemble des paramêtres suivant trouvés sur la ligne de commande.
* @var array
*/
private $parametres_autorises_defaut = array(
'-a' => array(true, true, 'Action à réaliser'),
'-v' => array(false, '1', 'Mode verbeux : 1 ou 2'));
/**
* Paramêtres autorisés par le script.
* le tableau est de la forme suivante :
* - clé = nom du paramêtre '-foo'
* - value = contient un nouveau tableau composé de cette façon :
* - booléen: true si le paramêtre est obligatoire
* - booléen ou var : true si le paramêtre nécessite un valeur à sa suite ou la valeur par défaut
* - string: description du contenu du paramêtre
* Les paramêtres optionels devraient être déclaré à la fin du tableau.
* Le dernier parametre du tableau peut avoir la valeur '...',
* il contiendra alors l'ensemble des paramêtres suivant trouvés sur la ligne de commande.
* @var array
*/
protected $parametres_autorises = null;
/**
* Contient les valeurs des paramêtres récupérés de la ligne de commande :
* le tableau se construit de la forme suivnate :
* - clé = nom du paramêtre '-foo'
* - valeur = la valeur récupérée sur la ligne de commande
* @var array
*/
private $parametres_cli = null;
/**
* Contient le tableau des paramètres disponible après vérification :
* le tableau est de la forme suivante :
* - clé = nom du paramêtre '-foo'
* - valeur = la valeur récupérée sur la ligne de commande
* @var array
*/
protected $parametres = null;
/** Tableau associatif permettant de stocker l'avancement dans une boucle.
* La clé est un md5 du message à afficher au démarrage de la boucle.
* @var array
*/
private static $avancement = array();
/** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
private static $parametres_obligatoires = array('chemin_modules', 'log_script');
public function __construct($script_nom, $parametres_cli) {
$this->script_nom = $script_nom;
$this->parametres_cli = $parametres_cli;
Config::verifierPresenceParametres(self::$parametres_obligatoires);
$fichier_ini_script = $this->getScriptChemin().'config.ini';
Config::charger($fichier_ini_script);
$this->chargerParametresAutorises();
$this->chargerParametres();
}
private static function getMsgNiveauTxt($niveau) {
return self::$msg_niveaux_txt[$niveau];
}
protected function getScriptNom() {
return $this->script_nom;
}
protected function getScriptChemin($doit_exister = true) {
$chemin = Config::get('chemin_modules').$this->getScriptNom().DS;
if (!file_exists($chemin) && $doit_exister) {
trigger_error("Erreur: le module '".$this->getScriptNom()."' n'existe pas ($chemin)\n", E_USER_ERROR);
}
return $chemin;
}
protected function getParametre($parametre) {
$retour = false;
if (!is_null($parametre)) {
$parametre = ltrim($parametre, '-');
if (isset($this->parametres[$parametre])) {
$retour = $this->parametres[$parametre];
} else {
trigger_error("Erreur: la ligne de commande ne contenait pas le paramêtre '$parametre'\n", E_USER_WARNING);
}
}
return $retour;
}
abstract public function executer();
private function chargerParametresAutorises() {
foreach ($this->parametres_autorises_defaut as $c => $v) {
if (isset($this->parametres_autorises[$c])) {
trigger_error("Erreur: le script '".$this->getScriptNom()."' ne peut définir le paramêtre '$c' car il existe déjà\n", E_USER_ERROR);
} else {
$this->parametres_autorises[$c] = $v;
}
}
}
private function chargerParametres() {
$parametres_cli = $this->parametres_cli;
 
// Récupération des paramêtresgetMsgNiveauTxt
foreach ($this->parametres_autorises as $p_nom => $p_val) {
if (count($parametres_cli) == 0) {
if ($p_val[0]) {
trigger_error("Erreur: paramêtre manquant '".$p_nom."' \n", E_USER_WARNING);
}
}
if ($p_nom == '...') {
$this->parametres['...'] = array();
foreach ($parametres_cli as $arg) {
$this->parametres['...'][] = $arg;
}
$parametres_cli = array();
break;
} else {
if (isset($parametres_cli[$p_nom])) {
// Attribution de la valeur issue de la ligne de commande
$this->parametres[ltrim($p_nom, '-')] = $parametres_cli[$p_nom];
unset($parametres_cli[$p_nom]);
} else {
// Attribution de la valeur par défaut
if ($p_val[1] !== true) {
$this->parametres[ltrim($p_nom, '-')] = $p_val[1];
unset($parametres_cli[$p_nom]);
}
}
}
}
// Gestion de l'excédant de paramêtres
if (count($parametres_cli)) {
trigger_error("Erreur: trop de paramêtres\n", E_USER_ERROR);
}
}
/**
* Affiche un message d'erreur formaté.
* Si le paramétre de verbosité (-v) vaut 1 ou plus, le message est écrit dans le fichier de log et afficher dans la console.
*
* @param string le message d'erreur avec des %s.
* @param array le tableau des paramêtres à insérer dans le message d'erreur.
* @return void.
*/
protected function traiterErreur($message, $tab_arguments = array()) {
$this->traiterMessage($message, $tab_arguments, self::MSG_ERREUR);
}
/**
* Affiche un message d'avertissement formaté.
* Si le paramétre de verbosité (-v) vaut 1, le message est écrit dans le fichier de log.
* Si le paramétre de verbosité (-v) vaut 2 ou plus, le message est écrit dans le fichier de log et afficher dans la console.
*
* @param string le message d'erreur avec des %s.
* @param array le tableau des paramêtres à insérer dans le message d'erreur.
* @return void.
*/
protected function traiterAvertissement($message, $tab_arguments = array()) {
$this->traiterMessage($message, $tab_arguments, self::MSG_AVERTISSEMENT);
}
/**
* Retourne un message d'information formaté.
* Si le paramétre de verbosité (-v) vaut 1 ou 2 , le message est écrit dans le fichier de log.
* Si le paramétre de verbosité (-v) vaut 3 ou plus, le message est écrit dans le fichier de log et afficher dans la console.
*
* @param string le message d'information avec des %s.
* @param array le tableau des paramêtres à insérer dans le message d'erreur.
* @return void.
*/
protected function traiterInfo($message, $tab_arguments = array()) {
$this->traiterMessage($message, $tab_arguments, self::MSG_INFO);
}
/**
* Retourne un message formaté en le stockant dans un fichier de log si nécessaire.
*
* @param string le message d'erreur avec des %s.
* @param array le tableau des paramêtres à insérer dans le message d'erreur.
* @param int le niveau de verbosité à dépasser pour afficher les messages.
* @return void.
*/
private function traiterMessage($message, $tab_arguments, $niveau = self::MSG_LOG) {
$log = $this->formaterMsg($message, $tab_arguments, $niveau);
if ($this->getParametre('v') > ($niveau - 1)) {
echo $log;
if (Config::get('log_script')) {
// TODO : lancer le log
}
}
}
/**
* Retourne un message d'information formaté.
*
* @param string le message d'information avec des %s.
* @param array le tableau des paramêtres à insérer dans le message d'erreur.
* @return string le message d'erreur formaté.
*/
protected function formaterMsg($message, $tab_arguments = array(), $niveau = null) {
$texte = vsprintf($message, $tab_arguments);
$prefixe = date('Y-m-j_H:i:s', time());
$prefixe .= is_null($niveau) ? ' : ' : ' - '.self::getMsgNiveauTxt($niveau).' : ';
$log = $prefixe.$texte."\n";
return $log;
}
/**
* Utiliser cette méthode dans une boucle pour afficher un message suivi du nombre de tour de boucle effectué.
* Vous devrez vous même gérer le retour à la ligne à la sortie de la boucle.
*
* @param string le message d'information.
* @param int le nombre de départ à afficher.
* @return void le message est affiché dans la console.
*/
protected function afficherAvancement($message, $depart = 0) {
if (! isset(self::$avancement[$message])) {
self::$avancement[$message] = $depart;
echo "$message : ";
$actuel =& self::$avancement[$message];
echo $actuel++;
} else {
$actuel =& self::$avancement[$message];
// Cas du passage de 99 (= 2 caractères) à 100 (= 3 caractères)
$passage = 0;
if (strlen((string) ($actuel - 1)) < strlen((string) ($actuel))) {
$passage = 1;
}
echo str_repeat(chr(8), (strlen((string) $actuel) - $passage));
echo $actuel++;
}
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/Config.php
New file
0,0 → 1,281
<?php
// declare(encoding='UTF-8');
/**
* Config permet de charger automatiquement les fichiers ini du Framework et de l'application.
* Elle offre l'accès en lecture seule aux paramètres de config.
* C'est une Singleton.
* Si vous avez besoin de modifier dynamiquement des paramètres de configuration, utiliser le @see Registe, il est fait pour ça.
*
* @category PHP 5.2
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2009, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL-v3
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL-v2
* @version $Id$
* @link /doc/framework/
*/
 
class Config {
 
/** Instance de la classe pointant sur elle même (pour le pattern singleton). */
private static $instance = null;
 
/** Paramètres de configuration. */
private static $parametres = array();
 
private function __construct() {
// Définition de paramètres avant chargement du config.ini
self::$parametres = array(
'fichier_config' => 'config%s.ini',
'chemin_framework' => dirname(__FILE__).DS
);
 
// Chargement du fichier config.ini du Framework
$existe = self::parserFichierIni(self::$parametres['chemin_framework'].sprintf(self::$parametres['fichier_config'], ''));
if ($existe === false) {
trigger_error("Veuillez configurer le Framework en renommant le fichier config.defaut.ini en config.ini.", E_USER_ERROR);
}
 
// Chargement du fichier config.ini par défaut de l'application
$chemin_config_defaut_appli = self::$parametres['chemin_configurations'].sprintf(self::$parametres['fichier_config'], '');
self::parserFichierIni($chemin_config_defaut_appli);
 
// Chargement des fichiers config.ini contextuels
if (PHP_SAPI == 'cli') {// mode console
foreach ($_SERVER['argv'] as $cle => $valeur) {
if ($valeur == '-contexte') {
chargerFichierContexte($_SERVER['argv'][($cle+1)]);
break;
}
}
} else {// mode web
// Pour Papyrus
if (defined('PAP_VERSION')) {
self::chargerFichierContexte('papyrus');
}
// Via le fichie .ini par défaut de l'appli
if (Config::existeValeur('info.contexte', self::$parametres)) {
self::chargerFichierContexte(Config::get('info.contexte'));
}
 
// Chargement du contexte présent dans le GET
if (isset($_GET['contexte'])) {
$_GET['contexte'] = strip_tags($_GET['contexte']);
self::chargerFichierContexte($_GET['contexte']);
}
 
// Chargement du contexte présent dans le POST
if (isset($_POST['contexte'])) {
$_POST['contexte'] = strip_tags($_POST['contexte']);
self::chargerFichierContexte($_POST['contexte']);
}
}
}
 
/**
* Charge le fichier de config correspondant au contexte
* @param string $contexte le contexte
*/
private static function chargerFichierContexte($contexte) {
$chemin_config_appli_contextuel = self::$parametres['chemin_configurations'];
$chemin_config_appli_contextuel .= sprintf(self::$parametres['ffichier_config'], '_'.$contexte);
self::parserFichierIni($chemin_config_appli_contextuel);
}
 
/**
* Parse le fichier ini donné en paramètre
* @param string $fichier_ini nom du fichier ini à parser
* @return array tableau contenant les paramètres du fichier ini
*/
private static function parserFichierIni($fichier_ini) {
$retour = false;
if (file_exists($fichier_ini)) {
$ini = parse_ini_file($fichier_ini, true);
$ini = self::analyserTableauIni($ini);
self::fusionner($ini);
$retour = true;
}
return $retour;
}
 
/**
* Fusionne un tableau de paramètres avec le tableau de paramètres global
* @param array $ini le tableau à fusionner
*/
private static function fusionner(array $ini) {
self::$parametres = array_merge(self::$parametres, $ini);
}
 
/**
* Renvoie la valeur demandée grâce une chaîne de paramètres
* @param string $param la chaine de paramètres
* @param array $config le tableau de paramètre
* @return string la valeur de la chaine demandée
*/
private static function getValeur($param, $config) {
if ($param === null) {
return null;
} else {
if (isset($config[$param])) {
return $config[$param];
} else if (strpos($param, '.') !== false) {
$pieces = explode('.', $param, 2);
if (strlen($pieces[0]) && strlen($pieces[1])) {
if (isset($config[$pieces[0]])) {
if (is_array($config[$pieces[0]])) {
return self::getValeur($pieces[1], $config[$pieces[0]]);
}
}
}
} else {
return null;
}
}
}
 
/**
* Teste si param existe dans le tableau config
* @param string $param nom du paramètre
* @param array tableau de configuration
*/
private static function existeValeur($param, $config) {
$retour = false;
if (self::getValeur($param, $config) !== null) {
$retour = true;
}
return $retour;
}
 
/**
* Vérifie si l'instance de classe à été crée, si non la crée
*/
private static function verifierCreationInstance() {
if (empty(self::$instance)) {
self::$instance = new Config();
}
}
 
/**
* Analyse un tableau de paramètres.
* @param array $config le tableau de paramètres
* @return array le tableau analysé
*/
private static function analyserTableauIni($config = array()) {
foreach ($config as $cle => &$valeur) {
if (is_array($valeur)) {
$config[$cle] = self::analyserTableauIni($valeur);
} else {
self::evaluerReferences($config, $cle);
self::evaluerPhp($config, $cle);
self::evaluerCle($config, $cle, $config[$cle]);
}
}
return $config;
}
 
/**
* Dans le cas des chaine de configuration à sous clé (ex.: cle.souscle)
* évalue les valeurs correspondantes et crée les sous tableaux associés.
* @param array $config tableau de configuration (par référence)
* @param string $cle la cle dans le tableau
* @param string $valeur la valeur à affecter
*/
private static function evaluerCle(&$config, $cle, $valeur) {
if (strpos($cle, '.') !== false) {
unset($config[$cle]);
$pieces = explode('.', $cle, 2);
if (strlen($pieces[0]) && strlen($pieces[1])) {
if (isset($config[$pieces[0]]) && !is_array($config[$pieces[0]])) {
$m = "Ne peut pas créer de sous-clé pour '{$pieces[0]}' car la clé existe déjà";
trigger_error($m, E_USER_WARNING);
} else {
$config[$pieces[0]][$pieces[1]] = $valeur;
$config[$pieces[0]] = self::evaluerCle($config[$pieces[0]], $pieces[1], $valeur);
}
} else {
$m = "Clé invalide '$cle'";
trigger_error($m, E_USER_WARNING);
}
} else {
$config[$cle] = $valeur;
}
return $config;
}
 
/**
* Évalue les valeurs de références à une clé dans le tableau config (cas du ref:cle).
* @param array $config tableau de configuration
* @param string $cle la clé dont il faut évaluer les références
*/
private static function evaluerReferences(&$config, $cle) {
if (preg_match_all('/{ref:([A-Za-z0-9_.-]+)}/', $config[$cle], $correspondances, PREG_SET_ORDER)) {
foreach ($correspondances as $ref) {
$config[$cle] = str_replace($ref[0], self::getValeur($ref[1], $config), $config[$cle]);
}
}
}
 
/**
* Évalue le code php contenu dans un clé tu tableau config.
* @param array $config tableau de configuration (par référence)
* @param string $cle le clé du tableau dont il faut évaluer la valeur
*/
private static function evaluerPhp(&$config, $cle) {
if (preg_match('/^php:(.+)$/', $config[$cle], $correspondances)) {
eval('$config["'.$cle.'"] = '.$correspondances[1].';');
}
}
 
/**
* Charge un fichier ini dans le tableau des paramètres de l'appli.
* @param string $fichier_ini le nom du fichier à charger
* @return array le fichier ini parsé
*/
public static function charger($fichier_ini) {
self::verifierCreationInstance();
return self::parserFichierIni($fichier_ini);
}
 
/**
* Accesseur pour la valeur d'un paramètre.
* @param string $param le nom du paramètre
* @return string la valeur du paramètre
*/
public static function get($param = null) {
self::verifierCreationInstance();
return self::getValeur($param, self::$parametres);
}
 
/**
* Vérifie si la valeur d'un paramètre existe.
* @param string $param le nom du paramètre
* @return boolean vrai si le paramètre existe, false sinon
*/
public static function existe($param) {
self::verifierCreationInstance();
return self::existeValeur($param, self::$parametres);
}
/**
* Vérifie que tous les paramêtres de config nécessaires au fonctionnement d'une classe existe dans les fichiers
* de configurations.
* L'utilisation de cette méthode depuis la classe Config évite de faire appel à une classe supplémentaire.
*
* @param array $parametres tableau des noms des paramètres de la config à verifier.
* @return boolean true si tous les paramétres sont présents sinon false.
*/
public static function verifierPresenceParametres(Array $parametres) {
$ok = true;
foreach ($parametres as $param) {
if (is_null(self::get($param))) {
$classe = get_class();
$m = "L'utilisation de la classe $classe nécessite de définir '$param' dans un fichier de configuration.";
trigger_error($m, E_USER_ERROR);
$ok = false;
}
}
return $ok;
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/GestionnaireException.php
New file
0,0 → 1,232
<?php
// declare(encoding='UTF-8');
/**
* Classe de gestion des exceptions.
* C'est un Singleton.
*
* @category PHP 5.2
* @package Framework
* @author Aurélien PERONNET <aurelien@tela-botanica.org>
* @author Jean-Pascal MILCENT <jmp@tela-botanica.org>
* @copyright Copyright (c) 2009, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
* @version $Id$$
* @link /doc/framework/
*
*/
class GestionnaireException {
const MODE_CLI = 'cli';
/** Liste des exceptions enregistrées */
private static $exceptions = array();
 
/** Détermine si l'on affiche ou non le contexte */
private static $contexte = false;
 
/** Détermine si l'on loggue ou non les erreurs */
private static $logger = false;
 
/** Détermine si l'affichage des erreurs est forcé (true) ou pas (false) à la destruction de la classe */
private static $afficher = false;
 
/** Definit si php est lancé en ligne de commande ou en mode serveur */
private static $mode = null ;
 
/** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
private static $parametres_obligatoires = array('debogage', 'debogage_contexte', 'log_debogage');
/** Initialise le Gestionnaire d'exceptions et d'erreur sans tenir comptes des paramêtres de config. */
public static function initialiser() {
self::$mode = php_sapi_name();
// Désactivation des balises HTML dans les messages d'erreur de PHP en mode ligne de commande
if (self::$mode == self::MODE_CLI) {
ini_set('html_errors', 0);
}
set_exception_handler(array(get_class(),'gererException'));
set_error_handler(array(get_class(),'gererErreur'));
}
/** Configure le Gestionnaire d'exceptions et d'erreur à partir des paramêtres de config. */
public static function configurer() {
Config::verifierPresenceParametres(self::$parametres_obligatoires);
self::$contexte = Config::get('debogage_contexte');
self::$logger = Config::get('log_debogage');
self::$afficher = Config::get('debogage');
}
/**
* Renvoie le nombre d'exceptions et d'erreurs levées.
* @see getExceptions() pour obtenir les exceptions formatées.
* @since 0.3
* @return int le nombre d'exception actuellement levées
*/
public static function getExceptionsNbre() {
return count(self::$exceptions);
}
/**
* Renvoie le booleen définissant si l'on affiche le contexte ou non
* @return bool true si on affiche le contexte sinon false.
*/
public static function getContexte() {
return self::$contexte;
}
 
/**
* Definit si l'on veut afficher le contexte ou non
* @param bool true si on veut afficher le contexte, false sinon, par défaut vaut false
*/
public static function setContexte($contexte) {
self::$contexte = $contexte;
}
 
/**
* Fonction de gestion des exceptions, remplace le handler par défaut.
* Si une boucle génère de multiple exception (ou erreur) identique une seule sera stockée.
* @param Exception $e l'exception à traiter
*/
public static function gererException(Exception $e) {
$cle = hash('md5', $e->getMessage().'-'.$e->getFile().'-'.$e->getLine());
if (!isset(self::$exceptions[$cle])) {
self::$exceptions[$cle] = $e;
self::loggerException($e);
}
}
 
/**
* Gère les erreurs en les convertissant en exceptions (remplace la fonction gestion d'erreurs native de php)
* @param int $niveau le niveau de l'erreur
* @param string $message le message associé à l'erreur
* @param string $fichier le nom du fichier où l'erreur s'est produite
* @param int $ligne la ligne où l'erreur s'est produite
* @param string $contexte le contexte associé à l'erreur
*/
public static function gererErreur($niveau, $message, $fichier, $ligne, $contexte){
// Si un rapport d'erreur existe, création d'une exception
if (error_reporting() != 0) {
$e = new ErrorException($message, 0, $niveau, $fichier, $ligne);
self::gererException($e);
}
return null;
}
 
/**
* Renvoie les exceptions au format (X)HTML ou bien au format texte suivant le mode d'utilisation de PHP.
* @since 0.3
* @deprecated
* @see getExceptionsFormatees()
* @return string les exceptions formatées en texte ou (X)HTML.
*/
public static function getExceptions() {
return self::getExceptionsFormatees();
}
/**
* Renvoie les exceptions au format (X)HTML ou bien au format texte suivant le mode d'utilisation de PHP.
* @since 0.3
* @return string les exceptions formatées en texte ou (X)HTML.
*/
public static function getExceptionsFormatees() {
$retour = '';
if (self::getExceptionsNbre() > 0) {
foreach (self::$exceptions as $cle => $e) {
switch (self::$mode) {
case self::MODE_CLI :
$retour .= self::formaterExceptionTxt($e);
break;
default:
$retour .= self::formaterExceptionXhtml($e);
}
// Nous vidons le tableau des exceptions au fur et à mesure pour éviter le réaffichage avec le destructeur.
unset(self::$exceptions[$cle]);
}
}
return $retour;
}
/**
* Renvoie le tableau d'objets Exception générées par le script PHP triées du niveau de sévérité le plus élevé au moins élevé.
* Format du tableau :
* array{sévérité_1 = array{Exception1, Exception2, Exception3,...}, sévérité_1 = array{Exception1, Exception2, ...}, ...};
* ATTENTION : si vous utilisez cette méthode, c'est à vous de gérer l'affichage des Exceptions. Le gestionnaire d'exception
* n'enverra plus rien au navigateur ou à la console.
* @since 0.3
* @return array le tableau trié d'objet Exception.
*/
public static function getExceptionsTriees() {
$retour = array();
if (self::getExceptionsNbre() > 0) {
foreach (self::$exceptions as $cle => $e) {
$retour[$e->getSeverity()][] = $e;
// Nous vidons le tableau des exceptions au fur et à mesure pour éviter le réaffichage avec le destructeur.
unset(self::$exceptions[$cle]);
}
ksort($retour);
}
return $retour;
}
 
/**
* Logue une exception donnée sous une forme lisible si self::logger vaut true.
* @param Exception $e l'exception à logger
*/
private static function loggerException(Exception $e) {
if (self::$logger) {
$message = self::formaterExceptionTxt($e);
Log::ajouterEntree('erreurs', $message);
}
}
/**
* Formate en texte une exception passée en paramètre.
* @since 0.3
* @param Exception l'exception à formater.
*/
public static function formaterExceptionTxt(Exception $e) {
$message = '';
$message .= $e->getMessage()."\n";
$message .= 'Fichier : '.$e->getFile()."\n";
$message .= 'Ligne : '.$e->getLine()."\n";
if (self::getContexte()) {
$message .= 'Contexte : '."\n".print_r($e->getTraceAsString(), true)."\n";
}
$message .= "\n";
return $message;
}
/**
* Formate en (X)HTML une exception passée en paramètre.
* @since 0.3
* @param Exception l'exception à formater.
*/
public static function formaterExceptionXhtml(Exception $e) {
$message = '';
$message .= '<div class="debogage">'."\n";
$message .= $e->getMessage()."\n";
$message .= '<span class="debogage_fichier">'.'Fichier : '.$e->getFile().'</span>'."\n";
$message .= '<span class="debogage_ligne">'.'Ligne : '.$e->getLine().'</span>'."\n";
if (self::getContexte()) {
$message .= '<pre>'."\n";
$message .= '<strong>Contexte : </strong>'."\n".print_r($e->getTraceAsString(), true)."\n";
$message .= '</pre>'."\n";
}
$message .= '</div>'."\n";
return $message;
}
/**
* Lors de la destruction de la classe si des exceptions n'ont pas été affichées, et si le débogage est à true, elles sont
* affichées.
*/
public function __destruct() {
// Si des erreurs n'ont pas été affichée nous forçons leur affichage
if (self::$afficher && self::getExceptionsNbre() > 0) {
echo self::getExceptionsFormatees();
}
}
 
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/Cli.php
New file
0,0 → 1,101
<?php
// declare(encoding='UTF-8');
/**
* CLI permet de récupérer les paramètres passés en ligne de commande pour instancier une classe héritant de la classe abstraite
* Script.
* Elle va déclencher l'éxecution du script via l'appel de la méthode executer().
* C'est une Singleton.
*
* @category PHP 5.2
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @author Delphine CAUQUIL <delphine@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL-v3
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL-v2
* @since 0.3
* @version $Id$
* @link /doc/framework/
*/
 
class Cli {
/** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
private static $parametres_obligatoires = array('chemin_modules');
/**
* Execute la ligne de commande en récupérant le nom du script à lancer et ses paramètres.
* Instancie la classe du script à lancer et appelle la méthode executer().
* @return void
*/
public static function executer() {
if ($_SERVER['argc'] < 2){
trigger_error("Erreur: vous n'avez pas indiqué le nom du script. Voir '".$_SERVER['argv'][0]." help'.\n", E_USER_ERROR);
}
// Récupération de la ligne de commande
$argv = $_SERVER['argv'];
// Nous dépilons le nom du fichier qui initialise le framework et appele cette méthode.
array_shift($argv);
// Nous dépilons le nom du script à lancer
$script = array_shift($argv);
// Récupération des paramètres d'execution du script
$parametres = self::getParametres($argv);
// Chargement du script à lancer
$Script = Cli::charger($script, $parametres);
if (!is_null($Script)) {
$Script->executer();
}
// Affichage des exceptions et erreurs générées par le script
echo GestionnaireException::getExceptions();
// Fin d'execution
exit(0);
}
private static function charger($script_nom, $parametres) {
$Script = null;
Config::verifierPresenceParametres(self::$parametres_obligatoires);
$classe_nom = self::obtenirNomClasse($script_nom);
$dossier_nom = strtolower($script_nom);
$fichier_script = Config::get('chemin_modules').$dossier_nom.DS.$classe_nom.'.php';
if (!file_exists($fichier_script)){
trigger_error("Erreur : script '$fichier_script' inconnu!\n", E_USER_ERROR);
} else {
require_once $fichier_script;
if (!class_exists( $classe_nom)) {
trigger_error("Erreur: impossible de trouver la classe de la commande : $classe_nom\n", E_USER_ERROR);
} else {
$Script = new $classe_nom($script_nom, $parametres);
}
}
return $Script;
}
private static function obtenirNomClasse($script_nom) {
$nom_classe = implode('', array_map('ucfirst', explode('_', strtolower($script_nom))));
return $nom_classe;
}
private static function getParametres($argv) {
$parametres = array();
// Récupération des options
while (count($argv)) {
if (isset($argv[1]) && $argv[1]{0} != '-') {
$param = array_shift($argv);
$parametres[$param] = array_shift($argv);
} elseif (!isset($argv[1]) || $argv[1]{0} == '-') {
$parametres[array_shift($argv)] = null;
} else {
trigger_error("Erreur: valeur manquante pour le paramêtre '".$argv[0]."' \n", E_USER_ERROR);
}
}
return $parametres;
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/utilitaires/Storage.php
New file
0,0 → 1,132
<?php
 
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Consumer
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
 
/**
* Abstract class to implement external storage for OpenID consumer
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Consumer
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Storage
{
 
/**
* Stores information about association identified by $url/$handle
*
* @param string $url OpenID server URL
* @param string $handle assiciation handle
* @param string $macFunc HMAC function (sha1 or sha256)
* @param string $secret shared secret
* @param long $expires expiration UNIX time
* @return void
*/
abstract public function addAssociation($url, $handle, $macFunc, $secret, $expires);
 
/**
* Gets information about association identified by $url
* Returns true if given association found and not expired and false
* otherwise
*
* @param string $url OpenID server URL
* @param string &$handle assiciation handle
* @param string &$macFunc HMAC function (sha1 or sha256)
* @param string &$secret shared secret
* @param long &$expires expiration UNIX time
* @return bool
*/
abstract public function getAssociation($url, &$handle, &$macFunc, &$secret, &$expires);
 
/**
* Gets information about association identified by $handle
* Returns true if given association found and not expired and false
* othverwise
*
* @param string $handle assiciation handle
* @param string &$url OpenID server URL
* @param string &$macFunc HMAC function (sha1 or sha256)
* @param string &$secret shared secret
* @param long &$expires expiration UNIX time
* @return bool
*/
abstract public function getAssociationByHandle($handle, &$url, &$macFunc, &$secret, &$expires);
 
/**
* Deletes association identified by $url
*
* @param string $url OpenID server URL
* @return void
*/
abstract public function delAssociation($url);
 
/**
* Stores information discovered from identity $id
*
* @param string $id identity
* @param string $realId discovered real identity URL
* @param string $server discovered OpenID server URL
* @param float $version discovered OpenID protocol version
* @param long $expires expiration UNIX time
* @return void
*/
abstract public function addDiscoveryInfo($id, $realId, $server, $version, $expires);
 
/**
* Gets information discovered from identity $id
* Returns true if such information exists and false otherwise
*
* @param string $id identity
* @param string &$realId discovered real identity URL
* @param string &$server discovered OpenID server URL
* @param float &$version discovered OpenID protocol version
* @param long &$expires expiration UNIX time
* @return bool
*/
abstract public function getDiscoveryInfo($id, &$realId, &$server, &$version, &$expires);
 
/**
* Removes cached information discovered from identity $id
*
* @param string $id identity
* @return bool
*/
abstract public function delDiscoveryInfo($id);
 
/**
* The function checks the uniqueness of openid.response_nonce
*
* @param string $provider openid.openid_op_endpoint field from authentication response
* @param string $nonce openid.response_nonce field from authentication response
* @return bool
*/
abstract public function isUniqueNonce($provider, $nonce);
 
/**
* Removes data from the uniqueness database that is older then given date
*
* @param string $date Date of expired data
*/
abstract public function purgeNonces($date=null);
}
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/utilitaires/StorageFile.php
New file
0,0 → 1,512
<?php
 
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Consumer
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id$
*/
 
/**
* External storage implemmentation using serialized files
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Consumer
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class StorageFile extends Storage
{
 
/**
* Directory name to store data files in
*
* @var string $_dir
*/
private $_dir;
 
/**
* Constructs storage object and creates storage directory
*
* @param string $dir directory name to store data files in
* @throws Zend_OpenId_Exception
*/
public function __construct($dir = null)
{
if ($dir === null) {
$tmp = getenv('TMP');
if (empty($tmp)) {
$tmp = getenv('TEMP');
if (empty($tmp)) {
$tmp = "/tmp";
}
}
$user = get_current_user();
if (is_string($user) && !empty($user)) {
$tmp .= '/' . $user;
}
$dir = $tmp . '/openid/consumer';
}
$this->_dir = $dir;
if (!is_dir($this->_dir)) {
if (!@mkdir($this->_dir, 0700, 1)) {
/**
* @see Zend_OpenId_Exception
*/
require_once 'Zend/OpenId/Exception.php';
throw new Zend_OpenId_Exception(
'Cannot access storage directory ' . $dir,
Zend_OpenId_Exception::ERROR_STORAGE);
}
}
if (($f = fopen($this->_dir.'/assoc.lock', 'w+')) === null) {
/**
* @see Zend_OpenId_Exception
*/
/*require_once 'Zend/OpenId/Exception.php';
throw new Zend_OpenId_Exception(
'Cannot create a lock file in the directory ' . $dir,
Zend_OpenId_Exception::ERROR_STORAGE);*/
trigger_error('Cannot create a lock file in the directory ', E_STRICT);
}
fclose($f);
if (($f = fopen($this->_dir.'/discovery.lock', 'w+')) === null) {
/**
* @see Zend_OpenId_Exception
*/
/*require_once 'Zend/OpenId/Exception.php';
throw new Zend_OpenId_Exception(
'Cannot create a lock file in the directory ' . $dir,
Zend_OpenId_Exception::ERROR_STORAGE);*/
trigger_error('Cannot create a lock file in the directory', E_STRICT);
}
fclose($f);
if (($f = fopen($this->_dir.'/nonce.lock', 'w+')) === null) {
/**
* @see Zend_OpenId_Exception
*/
/*require_once 'Zend/OpenId/Exception.php';
throw new Zend_OpenId_Exception(
'Cannot create a lock file in the directory ' . $dir,
Zend_OpenId_Exception::ERROR_STORAGE);*/
trigger_error('Cannot create a lock file in the directory', E_STRICT);
}
fclose($f);
}
 
/**
* Stores information about association identified by $url/$handle
*
* @param string $url OpenID server URL
* @param string $handle assiciation handle
* @param string $macFunc HMAC function (sha1 or sha256)
* @param string $secret shared secret
* @param long $expires expiration UNIX time
* @return bool
*/
public function addAssociation($url, $handle, $macFunc, $secret, $expires)
{
$name1 = $this->_dir . '/assoc_url_' . md5($url);
$name2 = $this->_dir . '/assoc_handle_' . md5($handle);
$lock = @fopen($this->_dir . '/assoc.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name1, 'w+');
if ($f === false) {
fclose($lock);
return false;
}
$data = serialize(array($url, $handle, $macFunc, $secret, $expires));
fwrite($f, $data);
if (function_exists('symlink')) {
@unlink($name2);
if (symlink($name1, $name2)) {
fclose($f);
fclose($lock);
return true;
}
}
$f2 = @fopen($name2, 'w+');
if ($f2) {
fwrite($f2, $data);
fclose($f2);
@unlink($name1);
$ret = true;
} else {
$ret = false;
}
fclose($f);
fclose($lock);
return $ret;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
 
/**
* Gets information about association identified by $url
* Returns true if given association found and not expired and false
* otherwise
*
* @param string $url OpenID server URL
* @param string &$handle assiciation handle
* @param string &$macFunc HMAC function (sha1 or sha256)
* @param string &$secret shared secret
* @param long &$expires expiration UNIX time
* @return bool
*/
public function getAssociation($url, &$handle, &$macFunc, &$secret, &$expires)
{
$name1 = $this->_dir . '/assoc_url_' . md5($url);
$lock = @fopen($this->_dir . '/assoc.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name1, 'r');
if ($f === false) {
fclose($lock);
return false;
}
$ret = false;
$data = stream_get_contents($f);
if (!empty($data)) {
list($storedUrl, $handle, $macFunc, $secret, $expires) = unserialize($data);
if ($url === $storedUrl && $expires > time()) {
$ret = true;
} else {
$name2 = $this->_dir . '/assoc_handle_' . md5($handle);
fclose($f);
@unlink($name2);
@unlink($name1);
fclose($lock);
return false;
}
}
fclose($f);
fclose($lock);
return $ret;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
 
/**
* Gets information about association identified by $handle
* Returns true if given association found and not expired and false
* otherwise
*
* @param string $handle assiciation handle
* @param string &$url OpenID server URL
* @param string &$macFunc HMAC function (sha1 or sha256)
* @param string &$secret shared secret
* @param long &$expires expiration UNIX time
* @return bool
*/
public function getAssociationByHandle($handle, &$url, &$macFunc, &$secret, &$expires)
{
$name2 = $this->_dir . '/assoc_handle_' . md5($handle);
$lock = @fopen($this->_dir . '/assoc.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name2, 'r');
if ($f === false) {
fclose($lock);
return false;
}
$ret = false;
$data = stream_get_contents($f);
if (!empty($data)) {
list($url, $storedHandle, $macFunc, $secret, $expires) = unserialize($data);
if ($handle === $storedHandle && $expires > time()) {
$ret = true;
} else {
fclose($f);
@unlink($name2);
$name1 = $this->_dir . '/assoc_url_' . md5($url);
@unlink($name1);
fclose($lock);
return false;
}
}
fclose($f);
fclose($lock);
return $ret;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
 
/**
* Deletes association identified by $url
*
* @param string $url OpenID server URL
* @return bool
*/
public function delAssociation($url)
{
$name1 = $this->_dir . '/assoc_url_' . md5($url);
$lock = @fopen($this->_dir . '/assoc.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name1, 'r');
if ($f === false) {
fclose($lock);
return false;
}
$data = stream_get_contents($f);
if (!empty($data)) {
list($storedUrl, $handle, $macFunc, $secret, $expires) = unserialize($data);
if ($url === $storedUrl) {
$name2 = $this->_dir . '/assoc_handle_' . md5($handle);
fclose($f);
@unlink($name2);
@unlink($name1);
fclose($lock);
return true;
}
}
fclose($f);
fclose($lock);
return true;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
 
/**
* Stores information discovered from identity $id
*
* @param string $id identity
* @param string $realId discovered real identity URL
* @param string $server discovered OpenID server URL
* @param float $version discovered OpenID protocol version
* @param long $expires expiration UNIX time
* @return bool
*/
public function addDiscoveryInfo($id, $realId, $server, $version, $expires)
{
$name = $this->_dir . '/discovery_' . md5($id);
$lock = @fopen($this->_dir . '/discovery.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name, 'w+');
if ($f === false) {
fclose($lock);
return false;
}
$data = serialize(array($id, $realId, $server, $version, $expires));
fwrite($f, $data);
fclose($f);
fclose($lock);
return true;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
 
/**
* Gets information discovered from identity $id
* Returns true if such information exists and false otherwise
*
* @param string $id identity
* @param string &$realId discovered real identity URL
* @param string &$server discovered OpenID server URL
* @param float &$version discovered OpenID protocol version
* @param long &$expires expiration UNIX time
* @return bool
*/
public function getDiscoveryInfo($id, &$realId, &$server, &$version, &$expires)
{
$name = $this->_dir . '/discovery_' . md5($id);
$lock = @fopen($this->_dir . '/discovery.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name, 'r');
if ($f === false) {
fclose($lock);
return false;
}
$ret = false;
$data = stream_get_contents($f);
if (!empty($data)) {
list($storedId, $realId, $server, $version, $expires) = unserialize($data);
if ($id === $storedId && $expires > time()) {
$ret = true;
} else {
fclose($f);
@unlink($name);
fclose($lock);
return false;
}
}
fclose($f);
fclose($lock);
return $ret;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
 
/**
* Removes cached information discovered from identity $id
*
* @param string $id identity
* @return bool
*/
public function delDiscoveryInfo($id)
{
$name = $this->_dir . '/discovery_' . md5($id);
$lock = @fopen($this->_dir . '/discovery.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
@unlink($name);
fclose($lock);
return true;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
 
/**
* The function checks the uniqueness of openid.response_nonce
*
* @param string $provider openid.openid_op_endpoint field from authentication response
* @param string $nonce openid.response_nonce field from authentication response
* @return bool
*/
public function isUniqueNonce($provider, $nonce)
{
$name = $this->_dir . '/nonce_' . md5($provider.';'.$nonce);
echo $name;
$lock = @fopen($this->_dir . '/nonce.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name, 'x');
if ($f === false) {
fclose($lock);
return false;
}
fwrite($f, $provider.';'.$nonce);
fclose($f);
fclose($lock);
return true;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
 
/**
* Removes data from the uniqueness database that is older then given date
*
* @param mixed $date date of expired data
*/
public function purgeNonces($date=null)
{
$lock = @fopen($this->_dir . '/nonce.lock', 'w+');
if ($lock !== false) {
flock($lock, LOCK_EX);
}
try {
if (!is_int($date) && !is_string($date)) {
$nonceFiles = glob($this->_dir . '/nonce_*');
foreach ((array) $nonceFiles as $name) {
@unlink($name);
}
unset($nonceFiles);
} else {
if (is_string($date)) {
$time = time($date);
} else {
$time = $date;
}
$nonceFiles = glob($this->_dir . '/nonce_*');
foreach ((array) $nonceFiles as $name) {
if (filemtime($name) < $time) {
@unlink($name);
}
}
unset($nonceFiles);
}
if ($lock !== false) {
fclose($lock);
}
} catch (Exception $e) {
if ($lock !== false) {
fclose($lock);
}
throw $e;
}
}
}
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/utilitaires/DiffieHellmanUtil.php
New file
0,0 → 1,224
<?php
 
/**
* Classe utilitaire proposant des fonctions permettant la réalisation d'un
* échange de clé Diffie Hellman
*
* "En cryptographie, l'échange de clés Diffie-Hellman, du nom de ses auteurs
* Whitfield Diffie et Martin Hellman, est une méthode par laquelle deux
* personnes peuvent se mettre d'accord sur un nombre (qu'ils peuvent utiliser
* comme clé pour chiffrer la conversation suivante) sans qu'une troisième
* personne appelée Ève puisse découvrir le nombre, même en ayant écouté tous
* leurs échanges."
*
* Voir http://fr.wikipedia.org/wiki/%C3%89change_de_cl%C3%A9s_Diffie-Hellman
*
* */
class DiffieHellmanUtil {
// Default Diffie-Hellman key generator (1024 bit)
const DH_P = 'dcf93a0b883972ec0e19989ac5a2ce310e1d37717e8d9571bb7623731866e61ef75a2e27898b057f9891c2e27a639c3f29b60814581cd3b2ca3986d2683705577d45c2e7e52dc81c7a171876e5cea74b1448bfdfaf18828efd2519f14e45e3826634af1949e5b535cc829a483b8a76223e5d490a257f05bdff16f2fb22c583ab';
//Default Diffie-Hellman prime number (should be 2 or 5)
const DH_G = '02';
 
/**
* Performs the first step of a Diffie-Hellman key exchange by generating
* private and public DH values based on given prime number $p and
* generator $g. Both sides of key exchange MUST have the same prime number
* and generator. In this case they will able to create a random shared
* secret that is never send from one to the other.
*
* @param string $p prime number in binary representation
* @param string $g generator in binary representation
* @param string $priv_key private key in binary representation
* @return mixed
*/
public static function createDhKey($p, $g, $priv_key = null)
{
if (function_exists('openssl_dh_compute_key')) {
$dh_details = array(
'p' => $p,
'g' => $g
);
if ($priv_key !== null) {
$dh_details['priv_key'] = $priv_key;
}
return openssl_pkey_new(array('dh'=>$dh_details));
} else {
$bn_p = self::binToBigNum($p);
$bn_g = self::binToBigNum($g);
if ($priv_key === null) {
$priv_key = self::randomBytes(self::strlen($p));
}
$bn_priv_key = self::binToBigNum($priv_key);
if (extension_loaded('gmp')) {
$bn_pub_key = gmp_powm($bn_g, $bn_priv_key, $bn_p);
} else if (extension_loaded('bcmath')) {
$bn_pub_key = bcpowmod($bn_g, $bn_priv_key, $bn_p);
}
$pub_key = self::bigNumToBin($bn_pub_key);
 
return array(
'p' => $bn_p,
'g' => $bn_g,
'priv_key' => $bn_priv_key,
'pub_key' => $bn_pub_key,
'details' => array(
'p' => $p,
'g' => $g,
'priv_key' => $priv_key,
'pub_key' => $pub_key));
}
}
/**
* Returns an associative array with Diffie-Hellman key components in
* binary representation. The array includes original prime number 'p' and
* generator 'g', random private key 'priv_key' and corresponding public
* key 'pub_key'.
*
* @param mixed $dh Diffie-Hellman key
* @return array
*/
public static function getDhKeyDetails($dh)
{
if (function_exists('openssl_dh_compute_key')) {
$details = openssl_pkey_get_details($dh);
if (isset($details['dh'])) {
return $details['dh'];
}
} else {
return $dh['details'];
}
}
// Depuis OpenId.php, les fonctions de Diffie-Hellman
// TODO : voir si ça peut être externaliser pour être réutilisé ? => dans utilitaires
/**
* Computes the shared secret from the private DH value $dh and the other
* party's public value in $pub_key
*
* @param string $pub_key other party's public value
* @param mixed $dh Diffie-Hellman key
* @return string
* @throws Zend_OpenId_Exception
*/
public function computeDhSecret($pub_key, $dh)
{
if (function_exists('openssl_dh_compute_key')) {
$ret = openssl_dh_compute_key($pub_key, $dh);
if (ord($ret[0]) > 127) {
$ret = "\0" . $ret;
}
return $ret;
} else if (extension_loaded('gmp')) {
$bn_pub_key = self::binToBigNum($pub_key);
$bn_secret = gmp_powm($bn_pub_key, $dh['priv_key'], $dh['p']);
return self::bigNumToBin($bn_secret);
} else if (extension_loaded('bcmath')) {
$bn_pub_key = self::binToBigNum($pub_key);
$bn_secret = bcpowmod($bn_pub_key, $dh['priv_key'], $dh['p']);
return self::bigNumToBin($bn_secret);
}
/*require_once "Zend/OpenId/Exception.php";
throw new Zend_OpenId_Exception(
'The system doesn\'t have proper big integer extension',
Zend_OpenId_Exception::UNSUPPORTED_LONG_MATH);*/
trigger_error('Le système ne gère pas les nombre de taille arbitraire', E_STRICT);
}
/**
* Takes an arbitrary precision integer and returns its shortest big-endian
* two's complement representation.
*
* Arbitrary precision integers MUST be encoded as big-endian signed two's
* complement binary strings. Henceforth, "btwoc" is a function that takes
* an arbitrary precision integer and returns its shortest big-endian two's
* complement representation. All integers that are used with
* Diffie-Hellman Key Exchange are positive. This means that the left-most
* bit of the two's complement representation MUST be zero. If it is not,
* implementations MUST add a zero byte at the front of the string.
*
* @param string $str binary representation of arbitrary precision integer
* @return string big-endian signed representation
*/
public function btwoc($str)
{
if (ord($str[0]) > 127) {
return "\0" . $str;
}
return $str;
}
/**
* Produces string of random byte of given length.
*
* @param integer $len length of requested string
* @return string RAW random binary string
*/
public function randomBytes($len)
{
$key = '';
for($i=0; $i < $len; $i++) {
$key .= chr(mt_rand(0, 255));
}
return $key;
}
/**
* Returns lenght of binary string in bytes
*
* @param string $str
* @return int the string lenght
*/
static public function strlen($str)
{
if (extension_loaded('mbstring') &&
(((int)ini_get('mbstring.func_overload')) & 2)) {
return mb_strlen($str, 'latin1');
} else {
return strlen($str);
}
}
/**
* Converts binary representation into ext/gmp or ext/bcmath big integer
* representation.
*
* @param string $bin binary representation of big number
* @return mixed
* @throws Zend_OpenId_Exception
*/
protected function binToBigNum($bin)
{
if (extension_loaded('gmp')) {
return gmp_init(bin2hex($bin), 16);
} else if (extension_loaded('bcmath')) {
$bn = 0;
$len = self::strlen($bin);
for ($i = 0; $i < $len; $i++) {
$bn = bcmul($bn, 256);
$bn = bcadd($bn, ord($bin[$i]));
}
return $bn;
}
/*require_once "Zend/OpenId/Exception.php";
throw new Zend_OpenId_Exception(
'The system doesn\'t have proper big integer extension',
Zend_OpenId_Exception::UNSUPPORTED_LONG_MATH);*/
trigger_error('Le système ne gère pas les nombre de taille arbitraire', E_STRICT);
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/utilitaires/Encodage.php
New file
0,0 → 1,57
<?php
// declare(encoding='UTF-8');
/**
* Classe fournissant des méthodes statiques concernant l'encodage et le décodage des caractères de variable.
*
* @category PHP 5.2
* @package Utilitaire
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2009, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL-v3
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL-v2
* @version $Id$
* @link /doc/framework/
*/
class Encodage {
/**
* Méthode permettant d'encoder par défaut de ISO-8859-15 vers UTF-8 une variable ou un tableau de variables.
*
* @param mixed la chaine ou le tableau à encoder en UTF-8 depuis ISO-8859-15.
* @param string l'encodage d'origine si ce n'est pas ISO-8859-15.
* @return mixed la chaine ou le tableau encodé en UTF-8.
* @access protected
*/
public static function encoderEnUtf8(&$variable, $encodage = 'ISO-8859-15') {
//echo print_r($variable, true)."\n";
if (is_array($variable)) {
foreach ($variable as $c => $v) {
$variable[$c] = self::encoderEnUtf8($v);
}
} else {
// Nous vérifions si nous avons un bon encodage UTF-8
if (!is_numeric($variable) && !empty($variable) && !self::detecterUtf8($variable)) {
// Les nombres, les valeurs vides et ce qui est déjà en UTF-8 ne sont pas encodés.
$variable = mb_convert_encoding($variable, 'UTF-8', $encodage);
}
}
return $variable;
}
/**
* Méthode permettant de détecter réellement l'encodage UTF-8.
* mb_detect_encoding plante si la chaine de caractère se termine par un caractère accentué.
* Provient de PHPDIG.
*
* @param string la chaine à vérifier.
* @return bool true si c'est de UTF-8, sinon false.
* @access private
*/
public static function detecterUtf8($chaine) {
if ($chaine === mb_convert_encoding(mb_convert_encoding($chaine, 'UTF-32', 'UTF-8'), 'UTF-8', 'UTF-32')) {
return true;
} else {
return false;
}
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/utilitaires/Chaine.php
New file
0,0 → 1,68
<?php
// declare(encoding='UTF-8');
/**
* Classe fournissant des méthodes statiques de manipulation des chaînes de caractères (String).
*
* @category PHP 5.2
* @package Utilitaire
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL-v3
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL-v2
* @version $Id$
* @link /doc/framework/
*/
class Chaine {
 
private static $caracteres_accentues = array(
'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î',
'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'ß',
'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î',
'ï', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ', 'Ā',
'ā', 'Ă', 'ă', 'Ą', 'ą', 'Ć', 'ć', 'Ĉ', 'ĉ', 'Ċ', 'ċ', 'Č', 'č', 'Ď', 'ď',
'Đ', 'đ', 'Ē', 'ē', 'Ĕ', 'ĕ', 'Ė', 'ė', 'Ę', 'ę', 'Ě', 'ě', 'Ĝ', 'ĝ', 'Ğ',
'ğ', 'Ġ', 'ġ', 'Ģ', 'ģ', 'Ĥ', 'ĥ', 'Ħ', 'ħ', 'Ĩ', 'ĩ', 'Ī', 'ī', 'Ĭ', 'ĭ',
'Į', 'į', 'İ', 'ı', 'IJ', 'ij', 'Ĵ', 'ĵ', 'Ķ', 'ķ', 'Ĺ', 'ĺ', 'Ļ', 'ļ', 'Ľ',
'ľ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'Ń', 'ń', 'Ņ', 'ņ', 'Ň', 'ň', 'ʼn', 'Ō', 'ō', 'Ŏ',
'ŏ', 'Ő', 'ő', 'Œ', 'œ', 'Ŕ', 'ŕ', 'Ŗ', 'ŗ', 'Ř', 'ř', 'Ś', 'ś', 'Ŝ', 'ŝ',
'Ş', 'ş', 'Š', 'š', 'Ţ', 'ţ', 'Ť', 'ť', 'Ŧ', 'ŧ', 'Ũ', 'ũ', 'Ū', 'ū', 'Ŭ',
'ŭ', 'Ů', 'ů', 'Ű', 'ű', 'Ų', 'ų', 'Ŵ', 'ŵ', 'Ŷ', 'ŷ', 'Ÿ', 'Ź', 'ź', 'Ż',
'ż', 'Ž', 'ž', 'ſ', 'ƒ', 'Ơ', 'ơ', 'Ư', 'ư', 'Ǎ', 'ǎ', 'Ǐ', 'ǐ', 'Ǒ', 'ǒ',
'Ǔ', 'ǔ', 'Ǖ', 'ǖ', 'Ǘ', 'ǘ', 'Ǚ', 'ǚ', 'Ǜ', 'ǜ', 'Ǻ', 'ǻ', 'Ǽ', 'ǽ', 'Ǿ', 'ǿ');
 
private static $caracteres_normaux = array(
'A', 'A', 'A', 'A', 'A', 'A', 'AE', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I',
'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 's',
'a', 'a', 'a', 'a', 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i',
'i', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'y', 'y', 'A', 'a',
'A', 'a', 'A', 'a', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', 'D', 'd', 'D', 'd',
'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'G', 'g', 'G', 'g', 'G', 'g',
'G', 'g', 'H', 'h', 'H', 'h', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i',
'IJ', 'ij', 'J', 'j', 'K', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'l', 'l',
'N', 'n', 'N', 'n', 'N', 'n', 'n', 'O', 'o', 'O', 'o', 'O', 'o', 'OE', 'oe', 'R',
'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', 'T', 't', 'T', 't',
'T', 't', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'W', 'w', 'Y',
'y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 's', 'f', 'O', 'o', 'U', 'u', 'A', 'a', 'I',
'i', 'O', 'o', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'A', 'a', 'AE', 'ae', 'O', 'o');
/**
* Supprime ou remplace les accents d'une chaine en PHP.
* La solution retenu, provenant du site
* {@link http://www.lecoindunet.com/zone_php/scripts_utiles/remplacer-les-caracteres-accentues-dune-chaine-en-php-72 lecoindunet.com},
* consiste en deux tableaux (caractères avec et sans accents) car cela permetra éventuellement
* de fournir des méthodes pour récupérer ces tableaux pour d'autres traitements.
* Une autre solution aurait été d'utiliser les entités HTML comme proposé par le site
* {@link http://www.weirdog.com/blog/php/supprimer-les-accents-des-caracteres-accentues.html weirdog.com}.
*
* @param String $chaine la chaine de caractères dans laquelle supprimer les accents.
* @param String $encodage le code d'encodage de la chaine si ce n'est pas de l'UTF-8.
* @return la chaine de caractères sans accent.
*/
function supprimerAccents($chaine, $encodage = 'UTF-8') {
if ($encodage != 'UTF-8') {
mb_convert_variables($encodage, 'UTF-8', self::$caracteres_accentues, self::$caracteres_normaux);
}
return str_replace(self::$caracteres_accentues, self::$caracteres_normaux, $chaine);
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/utilitaires/Fichier.php
New file
0,0 → 1,202
<?php
// declare(encoding='UTF-8');
/**
* Classe fournissant des méthodes statiques de manipulation des fichiers.
*
* @category PHP 5.2
* @package Utilitaire
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2009, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL-v3
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL-v2
* @version $Id$
* @link /doc/framework/
*/
class Fichier {
/**
* Créer et stocke du contenu dans un fichier.
*
* @param string le chemin et le nom du fichier.
* @param string le contenu à stocker dans le fichier.
* @return string true en cas de succès sinon false.
*/
public static function creerFichier($fichier, $contenu) {
$erreur = null;
// Début de l'écriture du fichier
if ($resource = fopen($fichier, 'w')) {
if (!fwrite($resource, $contenu)) {
if (!fclose($resource)) {
$erreur = "Le fichier '$fichier' n'a pas pu être fermé.";
}
} else {
$erreur = "Le contenu texte n'a pas pu être écrit dans le fichier '$fichier'.";
}
} else {
$erreur = "Le fichier '$fichier' n'a pas pu être ouvert.";
}
 
// Gestion des erreurs et du retour
if (is_null($erreur)) {
return true;
} else {
trigger_error($erreur, E_USER_WARNING);
return false;
}
}
/**
* Créer et stocke du contenu dans un fichier compressé en Gzip.
*
* @param string le chemin et le nom du fichier.
* @param string le contenu à stocker dans le fichier.
* @return string true en cas de succès sinon false.
*/
public static function creerFichierGzip($fichier, $contenu) {
$erreur = null;
// Ajout de l'extension gz
if (substr($fichier, -3) != '.gz') {
$fichier = $fichier.'.gz';
}
// Début de l'écriture du fichier compressé
if ($resource = gzopen($fichier, 'w9')) {
if (gzwrite($resource, $contenu)) {
if (!gzclose($resource)) {
$erreur = "Le fichier compressé '$fichier' n'a pas pu être fermé.";
}
} else {
$erreur = "Le contenu texte n'a pas pu être écrit dans le fichier compressé '$fichier'.";
}
} else {
$erreur = "Le fichier compressé '$fichier' n'a pas pu être ouvert.";
}
// Gestion des erreurs et du retour
if (is_null($erreur)) {
return true;
} else {
trigger_error($erreur, E_USER_WARNING);
return false;
}
}
/**
* Supprime récursivement un dossier et tout son contenu.
*
* @param string $dossier le chemin vers le dossier à supprimer.
* @return void
*/
public static function supprimerDossier($dossier) {
if (is_dir($dossier)) {
$objets = scandir($dossier);
foreach ($objets as $objet) {
if ($objet != '.' && $objet != '..') {
$chemin = $dossier.'/'.$objet;
if (filetype($chemin) == 'dir') {
$this->supprimerDossier($chemin);
} else {
unlink($chemin);
}
}
}
reset($objets);
rmdir($dossier);
}
}
/**
* Convertion d'un nombre d'octet en kB, MB, GB.
* @link http://forum.webmaster-rank.info/developpement-site/code-taille-memoire-d-une-variable-en-php-t1344.html
* @param integer $taille la taille en octet à convertir
*
* @return string la chaine représentant la taille en octets.
*/
public static function convertirTaille($taille) {
$unite = array('B', 'kB', 'MB', 'GB');
return @round($taille / pow(1024, ($i = floor(log($taille,1024)))), 2).' '.$unite[$i];
}
/**
* Détermine le dossier système temporaire et détecte si nous y avons accès en lecture et écriture.
*
* Inspiré de Zend_File_Transfer_Adapter_Abstract & Zend_Cache
*
* @return string|false le chemine vers le dossier temporaire ou false en cas d'échec.
*/
public static function getDossierTmp() {
$dossier_tmp = false;
foreach (array($_ENV, $_SERVER) as $environnement) {
foreach (array('TMPDIR', 'TEMP', 'TMP', 'windir', 'SystemRoot') as $cle) {
if (isset($environnement[$cle])) {
if (($cle == 'windir') or ($cle == 'SystemRoot')) {
$dossier = realpath($environnement[$cle] . '\\temp');
} else {
$dossier = realpath($environnement[$cle]);
}
if (self::etreAccessibleEnLectureEtEcriture($dossier)) {
$dossier_tmp = $dossier;
break 2;
}
}
}
}
if ( ! $dossier_tmp) {
$dossier_televersement_tmp = ini_get('upload_tmp_dir');
if ($dossier_televersement_tmp) {
$dossier = realpath($dossier_televersement_tmp);
if (self::etreAccessibleEnLectureEtEcriture($dossier)) {
$dossier_tmp = $dossier;
}
}
}
if ( ! $dossier_tmp) {
if (function_exists('sys_get_temp_dir')) {
$dossier = sys_get_temp_dir();
if (self::etreAccessibleEnLectureEtEcriture($dossier)) {
$dossier_tmp = $dossier;
}
}
}
if ( ! $dossier_tmp) {
// Tentative de création d'un fichier temporaire
$fichier_tmp = tempnam(md5(uniqid(rand(), TRUE)), '');
if ($fichier_tmp) {
$dossier = realpath(dirname($fichier_tmp));
unlink($fichier_tmp);
if (self::etreAccessibleEnLectureEtEcriture($dossier)) {
$dossier_tmp = $dossier;
}
}
}
if ( ! $dossier_tmp && self::etreAccessibleEnLectureEtEcriture('/tmp')) {
$dossier_tmp = '/tmp';
}
if ( ! $dossier_tmp && self::etreAccessibleEnLectureEtEcriture('\\temp')) {
$dossier_tmp = '\\temp';
}
return $dossier_tmp;
}
/**
* Vérifie si le fichier ou dossier est accessible en lecture et écriture.
*
* @param $ressource chemin vers le dossier ou fichier à tester
* @return boolean true si la ressource est accessible en lecture et écriture.
*/
protected static function etreAccessibleEnLectureEtEcriture($ressource){
$accessible = false;
if (is_readable($ressource) && is_writable($ressource)) {
$accessible = true;
}
return $accessible;
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/utilitaires/Pattern.php
New file
0,0 → 1,24
<?php
// declare(encoding='UTF-8');
/**
* Classe fournissant des constantes correspondant à des expressions régulières de vérification très courrantes.
*
* @category PHP 5.2
* @package Utilitaire
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2009, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL-v3
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL-v2
* @version $Id$
* @link /doc/framework/
*/
class Pattern {
const PRENOM = "[\p{L}-]+";// Pattern prénom
const NOM = "[\p{Lu}]+";// Pattern nom
const COURRIEL = "[a-z0-9!#$%&'*+=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?";// Pattern courriel
const URL = "^(?:(?:ht|f)tp(?:s?)\\:\\/\\/|~/|/)?(?:\\w+:\\w+@)?(?:(?:[-\\w]+\\.)+(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|travel|[a-z]{2}))(?::[\\d]{1,5})?(?:(?:(?:/(?:[-\\w~!$+|.,=]|%[a-f\\d]{2})+)+|/)+|\\?|#)?(?:(?:\\?(?:[-\\w~!$+|.,*:]|%[a-f\\d{2}])+=(?:[-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)(?:&(?:[-\\w~!$+|.,*:]|%[a-f\\d{2}])+=(?:[-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)*)*(?:#(?:[-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)?$";
const HEURE_MINUTE = "^(?:[0-1][0-9]|2[0-4]):(?:[0-5][0-9]|60)$";// Heure au format 24h avec séparateur d'heure et minute ':'
const LATITUDE = "^-?([0-8]?[0-9]([.,][0-9]*)?|90)$"; // Nombre décimal positif ou négatif allant de 0 à 89 ou nombre entier valant 90 avec pour séparateur des décimales "." ou ","
const LONGITUDE = "^-?((1[0-7][0-9]|[1-9]?[0-9])([.,][0-9]*)?|180)$"; // Nombre décimal positif ou négatif allant de 0 à 179 ou nombre entier valant 180 avec pour séparateur des décimales "." ou ","
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/utilitaires/Tableau.php
New file
0,0 → 1,43
<?php
// declare(encoding='UTF-8');
/**
* Classe fournissant des méthodes statiques de manipulation des tableaux (Array).
*
* @category PHP 5.2
* @package Utilitaire
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2009, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL-v3
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL-v2
* @version $Id$
* @link /doc/framework/
*/
class Tableau {
/**
* Etend le tableau à étendre avec les données du tableau à copier. Si des clés sont identiques entre les deux tableaux
* une erreur est déclenchée et la valeur du tableau à étendre est gardée. Si les deux tableaux ont des clés numériques
* leurs valeurs sont gardées (à la différence de array_merge).
* Les tableaux sont passés par références et le tableau à copier est progressivement détruit pour éviter la consomation
* de mémoire.
*
* @param array $tableau_a_etendre
* @param array $tableau_a_copier
* @return void
*/
public static function etendre(Array &$tableau_a_etendre, Array &$tableau_a_copier) {
$cles_existantes = null;
foreach($tableau_a_copier as $cle => $val) {
if (!isset($tableau_a_etendre[$cle])) {
$tableau_a_etendre[$cle] = $val;
unset($tableau_a_copier[$cle]);
} else {
$cles_existantes = $cle;
}
}
if (is_array($cles_existantes)) {
$e = "Le tableau a étendre contenait déjà les clés suivantes : ".implode(', ', $cles_existantes);
trigger_error($e, E_USER_WARNING);
}
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/RestClient.php
New file
0,0 → 1,152
<?php
// declare(encoding='UTF-8');
/**
* Classe client permettant d'interroger des services web REST.
*
* @category php 5.2
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
* @version $Id$
*/
class RestClient {
const HTTP_URL_REQUETE_SEPARATEUR = '&';
private $http_methodes = array('GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS', 'CONNECT', 'TRACE');
protected $parametres = null;
private $url = null;
private $reponse_entetes = null;
//+----------------------------------------------------------------------------------------------------------------+
// ACCESSEURS
public function getReponseEntetes($cle) {
return $this->reponse_entetes;
}
public function getParametre($cle) {
$valeur = (isset($this->parametres[$cle])) ? $this->parametres[$cle] : null;
return $valeur;
}
public function ajouterParametre($cle, $valeur) {
$this->parametres[$cle] = $valeur;
}
public function supprimerParametre($cle) {
unset($this->parametres[$cle]);
}
public function nettoyerParametres() {
$this->parametres = null;
}
//+----------------------------------------------------------------------------------------------------------------+
// MÉTHODES
public function consulter($url) {
$retour = $this->envoyerRequete($url, 'GET');
return $retour;
}
public function ajouter($url, Array $donnees) {
$retour = $this->envoyerRequete($url, 'PUT', $donnees);
return $retour;
}
public function modifier($url, Array $donnees) {
$retour = $this->envoyerRequete($url, 'POST', $donnees);
return $retour;
}
public function supprimer($url) {
$retour = $this->envoyerRequete($url, 'DELETE');
return $retour;
}
public function envoyerRequete($url, $mode, Array $donnees = array()) {
$this->url = $url;
$contenu = false;
if (! in_array($mode, $this->http_methodes)) {
$e = "Le mode de requête '$mode' n'est pas accepté!";
trigger_error($e, E_USER_WARNING);
} else {
if ($mode == 'GET') {
$this->traiterUrlParametres();
}
$contexte = stream_context_create(array(
'http' => array(
'method' => $mode,
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'content' => http_build_query($donnees, null, self::HTTP_URL_REQUETE_SEPARATEUR))));
$flux = @fopen($url, 'r', false, $contexte);
if (!$flux) {
$this->reponse_entetes = $http_response_header;
$e = "L'ouverture de l'url '$url' par la méthode HTTP '$mode' a échoué!";
trigger_error($e, E_USER_WARNING);
} else {
// Informations sur les en-têtes et métadonnées du flux
$this->reponse_entetes = stream_get_meta_data($flux);
// Contenu actuel de $url
$contenu = stream_get_contents($flux);
fclose($flux);
}
$this->traiterEntete();
}
$this->reinitialiser();
return $contenu;
}
private function traiterUrlParametres() {
$parametres = array();
if (count($this->parametres) > 0) {
foreach ($this->parametres as $cle => $valeur) {
$parametres[] = $cle.self::HTTP_URL_REQUETE_CLE_VALEUR_SEPARATEUR.$valeur;
}
$url_parametres = implode(self::HTTP_URL_REQUETE_SEPARATEUR, $parametres);
$this->url = $this->url.'?'.$url_parametres;
}
}
private function traiterEntete() {
$infos = $this->analyserEntete();
$this->traiterEnteteDebogage($infos);
}
private function analyserEntete() {
$entetes = $this->reponse_entetes;
$infos = array('date' => null, 'uri' => $this->url, 'debogages' => null);
if (isset($entetes['wrapper_data'])) {
$entetes = $entetes['wrapper_data'];
}
foreach ($entetes as $entete) {
if (preg_match('/^X_REST_DEBOGAGE_MESSAGES: (.+)$/', $entete, $match)) {
$infos['debogages'] = json_decode($match[1]);
}
if (preg_match('/^Date: .+ ([012][0-9]:[012345][0-9]:[012345][0-9]) .*$/', $entete, $match)) {
$infos['date'] = $match[1];
}
}
return $infos;
}
private function traiterEnteteDebogage($entetes_analyses) {
if (isset($entetes['debogages'])) {
$date = $entetes['date'];
$uri = $entetes['uri'];
$debogages = $entetes['debogages'];
foreach ($debogages as $debogage) {
$e = "DEBOGAGE : $date - $uri :\n$debogage";
trigger_error($e, E_USER_NOTICE);
}
}
}
private function reinitialiser() {
$this->nettoyerParametres();
}
}
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/CacheSimple.php
New file
0,0 → 1,99
<?php
// declare(encoding='UTF-8');
/**
* Classe Cache permettant de mettre en cache des données de façon extremement simple.
* Le cache est stocker dans des fichiers textes.
* Le contrôle de la durée de vie du cache se fait avec la fonction PHP filemtime.
* Si la durée de vie du cache est modifiée dans le constructeur ou le fichier de config, alors la durée de vie de l'ensemble
* des fichiers de cache est modifiée en conséquence.
* Les clés pour le tableau des options et les valeurs par défaut sont indiquées dans l'attribut options de la classe.
*
* @category php 5.2
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @author Aurélien PERONNET <aurelien@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license http://framework.zend.com/license/new-bsd Licence New BSD
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
* @version $Id$
* @link /doc/framework/
*/
class CacheSimple {
private $mise_en_cache = null;
private $stockage_chemin = null;
private $duree_de_vie = null;
private $options = array(
'mise_en_cache' => 'true',
'stockage_chemin' => 'Fichier::getDossierTmp()',
'duree_de_vie' => '3600*24'
);
public function __construct($options = array()) {
extract($options);
$this->mise_en_cache = is_bool($mise_en_cache) ? $mise_en_cache : true;
if ($this->mise_en_cache) {
$this->stockage_chemin = isset($stockage_chemin) ? realpath($stockage_chemin) : Fichier::getDossierTmp();
$this->duree_de_vie = isset($duree_de_vie) ? $duree_de_vie : 3600*24;
}
}
private function initialiserOptionsParConfig() {
while (list($nom, $valeur) = each($this->options)) {
if (Config::existe($nom)) {
$this->$nom = Config::get($nom);
}
}
}
/**
* Teste si le cache est disponible pour l'id donné et (si oui) le retourne (sinon renvoie false)
*
* @param string $id l'identifiant du Cache.
* @return string|false les données en cache.
*/
public function charger($id) {
$contenu = false;
if ($this->mise_en_cache) {
$chemin_fichier_cache = $this->stockage_chemin.DS.$id.'.txt';
if (file_exists($chemin_fichier_cache ) && (time() - @filemtime($chemin_fichier_cache) < $this->duree_de_vie)) {
$contenu = file_get_contents($chemin_fichier_cache);
}
}
return $contenu;
}
/**
* Sauvegarde la chaine de données dans un fichier texte.
*
* Note : $contenu est toujours de type "string". C'est à vous de gérer la sérialisation.
*
* @param string $contenu les données à mettre en cache.
* @param string $id l'identifiant du Cache.
* @return boolean true si aucun problème
*/
public function sauver($contenu, $id) {
$ok = false;
if ($this->mise_en_cache) {
$chemin_fichier_cache = $this->stockage_chemin.DS.$id.'.txt';
if (!file_exists($chemin_fichier_cache) || (time() - @filemtime($chemin_fichier_cache) > $this->duree_de_vie)) {
$fh = fopen($chemin_fichier_cache,'w+');
if ($fh) {
if (fwrite($fh, $contenu)) {
if (fclose($fh)) {
$ok = true;
}
}
// Voir #ZF-4422 pour la raison de l'utilisation de octdec()
@chmod($chemin_fichier_cache, octdec('0777'));
}
}
}
return $ok;
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/OpenIdClient.php
New file
0,0 → 1,1193
<?php
/**
* La classe OpenIdClient est une implémentation d'un client OpenId, depuis une classe Zend.
* Elle permet d'établir une connexion avec un serveur, en fonction d'un identifiant OpenId.
* Elle permet de communiquer de manière sécurisée avec ce serveur, et doit aboutir a une
* identification centralisée.
* */
 
class OpenIdClient {
//OpenID 2.0 namespace. Tous les messages OpenID 2.0 DOIVENT contenir la variable openid.ns et sa valeur
const NS_2_0 = 'http://specs.openid.net/auth/2.0';
// TODO : remplacer _storage par une gestion par cache ?
/**
* Variable permettant le stockage d'informations, notammenent à propos des clés DiffieHellmann
* @var Storage $_storage
*/
protected $_storage = null;
/**
* Tableau "cache" interne permettant d'éviter des accès inutiles au fichier storage
* @var array $_cache
*/
protected $_cache = array();
 
// Client pour les requetes.
private $client;
/**
* Constructeur de l'application
* */
function __construct() {
$this->client = new Client();
$this->_storage = new StorageFile();
}
/**
* Fonction login
*
* Return true ou false
* > Ne retourne rien si true car redirige vers l'adresse du serveur OID
* */
//FIXME : le paramètre immediate ?
// A vérifier mais ça doit permettre de passer directement le mot de passe. Il reste plus qu'à trouver le nom de la variable mot de passe.
function login($id, $immediate = false) {
// L'original retourne la fonction checkId, avec le parametre immediate = true
// Je ne comprends pas l'utilité, je fusionne les deux pour l'instant
// FIXME : si pas de comportement étrange, valider.
//Tests et arrêt si non validé :
//Normaliser (traite si XRI ou URL, normalize URL)
//FIXME : voir avec JP pour équivalent dans framework
if (!$this->normalize($id)) {
return false;
}
//Discovery
// Récupérer les informations sur le serveur OPEN ID
/*
FIXME : ca change la valeur de l'id !!!
if (!$this->_discovery($id, $server, $version)) {
trigger_error('Discovery failed');
return false;
}*/
$retour_url = $this->client->consulter($id);
//Le retour contient les balises suivantes :
/*
*
* <link rel="openid.server" href="http://www.myopenid.com/server" />
* <link rel="openid2.provider" href="http://www.myopenid.com/server" />
*/
$metaServeur = $this->verifierVersion($retour_url);
//TODO : Voir avec JP : la classe client ne permet pas de vérifer le statut ??
if ($retour_url === false) {
trigger_error('L\'adresse $id est inacessible', E_USER_ERROR);
return false;
}
if ($metaServeur === false) {
return false;
}
if (!$this->_associate($metaServeur['serveur'], $metaServeur['version'])) {
trigger_error('Impossible de s\'associer avec le serveur');
}
/*TODO : fonctionnement différent
if (!$this->_getAssociation(
$server,
$handle,
$macFunc,
$secret,
$expires)) {
/* Use dumb mode *
unset($handle);
unset($macFunc);
unset($secret);
unset($expires);*
}*/
 
//on a la version, l'adresse du serveur et le realId si c'est une 2.0 dans metaServeur
if (isset($metaServeur['realId'])) {
$id = $metaServeur['realId'];
}
//Associate
//getAssociation
//Organisation des paramètres :
$params = array();
if ($metaServeur['version'] >= 2.0) {
$params['openid.ns'] = self::NS_2_0;
}
 
$params['openid.mode'] = $immediate ?
'checkid_immediate' : 'checkid_setup';
 
$params['openid.identity'] = $id;
 
//FIXME : Ex : $params['openid.claimed_id'] = $claimedId; > jvois pas l'intéret
$params['openid.claimed_id'] = $id;
/*
* TODO : gérer les sessions et namespace
* if ($metaServeur['version'] <= 2.0) {
if ($this->_session !== null) {
$this->_session->identity = $id;
$this->_session->claimed_id = $claimedId;
} else if (defined('SID')) {
$_SESSION["zend_openid"] = array(
"identity" => $id,
"claimed_id" => $claimedId);
} else {
require_once "Zend/Session/Namespace.php";
$this->_session = new Zend_Session_Namespace("zend_openid");
$this->_session->identity = $id;
$this->_session->claimed_id = $claimedId;
}
}*/
 
if (isset($handle)) {
$params['openid.assoc_handle'] = $handle;
}
 
//FIXME : $params['openid.return_to'] = $this->absoluteUrl($returnTo);
$params['openid.return_to'] = $this->absoluteUrl(null);
 
if (empty($root)) {
$root = $this->selfUrl();
if ($root[strlen($root)-1] != '/') {
$root = dirname($root);
}
}
if ($metaServeur['version'] >= 2.0) {
$params['openid.realm'] = $root;
} else {
$params['openid.trust_root'] = $root;
}
 
/*FIXME ::
if (!Zend_OpenId_Extension::forAll($extensions, 'prepareRequest', $params)) {
$this->_setError("Extension::prepareRequest failure");
return false;
}*/
 
$this->redirect($metaServeur['serveur'], $params);
return true;
//Renvoyer vers l'url
}
/**
* Verifies authentication response from OpenID server.
*
* This is the second step of OpenID authentication process.
* The function returns true on successful authentication and false on
* failure.
*
* @param array $params HTTP query data from OpenID server
* @param string &$identity this argument is set to end-user's claimed
* identifier or OpenID provider local identifier.
* @param mixed $extensions extension object or array of extensions objects
* @return bool
*/
public function verify($params, &$identity = "", $extensions = null)
{
if (isset($params['openid_ns']) &&
$params['openid_ns'] == $this->NS_2_0) {
$version = 2.0;
}
 
if (isset($params["openid_claimed_id"])) {
$identity = $params["openid_claimed_id"];
} else if (isset($params["openid_identity"])){
$identity = $params["openid_identity"];
} else {
$identity = "";
}
 
if ($version < 2.0 && !isset($params["openid_claimed_id"])) {
if ($this->_session !== null) {
if ($this->_session->identity === $identity) {
$identity = $this->_session->claimed_id;
}
} else if (defined('SID')) {
if (isset($_SESSION["zend_openid"]["identity"]) &&
isset($_SESSION["zend_openid"]["claimed_id"]) &&
$_SESSION["zend_openid"]["identity"] === $identity) {
$identity = $_SESSION["zend_openid"]["claimed_id"];
}
} else {
require_once "Zend/Session/Namespace.php";
$this->_session = new Zend_Session_Namespace("zend_openid");
if ($this->_session->identity === $identity) {
$identity = $this->_session->claimed_id;
}
}
}
 
if (empty($params['openid_mode'])) {
$this->_setError("Missing openid.mode");
return false;
}
if (empty($params['openid_return_to'])) {
$this->_setError("Missing openid.return_to");
return false;
}
if (empty($params['openid_signed'])) {
$this->_setError("Missing openid.signed");
return false;
}
if (empty($params['openid_sig'])) {
$this->_setError("Missing openid.sig");
return false;
}
if ($params['openid_mode'] != 'id_res') {
$this->_setError("Wrong openid.mode '".$params['openid_mode']."' != 'id_res'");
return false;
}
if (empty($params['openid_assoc_handle'])) {
$this->_setError("Missing openid.assoc_handle");
return false;
}
if ($params['openid_return_to'] != $this->selfUrl()) {
/* Ignore query part in openid.return_to */
$pos = strpos($params['openid_return_to'], '?');
if ($pos === false ||
SUBSTR($params['openid_return_to'], 0 , $pos) != $this->selfUrl()) {
 
/*$this->_setError("Wrong openid.return_to '".
$params['openid_return_to']."' != '" . $this->selfUrl() ."'");*/
trigger_error('Wrong openid.return_to', E_USER_ERROR);
return false;
}
}
 
if ($version >= 2.0) {
if (empty($params['openid_response_nonce'])) {
trigger_error('Missing openid.response_nonce', E_USER_ERROR);
return false;
}
if (empty($params['openid_op_endpoint'])) {
trigger_error('Missing openid.op_endpoint', E_USER_ERROR);
return false;
/* OpenID 2.0 (11.3) Checking the Nonce */
} else if (!$this->_storage->isUniqueNonce($params['openid_op_endpoint'], $params['openid_response_nonce'])) {
trigger_error('Duplicate openid.response_nonce', E_USER_ERROR);
return false;
}
}
 
if (!empty($params['openid_invalidate_handle'])) {
if ($this->_storage->getAssociationByHandle(
$params['openid_invalidate_handle'],
$url,
$macFunc,
$secret,
$expires)) {
$this->_storage->delAssociation($url);
}
}
 
if ($this->_storage->getAssociationByHandle(
$params['openid_assoc_handle'],
$url,
$macFunc,
$secret,
$expires)) {
$signed = explode(',', $params['openid_signed']);
$data = '';
foreach ($signed as $key) {
$data .= $key . ':' . $params['openid_' . strtr($key,'.','_')] . "\n";
}
if (base64_decode($params['openid_sig']) ==
Zend_OpenId::hashHmac($macFunc, $data, $secret)) {
/*
* FIXME dépendance je sais pas pour quoi : a voir :
* if (!Zend_OpenId_Extension::forAll($extensions, 'parseResponse', $params)) {
$this->_setError("Extension::parseResponse failure");
return false;
}*/
/* OpenID 2.0 (11.2) Verifying Discovered Information */
if (isset($params['openid_claimed_id'])) {
$id = $params['openid_claimed_id'];
if (!$this->normalize($id)) {
$this->_setError("Normalization failed");
return false;
} else if (!$this->_discovery($id, $discovered_server, $discovered_version)) {
$this->_setError("Discovery failed: " . $this->getError());
return false;
} else if ((!empty($params['openid_identity']) &&
$params["openid_identity"] != $id) ||
(!empty($params['openid_op_endpoint']) &&
$params['openid_op_endpoint'] != $discovered_server) ||
$discovered_version != $version) {
$this->_setError("Discovery information verification failed");
return false;
}
}
return true;
}
$this->_storage->delAssociation($url);
$this->_setError("Signature check failed");
return false;
}
else
{
/* Use dumb mode */
if (isset($params['openid_claimed_id'])) {
$id = $params['openid_claimed_id'];
} else if (isset($params['openid_identity'])) {
$id = $params['openid_identity'];
} else {
$this->_setError("Missing openid.claimed_id and openid.identity");
return false;
}
 
if (!$this->normalize($id)) {
trigger_error('Normalization failed', E_USER_ERROR);
return false;
} else if (!$this->_discovery($id, $server, $discovered_version)) {
trigger_error('Discovery failed', E_USER_ERROR);
return false;
}
 
/* OpenID 2.0 (11.2) Verifying Discovered Information */
if ((isset($params['openid_identity']) &&
$params["openid_identity"] != $id) ||
(isset($params['openid_op_endpoint']) &&
$params['openid_op_endpoint'] != $server) ||
$discovered_version != $version) {
trigger_error('Discovery information verification failed', E_USER_ERROR);
return false;
}
 
$params2 = array();
foreach ($params as $key => $val) {
if (strpos($key, 'openid_ns_') === 0) {
$key = 'openid.ns.' . substr($key, strlen('openid_ns_'));
} else if (strpos($key, 'openid_sreg_') === 0) {
$key = 'openid.sreg.' . substr($key, strlen('openid_sreg_'));
} else if (strpos($key, 'openid_') === 0) {
$key = 'openid.' . substr($key, strlen('openid_'));
}
$params2[$key] = $val;
}
$params2['openid.mode'] = 'check_authentication';
$ret = $this->client->modifier($serveur, $params2);
//_httpRequest($server, 'POST', $params2, $status);
if ($ret === false) {
trigger_error("'Dumb' signature verification HTTP request failed", E_USER_ERROR);
return false;
}
$r = array();
if (is_string($ret)) {
foreach(explode("\n", $ret) as $line) {
$line = trim($line);
if (!empty($line)) {
$x = explode(':', $line, 2);
if (is_array($x) && count($x) == 2) {
list($key, $value) = $x;
$r[trim($key)] = trim($value);
}
}
}
}
$ret = $r;
if (!empty($ret['invalidate_handle'])) {
if ($this->_storage->getAssociationByHandle(
$ret['invalidate_handle'],
$url,
$macFunc,
$secret,
$expires)) {
$this->_storage->delAssociation($url);
}
}
if (isset($ret['is_valid']) && $ret['is_valid'] == 'true') {
if (!Zend_OpenId_Extension::forAll($extensions, 'parseResponse', $params)) {
$this->_setError("Extension::parseResponse failure");
return false;
}
return true;
}
$this->_setError("'Dumb' signature verification failed");
return false;
}
}
/**
* Performs discovery of identity and finds OpenID URL, OpenID server URL
* and OpenID protocol version. Returns true on succees and false on
* failure.
*
* @param string &$id OpenID identity URL
* @param string &$server OpenID server URL
* @param float &$version OpenID protocol version
* @return bool
* @todo OpenID 2.0 (7.3) XRI and Yadis discovery
*/
protected function _discovery(&$id, &$server, &$version)
{
$realId = $id;
if ($this->_storage->getDiscoveryInfo(
$id,
$realId,
$server,
$version,
$expire)) {
$id = $realId;
return true;
}
/* TODO: OpenID 2.0 (7.3) XRI and Yadis discovery */
 
/* HTML-based discovery */
$clientDiscovery = new Client();
//TODO : rajouter un test sur le statut de la réponse
// Nécessite la prise en compte des entetes dans le framework
/*if ($status != 200 || !is_string($response)) {
return false;
}*/
$reponse = $clientDiscovery->consulter($id);
$metaServeur = $this->verifierVersion($reponse);
if (!isset($metaServeur) || empty($reponse)) {
trigger_error('Aucune donnée OpenId', E_USER_ERROR);
return false;
}
$expire = time() + 60 * 60;
$this->_storage->addDiscoveryInfo($id, $metaServeur['realId'], $metaServeur['serveur'], $metaServeur['version'], $expire);
if (!empty($metaServeur['realId'])) {
$id = $metaServeur['realId'];
}
return true;
}
//Parser l'HTML de réponse pour trouver la version du serveur OPEN ID
function verifierVersion($reponseHtml) {
// TODO : remplacer l'arlgorythme suivant par cette solution :
//1. Chercher l'existence d'une balise openidN.provider
//2. Déterminer la version en fonction de la chaine : openid2.provider => 2.0; openid.provider => 1.1
//3. Récupérer l'url du serveur href="serveur"
//4. SI 2.0, récupérer la valeur réelle de l'ID
//TODO : penser à tester les deux versions du serveur
$metaServeur = Array();
if (preg_match(
'/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.provider[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
$reponseHtml,
$r)) {
$metaServeur['version'] = 2.0;
$metaServeur['serveur'] = $r[3];
} else if (preg_match(
'/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.provider[ \t]*[^"\']*\\3[^>]*\/?>/i',
$reponseHtml,
$r)) {
$metaServeur['version'] = 2.0;
$metaServeur['serveur'] = $r[1];
} else if (preg_match(
'/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.server[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
$reponseHtml,
$r)) {
$metaServeur['version'] = 1.1;
$metaServeur['serveur'] = $r[3];
} else if (preg_match(
'/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.server[ \t]*[^"\']*\\3[^>]*\/?>/i',
$reponseHtml,
$r)) {
$metaServeur['version'] = 1.1;
$metaServeur['serveur'] = $r[2];
} else {
return false;
}
if ($metaServeur['version'] >= 2.0) {
if (preg_match(
'/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.local_id[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
$reponseHtml,
$r)) {
$metaServeur['realId'] = $r[3];
} else if (preg_match(
'/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.local_id[ \t]*[^"\']*\\3[^>]*\/?>/i',
$reponseHtml,
$r)) {
$metaServeur['realId'] = $r[2];
}
} else {
if (preg_match(
'/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.delegate[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
$reponseHtml,
$r)) {
$metaServeur['realId'] = $r[3];
} else if (preg_match(
'/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.delegate[ \t]*[^"\']*\\3[^>]*\/?>/i',
$reponseHtml,
$r)) {
$metaServeur['realId'] = $r[2];
}
}
return $metaServeur;
}
/**
* Create (or reuse existing) association between OpenID consumer and
* OpenID server based on Diffie-Hellman key agreement. Returns true
* on success and false on failure.
*
* @param string $url OpenID server url
* @param float $version OpenID protocol version
* @param string $priv_key for testing only
* @return bool
*/
protected function _associate($url, $version, $priv_key=null)
{
/* Check if we already have association in chace or storage */
/*
* TODO : Utiliser le stockage plutot
* */
if ($this->_getAssociation(
$url,
$handle,
$macFunc,
$secret,
$expires)) {
return true;
}
 
/*
* TODO : utiliser le fichier de config
* if ($this->_dumbMode) {
return true;
}*/
 
$params = array();
 
if ($version >= 2.0) {
$params = array(
'openid.ns' => $this->NS_2_0,
'openid.mode' => 'associate',
'openid.assoc_type' => 'HMAC-SHA256',
'openid.session_type' => 'DH-SHA256',
);
} else {
$params = array(
'openid.mode' => 'associate',
'openid.assoc_type' => 'HMAC-SHA1',
'openid.session_type' => 'DH-SHA1',
);
}
 
$dh = DiffieHellmanUtil::createDhKey(pack('H*', DiffieHellmanUtil::DH_P),
pack('H*', DiffieHellmanUtil::DH_G),
$priv_key);
$dh_details = DiffieHellmanUtil::getDhKeyDetails($dh);
 
$params['openid.dh_modulus'] = base64_encode(
DiffieHellmanUtil::btwoc($dh_details['p']));
$params['openid.dh_gen'] = base64_encode(
DiffieHellmanUtil::btwoc($dh_details['g']));
$params['openid.dh_consumer_public'] = base64_encode(
DiffieHellmanUtil::btwoc($dh_details['pub_key']));
 
while(1) {
//FIXME : c'est pas une modification ...
$ret = $this->client->modifier($url, $params); // FIXME : a quoi sert status ?, $status);
if ($ret === false) {
//$this->_setError("HTTP request failed");
trigger_error('La requête a échoué', E_USER_ERROR);
return false;
}
 
$r = array();
$bad_response = false;
foreach(explode("\n", $ret) as $line) {
$line = trim($line);
if (!empty($line)) {
$x = explode(':', $line, 2);
if (is_array($x) && count($x) == 2) {
list($key, $value) = $x;
$r[trim($key)] = trim($value);
} else {
$bad_response = true;
}
}
}
if ($bad_response && strpos($ret, 'Unknown session type') !== false) {
$r['error_code'] = 'unsupported-type';
}
$ret = $r;
 
if (isset($ret['error_code']) &&
$ret['error_code'] == 'unsupported-type') {
if ($params['openid.session_type'] == 'DH-SHA256') {
$params['openid.session_type'] = 'DH-SHA1';
$params['openid.assoc_type'] = 'HMAC-SHA1';
} else if ($params['openid.session_type'] == 'DH-SHA1') {
$params['openid.session_type'] = 'no-encryption';
} else {
trigger_error("The OpenID service responded with: " . $ret['error_code'], E_USER_ERROR);
return false;
}
} else {
break;
}
}
 
/*
FIXME : gestion du statut avec la classe client ??
if ($status != 200) {
$this->_setError("The server responded with status code: " . $status);
return false;
}*/
 
if ($version >= 2.0 &&
isset($ret['ns']) &&
$ret['ns'] != $this->NS_2_0) {
$this->_setError("Wrong namespace definition in the server response");
return false;
}
 
if (!isset($ret['assoc_handle']) ||
!isset($ret['expires_in']) ||
!isset($ret['assoc_type']) ||
$params['openid.assoc_type'] != $ret['assoc_type']) {
if ($params['openid.assoc_type'] != $ret['assoc_type']) {
$this->_setError("The returned assoc_type differed from the supplied openid.assoc_type");
} else {
$this->_setError("Missing required data from provider (assoc_handle, expires_in, assoc_type are required)");
}
return false;
}
 
$handle = $ret['assoc_handle'];
$expiresIn = $ret['expires_in'];
 
if ($ret['assoc_type'] == 'HMAC-SHA1') {
$macFunc = 'sha1';
} else if ($ret['assoc_type'] == 'HMAC-SHA256' &&
$version >= 2.0) {
$macFunc = 'sha256';
} else {
$this->_setError("Unsupported assoc_type");
return false;
}
 
if ((empty($ret['session_type']) ||
($version >= 2.0 && $ret['session_type'] == 'no-encryption')) &&
isset($ret['mac_key'])) {
$secret = base64_decode($ret['mac_key']);
} else if (isset($ret['session_type']) &&
$ret['session_type'] == 'DH-SHA1' &&
!empty($ret['dh_server_public']) &&
!empty($ret['enc_mac_key'])) {
$dhFunc = 'sha1';
} else if (isset($ret['session_type']) &&
$ret['session_type'] == 'DH-SHA256' &&
$version >= 2.0 &&
!empty($ret['dh_server_public']) &&
!empty($ret['enc_mac_key'])) {
$dhFunc = 'sha256';
} else {
$this->_setError("Unsupported session_type");
return false;
}
if (isset($dhFunc)) {
$serverPub = base64_decode($ret['dh_server_public']);
$dhSec = DiffieHellmanUtil::computeDhSecret($serverPub, $dh);
if ($dhSec === false) {
$this->_setError("DH secret comutation failed");
return false;
}
$sec = $this->digest($dhFunc, $dhSec);
if ($sec === false) {
$this->_setError("Could not create digest");
return false;
}
$secret = $sec ^ base64_decode($ret['enc_mac_key']);
}
if ($macFunc == 'sha1') {
if (DiffieHellmanUtil::strlen($secret) != 20) {
$this->_setError("The length of the sha1 secret must be 20");
return false;
}
} else if ($macFunc == 'sha256') {
if (DiffieHellmanUtil::strlen($secret) != 32) {
$this->_setError("The length of the sha256 secret must be 32");
return false;
}
}
$this->_addAssociation(
$url,
$handle,
$macFunc,
$secret,
time() + $expiresIn);
/* $this->association['url'] = $url;
$this->association['handle'] = $handle;
$this->association['macFunc'] = $macFunc;
$this->association['secret'] = $secret;
$this->association['expiresIn'] = time() + $expiresIn;*/
return true;
}
/**
* Store assiciation in internal chace and external storage
*
* @param string $url OpenID server url
* @param string $handle association handle
* @param string $macFunc HMAC function (sha1 or sha256)
* @param string $secret shared secret
* @param integer $expires expiration UNIX time
* @return void
*/
protected function _addAssociation($url, $handle, $macFunc, $secret, $expires)
{
$this->_cache[$url] = array($handle, $macFunc, $secret, $expires);
return $this->_storage->addAssociation(
$url,
$handle,
$macFunc,
$secret,
$expires);
}
/**
* Retrive assiciation information for given $url from internal cahce or
* external storage
*
* @param string $url OpenID server url
* @param string &$handle association handle
* @param string &$macFunc HMAC function (sha1 or sha256)
* @param string &$secret shared secret
* @param integer &$expires expiration UNIX time
* @return void
*/
protected function _getAssociation($url, &$handle, &$macFunc, &$secret, &$expires)
{
if (isset($this->_cache[$url])) {
$handle = $this->_cache[$url][0];
$macFunc = $this->_cache[$url][1];
$secret = $this->_cache[$url][2];
$expires = $this->_cache[$url][3];
return true;
}
if ($this->_storage->getAssociation(
$url,
$handle,
$macFunc,
$secret,
$expires)) {
$this->_cache[$url] = array($handle, $macFunc, $secret, $expires);
return true;
}
return false;
}
/**
* Normalizes URL according to RFC 3986 to use it in comparison operations.
* The function gets URL argument by reference and modifies it.
* It returns true on success and false of failure.
*
* @param string &$id url to be normalized
* @return bool
*/
static public function normalizeUrl(&$id)
{
// RFC 3986, 6.2.2. Syntax-Based Normalization
 
// RFC 3986, 6.2.2.2 Percent-Encoding Normalization
$i = 0;
$n = strlen($id);
$res = '';
while ($i < $n) {
if ($id[$i] == '%') {
if ($i + 2 >= $n) {
return false;
}
++$i;
if ($id[$i] >= '0' && $id[$i] <= '9') {
$c = ord($id[$i]) - ord('0');
} else if ($id[$i] >= 'A' && $id[$i] <= 'F') {
$c = ord($id[$i]) - ord('A') + 10;
} else if ($id[$i] >= 'a' && $id[$i] <= 'f') {
$c = ord($id[$i]) - ord('a') + 10;
} else {
return false;
}
++$i;
if ($id[$i] >= '0' && $id[$i] <= '9') {
$c = ($c << 4) | (ord($id[$i]) - ord('0'));
} else if ($id[$i] >= 'A' && $id[$i] <= 'F') {
$c = ($c << 4) | (ord($id[$i]) - ord('A') + 10);
} else if ($id[$i] >= 'a' && $id[$i] <= 'f') {
$c = ($c << 4) | (ord($id[$i]) - ord('a') + 10);
} else {
return false;
}
++$i;
$ch = chr($c);
if (($ch >= 'A' && $ch <= 'Z') ||
($ch >= 'a' && $ch <= 'z') ||
$ch == '-' ||
$ch == '.' ||
$ch == '_' ||
$ch == '~') {
$res .= $ch;
} else {
$res .= '%';
if (($c >> 4) < 10) {
$res .= chr(($c >> 4) + ord('0'));
} else {
$res .= chr(($c >> 4) - 10 + ord('A'));
}
$c = $c & 0xf;
if ($c < 10) {
$res .= chr($c + ord('0'));
} else {
$res .= chr($c - 10 + ord('A'));
}
}
} else {
$res .= $id[$i++];
}
}
 
if (!preg_match('|^([^:]+)://([^:@]*(?:[:][^@]*)?@)?([^/:@?#]*)(?:[:]([^/?#]*))?(/[^?#]*)?((?:[?](?:[^#]*))?)((?:#.*)?)$|', $res, $reg)) {
return false;
}
$scheme = $reg[1];
$auth = $reg[2];
$host = $reg[3];
$port = $reg[4];
$path = $reg[5];
$query = $reg[6];
$fragment = $reg[7]; /* strip it */
 
if (empty($scheme) || empty($host)) {
return false;
}
 
// RFC 3986, 6.2.2.1. Case Normalization
$scheme = strtolower($scheme);
$host = strtolower($host);
 
// RFC 3986, 6.2.2.3. Path Segment Normalization
if (!empty($path)) {
$i = 0;
$n = strlen($path);
$res = "";
while ($i < $n) {
if ($path[$i] == '/') {
++$i;
while ($i < $n && $path[$i] == '/') {
++$i;
}
if ($i < $n && $path[$i] == '.') {
++$i;
if ($i < $n && $path[$i] == '.') {
++$i;
if ($i == $n || $path[$i] == '/') {
if (($pos = strrpos($res, '/')) !== false) {
$res = substr($res, 0, $pos);
}
} else {
$res .= '/..';
}
} else if ($i != $n && $path[$i] != '/') {
$res .= '/.';
}
} else {
$res .= '/';
}
} else {
$res .= $path[$i++];
}
}
$path = $res;
}
 
// RFC 3986,6.2.3. Scheme-Based Normalization
if ($scheme == 'http') {
if ($port == 80) {
$port = '';
}
} else if ($scheme == 'https') {
if ($port == 443) {
$port = '';
}
}
if (empty($path)) {
$path = '/';
}
 
$id = $scheme
. '://'
. $auth
. $host
. (empty($port) ? '' : (':' . $port))
. $path
. $query;
return true;
}
 
/**
* Normaliser l'identifiant OpenId qui peut être une URL ou nom XRI
* Retourne true ou false en cas d'erreur.
*
* Règles de normalisation :
* 1. If the user's input starts with one of the "xri://", "xri://$ip*",
* or "xri://$dns*" prefixes, they MUST be stripped off, so that XRIs
* are used in the canonical form, and URI-authority XRIs are further
* considered URL identifiers.
* 2. If the first character of the resulting string is an XRI Global
* Context Symbol ("=", "@", "+", "$", "!"), then the input SHOULD be
* treated as an XRI.
* 3. Otherwise, the input SHOULD be treated as an http URL; if it does
* not include a "http" or "https" scheme, the Identifier MUST be
* prefixed with the string "http://".
* 4. URL identifiers MUST then be further normalized by both following
* redirects when retrieving their content and finally applying the
* rules in Section 6 of [RFC3986] to the final destination URL.
* @param string &$id identifier to be normalized
* @return bool
*/
static public function normalize(&$id)
{
$id = trim($id);
if (strlen($id) === 0) {
return true;
}
 
// 7.2.1
if (strpos($id, 'xri://$ip*') === 0) {
$id = substr($id, strlen('xri://$ip*'));
} else if (strpos($id, 'xri://$dns*') === 0) {
$id = substr($id, strlen('xri://$dns*'));
} else if (strpos($id, 'xri://') === 0) {
$id = substr($id, strlen('xri://'));
}
 
// 7.2.2
if ($id[0] == '=' ||
$id[0] == '@' ||
$id[0] == '+' ||
$id[0] == '$' ||
$id[0] == '!') {
return true;
}
 
// 7.2.3
if (strpos($id, "://") === false) {
$id = 'http://' . $id;
}
 
// 7.2.4
return self::normalizeURL($id);
}
/**
* Generates a hash value (message digest) according to given algorithm.
* It returns RAW binary string.
*
* This is a wrapper function that uses one of available internal function
* dependent on given PHP configuration. It may use various functions from
* ext/openssl, ext/hash, ext/mhash or ext/standard.
*
* @param string $func digest algorithm
* @param string $data data to sign
* @return string RAW digital signature
* @throws Zend_OpenId_Exception
*/
public function digest($func, $data)
{
if (function_exists('openssl_digest')) {
return openssl_digest($data, $func, true);
} else if (function_exists('hash')) {
return hash($func, $data, true);
} else if ($func === 'sha1') {
return sha1($data, true);
} else if ($func === 'sha256') {
if (function_exists('mhash')) {
return mhash(MHASH_SHA256 , $data);
}
}
/*require_once "Zend/OpenId/Exception.php";
throw new Zend_OpenId_Exception(
'Unsupported digest algorithm "' . $func . '".',
Zend_OpenId_Exception::UNSUPPORTED_DIGEST);*/
trigger_error('Unsupported digest algorithm '.$func , E_USER_ERROR);
}
/**
* Returns a full URL that was requested on current HTTP request.
*
* @return string
*/
public function selfUrl()
{
/*FIXME :
* if ($this->$selfUrl !== null) {
return $this->$selfUrl;
} */
if (isset($_SERVER['SCRIPT_URI'])) {
return $_SERVER['SCRIPT_URI'];
}
$url = '';
$port = '';
if (isset($_SERVER['HTTP_HOST'])) {
if (($pos = strpos($_SERVER['HTTP_HOST'], ':')) === false) {
if (isset($_SERVER['SERVER_PORT'])) {
$port = ':' . $_SERVER['SERVER_PORT'];
}
$url = $_SERVER['HTTP_HOST'];
} else {
$url = substr($_SERVER['HTTP_HOST'], 0, $pos);
$port = substr($_SERVER['HTTP_HOST'], $pos);
}
} else if (isset($_SERVER['SERVER_NAME'])) {
$url = $_SERVER['SERVER_NAME'];
if (isset($_SERVER['SERVER_PORT'])) {
$port = ':' . $_SERVER['SERVER_PORT'];
}
}
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
$url = 'https://' . $url;
if ($port == ':443') {
$port = '';
}
} else {
$url = 'http://' . $url;
if ($port == ':80') {
$port = '';
}
}
 
$url .= $port;
if (isset($_SERVER['HTTP_X_REWRITE_URL'])) {
$url .= $_SERVER['HTTP_X_REWRITE_URL'];
} elseif (isset($_SERVER['REQUEST_URI'])) {
$query = strpos($_SERVER['REQUEST_URI'], '?');
if ($query === false) {
$url .= $_SERVER['REQUEST_URI'];
} else {
$url .= substr($_SERVER['REQUEST_URI'], 0, $query);
}
} else if (isset($_SERVER['SCRIPT_URL'])) {
$url .= $_SERVER['SCRIPT_URL'];
} else if (isset($_SERVER['REDIRECT_URL'])) {
$url .= $_SERVER['REDIRECT_URL'];
} else if (isset($_SERVER['PHP_SELF'])) {
$url .= $_SERVER['PHP_SELF'];
} else if (isset($_SERVER['SCRIPT_NAME'])) {
$url .= $_SERVER['SCRIPT_NAME'];
if (isset($_SERVER['PATH_INFO'])) {
$url .= $_SERVER['PATH_INFO'];
}
}
return $url;
}
//TODO : vérifier si les fonctions FWK & ZEND sont bien équivalente
/**
* Retourne l'url absolue d'une url donnée
*
* @param string $url absilute or relative URL
* @return string
*/
public function absoluteUrl($url)
{
if (!empty($ur)) {
$urlAbsolue = new Url($url);
$urlAbsolue->normaliser();
$url = $urlAbsolue->getUrl();
} else {
$url = $this->selfUrl();
}
return $url;
/*
if (empty($url)) {
return $this->selfUrl();
} else if (!preg_match('|^([^:]+)://|', $url)) {
if (preg_match('|^([^:]+)://([^:@]*(?:[:][^@]*)?@)?([^/:@?#]*)(?:[:]([^/?#]*))?(/[^?]*)?((?:[?](?:[^#]*))?(?:#.*)?)$|', $this->selfUrl(), $reg)) {
$scheme = $reg[1];
$auth = $reg[2];
$host = $reg[3];
$port = $reg[4];
$path = $reg[5];
$query = $reg[6];
if ($url[0] == '/') {
return $scheme
. '://'
. $auth
. $host
. (empty($port) ? '' : (':' . $port))
. $url;
} else {
$dir = dirname($path);
return $scheme
. '://'
. $auth
. $host
. (empty($port) ? '' : (':' . $port))
. (strlen($dir) > 1 ? $dir : '')
. '/'
. $url;
}
}
}
return $url;*/
}
//TODO : voir si on ne peut pas glisser ça dans client ?
//FIXME : je met une fonction SIMPLISSIME a améliorer et reécrire
// La fonction de Zend est plus poussée est prend en compte le cas ou l'header ne peut pas etre envoyé
/**
* Rediriger vers la page du serveur avec les paramètres de confiration
*
* @param string $url URL de retour
* @param array $params paramètres additionnels
*/
public function redirect($url, $params) {
//1. fabriquer l'url Get
$urlRedirection = new Url($url);
$urlRedirection->setRequete($params);
//echo $urlRedirection->getUrl();
try {
header('Location:'.$urlRedirection->getUrl());
} catch (Exception $e) {
//TODO : voir autres méthodes de redirection
// > balise META
// > formulaire HTML
// > JS
}
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/I18n.php
New file
0,0 → 1,235
<?php
// declare(encoding='UTF-8');
/**
* I18n permet de traduire une application à partir de données stockées dans des fichiers ini.
* Si vous souhaitez utiliser le fonctionnement par défaut vous devrez :
* - déposer les fichiers ini dans le dossier définit par la variable de config "chemin_i18n".
* - nommer les fichiers selon la forme "locale.ini" (Ex.: fr.ini ou fr_CH.ini ).
*
* Elle offre l'accès en lecture seule aux paramètres des fichiers ini.
* C'est une Singleton. Une seule classe de traduction peut être instanciée par Application.
*
* @category PHP 5.2
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
* @since 0.3
* @version $Id$
* @link /doc/framework/
*/
class I18n {
/** Format de traduction utilisant les fichier .ini */
const FORMAT_INI = '.ini';
/** Instance de la classe pointant sur elle même (pour le pattern singleton) */
private static $instance = null;
/** Fichiers de traduction disponibles. */
private static $traductions = array();
/** Langue courrante utilisée par l'application. */
private static $langue = null;
/** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
private static $parametres_obligatoires = array('chemin_i18n', 'i18n_url_parametre', 'i18n_langue_defaut', 'debogage');
private function __construct() {
Config::verifierPresenceParametres(self::$parametres_obligatoires);
self::trouverLangue();
}
/**
* Accesseur pour la valeur d'une traduction
* @param string $param le nom du paramètre
* @return string la valeur du paramètre
*/
public static function get($identifiant, $langue = null) {
self::verifierCreationInstance();
$texte = '';
// Récupération de la langue actuellement demandée
$langue_a_charger = self::$langue;
if (!is_null($langue)) {
$langue_a_charger = $langue;
}
if (!isset(self::$traductions[$langue_a_charger])) {
// Tentative de chargement du fichier de traduction
$chargement = self::charger($langue_a_charger);
if ($chargement === false) {
$m = "Le fichier d'i18n pour la langue '$langue_a_charger' demandée n'a pas été trouvé.";
self::ajouterErreur($m);
}
}
// Recherche de la langue dans le tableau des traductions
if (isset(self::$traductions[$langue_a_charger]) && self::$traductions[$langue_a_charger] !== false) {
// Recherche de la traduction demandée
$valeur = self::getValeur($identifiant, self::$traductions[$langue_a_charger]);
if ($valeur !== false) {
$texte = $valeur;
} else {
$m = "Le traduction n'existe pas pour l'identifiant '$identifiant' demandé.";
self::ajouterErreur($m);
}
}
return $texte;
}
/**
* Charge un fichier ini dans le tableau des paramètres de l'appli
* @param string $fichier_ini le nom du fichier à charger
* @return boolean true, si le fichier a été trouvé et correctement chargé, sinon false.
*/
public static function charger($langue, $fichier = null, $format = self::FORMAT_INI) {
self::verifierCreationInstance();
$ok = false;
// Création du chemin vers le fichier de traduction par défaut
if (is_null($fichier)) {
$fichier = Config::get('chemin_i18n').$langue.$format;
}
 
// Chargement
if ($format == self::FORMAT_INI) {
$ok = self::chargerFichierIni($fichier, $langue);
} else {
$m = "Le format '$format' de fichier de traduction n'est pas pris en compte par le Framework.";
self::ajouterErreur($m);
}
return $ok;
}
/**
* Définit la langue utiliser pour rechercher une traduction.
* @param string $fichier_ini le nom du fichier à charger
* @return array le fichier ini parsé
*/
public static function setLangue($langue) {
self::verifierCreationInstance();
self::$langue = $langue;
}
/**
* Renvoie la valeur demandé grâce une chaine de paramètres
* @param string $param la chaine identifiante
* @param array $i18n le tableau de traductions
* @return mixed la valeur correspondante à la chaine identifiante si elle est trouvée, sinon false.
*/
private static function getValeur($param, $i18n) {
if ($param === null) {
return false;
} else {
if (isset($i18n[$param])) {
return $i18n[$param];
} else if (strpos($param, '.') !== false) {
$pieces = explode('.', $param, 2);
if (strlen($pieces[0]) && strlen($pieces[1])) {
if (isset($i18n[$pieces[0]])) {
if (is_array($i18n[$pieces[0]])) {
return self::getValeur($pieces[1], $i18n[$pieces[0]]);
}
}
}
} else {
return false;
}
}
}
/**
* Parse le fichier ini donné en paramètre
* @param string $fichier_ini nom du fichier ini à parser
* @param string $langue la langue correspondant au fichier
* @return boolean true si le chargement c'est bien passé, sinon false.
*/
private static function chargerFichierIni($fichier_ini, $langue) {
self::$traductions[$langue] = false;
if (file_exists($fichier_ini)) {
$ini = parse_ini_file($fichier_ini, true);
$ini = self::analyserTableauIni($ini);
self::$traductions[$langue] = $ini;
}
return (self::$traductions[$langue] === false) ? false : true;
}
/**
* Analyse un tableau de traductions pour évaluer les clés.
* @param array $i18n le tableau de traductions
* @return array le tableau analysé et modifié si nécessaire.
*/
private static function analyserTableauIni($i18n = array()) {
//ATTENTION : il est important de passer la valeur par référence car nous la modifions dynamiquement dans la boucle
foreach ($i18n as $cle => &$valeur) {
if (is_array($valeur)) {
$i18n[$cle] = self::analyserTableauIni($valeur);
} else {
$i18n = self::evaluerCle($i18n, $cle, $valeur);
}
}
return $i18n;
}
/**
* Dans le cas des chaines de traduction à sous clé (ex.: cle.souscle), cette méthode
* évalue les valeurs correspondantes et créée les sous tableaux associés.
* @param array $i18n tableau de traductions (par référence)
* @param string $cle la cle dans le tableau
* @param string $valeur la valeur à affecter
*/
private static function evaluerCle($i18n, $cle, $valeur) {
if (strpos($cle, '.') !== false) {
unset($i18n[$cle]);
$pieces = explode('.', $cle, 2);
if (strlen($pieces[0]) && strlen($pieces[1])) {
if (isset($i18n[$pieces[0]]) && !is_array($i18n[$pieces[0]])) {
$m = "Ne peut pas créer de sous-clé pour '{$pieces[0]}' car la clé existe déjà";
trigger_error($m, E_USER_WARNING);
} else {
$i18n[$pieces[0]][$pieces[1]] = $valeur;
$i18n[$pieces[0]] = self::evaluerCle($i18n[$pieces[0]], $pieces[1], $valeur);
}
} else {
$m = "Clé invalide '$cle'";
trigger_error($m, E_USER_WARNING);
}
} else {
$i18n[$cle] = $valeur;
}
return $i18n;
}
/**
* Cherche l'information sur la langue demandée par l'application
*/
private static function trouverLangue() {
if (isset($_GET[Config::get('i18n_url_parametre')])) {
self::$langue = $_GET[Config::get('i18n_url_parametre')];
} else {
self::$langue = Config::get('i18n_langue_defaut');
}
}
/**
* Vérifie si l'instance de classe à été crée, si non la crée
*/
private static function verifierCreationInstance() {
if (empty(self::$instance)) {
self::$instance = new I18n();
}
}
/**
* Ajouter une message d'erreur
*/
private static function ajouterErreur($m, $e = E_USER_WARNING) {
if (Config::get('debogage') === true) {
trigger_error($m, $e);
}
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/Log.php
New file
0,0 → 1,149
<?php
//declare(encoding='UTF-8');
/**
* Classe permettant de logger des messages dans les fichier situés dans le dossier de log.
*
* @category PHP 5.2
* @package Framework
* @author Aurélien PERONNET <aurelien@tela-botanica.org>
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2009, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
* @version $Id$
* @link /doc/framework/
*/
class Log {
 
/** Boolean indiquant si l'on doit utiliser les logs ou pas. */
private static $logger = false;
 
/** Tableau associatif stockant les descripteurs de fichiers. */
private static $fichiersLog = array();
 
/** Chemin de base du dossier log de l'application. */
private static $cheminLogs = '';
 
/** Booleen indiquant si l'on peut correctement écrire dans les fichiers de logs. */
private static $droitLogger = true;
 
/** Zone horaire (pour éviter des avertissements dans les dates). */
private static $timeZone = 'Europe/Paris';
 
/** Taille maximum d'un fichier de log avant que celui ne soit archivé (en octets). */
private static $tailleMax = 10000;
 
/** séparateur de dossier dans un chemin. */
private static $sd = DIRECTORY_SEPARATOR;
 
/** Extension des fichiers de log. */
private static $ext = '.log';
/** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
private static $parametres_obligatoires = array('chemin_logs', 'i18n_timezone', 'log_taille_max', 'log_debogage');
 
/** Initialiser les logs par défaut, sans tenir comptes des paramêtres de config. */
public static function initialiser() {
// gestion de la timezone pour éviter des erreurs
if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get')) {
date_default_timezone_set(self::$timeZone);
}
 
if (self::$logger && (!is_dir(self::$cheminLogs) || !is_writable(self::$cheminLogs))) {
self::desactiverEcriture();
}
}
/** Configure le Log à partir des paramêtres de config. */
public static function configurer() {
Config::verifierPresenceParametres(self::$parametres_obligatoires);
self::$cheminLogs = Config::get('chemin_logs');
self::$timeZone = (Config::get('i18n_timezone') != '') ? Config::get('i18n_timezone') : self::$timeZone;
self::$tailleMax = (Config::get('log_taille_max') != '') ? Config::get('log_taille_max') : self::$tailleMax;
self::$logger = (Config::get('log_debogage') != '') ? Config::get('log_debogage') : self::$logger;
self::initialiser();
}
 
/**
* Ajoute une entrée au log spécifié par le paramètre $nomFichier
* @param string $nomFichier le nom du fichier dans lequel écrire
*/
public static function ajouterEntree($nomFichier, $entree, $mode = 'a+') {
if (self::$droitLogger) {
$date = "\n\n".date('d m Y H:i')."\n" ;
 
if (self::verifierOuvrirFichier($nomFichier, $mode)) {
fwrite(self::$fichiersLog[$nomFichier], $date.$entree);
self::verifierTailleFichierOuArchiver($nomFichier);
} else {
self::desactiverEcriture($nomFichier);
}
}
}
 
/**
* Vide un fichier log indiqué
* @param string $nomFichier le nom du fichier à vider
*/
public static function viderLog($nomFichier) {
self::ajouterEntree($nomFichier, '', 'w');
}
 
/**
* Vérifie la présence d'un fichier dans le tableau, ses droits d'écriture, l'ouvre si nécessaire.
*
* @param string $nomFichier le nom du fichier dont on doit vérifier la présence
* @return boolean true si le fichier est ouvert ou maintenant accessible, false sinon
*/
public static function verifierOuvrirFichier($nomFichier,$mode) {
if (in_array($nomFichier, self::$fichiersLog)) {
if (is_writable(self::$cheminLogs.$nomFichier.self::$ext)) {
return true;
}
return false;
} else {
$fp = @fopen(self::$cheminLogs.$nomFichier.self::$ext,$mode);
if ($fp && is_writable(self::$cheminLogs.$nomFichier.self::$ext)) {
self::$fichiersLog[$nomFichier] = $fp;
return true;
}
return false;
}
}
 
/**
* Vérifie la taille d'un fichier donné et si celle ci est trop importante
* archive le fichier de log
* @param string $nomFichier nom du fichier à vérifier
*/
private static function verifierTailleFichierOuArchiver($nomFichier) {
if(filesize(self::$cheminLogs.$nomFichier.self::$ext) > self::$tailleMax) {
rename(self::$cheminLogs.$nomFichier.self::$ext,self::$cheminLogs.$nomFichier.date('d_m_Y_H:i').self::$ext);
self::ajouterEntree($nomFichier,'');
}
}
 
/**
* Désactive l'écriture du log et envoie un message au gestionnaire d'erreurs
* @param string $nomFichier le nom du fichier qui a causé l'erreur
*/
private static function desactiverEcriture($nomFichier = '') {
self::$droitLogger = false;
if ($nomFichier != '') {
$fichierDossier = 'fichier '.$nomFichier ;
} else {
$fichierDossier = 'dossier des logs';
}
$message = 'Écriture impossible dans le '.$fichierDossier.', Assurez-vous des droits du dossier et des fichiers';
$e = new ErrorException($message, 0, E_USER_WARNING, __FILE__, __LINE__);
GestionnaireException::gererException($e);
}
 
/** Destructeur de classe, ferme les descripteurs ouverts. */
public function __destruct() {
foreach(self::$fichiersLog as $nomFichier => $fp) {
fclose($fp);
}
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/SquelettePhp.php
New file
0,0 → 1,73
<?php
// declare(encoding='UTF-8');
/**
* Classe SquelettePhp, traitant les squelette Php utilisant la syntaxe courte php ou pas.
* Ces méthodes sont statiques.
*
* @category php5
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
* @version $Id$
* @link /doc/framework/
*/
class SquelettePhp {
 
/**
* Fonction prenant en paramètre un chemin de fichier squelette et un tableau associatif de données,
* en extrait les variables, charge le squelette et retourne le résultat des deux combinés.
*
* @param String $fichier le chemin du fichier du squelette
* @param Array $donnees un tableau associatif contenant les variables a injecter dans le squelette.
* @return boolean false si la vue n'existe pas, sinon la chaine résultat.
*/
public static function analyser($fichier, Array &$donnees = array()) {
$sortie = false;
if (file_exists($fichier)) {
// Extraction des variables du tableau de données
extract($donnees);
 
// Démarage de la bufferisation de sortie
ob_start();
// Si les tags courts sont activés
if ((bool) @ini_get('short_open_tag') === true) {
// Simple inclusion du squelette
include $fichier;
} else {
// Sinon, remplacement des tags courts par la syntaxe classique avec echo
$html_et_code_php = self::traiterTagsCourts($fichier);
// Pour évaluer du php mélangé dans du html il est nécessaire de fermer la balise php ouverte par eval
$html_et_code_php = '?>'.$html_et_code_php;
// Interprétation du html et du php dans le buffer
echo eval($html_et_code_php);
}
// Récupèration du contenu du buffer
$sortie = ob_get_contents();
// Suppression du buffer
@ob_end_clean();
} else {
$msg = "Le fichier du squelette '$fichier' n'existe pas.";
trigger_error($msg, E_USER_WARNING);
}
// Retourne le contenu
return $sortie;
}
 
/**
* Fonction chargeant le contenu du squelette et remplaçant les tags court php (<?= ...) par un tag long avec echo.
*
* @param String $chemin_squelette le chemin du fichier du squelette
* @return string le contenu du fichier du squelette php avec les tags courts remplacés.
*/
private static function traiterTagsCourts($chemin_squelette) {
$contenu = file_get_contents($chemin_squelette);
// Remplacement de tags courts par un tag long avec echo
$contenu = str_replace('<?=', '<?php echo ', $contenu);
// Ajout systématique d'un point virgule avant la fermeture php
$contenu = preg_replace("/;*\s*\?>/", "; ?>", $contenu);
return $contenu;
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/Registre.php
New file
0,0 → 1,68
<?php
// declare(encoding='UTF-8');
/**
* Classe Registre, qui permet un accès à différentes variables et paramètres à travers les autres classes.
* C'est un remplaçant à la variable magique $_GLOBALS de Php.
* C'est un singleton.
* Si vous voulez paramètré votre application via un fichier de configuration, utilisez plutôt la classe @see Config.
*
* @category php 5.2
* @package Framework
* @author Jean-Pascal MILCENT <jmp@tela-botanica.org>
* @copyright Copyright (c) 2009, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
* @version $Id$
* @link /doc/framework/
*
*/
class Registre {
 
/** Tableau associatif stockant les variables. */
private static $stockage = array();
/**
* Ajoute un objet au tableau selon un intitulé donné.
* @param string l'intitulé sous lequel l'objet sera conservé
* @param mixed l'objet à conserver
*/
public static function set($intitule, $objet) {
if (is_array($objet) && isset(self::$stockage[$intitule])) {
self::$stockage[$intitule] = array_merge((array) self::$stockage[$intitule], (array) $objet);
$message = "Le tableau $intitule présent dans le registre a été fusionné avec un nouveau tableau de même intitulé !";
trigger_error($message, E_USER_WARNING);
} else {
self::$stockage[$intitule] = $objet;
}
}
 
/**
* Renvoie le contenu associé à l'intitulé donné en paramètre.
* @return mixed l'objet associé à l'intitulé ou null s'il n'est pas présent
*/
public static function get($intitule) {
$retour = (isset(self::$stockage[$intitule])) ? self::$stockage[$intitule] : null;
return $retour;
}
 
/**
* Détruit l'objet associé à l'intitulé, n'a pas d'effet si il n'y a pas d'objet associé.
* @param string l'intitulé de l'entrée du registre à détruire.
*/
public static function detruire($intitule) {
if (isset(self::$stockage[$intitule])) {
unset(self::$stockage[$intitule]);
}
}
 
/**
* Teste si le registre contient une donnée pour un intitulé d'entrée donné.
* @param string l'intitulé de l'entrée du registre à tester.
* @return boolean true si un objet associé à cet intitulé est présent, false sinon
*/
public static function existe($intitule) {
$retour = (isset(self::$stockage[$intitule])) ? true : false;
return $retour;
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/Chronometre.php
New file
0,0 → 1,121
<?php
// declare(encoding='UTF-8');
/** Chronometre permet de stocker et d'afficher les temps d'éxécution de script.
*
* Cette classe permet de réaliser un ensemble de mesure de temps prises à différents endroits d'un script.
* Ces mesures peuvent ensuite être affichées au sein d'un tableau XHTML.
*
* @category PHP 5.2
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL-v3
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL-v2
* @version $Id$
* @link /doc/framework/
*/
class Chronometre {
/*** Attributs : ***/
private static $pointArretNumero = 1;
private static $temps = array();
 
/** Accesseurs :
*
* @param string $cle la cle associée à un chronomètre particulier
*
* @return int le temps écoulé
*/
private static function getTemps($cle = null) {
$temps = (is_null($cle)) ? self::$temps : self::$temps[$cle];
return $temps;
}
 
/** Setteur pour la variable temps
*
* @param array() $moment ajoute des points de chronométrage au tableau _temps
*
* @return null
*/
private static function setTemps($cle, $moment) {
array_push(self::$temps, array($cle => $moment));
}
 
/*** Méthodes : ***/
/**
* Effectue un chronometrage.
* Vous pouvez indiquer le nom du point de chronométrage.
* Si vous n'indiquez rien, un nombre sera généré en débutant à 1.
*
* @param string le nom du point de chronométrage
* @return null
*/
public static function chrono($cle = null) {
$cle = ($cle == null) ? self::$pointArretNumero++ : $cle;
$moment = microtime();
self::setTemps($cle, $moment);
}
/**
* Permet d'afficher les temps d'éxécution de différentes parties d'un script.
*
* Cette fonction permet d'afficher un ensemble de mesure de temps prises à différents endroits d'un script.
* Ces mesures sont affichées au sein d'un tableau XHTML dont on peut controler l'indentation des balises.
* Pour un site en production, il suffit d'ajouter un style #chrono {display:none;} dans la css.
* De cette façon, le tableau ne s'affichera pas. Le webmaster lui pourra rajouter sa propre feuille de style
* affichant le tableau.
* Le développeur initial de cette fonction est Loic d'Anterroches.
* Elle a été modifiée par Jean-Pascal Milcent.
*
* @author Loic d'Anterroches
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @param string l'eventuel nom du point de chronométrage de fin.
* @return string la chaine XHTML de mesure des temps.
*/
public static function afficherChrono($cle = null) {
// Création du chrono de fin
self::chrono();
 
$total_tps_ecoule = 0;
// Récupération de la premiére mesure
$tab_depart = self::getTemps(0);
list ($usec, $sec) = explode(' ', $tab_depart['depart']);
 
// Ce temps correspond à tps_fin
$tps_debut = ((float) $usec + (float) $sec);
$tbody = '';
foreach (self::getTemps() as $tab_temps) {
foreach ($tab_temps as $cle => $valeur) {
list ($usec, $sec) = explode(' ', $valeur);
$tps_fin = ((float) $usec + (float) $sec);
 
$tps_ecoule = abs($tps_fin - $tps_debut);
$total_tps_ecoule += $tps_ecoule;
$tps_debut = $tps_fin;
// Gestion affichage
$total_tps_ecoule_fmt = number_format($total_tps_ecoule, 3, ',', ' ');
$tps_ecoule_fmt = number_format($tps_ecoule, 3, ',', ' ');
$tbody .= '<tr><th>'.$cle.'</th><td>'.$tps_ecoule_fmt.'</td><td>'.$total_tps_ecoule_fmt.'</td></tr>'."\n";
}
}
$total_tps_ecoule_final_fmt = number_format($total_tps_ecoule, 3, ',', ' ');
// Début création de l'affichage
$sortie = '<table id="chrono" lang="fr" summary="Résultat duchronométrage du programme affichant la page actuelle.">'."\n".
'<caption>Chronométrage</caption>'."\n".
'<thead>'."\n".
' <tr><th>Action</th><th>Temps écoulé (en s.)</th><th>Cumul du temps écoulé (en s.)</th></tr>'."\n".
'</thead>'."\n".
'<tbody>'."\n".
$tbody.
'</tbody>'."\n".
'<tfoot>'."\n".
' <tr><th>Total du temps écoulé (en s.)</th><td colspan="2">'.$total_tps_ecoule_final_fmt.'</td></tr>'."\n".
'</tfoot>'."\n".
'</table>'."\n";
 
return $sortie;
}
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/CacheSqlite.php
New file
0,0 → 1,617
<?php
class CacheSqlite {
/**
* Options disponibles :
*
* ====> (string) stockage_chemin :
* Chemin vers le fichier contenant la base SQLite.
*
*
* ====> (int) defragmentation_auto :
* - Désactive / Régler le processus de défragmentation automatique
* - Le processus de défragmentation automatiques réduit la taille du fichier contenant la base de données
* quand un ajout ou une suppression de cache est réalisée :
* 0 => pas de défragmentation automatique
* 1 => défragmentation automatique systématique
* x (integer) > 1 => défragmentation automatique toutes les 1 fois (au hasard) sur x ajout ou suppression de cache
*
* @var array options disponibles
*/
protected $options = array(
'stockage_chemin' => null,
'defragmentation_auto' => 10
);
/**
* DB ressource
*
* @var mixed $db
*/
private $bdd = null;
 
/**
* Boolean to store if the structure has benn checked or not
*
* @var boolean $structure_ok
*/
private $structure_ok = false;
 
private $Cache = null;
/**
* Constructor
*
* @param array $options Associative array of options
* @throws Zend_cache_Exception
* @return void
*/
public function __construct(array $options = array(), Cache $cache) {
$this->Cache = $cache;
if (extension_loaded('sqlite')) {
$this->initialiserOptionsParConfig();
$this->setOptions($options);
} else {
$e = "Impossible d'utiliser le cache SQLITE car l'extenssion 'sqlite' n'est pas chargée dans l'environnement PHP courrant.";
trigger_error($e, E_USER_ERROR);
}
}
private function initialiserOptionsParConfig() {
while (list($nom, $valeur) = each($this->options)) {
if (Config::existe($nom)) {
$this->options[$nom] = Config::get($nom);
}
}
}
/**
* Destructor
*
* @return void
*/
public function __destruct() {
@sqlite_close($this->getConnexion());
}
private function setOptions($options) {
while (list($nom, $valeur) = each($options)) {
if (!is_string($nom)) {
trigger_error("Nom d'option incorecte : $nom", E_USER_WARNING);
}
$nom = strtolower($nom);
if (array_key_exists($nom, $this->options)) {
$this->options[$nom] = $valeur;
}
}
}
public function setEmplacement($emplacement) {
if (extension_loaded('sqlite')) {
$this->options['stockage_chemin'] = $emplacement;
} else {
trigger_error("Impossible d'utiliser le mode de sotckage SQLite car l'extenssion 'sqlite' n'est pas chargé dans ".
"l'environnement PHP courrant.", E_USER_ERROR);
}
}
 
/**
* Test if a cache is available for the given id and (if yes) return it (false else)
*
* @param string $id Cache id
* @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
* @return string|false Cached datas
*/
public function charger($id, $ne_pas_tester_validiter_du_cache = false) {
$this->verifierEtCreerStructureBdd();
$requete = "SELECT content FROM cache WHERE id = '$id'".
(($ne_pas_tester_validiter_du_cache) ? '' : ' AND (expire = 0 OR expire > '.time().')');
$resultat = $this->requeter($requete);
$ligne = @sqlite_fetch_array($resultat);
return ($ligne) ? $ligne['content'] : false;
}
 
/**
* Test if a cache is available or not (for the given id)
*
* @param string $id Cache id
* @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record
*/
public function tester($id) {
$this->verifierEtCreerStructureBdd();
$requete = "SELECT lastModified FROM cache WHERE id = '$id' AND (expire = 0 OR expire > ".time().')';
$resultat = $this->requeter($requete);
$ligne = @sqlite_fetch_array($resultat);
return ($ligne) ? ((int) $ligne['lastModified']) : false;
}
 
/**
* Save some string datas into a cache record
*
* Note : $data is always "string" (serialization is done by the
* core not by the backend)
*
* @param string $data Datas to cache
* @param string $id Cache id
* @param array $tags Array of strings, the cache record will be tagged by each string entry
* @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
* @throws Zend_Cache_Exception
* @return boolean True if no problem
*/
public function sauver($donnees, $id, $tags = array(), $duree_vie_specifique = false) {
$this->verifierEtCreerStructureBdd();
//FIXME : si l'extension n'est pas installée, le cache passe tout de même par cette fonction et s'arrête à cet endroit.
$donnees = @sqlite_escape_string($donnees);
$timestamp_courrant = time();
$expiration = $this->Cache->getTimestampExpiration($duree_vie_specifique);
 
$this->requeter("DELETE FROM cache WHERE id = '$id'");
$sql = "INSERT INTO cache (id, content, lastModified, expire) VALUES ('$id', '$donnees', $timestamp_courrant, $expiration)";
$resultat = $this->requeter($sql);
if (!$resultat) {
// TODO : ajouter un log sauver() : impossible de stocker le cache d'id '$id'
Debug::printr("sauver() : impossible de stocker le cache d'id '$id'");
$resultat = false;
} else {
$resultat = true;
foreach ($tags as $tag) {
$resultat = $this->enregisterTag($id, $tag) && $resultat;
}
}
return $resultat;
}
 
/**
* Remove a cache record
*
* @param string $id Cache id
* @return boolean True if no problem
*/
public function supprimer($id) {
$this->verifierEtCreerStructureBdd();
$resultat = $this->requeter("SELECT COUNT(*) AS nbr FROM cache WHERE id = '$id'");
$resultat_nbre = @sqlite_fetch_single($resultat);
$suppression_cache = $this->requeter("DELETE FROM cache WHERE id = '$id'");
$suppression_tags = $this->requeter("DELETE FROM tag WHERE id = '$id'");
$this->defragmenterAutomatiquement();
return ($resultat_nbre && $suppression_cache && $suppression_tags);
}
 
/**
* Clean some cache records
*
* Available modes are :
* Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode Clean mode
* @param array $tags Array of tags
* @return boolean True if no problem
*/
public function nettoyer($mode = Cache::NETTOYAGE_MODE_TOUS, $tags = array()) {
$this->verifierEtCreerStructureBdd();
$retour = $this->nettoyerSqlite($mode, $tags);
$this->defragmenterAutomatiquement();
return $retour;
}
 
/**
* Return an array of stored cache ids
*
* @return array array of stored cache ids (string)
*/
public function getIds() {
$this->verifierEtCreerStructureBdd();
$resultat = $this->requeter('SELECT id FROM cache WHERE (expire = 0 OR expire > '.time().')');
$retour = array();
while ($id = @sqlite_fetch_single($resultat)) {
$retour[] = $id;
}
return $retour;
}
 
/**
* Return an array of stored tags
*
* @return array array of stored tags (string)
*/
public function getTags() {
$this->verifierEtCreerStructureBdd();
$resultat = $this->requeter('SELECT DISTINCT(name) AS name FROM tag');
$retour = array();
while ($id = @sqlite_fetch_single($resultat)) {
$retour[] = $id;
}
return $retour;
}
 
/**
* Return an array of stored cache ids which match given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of matching cache ids (string)
*/
public function getIdsAvecLesTags($tags = array()) {
$this->verifierEtCreerStructureBdd();
$premier = true;
$ids = array();
foreach ($tags as $tag) {
$resultat = $this->requeter("SELECT DISTINCT(id) AS id FROM tag WHERE name='$tag'");
if ($resultat) {
$lignes = @sqlite_fetch_all($resultat, SQLITE_ASSOC);
$ids_tmp = array();
foreach ($lignes as $ligne) {
$ids_tmp[] = $ligne['id'];
}
if ($premier) {
$ids = $ids_tmp;
$premier = false;
} else {
$ids = array_intersect($ids, $ids_tmp);
}
}
}
$retour = array();
if (count($ids) > 0) {
foreach ($ids as $id) {
$retour[] = $id;
}
}
return $retour;
}
 
/**
* Return an array of stored cache ids which don't match given tags
*
* In case of multiple tags, a logical OR is made between tags
*
* @param array $tags array of tags
* @return array array of not matching cache ids (string)
*/
public function getIdsSansLesTags($tags = array()) {
$this->verifierEtCreerStructureBdd();
$resultat = $this->requeter('SELECT id FROM cache');
$lignes = @sqlite_fetch_all($resultat, SQLITE_ASSOC);
$retour = array();
foreach ($lignes as $ligne) {
$id = $ligne['id'];
$correspondance = false;
foreach ($tags as $tag) {
$resultat = $this->requeter("SELECT COUNT(*) AS nbr FROM tag WHERE name = '$tag' AND id = '$id'");
if ($resultat) {
$nbre = (int) @sqlite_fetch_single($resultat);
if ($nbre > 0) {
$correspondance = true;
}
}
}
if (!$correspondance) {
$retour[] = $id;
}
}
return $retour;
}
 
/**
* Return an array of stored cache ids which match any given tags
*
* In case of multiple tags, a logical AND is made between tags
*
* @param array $tags array of tags
* @return array array of any matching cache ids (string)
*/
public function getIdsAvecUnTag($tags = array()) {
$this->verifierEtCreerStructureBdd();
$premier = true;
$ids = array();
foreach ($tags as $tag) {
$resultat = $this->requeter("SELECT DISTINCT(id) AS id FROM tag WHERE name = '$tag'");
if ($resultat) {
$lignes = @sqlite_fetch_all($resultat, SQLITE_ASSOC);
$ids_tmp = array();
foreach ($lignes as $ligne) {
$ids_tmp[] = $ligne['id'];
}
if ($premier) {
$ids = $ids_tmp;
$premier = false;
} else {
$ids = array_merge($ids, $ids_tmp);
}
}
}
$retour = array();
if (count($ids) > 0) {
foreach ($ids as $id) {
$retour[] = $id;
}
}
return $retour;
}
 
/**
* Return the filling percentage of the backend storage
*
* @throws Zend_Cache_Exception
* @return int integer between 0 and 100
*/
public function getPourcentageRemplissage() {
$dossier = dirname($this->options['stockage_chemin']);
$libre = disk_free_space($dossier);
$total = disk_total_space($dossier);
$pourcentage = 0;
if ($total == 0) {
trigger_error("Impossible d'utiliser la fonction disk_total_space", E_USER_WARNING);
} else {
$pourcentage = ($libre >= $total) ? 100 : ((int) (100. * ($total - $libre) / $total));
}
return $pourcentage;
}
 
/**
* Return an array of metadatas for the given cache id
*
* The array must include these keys :
* - expire : the expire timestamp
* - tags : a string array of tags
* - mtime : timestamp of last modification time
*
* @param string $id cache id
* @return array array of metadatas (false if the cache id is not found)
*/
public function getMetadonnees($id) {
$this->verifierEtCreerStructureBdd();
$tags = array();
$resultat = $this->requeter("SELECT name FROM tag WHERE id = '$id'");
if ($resultat) {
$lignes = @sqlite_fetch_all($resultat, SQLITE_ASSOC);
foreach ($lignes as $ligne) {
$tags[] = $ligne['name'];
}
}
$resultat = $this->requeter("SELECT lastModified, expire FROM cache WHERE id = '$id'");
if ($resultat) {
$ligne = @sqlite_fetch_array($resultat, SQLITE_ASSOC);
$resultat = array(
'tags' => $tags,
'mtime' => $ligne['lastModified'],
'expiration' => $ligne['expire']);
} else {
$resultat = false;
}
return $resultat;
}
 
/**
* Give (if possible) an extra lifetime to the given cache id
*
* @param string $id cache id
* @param int $extraLifetime
* @return boolean true if ok
*/
public function ajouterSupplementDureeDeVie($id, $supplement_duree_de_vie) {
$this->verifierEtCreerStructureBdd();
$augmentation = false;
$requete = "SELECT expire FROM cache WHERE id = '$id' AND (expire = 0 OR expire > ".time().')';
$resultat = $this->requeter($requete);
if ($resultat) {
$expiration = @sqlite_fetch_single($resultat);
$nouvelle_expiration = $expiration + $supplement_duree_de_vie;
$resultat = $this->requeter('UPDATE cache SET lastModified = '.time().", expire = $nouvelle_expiration WHERE id = '$id'");
$augmentation = ($resultat) ? true : false;
}
return $augmentation;
}
 
/**
* Return the connection resource
*
* If we are not connected, the connection is made
*
* @throws Zend_Cache_Exception
* @return resource Connection resource
*/
private function getConnexion() {
if (!is_resource($this->bdd)) {
if ($this->options['stockage_chemin'] === null) {
$e = "L'emplacement du chemin vers le fichier de la base de données SQLite n'a pas été défini";
trigger_error($e, E_USER_ERROR);
} else {
$this->bdd = sqlite_open($this->options['stockage_chemin']);
if (!(is_resource($this->bdd))) {
$e = "Impossible d'ouvrir le fichier '".$this->options['stockage_chemin']."' de la base de données SQLite.";
trigger_error($e, E_USER_ERROR);
$this->bdd = null;
}
}
}
return $this->bdd;
}
 
/**
* Execute une requête SQL sans afficher de messages d'erreur.
*
* @param string $requete requête SQL
* @return mixed|false resultats de la requête
*/
private function requeter($requete) {
$bdd = $this->getConnexion();
//Debug::printr($requete);
$resultat = (is_resource($bdd)) ? @sqlite_query($bdd, $requete, SQLITE_ASSOC, $e_sqlite) : false;
if (is_resource($bdd) && ! $resultat) {
Debug::printr("Erreur SQLITE :\n$e_sqlite\nPour la requête :\n$requete\nRessource : $bdd");
}
return $resultat;
}
 
/**
* Deal with the automatic vacuum process
*
* @return void
*/
private function defragmenterAutomatiquement() {
if ($this->options['defragmentation_auto'] > 0) {
$rand = rand(1, $this->options['defragmentation_auto']);
if ($rand == 1) {
$this->requeter('VACUUM');
@sqlite_close($this->getConnexion());
}
}
}
 
/**
* Register a cache id with the given tag
*
* @param string $id Cache id
* @param string $tag Tag
* @return boolean True if no problem
*/
private function enregisterTag($id, $tag) {
$requete_suppression = "DELETE FROM tag WHERE name = '$tag' AND id = '$id'";
$resultat = $this->requeter($requete_suppression);
$requete_insertion = "INSERT INTO tag(name,id) VALUES ('$tag','$id')";
$resultat = $this->requeter($requete_insertion);
if (!$resultat) {
// TODO : ajouter un log -> impossible d'enregistrer le tag=$tag pour le cache id=$id");
Debug::printr("Impossible d'enregistrer le tag=$tag pour le cache id=$id");
}
return ($resultat) ? true : false;
}
 
/**
* Build the database structure
*
* @return false
*/
private function creerStructure() {
$this->requeter('DROP INDEX IF EXISTS tag_id_index');
$this->requeter('DROP INDEX IF EXISTS tag_name_index');
$this->requeter('DROP INDEX IF EXISTS cache_id_expire_index');
$this->requeter('DROP TABLE IF EXISTS version');
$this->requeter('DROP TABLE IF EXISTS cache');
$this->requeter('DROP TABLE IF EXISTS tag');
$this->requeter('CREATE TABLE version (num INTEGER PRIMARY KEY)');
$this->requeter('CREATE TABLE cache(id TEXT PRIMARY KEY, content BLOB, lastModified INTEGER, expire INTEGER)');
$this->requeter('CREATE TABLE tag (name TEXT, id TEXT)');
$this->requeter('CREATE INDEX tag_id_index ON tag(id)');
$this->requeter('CREATE INDEX tag_name_index ON tag(name)');
$this->requeter('CREATE INDEX cache_id_expire_index ON cache(id, expire)');
$this->requeter('INSERT INTO version (num) VALUES (1)');
}
 
/**
* Check if the database structure is ok (with the good version)
*
* @return boolean True if ok
*/
private function verifierBddStructureVersion() {
$version_ok = false;
$resultat = $this->requeter('SELECT num FROM version');
if ($resultat) {
$ligne = @sqlite_fetch_array($resultat);
if ($ligne) {
if (((int) $ligne['num']) == 1) {
$version_ok = true;
} else {
// TODO : ajouter un log CacheSqlite::verifierBddStructureVersion() : vielle version de la structure de la base de données de cache détectée => le cache est entrain d'être supprimé
}
}
}
return $version_ok;
}
 
/**
* Clean some cache records
*
* Available modes are :
* Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
* Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
* ($tags can be an array of strings or a single string)
* Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
* ($tags can be an array of strings or a single string)
*
* @param string $mode Clean mode
* @param array $tags Array of tags
* @return boolean True if no problem
*/
private function nettoyerSqlite($mode = Cache::NETTOYAGE_MODE_TOUS, $tags = array()) {
$nettoyage_ok = false;
switch ($mode) {
case Cache::NETTOYAGE_MODE_TOUS:
$suppression_cache = $this->requeter('DELETE FROM cache');
$suppression_tag = $this->requeter('DELETE FROM tag');
$nettoyage_ok = $suppression_cache && $suppression_tag;
break;
case Cache::NETTOYAGE_MODE_EXPIRATION:
$mktime = time();
$suppression_tag = $this->requeter("DELETE FROM tag WHERE id IN (SELECT id FROM cache WHERE expire > 0 AND expire <= $mktime)");
$suppression_cache = $this->requeter("DELETE FROM cache WHERE expire > 0 AND expire <= $mktime");
return $suppression_tag && $suppression_cache;
break;
case Cache::NETTOYAGE_MODE_AVEC_LES_TAGS:
$ids = $this->getIdsAvecLesTags($tags);
$resultat = true;
foreach ($ids as $id) {
$resultat = $this->supprimer($id) && $resultat;
}
return $resultat;
break;
case Cache::NETTOYAGE_MODE_SANS_LES_TAGS:
$ids = $this->getIdsSansLesTags($tags);
$resultat = true;
foreach ($ids as $id) {
$resultat = $this->supprimer($id) && $resultat;
}
return $resultat;
break;
case Cache::NETTOYAGE_MODE_AVEC_UN_TAG:
$ids = $this->getIdsAvecUnTag($tags);
$resultat = true;
foreach ($ids as $id) {
$resultat = $this->supprimer($id) && $resultat;
}
return $resultat;
break;
default:
break;
}
return $nettoyage_ok;
}
 
/**
* Check if the database structure is ok (with the good version), if no : build it
*
* @throws Zend_Cache_Exception
* @return boolean True if ok
*/
private function verifierEtCreerStructureBdd() {
if (! $this->structure_ok) {
if (! $this->verifierBddStructureVersion()) {
$this->creerStructure();
if (! $this->verifierBddStructureVersion()) {
$e = "Impossible de construire la base de données de cache dans ".$this->options['stockage_chemin'];
trigger_error($e, E_USER_WARNING);
$this->structure_ok = false;
}
}
$this->structure_ok = true;
}
return $this->structure_ok;
}
 
}
?>
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/.htaccess
New file
0,0 → 1,2
# Ce fichier est là pour éviter l'accès au fichier .ini depuis un navigateur.
deny from all
Property changes:
Added: svn:keywords
+Id Author Date Revision HeadURL
\ No newline at end of property
/tags/v0.3-aleaume/framework/.
New file
Property changes:
Added: svn:ignore
+config.ini