/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 |
/v0.3-aleaume/framework/Registre.php |
---|
New file |
0,0 → 1,69 |
<?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 avez besoin de modifier dynamiquement des paramètres de configuration, utiliser le @see Registe, il est fait pour ça. |
* Si vous voulez paramètré votre application via le fichier config.ini, 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 |
/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 |
/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; |
} |
} |
?> |
/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 |
/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 |
/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 |
/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)); |
} |
} |
} |
} |
?> |
/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 |
/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); |
} |
} |
?> |
/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 |
/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."; |
} |
} |
?> |
/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 |
/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; |
} |
} |
/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 = "&" |
url_arg_separateur_sortie = "&" |
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 |
/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++; |
} |
} |
} |
?> |
/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 |
/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 |
/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; |
} |
} |
?> |
/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: Storage.php 20096 2010-01-06 02:05:09Z bkarwin $ |
*/ |
/** |
* 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); |
} |
/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: File.php 23161 2010-10-19 16:08:36Z matthew $ |
*/ |
/** |
* 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; |
} |
} |
} |
/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); |
} |
} |
?> |
/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; |
} |
} |
} |
?> |
/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); |
} |
} |
?> |
/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; |
} |
} |
?> |
/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 "," |
} |
?> |
/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); |
} |
} |
} |
?> |
/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(); |
} |
} |
/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; |
} |
} |
?> |
/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 |
} |
} |
} |
?> |
/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); |
} |
} |
} |
?> |
/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 |
/v0.3-aleaume/framework/. |
---|
New file |
Property changes: |
Added: svn:ignore |
+config.ini |