Subversion Repositories Applications.framework

Compare Revisions

Ignore whitespace Rev 231 → Rev 232

/trunk/framework/GestionnaireException.php
4,17 → 4,15
* Classe de gestion des exceptions.
* C'est un Singleton.
*
* PHP Version 5
* @category PHP 5.2
* @package Framework
* @author Aurélien PERONNET <aurelien@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/
*
* @category Class
* @package Framework
* @author aurelien <aurelien@tela-botanica.org>
* @copyright 2009 Tela-Botanica
* @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 GestionnaireException {
54,7 → 52,20
self::$afficher = Config::get('fw_debogage');
}
/** Renvoie le booleen définissant si l'on affiche le contexte ou non */
/**
* 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;
}
98,61 → 109,117
}
 
/**
* Renvoie les exceptions au format (X)HTML
* ou bien au format texte suivant le mode d'utilisation de PHP
* 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 = '';
foreach (self::$exceptions as $cle => $e) {
switch (self::$mode) {
case self::MODE_CLI :
$retour .= $e->getMessage()."\n";
$retour .= 'Fichier : '.$e->getFile()."\n";
$retour .= 'Ligne : '.$e->getLine()."\n";
if (self::getContexte()) {
$retour .= 'Contexte : '."\n".print_r($e->getTraceAsString(), true)."\n";
}
break;
default:
$retour .= '<div class="debogage">'."\n";
$retour .= $e->getMessage()."\n";
$retour .= '<span class="debogage_fichier">'.'Fichier : '.$e->getFile().'</span>'."\n";
$retour .= '<span class="debogage_ligne">'.'Ligne : '.$e->getLine().'</span>'."\n";
if (self::getContexte()) {
$retour .= '<pre>'."\n";
$retour .= '<strong>Contexte : </strong>'."\n".print_r($e->getTraceAsString(), true)."\n";
$retour .= '</pre>'."\n";
}
$retour .= '</div>'."\n";
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]);
}
// Nous vidons le tableau des exceptions au fur et à mesure
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($e) {
private static function loggerException(Exception $e) {
if (self::$logger) {
$erreur = '';
$erreur .= $e->getMessage()."\n";
$erreur .= 'Fichier : '.$e->getFile()."\n";
$erreur .= 'Ligne : '.$e->getLine()."\n";
if (self::getContexte()) {
$erreur .= 'Contexte : '."\n".print_r($e->getTraceAsString(), true)."\n";
}
$erreur .= "\n";
Log::ajouterEntree('erreurs', $erreur);
$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 && count(self::$exceptions) > 0) {
echo self::getExceptions();
if (self::$afficher && self::getExceptionsNbre() > 0) {
echo self::getExceptionsFormatees();
}
}
 
/trunk/framework/I18n.php
15,6 → 15,7
* @copyright 2010 Tela-Botanica
* @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/
*/
/trunk/framework/Debug.php
11,7 → 11,7
* @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 SVN : $Id$
* @version $Id$
* @link /doc/framework/
*/
class Debug {
72,7 → 72,10
/**
* 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
89,7 → 92,10
 
/**
* 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
*
/trunk/framework/Serveur.php
1,76 → 1,148
<?php
/**
* Classe principale gérant les services.
* 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
*
*
* Encodage en entrée : utf8
* Encodage en sortie : utf8
*
* @category Php 5.2
* @package JRest
* @package Framework
* @author Jean-Pascal MILCENT <jpm@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>
* @copyright 2010 Tela-Botanica
* @version $Id$
* @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>
* @version $Id$
* @link /doc/framework/
*/
// TODO : gerer les retours : dans ce controleur : code retour et envoi ...
class Serveur {
/** Nom de la méthode appelée dans un service pour éxécuter une requête de type GET. */
const METHODE_GET = 'getElement';
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 = 'getElement';
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 = 'getElement';
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 = 'getElement';
const METHODE_PUT = 'ajouter';
/** Les paramètres de configuration dynamiques internes au serveur. */
private static $config;
/** 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';
/** La méthode de la requête HTTP utilisée. */
/** 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';
/** Les paramètres de configuration dynamiques internes au serveur.
* @var array */
private static $config = array();
/** La méthode de la requête HTTP utilisée.
* @var string */
private $methode = 'GET';
 
/** Le contenu de la requête HTTP (s'il y en a). */
private $requeteDonnees = null;//requestData
/** 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.
* Généralement deux nombres séparés par un point. Ex. : 1.0
* Ex. http://www.mondomaine.org/services/[apiVersion]/monService/
* 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/[monService]/
* Ex. http://www.mondomaine.org/services/apiVersion/[mon-service]/
* @var string par défaut vaut null.
*/
private $service = null;// $ressource
private $service = null;
/** Morceaux de l'url servant à préciser la ressource concerné pour service demandé.
* Ex. http://www.mondomaine.org/services/apiVersion/monService/[maRessource/maSousResource...]
/** 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();// $uid
private $ressources = array();
/** Partie de l'url servant à paramétrer le service demandé.
* Ex. http://www.mondomaine.org/services/apiVersion/monService?monParametre1=maValeur1&monParametre2=maValeur2
/** 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();
/** Codes HTTP. */
private static $http10 = array(
'201' => 'Created',
'204' => 'No Content',
'400' => 'Bad Request',
'401' => 'Unauthorized',
'404' => 'Not Found',
'405' => 'Method Not Allowed',
'406' => 'Not Acceptable',
'411' => 'Length Required',
'500' => 'Internal Server Error'
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'
);
 
/**
79,52 → 151,16
*/
public function __construct() {
if (isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && isset($_SERVER['QUERY_STRING'])) {
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);
}
if (strlen($_SERVER['QUERY_STRING']) == 0) {
$tailleURL = strlen($_SERVER['REQUEST_URI']);
} else {
$tailleURL = -(strlen($_SERVER['QUERY_STRING']) + 1);
}
$urlString = substr($_SERVER['REQUEST_URI'], strlen(Config::get('serveur.baseURL')), $tailleURL);
 
$urlParts = explode('/', $urlString);
if (isset($urlParts[0]) && !empty($urlParts[0])) {
$this->apiVersion = $urlParts[0];
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);
}
$this->initialiserMethode();
$this->initialiserRequeteDonnees();
if (isset($urlParts[1]) && !empty($urlParts[1])) {
$this->service = $this->traiterNomService($urlParts[1]);
} 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);
}
$urlParts = $this->decouperUrlChemin();
$this->initialiserApiVersion(array_shift($urlParts));
$this->initialiserServiceNom(array_shift($urlParts));
$this->initialiserRessource($urlParts);
if (count($urlParts) > 2 && $urlParts[2] != '') {
array_shift($urlParts);
array_shift($urlParts);
foreach ($urlParts as $ressource) {
if ($ressource != '') {
$this->ressources[] = urldecode($ressource);
}
}
}
$this->nettoyerGet();
$this->parametres = $_GET;
 
$this->methode = $_SERVER['REQUEST_METHOD'];
$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 {
133,11 → 169,76
}
}
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 = substr($_SERVER['REQUEST_URI'], strlen(Config::get('serveur.baseURL')), $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", ';');
182,11 → 283,14
$this->delete();
break;
case 'PUT':
$this->add();
$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
echo GestionnaireException::getExceptions();
$this->gererErreurs();
}
 
/**
195,143 → 299,143
* database contents.
*/
private function get() {
Debug::printr($this);
$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 = "La classe '{$this->service}' ne contient pas de méthode '".self::METHODE_GET."'.";
trigger_error($e, E_USER_ERROR);
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() {
$pairs = array();
// Récupération des paramètres passés dans le contenu de la requête HTTP (= POST)
if ($this->requestData) {
$pairs = $this->parserDonneesRequete();
}
$paires = $this->parserDonneesRequete();
 
// Ajout des informations concernant l'upload de fichier passées dans la variable $_FILE
if(isset($_FILES)) {
foreach ($_FILES as $v) {
$pairs[$v['name']] = $v;
}
 
// Ne pas effacer cette ligne ! Elle est indispensable pour les services du Carnet en ligne
// qui n'utilisent que le tableau pairs dans les posts
$pairs = array_merge($pairs, $_POST);
}
 
// Gestion du contenu du post
if(isset($_POST))
{
// Safari ne sait pas envoyer des DELETE avec gwt...
// Nous utilisons le parametre "action" passé dans le POST qui doit contenir DELETE pour lancer la supression
if ($pairs['action'] == 'DELETE') {
if (count($paires) != 0) {
if (isset($paires['action']) && $paires['action'] == 'DELETE') {// Altnative à l'utilisation de DELETE
$this->delete();
return;
}
 
if (count($pairs) != 0) {
if ($this->uid) { // get a resource element
$resource_file = self::$config['settings']['servicesDir'].$this->ressource.'.php';
$resource_class = $this->ressource;
if (file_exists($resource_file)) {
include_once $resource_file;
if (class_exists($resource_class)) {
$service = new $resource_class(self::$config);
if (method_exists($service,'updateElement')) { // Update element
// TODO : a voir le retour ...
if ($service->updateElement($this->uid, $pairs)) {
$this->envoyerEnteteHttp(201);// Created
}
}
} 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 { // get all elements of a ressource
$this->add($pairs);
}
} else {
$this->envoyerEnteteHttp(411);// Length required
}
}
} else {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CONTENU_REQUIS);
}
}
 
private function delete() {
$resource_file = self::$config['settings']['servicesDir'].$this->ressource.'.php';
$resource_class = $this->ressource;
if (file_exists($resource_file)) {
include_once $resource_file;
if (class_exists($resource_class)) {
$service = new $resource_class(self::$config);
if ($this->uid) { // get a resource element
if (method_exists($service, 'deleteElement')) { // Delete element
if ($service->deleteElement($this->uid)) {
$this->envoyerEnteteHttp(204);// No Content
}
}
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 add($pairs = null) {
if (is_null($pairs)) {
$pairs = array();
// Récupération des paramètres passés dans le contenu de la requête HTTP (= POST)
// FIXME : vérifier que l'on récupère bien les données passées par PUT
if ($this->requestData) {
$pairs = $this->parserDonneesRequete();
}
}
 
if (count($pairs) != 0) {
$resource_file = self::$config['settings']['servicesDir'].$this->ressource.'.php';
$resource_class = $this->ressource;
if (file_exists($resource_file)) {
include_once $resource_file;
if (class_exists($resource_class)) {
$service = new $resource_class(self::$config);
if (method_exists($service,'createElement')) { // Create a new element
if ($service->createElement($pairs)) {
$this->envoyerEnteteHttp(201);// Created
}
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->envoyerEnteteHttp(411);// Length required
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
}
}
 
/**
* Parse les données de la requête HTTP.
* @return str[] Array of name value pairs
* 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() {
$values = array();
$pairs = explode('&', $this->requeteDonnees);
foreach ($pairs as $pair) {
$parts = explode('=', $pair);
if (isset($parts[0]) && isset($parts[1])) {
$parts[1] = rtrim(urldecode($parts[1]));
$values[$parts[0]] = $parts[1];
$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 $values;
return $donnees;
}
/**
* Envoyer un entête HTTP.
* @param int $code entier indiquant le code de l'entête http à envoyer
* 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 envoyerEnteteHttp($code) {
public static function envoyerEnteteStatutHttp($code) {
if (isset(self::$http10[$code])) {
$txt = self::$http[$code];
header("HTTP/1.0 $code $txt");
$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.
*/
public static function gererErreurs() {
if (Config::get('fw_debogage') && GestionnaireException::getExceptionsNbre() > 0) {
$exceptionsTriees = GestionnaireException::getExceptionsTriees();
reset($exceptionsTriees);
if (! (count($exceptionsTriees) == 1 && key($exceptionsTriees) == E_USER_NOTICE)) {
self::envoyerEnteteStatutHttp(self::HTTP_CODE_ERREUR);
}
foreach ($exceptionsTriees as $exceptions) {
foreach ($exceptions as $e) {
echo GestionnaireException::formaterExceptionXhtml($e);
}
}
}
}
}
?>
/trunk/framework/Framework.php
16,7 → 16,8
* @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 SVN : $Id$
* @version $Id$
* @since 0.3
* @link /doc/framework/
*/
class Framework {
/trunk/framework/Service.php
New file
0,0 → 1,84
<?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>
* @version SVN : $Id$
* @link /doc/framework/
*/
abstract class Service {
public function __construct($config) {
}
/**
* 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) {
Serveur::envoyerEnteteStatutHttp(Serveur::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) {
Serveur::envoyerEnteteStatutHttp(Serveur::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) {
Serveur::envoyerEnteteStatutHttp(Serveur::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) {
Serveur::envoyerEnteteStatutHttp(Serveur::HTTP_CODE_METHODE_NON_AUTORISE);
echo "Le service '".get_class($this)."' n'autorise pas la suppression.";
}
}
?>