/branches/v1.7-oxygene/services/bibliotheque/Contexte.php |
---|
New file |
0,0 → 1,136 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Contexte permet d'encapsuler les super globales et de définir le contexte du web service courrant. |
* |
* @category DEL |
* @package Services |
* @package Bibliotheque |
* @version 0.1 |
* @author Mathias CHOUET <mathias@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @author Aurelien PERONNET <aurelien@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 1999-2014 Tela Botanica <accueil@tela-botanica.org> |
*/ |
class Contexte { |
private $conteneur; |
private $get; |
private $getBrut; |
private $post; |
private $session; |
private $cookie; |
private $server; |
private $urlRessource; |
private $mapping = array('getPhp' => 'get', |
'getQS' => 'getBrut', |
'getPost' => 'post', |
'getServer' => 'server', |
'getSession' => 'session', |
'getCookie' => 'cookie', |
'getRessource' => 'urlRessource', |
'setCookie' => 'cookie'); |
public function __construct($conteneur, &$server, &$get, &$post, &$session, &$cookie) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$this->server = $server; |
$this->get = $this->nettoyerParametres($get); |
$this->getBrut = $this->recupererParametresBruts(); |
$this->post = $post; |
$this->session = $session; |
$this->cookie = $cookie; |
$this->urlRessource = $this->decouperUrlChemin(); |
} |
public function __call($nom, $arguments) { |
if (!isset($this->mapping[$nom])) { |
$msg = "La méthode $nom n'existe pas dans l'objet {get_class()}"; |
throw new Exception($msg, RestServeur::HTTP_CODE_ERREUR); |
} |
$attributNom = $this->mapping[$nom]; |
$data = $this->$attributNom; |
if (substr($nom, 0, 3) == 'get') { |
$cle = isset($arguments[0]) ? $arguments[0] : null; |
return $this->getGenerique($data, $cle); |
} else if (substr($nom, 0, 3) == 'set') { |
$cle = isset($arguments[0]) ? $arguments[0] : null; |
$valeur = isset($arguments[1]) ? $arguments[1] : null; |
return $this->setGenerique($data, $cle, $valeur); |
} |
} |
private function getGenerique($data, $cle) { |
$retour = null; |
if ($cle === null) { |
$retour = $data; |
} else if (isset($data[$cle])) { |
$retour = $data[$cle]; |
} |
return $retour; |
} |
private function setGenerique($data, $cle, $valeur) { |
if ($valeur === null) { |
unset($data[$cle]); |
} else { |
$data[$cle] = $valeur; |
} |
} |
private function nettoyerParametres(Array $parametres) { |
// Pas besoin d'utiliser urldecode car déjà fait par php pour les clés et valeur de $_GET |
if (isset($parametres) && count($parametres) > 0) { |
foreach ($parametres as $cle => $valeur) { |
// les quotes, guillements et points-virgules ont été retirés des caractères à vérifier car |
//ça n'a plus lieu d'être maintenant que l'on utilise protéger à peu près partout |
$verifier = array('NULL', "\\", "\x00", "\x1a"); |
$parametres[$cle] = strip_tags(str_replace($verifier, '', $valeur)); |
} |
} |
return $parametres; |
} |
private function recupererParametresBruts() { |
$parametres_bruts = array(); |
if (isset($this->server['QUERY_STRING']) && !empty($this->server['QUERY_STRING'])) { |
$paires = explode('&', $this->server['QUERY_STRING']); |
foreach ($paires as $paire) { |
if ($paire != '' && substr_count($paire, '=') == 1) { |
$nv = explode('=', $paire); |
$nom = urldecode($nv[0]); |
$valeur = urldecode($nv[1]); |
$parametres_bruts[$nom] = $valeur; |
} |
} |
$parametres_bruts = $this->nettoyerParametres($parametres_bruts); |
} |
return $parametres_bruts; |
} |
private function decouperUrlChemin() { |
if (isset($this->server['REDIRECT_URL']) && $this->server['REDIRECT_URL'] != '') { |
if (isset($this->server['REDIRECT_QUERY_STRING']) && !empty($this->server['REDIRECT_QUERY_STRING'])) { |
$url = $this->server['REDIRECT_URL'].'?'.$this->server['REDIRECT_QUERY_STRING']; |
} else { |
$url = $this->server['REDIRECT_URL']; |
} |
} else { |
$url = $this->server['REQUEST_URI']; |
} |
$tailleQueryString = strlen($this->server['QUERY_STRING']); |
$tailleURL = ($tailleQueryString == 0) ? strlen($url) : -($tailleQueryString + 1); |
$urlChaine = ''; |
if (strpos($url, $this->conteneur->getParametre('serveur.baseURL')) !== false) { |
$urlChaine = substr($url, strlen($this->conteneur->getParametre('serveur.baseURL')), $tailleURL); |
} else if (strpos($url, $this->conteneur->getParametre('serveur.baseAlternativeURL')) !== false) { |
$urlChaine = substr($url, strlen($this->conteneur->getParametre('serveur.baseAlternativeURL')), $tailleURL); |
} |
return explode('/', $urlChaine); |
} |
} |
Property changes: |
Added: svnkit:entry:sha1-checksum |
+16702488d5977ffc5aaaf3430bb115a5487d24c5 |
\ No newline at end of property |
/branches/v1.7-oxygene/services/bibliotheque/ReponseHttp.php |
---|
New file |
0,0 → 1,80 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Classe créant la réponse HTTP pour les services de DEL. |
* |
* Vérifie qu'aucune erreur n'a été générée. Si une erreur existe, retourne le contenu de l'erreur. |
* |
* @category DEL |
* @package Services |
* @package Bibliotheque |
* @version 0.1 |
* @author Mathias CHOUET <mathias@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @author Aurelien PERONNET <aurelien@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 1999-2014 Tela Botanica <accueil@tela-botanica.org> |
*/ |
class ReponseHttp { |
private $resultatService = null; |
private $erreurs = array(); |
public function __construct() { |
$this->resultatService = new ResultatService(); |
} |
public function setResultatService($resultat) { |
if (!($resultat instanceof ResultatService)) { |
$this->resultatService->corps = $resultat; |
} else { |
$this->resultatService = $resultat; |
} |
} |
public function getCorps() { |
if ($this->etreEnErreur()) { |
foreach ($this->erreurs as $erreur) { |
$this->resultatService->corps .= $erreur['message']."\n"; |
} |
} else { |
$this->transformerReponseCorpsSuivantMime(); |
} |
return $this->resultatService->corps; |
} |
public function ajouterErreur(Exception $e) { |
$this->erreurs[] = array('entete' => $e->getCode(), 'message' => $e->getMessage()); |
} |
public function emettreLesEntetes() { |
$enteteHttp = new EnteteHttp(); |
if ($this->etreEnErreur()) { |
$enteteHttp->code = $this->erreurs[0]['entete']; |
$enteteHttp->mime = 'text/html'; |
} else { |
$enteteHttp->encodage = $this->resultatService->encodage; |
$enteteHttp->mime = $this->resultatService->mime; |
} |
header("Content-Type: $enteteHttp->mime; charset=$enteteHttp->encodage"); |
RestServeur::envoyerEnteteStatutHttp($enteteHttp->code); |
} |
private function etreEnErreur() { |
$enErreur = false; |
if (count($this->erreurs) > 0) { |
$enErreur = true; |
} |
return $enErreur; |
} |
private function transformerReponseCorpsSuivantMime() { |
switch ($this->resultatService->mime) { |
case 'application/json' : |
$this->resultatService->corps = json_encode($this->resultatService->corps); |
break; |
} |
} |
} |
/branches/v1.7-oxygene/services/bibliotheque/Navigation.php |
---|
New file |
0,0 → 1,204 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Navigation gère les url de navigation en fonction d'un départ et d'une limite |
* |
* @category DEL |
* @package Services |
* @package Bibliotheque |
* @version 0.1 |
* @author Mathias CHOUET <mathias@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @author Aurelien PERONNET <aurelien@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 1999-2014 Tela Botanica <accueil@tela-botanica.org> |
*/ |
class Navigation { |
private $conteneur; |
private $parametresUrl; |
private $ressourcesUrl; |
private $serviceNom; |
private $filtresPossibles; |
private $filtresActifs; |
private $total; |
private $sansLimite; |
/** |
* Constructeur de la classe Navigation |
* @param Array $parametresUrl (optionnel) la liste des paramètre issus du Conteneur |
*/ |
public function __construct($conteneur) { |
$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur; |
$contexte = $this->conteneur->getContexte(); |
$this->parametresUrl = $contexte->getQS(); |
$this->serviceNom = $contexte->getRessource(1); |
$ressources = $contexte->getRessource(); |
$this->ressourcesUrl = implode('/', array_slice($ressources, 1)); |
$this->filtresPossibles = $this->conteneur->getparametreTableau($this->serviceNom.'.masques_possibles'); |
$this->chargerFiltresActifs(); |
} |
private function chargerFiltresActifs() { |
if ($this->parametresUrl != null) { |
foreach ($this->parametresUrl as $paramNom => $valeur) { |
if (in_array($paramNom, $this->filtresPossibles)) { |
$this->filtresActifs[$paramNom] = $valeur; |
} |
} |
} |
} |
/** |
* Obtenir la valeur courante de départ |
*/ |
public function getDepart() { |
$navDepart = $this->getParamUrl('navigation.depart'); |
return ($navDepart == null) ? 0 : $navDepart ; |
} |
/** |
* Obtenir la limite courante |
*/ |
public function getLimite() { |
$limiteParam = $this->getParamUrl('navigation.limite'); |
$limite = 10; |
if ($limiteParam != null && is_numeric($limiteParam)) { |
$limite = ($limiteParam < 1000) ? $limiteParam : 1000;// Pour éviter les abus ! |
} |
return $limite; |
} |
private function getParamUrl($nom) { |
$valeur = isset($this->parametresUrl[$nom]) ? $this->parametresUrl[$nom] : null; |
return $valeur; |
} |
/** |
* Récupérer l'url de navigation en concaténant d'éventuels paramètres |
* @param $depart l'entier de départ de la recherche |
* @param $limite le nombre de résultats à retourner |
* @param $parametresAdditionnels le tableau contenant les parametres => valeurs additionnels |
*/ |
private function obtenirUrlNavigation($depart, $limite) { |
$parametres = $this->parametresUrl; |
$parametres['navigation.depart'] = $depart; |
$parametres['navigation.limite'] = $limite; |
$urlServiceBase = $this->conteneur->getParametre('url_service_base').$this->ressourcesUrl; |
$urlNavigation = $this->conteneur->getUrl($urlServiceBase); |
$urlNavigation->setOption(Url::OPTION_ENCODER_VALEURS, true); |
$urlNavigation->setRequete($parametres); |
$url = $urlNavigation->getURL(); |
return $url; |
} |
/** |
* Récupérer le lien pour afficher les images précédentes en fonction des paramètres |
*/ |
public function recupererHrefPrecedent() { |
$departActuel = $this->getDepart(); |
$limite = $this->getLimite(); |
$departPrecedent = $departActuel - $limite; |
$url = null; |
if ($departActuel > 0) { |
$url = $this->obtenirUrlNavigation($departPrecedent, $limite); |
} |
return $url; |
} |
/** |
* Récupérer le lien pour afficher les images suivantes en fonction des paramètres |
*/ |
public function recupererHrefSuivant() { |
$departActuel = $this->getDepart(); |
$limite = $this->getLimite(); |
$departSuivant = $departActuel + $limite; |
$url = null; |
if ($departSuivant < $this->total) { |
$url = $this->obtenirUrlNavigation($departSuivant, $limite); |
} |
return $url; |
} |
/** |
* Retourner le nombre total d'éléments |
*/ |
public function getTotal() { |
return $this->total; |
} |
/** |
* Enregistrer le nombre total d'éléments |
* @param int $total le nombre d'éléments |
*/ |
public function setTotal($total) { |
$this->total = $total; |
} |
/** |
* Changer la valeur de sans limite pour ne pas l'afficher dans l'entete |
* */ |
public function setSansLimite() { |
$this->sansLimite = true; |
} |
/** |
* Génère un tableau contenant les informations pour l'entête des services renvoyant une liste de résultats. |
* |
* @return array Le tableau d'entête prés à être encodé en JSON. |
*/ |
public function getEntete() { |
$entete = array(); |
$entete['masque'] = $this->getChaineFiltresActifs(); |
$entete['total'] = $this->getTotal(); |
if ($this->sansLimite == false) { |
$entete['depart'] = (int) $this->getDepart(); |
$entete['limite'] = (int) $this->getLimite(); |
$lienPrecedent = $this->recupererHrefPrecedent(); |
if ($lienPrecedent != null) { |
$entete['href.precedent'] = $lienPrecedent; |
} |
$lienSuivant = $this->recupererHrefSuivant(); |
if ($lienSuivant != null) { |
$entete['href.suivant'] = $lienSuivant; |
} |
} |
return $entete; |
} |
/** |
* Retourne les filtres au format chaine sous la forme filtre1=valeur1&filtre2=valeur2. |
* |
* @return String la chaine de caractères ou une chaine vide si pas de filtre. |
*/ |
private function getChaineFiltresActifs() { |
return (!empty($this->filtresActifs)) ? http_build_query($this->filtresActifs) : ''; |
} |
/** |
* Récupérer tout ou partie des filtres présent dans l'url. |
* |
* @param String $filtreNom (optionnel) le nom du filtre tel que présent dans l'url. |
* @return mixed si un filtre est passé en paramètre retourn la valeur correspondante, si pas de paramétre |
* retourne le tableau complet des filtres. False en cas d'erreur. |
* */ |
public function getFiltre($filtreNom = null) { |
$retour = false; |
if ($filtreNom == null) { |
$retour = $this->filtresActifs; |
} else if ($filtreNom != null && isset($this->filtresActifs[$filtreNom])) { |
$retour = $this->filtresActifs[$filtreNom]; |
} |
return $retour; |
} |
} |
Property changes: |
Added: svnkit:entry:sha1-checksum |
+c6e827965fa2b8632258e19c6a4f96069d43d7a7 |
\ No newline at end of property |
/branches/v1.7-oxygene/services/bibliotheque/Sql.php |
---|
New file |
0,0 → 1,733 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Classe contenant des méthodes permettant de construire les requêtes SQL complexe concernant les images et obs. |
* Rempli un tableau des clauses "join", "where", "group by" et "oder by" nécessaire à la *recherche* des ids des |
* observations/images correspondantes aux filtres passés dans l'url du web service de recherche |
* (ListeImages et ListeObservations). |
* |
* Attention, cela signifie que toutes les tables ne sont pas *forcément* jointées, par exemple si aucune |
* contrainte ne le nécessite. |
* La requête construite ici est utile pour récupérer la liste des ids d'observations/images qui match. |
* Pour la récupération effective de "toutes" les données nécessaire au retour du web service en json, c'est une autre |
* requête directement dans le web service qui s'en charge. Cette technique en deux étapes est la plus rapide ! |
* |
* Note: toujours rajouter les préfixes de table (di, do ou du), en fonction de ce que défini |
* les JOIN qui sont utilisés : |
* - le préfix de del_image est "di" |
* - le préfix de del_observation est "do" |
* - le préfix de del_utilisateur est "du" |
* |
* @category DEL |
* @package Services |
* @package Bibliotheque |
* @version 0.1 |
* @author Mathias CHOUET <mathias@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @author Aurelien PERONNET <aurelien@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 1999-2014 Tela Botanica <accueil@tela-botanica.org> |
*/ |
class Sql { |
const APPLI_IMG = 'IMG'; |
const APPLI_OBS = 'OBS'; |
private $conteneur; |
private $bdd; |
private $parametres = array(); |
private $appli; |
private $requete = array( |
'join' => array(), |
'where' => array(), |
'groupby' => array(), |
'orderby' => array()); |
private $champsPrenom = array('du.prenom', 'prenom_utilisateur'); |
private $champsNom = array('du.nom', 'nom_utilisateur'); |
private $champsSousRequeteObs = array('masque.genre', 'masque.famille', 'masque.ns', 'masque.commune', 'masque.milieu', 'masque.pays'); |
public function __construct(Conteneur $conteneur) { |
$this->conteneur = $conteneur; |
$this->bdd = $this->conteneur->getBdd(); |
} |
public function setParametres(Array $parametres) { |
$this->parametres = $parametres; |
} |
public function setAppli($appliType) { |
if ($appliType == 'IMG' || $appliType == 'OBS') { |
$this->appli = $appliType; |
} else { |
throw new Exception("Les types d'appli disponible sont : IMG (pour PictoFlora) et OBS (pour IdentiPlante)"); |
} |
} |
private function getPrefixe() { |
return $this->appli === 'IMG' ? 'di' : 'do'; |
} |
private function etreAppliImg() { |
return $this->appli === 'IMG' ? true : false; |
} |
private function etreAppliObs() { |
return $this->appli === 'OBS' ? true : false; |
} |
public function getRequeteSql() { |
return $this->requete; |
} |
private function addJoin($join) { |
if (!isset($this->requete['join'][$join])) { |
$this->requete['join'][$join] = $join; |
} |
} |
public function getJoin() { |
return ($this->requete['join'] ? implode(' ', array_unique($this->requete['join'])).' ' : ''); |
} |
private function addJoinDis($join) { |
$this->requete['join']['dis'] = $join; |
} |
private function addWhere($idParam, $where) { |
if (isset($this->parametres['_parametres_condition_or_']) |
&& in_array($idParam, $this->parametres['_parametres_condition_or_'])) { |
if ($this->etreAppliImg() && in_array($idParam, $this->champsSousRequeteObs)) { |
$this->requete['where']['OR_SOUS_REQUETE'][] = $where; |
} else { |
$this->requete['where']['OR'][] = $where; |
} |
} else { |
$this->requete['where']['AND'][] = $where; |
} |
} |
public function getWhere() { |
// Sous-requete spéciale pour éviter de rechercher dans la table obs jointe à img depuis Pictoflora... |
if (isset($this->requete['where']['OR_SOUS_REQUETE']) && count($this->requete['where']['OR_SOUS_REQUETE']) > 0) { |
$clauseWhereSousRequete = implode(' OR ', $this->requete['where']['OR_SOUS_REQUETE']); |
$sousRequete = 'di.ce_observation IN '. |
"(SELECT id_observation FROM del_observation AS do WHERE $clauseWhereSousRequete ) "; |
$this->requete['where']['OR'][] = "( $sousRequete )"; |
unset($this->requete['join']['LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) ']); |
} |
if (isset($this->requete['where']['OR']) && count($this->requete['where']['OR']) > 0) { |
$this->requete['where']['AND'][] = '('.implode(' OR ', $this->requete['where']['OR']).')'; |
} |
$where = ' TRUE '; |
if (isset($this->requete['where']['AND']) && count($this->requete['where']['AND']) > 0) { |
$where = implode(' AND ', $this->requete['where']['AND']).' '; |
} |
return $where; |
} |
private function addGroupBy($groupBy) { |
$this->requete['groupby'][] = $groupBy; |
} |
public function getGroupBy() { |
$groupby = ''; |
if (isset($this->requete['groupby']) && count($this->requete['groupby']) > 0) { |
$groupby = 'GROUP BY '.implode(', ', array_unique($this->requete['groupby'])).' '; |
} |
return $groupby; |
} |
private function addOrderBy($orderby) { |
$this->requete['orderby'][] = $orderby; |
} |
public function getOrderBy() { |
$orderby = ''; |
if (isset($this->requete['orderby']) && count($this->requete['orderby']) > 0) { |
$orderby = 'ORDER BY '.implode(', ', array_unique($this->requete['orderby'])).' '; |
} |
return $orderby; |
} |
public function getLimit() { |
return 'LIMIT '.$this->parametres['navigation.depart'].','.$this->parametres['navigation.limite'].' '; |
} |
/** |
* |
* @param $p les paramètres (notamment de masque) passés par l'URL et déjà traités/filtrés (sauf quotes) |
* @param $req le tableau, passé par référence représentant les composants de la requête à bâtir |
*/ |
public function ajouterContraintes() { |
$this->ajouterContrainteAuteur(); |
$this->ajouterContrainteDate(); |
$this->ajouterContraintePays(); |
$this->ajouterContrainteDepartement(); |
$this->ajouterContrainteIdZoneGeo(); |
$this->ajouterContrainteGenre(); |
$this->ajouterContrainteFamille(); |
$this->ajouterContrainteNs(); |
$this->ajouterContrainteNn(); |
$this->ajouterContrainteReferentiel(); |
$this->ajouterContrainteCommune(); |
} |
private function ajouterContrainteAuteur() { |
if (isset($this->parametres['masque.auteur'])) { |
$auteur = $this->parametres['masque.auteur']; |
// id du poster de l'obs |
$prefixe = $this->getPrefixe(); |
$this->addJoin("LEFT JOIN del_utilisateur AS du ON (du.id_utilisateur = $prefixe.ce_utilisateur) "); |
if (is_numeric($auteur)) { |
$this->ajouterContrainteAuteurId(); |
} elseif(preg_match('/@[a-z0-9-]+(?:\.[a-z0-9-]+)*\.[a-z]{2,}$/i', $auteur)) { |
$this->ajouterContrainteAuteurEmail(); |
} else { |
$this->ajouterContrainteAuteurIntitule(); |
} |
} |
} |
private function ajouterContrainteAuteurId() { |
$id = $this->parametres['masque.auteur']; |
$prefixe = $this->getPrefixe(); |
$sqlTpl = "(du.id_utilisateur = %1\$d OR $prefixe.ce_utilisateur = %1\$d)"; |
$whereAuteur = sprintf($sqlTpl, $id); |
$this->addWhere('masque.auteur', $whereAuteur); |
} |
private function ajouterContrainteAuteurEmail() { |
$email = $this->parametres['masque.auteur']; |
$prefixe = $this->getPrefixe(); |
$sqlTpl = "(du.courriel LIKE %1\$s OR $prefixe.courriel_utilisateur LIKE %1\$s )"; |
$emailP = $this->bdd->proteger("$email%"); |
$whereAuteur = sprintf($sqlTpl, $emailP); |
$this->addWhere('masque.auteur', $whereAuteur); |
} |
/** |
* Retourne une clause where du style: |
* CONCAT(IF(du.prenom IS NULL, "", du.prenom), [...] vdi.i_nomutilisateur) REGEXP 'xxx' |
*/ |
private function ajouterContrainteAuteurIntitule() { |
$auteurExplode = explode(' ', $this->parametres['masque.auteur']); |
$nbreMots = count($auteurExplode); |
if ($nbreMots == 1) { |
$this->ajouterContrainteAuteurPrenomOuNom(); |
} else if ($nbreMots == 2) { |
$this->ajouterContrainteAuteurPrenomEtNom(); |
} |
} |
private function ajouterContrainteAuteurPrenomOuNom() { |
$prenomOuNom = $this->parametres['masque.auteur']; |
$sqlTpl = 'CONCAT(%s,%s) LIKE %s'; |
$prefixe = $this->getPrefixe(); |
$champsPrenomSql = self::ajouterIfNullPourConcat($this->champsPrenom, $prefixe); |
$champsNomSql = self::ajouterIfNullPourConcat($this->champsNom, $prefixe); |
$auteurMotif = $this->bdd->proteger("%$prenomOuNom%"); |
$auteurWhere = sprintf($sqlTpl, $champsPrenomSql, $champsNomSql, $auteurMotif); |
$this->addWhere('masque.auteur', $auteurWhere); |
} |
private function ajouterContrainteAuteurPrenomEtNom() { |
list($prenom, $nom) = explode(' ', $this->parametres['masque.auteur']); |
$sqlTpl = '(CONCAT(%1$s,%2$s) LIKE %3$s AND CONCAT(%1$s,%2$s) LIKE %4$s)'; |
$prefixe = $this->getPrefixe(); |
$champsPrenomSql = self::ajouterIfNullPourConcat($this->champsPrenom, $prefixe); |
$champsNomSql = self::ajouterIfNullPourConcat($this->champsNom, $prefixe); |
$prenomMotif = $this->bdd->proteger("%$prenom%"); |
$nomMotif = $this->bdd->proteger("%$nom%"); |
$auteurWhere = sprintf($sqlTpl, $champsPrenomSql, $champsNomSql, $prenomMotif, $nomMotif); |
$this->addWhere('masque.auteur', $auteurWhere); |
} |
/** |
* Lorsque l'on concatène des champs, un seul NULL prend le dessus. |
* Il faut donc utiliser la syntaxe IFNULL(%s, ""). |
* Cette fonction effectue aussi l'implode() "final". |
*/ |
private static function ajouterIfNullPourConcat($champs, $prefixe) { |
$champsProteges = array(); |
foreach ($champs as $champ) { |
if (strstr($champ, '.') === false) { |
$champ = "$prefixe.$champ"; |
} |
$champsProteges[] = "IFNULL($champ, '')"; |
} |
return implode(',', $champsProteges); |
} |
private function ajouterContrainteDate() { |
if (isset($this->parametres['masque.date'])) { |
$date = $this->parametres['masque.date']; |
if (preg_match('/^\d{4}$/', $date) && $date < 2030 && $date > 1600) { |
$sqlTpl = "YEAR(do.date_observation) = %d"; |
$dateWhere = sprintf($sqlTpl, $date); |
$this->addWhere('masque.date', $dateWhere); |
} else { |
$sqlTpl = "do.date_observation = %s"; |
$dateP = $this->bdd->proteger($date); |
$dateWhere = sprintf($sqlTpl, $dateP); |
$this->addWhere('masque.date', $dateWhere); |
} |
if ($this->etreAppliImg()) { |
$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) '); |
} |
} |
} |
private function ajouterContrainteDepartement() { |
if (isset($this->parametres['masque.departement'])) { |
$dept = $this->parametres['masque.departement']; |
$deptMotif = $this->bdd->proteger("INSEE-C:$dept"); |
$this->addWhere('masque.departement', "do.ce_zone_geo LIKE $deptMotif"); |
if ($this->etreAppliImg()) { |
$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) '); |
} |
} |
} |
private function ajouterContraintePays() { |
if (isset($this->parametres['masque.pays'])) { |
// Attention le standard contient parfois FX pour la france métropolitaine |
// Dans ce cas particulier on cherche donc FR et FX |
$this->parametres['masque.pays'] = strtoupper($this->parametres['masque.pays']); |
if(strpos($this->parametres['masque.pays'], 'FR') !== false) { |
$this->parametres['masque.pays'] = str_replace('FR', 'FR,FX', $this->parametres['masque.pays']); |
} |
$pays = explode(',', $this->parametres['masque.pays']); |
$pays = implode(',', $this->bdd->proteger($pays)); |
$this->addWhere('masque.pays', "do.pays IN ($pays)"); |
if ($this->etreAppliImg()) { |
$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) '); |
} |
} |
} |
private function ajouterContrainteIdZoneGeo() { |
if (isset($this->parametres['masque.id_zone_geo'])) { |
$idZgMotif = $this->bdd->proteger($this->parametres['masque.id_zone_geo']); |
$this->addWhere('masque.id_zone_geo', "do.ce_zone_geo = $idZgMotif"); |
if ($this->etreAppliImg()) { |
$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) '); |
} |
} |
} |
private function ajouterContrainteGenre() { |
if (isset($this->parametres['masque.genre'])) { |
$genre = $this->parametres['masque.genre']; |
$genreMotif = $this->bdd->proteger("%$genre% %"); |
$this->addWhere('masque.genre', "do.nom_sel LIKE $genreMotif"); |
if ($this->etreAppliImg()) { |
$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) '); |
} |
} |
} |
private function ajouterContrainteFamille() { |
if (isset($this->parametres['masque.famille'])) { |
$familleMotif = $this->bdd->proteger($this->parametres['masque.famille']); |
$this->addWhere('masque.famille', "do.famille = $familleMotif"); |
if ($this->etreAppliImg()) { |
$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) '); |
} |
} |
} |
private function ajouterContrainteNs() { |
if (isset($this->parametres['masque.ns'])) { |
$ns = $this->parametres['masque.ns']; |
$nsMotif = $this->bdd->proteger("$ns%"); |
$this->addWhere('masque.ns', "do.nom_sel LIKE $nsMotif"); |
if ($this->etreAppliImg()) { |
$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) '); |
} |
} |
} |
private function ajouterContrainteNn() { |
if (isset($this->parametres['masque.nn'])) { |
$sqlTpl = '(do.nom_sel_nn = %1$d OR do.nom_ret_nn = %1$d)'; |
$nnWhere = sprintf($sqlTpl, $this->parametres['masque.nn']); |
$this->addWhere('masque.nn', $nnWhere); |
if ($this->etreAppliImg()) { |
$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) '); |
} |
} |
} |
private function ajouterContrainteReferentiel() { |
if (isset($this->parametres['masque.referentiel'])) { |
$ref = $this->parametres['masque.referentiel']; |
$refMotif = $this->bdd->proteger("$ref%"); |
$this->addWhere('masque.referentiel', "do.nom_referentiel LIKE $refMotif"); |
if ($this->etreAppliImg()) { |
$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) '); |
} |
} |
} |
private function ajouterContrainteCommune() { |
if (isset($this->parametres['masque.commune'])) { |
$commune = $this->parametres['masque.commune']; |
$communeMotif = $this->bdd->proteger("$commune%"); |
$this->addWhere('masque.commune', "do.zone_geo LIKE $communeMotif"); |
if ($this->etreAppliImg()) { |
$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) '); |
} |
} |
} |
public function ajouterConstrainteAppliObs() { |
$this->ajouterContrainteTagCel(); |
$this->ajouterContrainteType(); |
// TODO : ATTENTION -> vue que l'on utilise une vue basée sur les images, nous devons grouper par obs |
$this->addGroupBy('do.id_observation'); |
} |
private function ajouterContrainteType() { |
// Les contraintes régissant les onglets sont issus de la réunion dont le compte rendu |
// disponible ici : http://tela-botanica.net/intranet/wakka.php?wiki=Octobre2014 |
// Ce lien est à modifier pour pointer vers toute nouvelle réunion modifiant ce fonctionnement |
if (isset($this->parametres['masque.type'])) { |
if (array_key_exists('adeterminer', $this->parametres['masque.type'])) { |
// A DETERMINER : toutes les observations qui ont le tag "aDeterminer" |
// *ou* qui n'ont pas de nom d'espèce |
// *ou* qui ont la "certitude" à ("aDeterminer" *ou* "douteux") |
$this->addWhere('masque.type', '('. |
'do.certitude = "aDeterminer" '. |
'OR do.certitude = "douteux" '. |
'OR do.mots_cles_texte LIKE "%aDeterminer%" '. |
'OR do.nom_sel_nn IS NULL '. |
'OR do.nom_sel_nn = 0 '.// il ne DEVRAIT pas y avoir d'entrées à 0, mais il y en a quand-même !! |
')'); |
} |
if (array_key_exists('validees', $this->parametres['masque.type'])) { |
// VALIDEES : toutes les observations ayant un commentaire doté de proposition_retenue = 1 |
// ou bien possédant une proposition initiale avec un nom valide ayant totalisé un score d'au moins 4 |
// (ce qui correspond à au moins deux votes positifs dans la plupart des cas, dont un identifié) |
$sous_requete_score_prop_votees = $this->getSousRequeteSommeVotesPropositions(); |
$this->addJoin('INNER JOIN del_commentaire AS dc '. |
'ON ( '. |
'do.id_observation = dc.ce_observation '. |
'AND ( '. |
'dc.proposition_retenue = 1 OR '. |
'( '. |
'dc.proposition_initiale = 1 '. |
'AND dc.nom_sel_nn != 0 '. |
'AND dc.nom_sel_nn IS NOT NULL '. |
' AND dc.id_commentaire IN ('.$sous_requete_score_prop_votees.' >= 4) '. |
') '. |
') '. |
')' |
); |
} |
if(array_key_exists('aconfirmer', $this->parametres['masque.type'])) { |
// A CONFIRMER : toutes les observations moins les validées et à confirmer |
// i.e. : des observations avec un nom valide, qui ne sont pas à déterminer |
// (ni certitude "aDeterminer" ou "douteuse", ni mot clé), |
// ne possédant pas de proposition officiellement retenue |
// et ayant une proposition initiale totalisant un score de moins de 4 |
$sous_requete_score_prop_votees = $this->getSousRequeteSommeVotesPropositions(); |
$this->addWhere('masque.type', |
'('. |
'do.id_observation IN ('. |
'SELECT dc.ce_observation FROM del_commentaire dc WHERE dc.proposition_retenue = 0'. |
' AND ( '. |
'dc.proposition_initiale = 1 '. |
'AND dc.nom_sel_nn != 0 '. |
'AND dc.nom_sel_nn IS NOT NULL '. |
'AND dc.id_commentaire IN ('.$sous_requete_score_prop_votees.' < 4) '. |
') '. |
') AND do.id_observation NOT IN ('. |
'SELECT dc.ce_observation FROM del_commentaire dc '. |
'WHERE '. |
' dc.proposition_retenue = 1'. |
') '. |
'AND do.certitude != "douteux" AND do.certitude != "aDeterminer" '. |
'AND do.mots_cles_texte NOT LIKE "%aDeterminer%" '. |
'AND do.nom_sel_nn != 0 '. |
'AND do.nom_sel_nn IS NOT NULL'. |
') ' |
); |
} |
if ($this->etreAppliImg()) { |
$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) '); |
} |
} |
} |
private function getSousRequeteSommeVotesPropositions() { |
// ATTENTION : un vote identifié compte 3 votes anonymes (dans les deux sens) |
return 'SELECT ce_proposition '. |
'FROM del_commentaire_vote dcv '. |
'GROUP BY ce_proposition HAVING '. |
'SUM(CASE '. |
' WHEN valeur = 1 AND dcv.ce_utilisateur REGEXP \'^-?[0-9]+$\' != 0 THEN 3 '. |
' WHEN valeur = 0 AND dcv.ce_utilisateur REGEXP \'^-?[0-9]+$\' != 0 THEN -3 '. |
' WHEN valeur = 1 AND dcv.ce_utilisateur REGEXP \'^-?[0-9]+$\' = 0 THEN 1 '. |
' WHEN valeur = 0 AND dcv.ce_utilisateur REGEXP \'^-?[0-9]+$\' = 0 THEN -1 '. |
'END '. |
') '; |
} |
public function ajouterConstrainteAppliImg() { |
$this->ajouterContrainteMilieu(); |
$this->ajouterContrainteTri(); |
$this->ajouterContrainteTagCel(); |
$this->ajouterContrainteTagDel(); |
} |
private function ajouterContrainteMilieu() { |
if (isset($this->parametres['masque.milieu'])) { |
$milieu = $this->parametres['masque.milieu']; |
$milieuMotif = $this->bdd->proteger("%$milieu%"); |
$this->addWhere('masque.milieu', "do.milieu LIKE $milieuMotif"); |
if ($this->etreAppliImg()) { |
$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) '); |
} |
} |
} |
private function ajouterContrainteTri() { |
if (isset($this->parametres['tri'])) { |
$tri = $this->parametres['tri']; |
if (isset($this->parametres['protocole']) && ($tri == 'moyenne-arithmetique' || $tri == 'points')) { |
// $this->parametres['protocole'] *est* défini (cf Outils::filtrerUrlsParams...()) |
$sqlTpl = 'LEFT JOIN del_image_stat AS dis ON di.id_image = dis.ce_image AND dis.ce_protocole = %d'; |
$triSql = sprintf($sqlTpl, $this->parametres['protocole']); |
$this->addJoinDis($triSql); |
} |
if (isset($this->parametres['ordre']) && $tri == 'tags') { |
$typeJointure = ($this->parametres['ordre'] == 'desc') ? 'INNER' : 'LEFT'; |
$this->addJoin("$typeJointure JOIN del_image_stat AS dis ON di.id_image = dis.ce_image"); |
} |
} |
} |
private function ajouterContrainteTagCel() { |
if (isset($this->parametres['masque.tag_cel'])) { |
if (isset($this->parametres['masque.tag_cel']['AND'])) { |
$tags = $this->parametres['masque.tag_cel']['AND']; |
$clausesWhere = array(); |
foreach ($tags as $tag) { |
$tagMotif = $this->bdd->proteger("%$tag%"); |
if ($this->etreAppliImg()) { |
$sousRequete = 'SELECT id_observation '. |
'FROM del_observation '. |
"WHERE mots_cles_texte LIKE $tagMotif "; |
$sql = " (di.mots_cles_texte LIKE $tagMotif OR di.id_image IN ($sousRequete) ) "; |
} else { |
// WARNING : la sous-requête est la meilleure solution trouvée pour contrer le fonctionnement |
// étrange de l'optimiseur de MYSQL 5.6 (à retester avec Mysql 5.7 et suivant). |
$sousRequete = 'SELECT DISTINCT ce_observation '. |
'FROM del_image '. |
"WHERE mots_cles_texte LIKE $tagMotif ". |
'AND ce_observation IS NOT NULL'; |
$sql = " (do.mots_cles_texte LIKE $tagMotif OR do.id_observation IN ($sousRequete)) "; |
} |
$clausesWhere[] = $sql; |
} |
$whereTags = implode(' AND ', $clausesWhere); |
$this->addWhere('masque.tag_cel', "($whereTags)"); |
} else if (isset($this->parametres['masque.tag_cel']['OR'])) { |
$tags = $this->parametres['masque.tag_cel']['OR']; |
$tagMotif = $this->bdd->proteger(implode('|', $tags)); |
$sqlTpl = "CONCAT(IFNULL(do.mots_cles_texte,''),IFNULL(di.mots_cles_texte,'')) REGEXP %s"; |
$tagSql = sprintf($sqlTpl, $tagMotif); |
$this->addWhere('masque.tag_cel', $tagSql); |
if ($this->etreAppliObs()) { |
$this->addJoin('LEFT JOIN del_image AS di ON (di.ce_observation = do.id_observation) '); |
} |
} |
if ($this->etreAppliImg()) { |
$this->addJoin('LEFT JOIN del_observation AS do ON (di.ce_observation = do.id_observation) '); |
} |
} |
} |
/** |
* Plusieurs solutions sont disponibles dans les anciennes versions (voir DelTk et l'historique SVN de ce fichier). |
*/ |
private function ajouterContrainteTagDel() { |
if (isset($this->parametres['masque.tag_del'])) { |
$tagsMotif = $this->construireTagsMotif(); |
if (is_null($tagsMotif) === false) { |
$sousRequete = 'SELECT ce_image '. |
'FROM del_image_tag '. |
'WHERE actif = 1 '. |
'GROUP BY ce_image '. |
"HAVING GROUP_CONCAT(DISTINCT tag_normalise ORDER BY tag_normalise) REGEXP $tagsMotif "; |
$this->addWhere('masque.tag_del', "di.id_image IN ($sousRequete)"); |
} |
} |
} |
private function construireTagsMotif() { |
$tagsMotif = null; |
if (isset($this->parametres['masque.tag_del']['AND'])) { |
$tags = $this->parametres['masque.tag_del']['AND']; |
// ATTENTION -> optimisation: en cas de "AND" on sort() l'input et le GROUP_CONCAT() |
// donc nous utilisons des ".*" plutôt que de multiples conditions et "|" |
sort($tags); |
$tagsMotif = $this->bdd->proteger(implode('.*', $tags)); |
} else if (isset($this->parametres['masque.tag_del']['OR'])) { |
$tags = $this->parametres['masque.tag_del']['OR']; |
$tagsMotif = $this->bdd->proteger(implode('|', $tags)); |
} |
return $tagsMotif; |
} |
/** |
* Partie spécifique à PictoFlora: |
* Attention : si le critère de tri n'est pas suffisant, les résultats affichés peuvent varier à chaque appel |
* de la même page de résultat de PictoFlora. |
*/ |
public function definirOrdreSqlAppliImg() { |
$ordre = $this->parametres['ordre']; |
$tri = isset($this->parametres['tri']) ? $this->parametres['tri'] : ''; |
switch ($tri) { |
case 'moyenne-arithmetique' : |
$this->addOrderBy("dis.moyenne $ordre, dis.nb_votes $ordre, id_image $ordre"); |
break; |
case 'points' : |
$this->addOrderBy("dis.nb_points $ordre, dis.moyenne $ordre, dis.nb_votes $ordre, id_image $ordre"); |
break; |
case 'tags' : |
$this->addOrderBy("dis.nb_tags $ordre, id_image $ordre"); |
break; |
case 'date_observation' : |
$this->addOrderBy("date_observation $ordre, ce_observation $ordre"); |
break; |
case 'date_transmission' : |
default: |
$this->addOrderBy("di.date_transmission $ordre, ce_observation $ordre"); |
} |
} |
public function definirOrdreSqlAppliObs() { |
$ordre = $this->parametres['ordre']; |
// parmi self::$tri_possible |
$tri = isset($this->parametres['tri']) ? $this->parametres['tri'] : ''; |
switch ($tri) { |
case 'date_observation' : |
$this->addOrderBy("date_observation $ordre, id_observation $ordre"); |
break; |
case 'nb_commentaires' : |
$sql_nb_comms = '(SELECT COUNT(id_commentaire) FROM del_commentaire AS dc WHERE ce_observation = id_observation)'; |
$this->addOrderBy("$sql_nb_comms $ordre, id_observation $ordre"); |
break; |
case 'date_transmission' : |
default: |
$this->addOrderBy("do.date_transmission $ordre, id_observation $ordre"); |
} |
} |
public function getAliasDesChamps($champsEtAlias, $select = null, $prefix = null) { |
$arr = ($select) ? array_intersect_key($champsEtAlias, array_flip($select)) : $champsEtAlias; |
$keys = array_keys($arr); |
if ($prefix) { |
array_walk($keys, create_function('&$val, $k, $prefix', '$val = sprintf("%s.`%s`", $prefix, $val);'), $prefix); |
} else { |
array_walk($keys, create_function('&$val, $k', '$val = sprintf("`%s`", $val);')); |
} |
return implode(', ', array_map(create_function('$v, $k', 'return sprintf("%s AS `%s`", $k, $v);'), $arr, $keys)); |
} |
public function getVotesDesImages($idsImages, $protocole = null) { |
if (!$idsImages) return; |
$mappingVotes = $this->conteneur->getParametreTableau('votes.mapping'); |
$mappingProtocoles = $this->conteneur->getParametreTableau('protocoles.mapping'); |
$selectVotes = array('id_vote', 'ce_image', 'ce_protocole', 'ce_utilisateur', 'valeur', 'date'); |
$selectProtocole = array('id_protocole', 'intitule', 'descriptif', 'tag'); |
$voteChamps = $this->getAliasDesChamps($mappingVotes, $selectVotes, 'v'); // "v": cf alias dans la requête |
$protoChamps = $this->getAliasDesChamps($mappingProtocoles, $selectProtocole, 'p'); |
$idImgsConcat = implode(',', $idsImages); |
$requete = "SELECT $voteChamps, $protoChamps ". |
'FROM del_image_vote AS v '. |
' INNER JOIN del_image_protocole AS p ON (v.ce_protocole = p.id_protocole) '. |
"WHERE v.ce_image IN ($idImgsConcat) ". |
($protocole ? " AND v.ce_protocole = $protocole " : ''). |
"ORDER BY FIELD(v.ce_image, $idImgsConcat) ". |
'-- '.__FILE__.':'.__LINE__; |
return $this->bdd->recupererTous($requete); |
} |
/** |
* Ajoute les informations sur le protocole et les votes aux images. |
* |
* ATTENTION : Subtilité, nous passons ici le tableau d'images indexé par id_image qui est bien |
* plus pratique pour associer les vote à un tableau, puisque nous ne connaissons pas les id d'observation. |
* Mais magiquement (par référence), cela va remplir notre tableau indexé par couple d'id (id_image, id_observation) |
* cf ListeImages::reformateImagesDoubleIndex() à qui revient la tâche de créer ces deux versions |
* simultanément lorsque c'est encore possible. |
*/ |
// TODO : supprimer cette "subtilité" source d'erreurs |
public function ajouterInfosVotesProtocoles($votes, &$images) { |
if (!$votes) return; |
$mappingVotes = $this->conteneur->getParametreTableau('votes.mapping'); |
$mappingProtocoles = $this->conteneur->getParametreTableau('protocoles.mapping'); |
// pour chaque vote |
foreach ($votes as $vote) { |
$imgId = $vote['image.id']; |
$protoId = $vote['protocole.id']; |
if (!array_key_exists('protocoles_votes', $images[$imgId]) || |
!array_key_exists($protoId, $images[$imgId]['protocoles_votes'])) { |
// extrait les champs spécifique au protocole (le LEFT JOIN de chargerVotesImage les ramène en doublons |
$protocole = array_intersect_key($vote, array_flip($mappingProtocoles)); |
$images[$imgId]['protocoles_votes'][$protoId] = $protocole; |
} |
$chpsVotes = array('id_vote', 'ce_image', 'ce_utilisateur', 'valeur', 'date'); |
$voteSelection = array_intersect_key($mappingVotes, array_flip($chpsVotes)); |
$vote = array_intersect_key($vote, array_flip($voteSelection)); |
$images[$imgId]['protocoles_votes'][$protoId]['votes'][$vote['vote.id']] = $vote; |
} |
} |
public function getTotalLignesTrouvees() { |
$resultat = $this->bdd->recuperer('SELECT FOUND_ROWS() AS nbre -- '.__FILE__.':'.__LINE__); |
return intval($resultat['nbre']); |
} |
} |
Property changes: |
Added: svnkit:entry:sha1-checksum |
+d671d5d650c4560e1a9b099d98db1e0c78f00002 |
\ No newline at end of property |
/branches/v1.7-oxygene/services/bibliotheque/ParametresFiltrage.php |
---|
New file |
0,0 → 1,475 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Classe contenant des méthodes de filtrage/formatage des paramètres de recherche passés dans l'URL. |
* |
* Cette classe filtre et formate les parametres passées dans l'URL et construit un tableau associatif contenant |
* le résultat des filtrages/formatages et les infos nécessaires à la construction d'une requête SQL. |
* |
* @category DEL |
* @package Services |
* @package Bibliotheque |
* @version 0.1 |
* @author Mathias CHOUET <mathias@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @author Aurelien PERONNET <aurelien@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 1999-2014 Tela Botanica <accueil@tela-botanica.org> |
*/ |
class ParametresFiltrage { |
const APPLI_IMG = 'IMG'; |
const APPLI_OBS = 'OBS'; |
const LISTE_OBS_MAX_RESULT_LIMIT = 1000; |
const LISTE_OBS_MAX_ID_OBS = 10e7; |
const LISTE_OBS_MAX_BDTFX_NT = 1000000; // SELECT MAX(num_taxonomique) FROM bdtfx_v2_00; // 44378 + 1000 |
const LISTE_OBS_MAX_BDTFX_NN = 1000000; // SELECT MAX(num_nom) FROM bdtfx_v2_00;// 120816 + 10000 |
private $conteneur; |
private $contexte; |
private $parametres = array(); |
private $parametresFiltres = array(); |
private $appli; |
public function __construct($conteneur) { |
$this->conteneur = $conteneur; |
$this->contexte = $this->conteneur->getContexte(); |
$this->parametres = $this->contexte->getQS(); |
} |
private function etreAppliImg() { |
return $this->appli === 'IMG' ? true : false; |
} |
private function etreAppliObs() { |
return $this->appli === 'OBS' ? true : false; |
} |
public function filtrerUrlParamsAppliImg() { |
$this->appli = self::APPLI_IMG; |
$this->maintenirCompatibilitesParametres(); |
$parametresAutorises = $this->conteneur->getParametreTableau('images.masques_possibles'); |
$this->eliminerParametresInconnus($parametresAutorises); |
$this->repartirMasqueGeneral(); |
$paramsParDefaut = $this->conteneur->getParametreTableau('images.parametres_valeurs_defaut'); |
$this->definirParametresDefauts($paramsParDefaut); |
$this->filtrerUrlParamsGeneraux(); |
$trisPossibles = $this->conteneur->getParametreTableau('appli_img.tris_possibles'); |
$this->detruireParametreInvalide('tri', $trisPossibles); |
$formatsImgPossibles = $this->conteneur->getParametreTableau('appli_img.img_formats_possibles'); |
$this->detruireParametreInvalide('format', $formatsImgPossibles); |
$this->filtrerProtocole(); |
$this->supprimerParametresFiltresInvalides(); |
return $this->parametresFiltres; |
} |
public function filtrerUrlParamsAppliObs() { |
$this->appli = self::APPLI_OBS; |
$this->maintenirCompatibilitesParametres(); |
$parametresAutorises = $this->conteneur->getParametreTableau(('observations.masques_possibles')); |
$this->eliminerParametresInconnus($parametresAutorises); |
$this->repartirMasqueGeneral(); |
$paramsParDefaut = $this->conteneur->getParametreTableau('observations.parametres_valeurs_defaut'); |
$this->definirParametresDefauts($paramsParDefaut); |
$this->filtrerUrlParamsGeneraux(); |
$trisPossibles = $this->conteneur->getParametreTableau('appli_obs.tris_possibles'); |
$this->detruireParametreInvalide('tri', $trisPossibles); |
$this->supprimerParametresFiltresInvalides(); |
return $this->parametresFiltres; |
} |
private function maintenirCompatibilitesParametres() { |
$this->renommerParametres(); |
if ($this->etreAppliImg() && !isset($this->parametres['masque.tag_del']) && isset($this->parametres['masque.tag'])) { |
$this->parametres['masque.tag_del'] = $this->parametres['masque.tag']; |
unset($this->parametres['masque.tag']); |
} |
if ($this->etreAppliobs() && !isset($this->parametres['masque.tag_cel']) && isset($this->parametres['masque.tag'])) { |
$this->parametres['masque.tag_cel'] = $this->parametres['masque.tag']; |
unset($this->parametres['masque.tag']); |
} |
} |
private function renommerParametres() { |
$renomages = array('masque.tag_pictoflora' => 'masque.tag_del'); |
foreach ($renomages as $ancienNom => $nouveauNom) { |
if (isset($this->parametres[$ancienNom])) { |
$this->parametres[$nouveauNom] = $this->parametres[$ancienNom]; |
unset($this->parametres[$ancienNom]); |
} |
} |
} |
/** |
* Suppression de toutes les clefs NON présentes dans le paramètre de config : images|observations.masques_possibles |
* @param array $parametresAutorises tableau des paramètres pouvant être utilisé dans l'url. |
*/ |
private function eliminerParametresInconnus(Array $parametresAutorises = null) { |
if ($parametresAutorises) { |
$this->parametres = array_intersect_key($this->parametres, array_flip($parametresAutorises)); |
} |
} |
/** |
* Les paramètres par défaut sont écrasés par ceux passés dans l'url. |
* |
* @param array $paramsParDefaut tableau associatif des paramètres d'url par défaut |
*/ |
private function definirParametresDefauts(Array $paramsParDefaut) { |
$this->parametres = array_merge($paramsParDefaut, $this->parametres); |
} |
/** |
* "masque" ne fait jamais que faire une requête sur la plupart des champs, (presque) tous traités |
* de manière identique à la seule différence que: |
* 1) ils sont combinés par des "OU" logiques plutôt que des "ET". |
* 2) les tags sont traités différemment pour conserver la compatibilité avec l'utilisation historique: |
* Tous les mots-clefs doivent matcher et sont séparés par des espaces. |
*/ |
private function repartirMasqueGeneral() { |
if (isset($this->parametres['masque']) && !empty(trim($this->parametres['masque']))) { |
$masqueGeneral = trim($this->parametres['masque']); |
$masquesDetailCles = array('masque.auteur', 'masque.departement', 'masque.commune', 'masque.id_zone_geo', |
'masque.ns', 'masque.famille', 'masque.date', 'masque.genre', 'masque.milieu'); |
// Suppression de la génération de SQL du masque général sur les champ spécifiques qui sont traités avec leur valeur propre. |
foreach ($masquesDetailCles as $cle) { |
if (isset($this->parametres[$cle]) === false) { |
$this->parametres[$cle] = $masqueGeneral; |
$this->parametresFiltres['_parametres_condition_or_'][] = $cle; |
} |
} |
} |
} |
/** |
* Filtre et valide les paramètres reconnus. Effectue *toute* la sanitization *sauf* l'escape-string |
* Cette fonction est appelée: |
* - une fois sur les champs de recherche avancées |
* - une fois sur le masque général si celui-ci à été spécifié. Dans ce cas, |
* la chaîne générale saisie est utilisée comme valeur pour chacun des champs particuliers |
* avec les traitements particuliers qui s'imposent |
* Par exemple: si l'on cherche "Languedoc", cela impliquera: |
* WHERE (nom_sel like "Languedoc" OR nom_ret ... OR ...) mais pas masque.date ou masque.departement |
* qui s'assure d'un pattern particulier |
* |
* masque.genre est un alias pour masque.ns (nom_sel), mais permet de rajouter une clause supplémentaire |
* sur nom_sel. Précédemment: WHERE nom_sel LIKE '%<masque.genre>% %'. |
* Désormais masque.genre doit être intégralement spécifié, les caractères '%' et '_' seront interprétés. |
* Attention toutefois car la table del_observation intègre des nom_sel contenant '_' |
*/ |
// TODO: ajouter un filtre sur le masque (général) |
private function filtrerUrlParamsGeneraux() { |
$this->detruireParametreInvalide('ordre', $this->conteneur->getParametreTableau('valeurs_ordre')); |
$this->detruireParametreInvalide('masque.referentiel', $this->conteneur->getParametreTableau('valeurs_referentiel')); |
$this->filtrerNavigationLimite(); |
$this->filtrerNavigationDepart(); |
$this->filtrerDepartement(); |
$this->filtrerDate(); |
$this->filtrerNn(); |
$this->filtrerNt(); |
$parametresATrimer = array('masque', 'masque.ns', 'masque.genre', 'masque.espece', 'masque.auteur', 'masque.milieu'); |
$this->supprimerCaracteresInvisibles($parametresATrimer); |
$this->filtrerFamille(); |
$this->filtrerPays(); |
$this->filtrerIdZoneGeo(); |
$this->filtrerCommune(); |
$this->filtrerType(); |
$this->filtrerTagCel(); |
$this->filtrerTagDel(); |
} |
/** |
* Supprime l'index du tableau des paramètres si sa valeur ne correspond pas |
* au spectre passé par $values. |
*/ |
private function detruireParametreInvalide($index, Array $valeursAutorisees) { |
if (array_key_exists($index, $this->parametres)) { |
if (!in_array($this->parametres[$index], $valeursAutorisees)) { |
unset($this->parametres[$index]); |
} else { |
$this->parametresFiltres[$index] = $this->parametres[$index]; |
} |
} |
} |
private function filtrerNavigationLimite() { |
if (isset($this->parametres['navigation.limite'])) { |
$options = array( |
'options' => array( |
'default' => null, |
'min_range' => 1, |
'max_range' => self::LISTE_OBS_MAX_RESULT_LIMIT)); |
$paramFiltre = filter_var($this->parametres['navigation.limite'], FILTER_VALIDATE_INT, $options); |
$this->parametresFiltres['navigation.limite'] = $paramFiltre; |
} |
} |
private function filtrerNavigationDepart() { |
if (isset($this->parametres['navigation.depart'])) { |
$options = array( |
'options' => array( |
'default' => null, |
'min_range' => 0, |
'max_range' => self::LISTE_OBS_MAX_ID_OBS)); |
$paramFiltre = filter_var($this->parametres['navigation.depart'], FILTER_VALIDATE_INT, $options); |
$this->parametresFiltres['navigation.depart'] = $paramFiltre; |
} |
} |
/** |
* STRING: 0 -> 95, 971 -> 976, 2A + 2B (./services/configurations/config_departements_bruts.ini) |
* accept leading 0 ? |
* TODO; filter patterns like 555. |
* |
* @return type |
*/ |
private function filtrerDepartement() { |
if (isset($this->parametres['masque.departement'])) { |
$dept = $this->parametres['masque.departement']; |
$paramFiltre = null; |
if (preg_match('/^(\d{2}|\d{3}|2a|2b)$/i', $dept) != 0) { |
$paramFiltre = is_numeric($dept) ? str_pad($dept, 5, '_') : $dept; |
} else { |
$dept_translit = iconv('UTF-8', 'ASCII//TRANSLIT', $dept); |
$dpt_chaine = strtolower(str_replace(' ', '-', $dept_translit)); |
$this->conteneur->chargerConfiguration('config_departements_bruts.ini'); |
$dpt_numero = $this->conteneur->getParametre($dpt_chaine); |
if (!empty($dpt_numero)) { |
$paramFiltre = str_pad($dpt_numero, 5, '_'); |
} |
} |
$this->parametresFiltres['masque.departement'] = $paramFiltre; |
} |
} |
private function filtrerDate() { |
if (isset($this->parametres['masque.date'])) { |
$date = $this->parametres['masque.date']; |
$paramFiltre = null; |
if (preg_match('/^\d{4}$/', $date)) { |
$paramFiltre = $date; |
} else if (strpos($date, '/') !== false) { |
// Format d'entrée DEL : jj/mm/yyyy |
list($jour, $mois, $annee) = explode('/', $date); |
$paramFiltre = "$annee-$mois-$jour"; |
} else if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) { |
$paramFiltre = $date; |
} |
$this->parametresFiltres['masque.date'] = $paramFiltre; |
} |
} |
private function filtrerNn() { |
if (isset($this->parametres['masque.nn'])) { |
$options = array( |
'options' => array( |
'default' => null, |
'min_range' => 0, |
'max_range' => self::LISTE_OBS_MAX_BDTFX_NN)); |
$paramFiltre = filter_var($this->parametres['masque.nn'], FILTER_VALIDATE_INT, $options); |
$this->parametresFiltres['masque.nn'] = $paramFiltre; |
} |
} |
private function filtrerNt() { |
if (isset($this->parametres['masque.nt'])) { |
$options = array( |
'options' => array( |
'default' => null, |
'min_range' => 0, |
'max_range' => self::LISTE_OBS_MAX_BDTFX_NT)); |
$paramFiltre = filter_var($this->parametres['masque.nt'], FILTER_VALIDATE_INT, $options); |
$this->parametresFiltres['masque.nt'] = $paramFiltre; |
} |
} |
private function supprimerCaracteresInvisibles(Array $liste_params) { |
foreach ($liste_params as $param) { |
if (isset($this->parametres[$param])) { |
$this->parametresFiltres[$param] = trim($this->parametres[$param]); |
} |
} |
} |
private function filtrerFamille() { |
if (isset($this->parametres['masque.famille'])) { |
// mysql -N<<<"SELECT DISTINCT famille FROM bdtfx_v1_02;"|sed -r "s/(.)/\1\n/g"|sort -u|tr -d "\n" |
$familleTranslit = iconv('UTF-8', 'ASCII//TRANSLIT',$this->parametres['masque.famille']); |
$paramFiltre = preg_replace('/[^a-zA-Z %_]/', '', $familleTranslit); |
$this->parametresFiltres['masque.famille'] = $paramFiltre; |
} |
} |
// Idem pour id_zone_geo qui mappait à ce_zone_geo: |
private function filtrerIdZoneGeo() { |
if (isset($this->parametres['masque.id_zone_geo'])) { |
if (preg_match('/^(INSEE-C:\d{5}|\d{2})$/', $this->parametres['masque.id_zone_geo'])) { |
$paramFiltre = $this->parametres['masque.id_zone_geo']; |
$this->parametresFiltres['masque.id_zone_geo'] = $paramFiltre; |
} |
} |
} |
// Idem pour id_zone_geo qui mappait à ce_zone_geo: |
private function filtrerPays() { |
if (isset($this->parametres['masque.pays'])) { |
// une liste de pays séparés par des virgules est acceptable |
if (preg_match('/^([a-zA-Z]{2},)*[a-zA-Z]{2}$/', $this->parametres['masque.pays'])) { |
// Nettoyage d'une virgule terminale au cas ou |
$this->parametres['masque.pays'] = rtrim($this->parametres['masque.pays'], ','); |
$paramFiltre = $this->parametres['masque.pays']; |
$this->parametresFiltres['masque.pays'] = $paramFiltre; |
} |
} |
} |
/** masque.commune (zone_geo) |
* TODO: que faire avec des '%' en INPUT ? |
* Le masque doit *permettre* une regexp et non l'imposer. Charge au client de faire son travail. |
*/ |
private function filtrerCommune() { |
if (isset($this->parametres['masque.commune'])) { |
$paramFiltre = str_replace(array('-',' '), '_', $this->parametres['masque.commune']); |
$this->parametresFiltres['masque.commune'] = $paramFiltre; |
} |
} |
private function filtrerTagCel() { |
if (isset($this->parametres['masque.tag_cel'])) { |
$this->parametresFiltres['masque.tag_cel'] = $this->construireTableauTags($this->parametres['masque.tag_cel'], 'OR', ','); |
} else if (isset($this->parametres['masque'])) { |
$this->parametresFiltres['masque.tag_cel'] = $this->construireTableauTags($this->parametres['masque'], 'AND', ' '); |
$this->parametresFiltres['_parametres_condition_or_'][] = 'masque.tag_cel'; |
} |
} |
private function filtrerTagDel() { |
if (isset($this->parametres['masque.tag_del'])) { |
$this->parametresFiltres['masque.tag_del'] = $this->construireTableauTags($this->parametres['masque.tag_del'], 'OR', ','); |
} else if (isset($this->parametres['masque'])) { |
$this->parametresFiltres['masque.tag_del'] = $this->construireTableauTags($this->parametres['masque'], 'AND', ' '); |
$this->parametresFiltres['_parametres_condition_or_'][] = 'masque.tag_del'; |
} |
} |
/** |
* Construit un (vulgaire) abstract syntax tree: |
* "AND" => [ "tag1", "tag2" ] |
* Idéalement (avec un parser simple comme proposé par http://hoa-project.net/Literature/Hack/Compiler.html#Langage_PP) |
* nous aurions: |
* "AND" => [ "tag1", "tag2", "OR" => [ "tag3", "tag4" ] ] |
* |
* Ici nous devons traiter les cas suivants: |
* tags séparés par des "ET/AND OU/OR", séparés par des espaces ou des virgules. |
* Mais la chaîne peut aussi avoir été issue du "masque général" (la barre de recherche générique). |
* ce qui implique des comportement par défaut différents afin de préserver la compatibilité. |
* |
* Théorie: |
* 1) tags passés par "champ tag": |
* - support du ET/OU, et explode par virgule. |
* - si pas d'opérande détectée: "OU" |
* |
* 2) tags passés par "recherche générale": |
* - support du ET/OU, et explode par whitespace. |
* - si pas d'opérande détectée: "ET" |
* |
* La présence de $additional_sep s'explique car ET/OU sous-entendent une séparation par des espaces. |
* Mais ce n'est pas toujours pertinent car: 1) la compatibilité suggère de considérer parfois |
* la virgule comme séparateur et 2) les tags *peuvent* contenir des espaces. Par conséquent: |
* * a,b,c => "a" $default_op "b" $default_op "c" |
* * a,b AND c => "a" AND "b" AND "c" |
* * a OR b AND c,d => "a" AND "b" AND "c" AND "d" |
* C'est à dire par ordre décroissant de priorité: |
* 1) opérande contenu dans la chaîne |
* 2) opérande par défaut |
* 3) les séparateurs présents sont substitués par l'opérande déterminée par 1) ou 2) |
* |
* // TODO: support des parenthèses, imbrications & co: "(", ")" |
* // http://codehackit.blogspot.fr/2011/08/expression-parser-in-php.html |
* // http://blog.angeloff.name/post/2012/08/05/php-recursive-patterns/ |
* |
* @param $str: la chaîne à "parser" |
* @param $operateur_par_defaut: "AND" ou "OR" |
* @param $separateur_additionnel: séparateur de mots: |
*/ |
public function construireTableauTags($str = null, $operateur_par_defaut, $separateur_additionnel = ',') { |
if (!$str) return; |
$op = $this->definirOperateurParDefaut($str, $operateur_par_defaut); |
$mots = preg_split('/ (OR|AND|ET|OU) /', $str, -1, PREG_SPLIT_NO_EMPTY); |
if ($separateur_additionnel) { |
foreach ($mots as $index => $mot) { |
$mot = trim($mot); |
$mots_separes = preg_split("/$separateur_additionnel/", $mot, -1, PREG_SPLIT_NO_EMPTY); |
$mots[$index] = array_shift($mots_separes); |
$mots = array_merge($mots, $mots_separes); |
} |
} |
$mots = array_filter($mots); |
return array($op => $mots); |
} |
private function definirOperateurParDefaut($str, $operateur_par_defaut) { |
$op = $operateur_par_defaut; |
if (preg_match('/\b(ET|AND)\b/', $str)) { |
$op = 'AND'; |
} else if(preg_match('/\b(OU|OR)\b/', $str)) { |
$op = 'OR'; |
} |
return $op; |
} |
// masque.type: ['adeterminer', 'aconfirmer', 'endiscussion', 'validees'] |
private function filtrerType() { |
if (isset($this->parametres['masque.type'])) { |
$typesArray = explode(';', $this->parametres['masque.type']); |
$typesFiltres = array_filter($typesArray); |
$typesAutorises = $this->conteneur->getParametreTableau('valeurs_type'); |
$typesValides = array_intersect($typesFiltres, $typesAutorises); |
$paramFiltre = array_flip($typesValides); |
$this->parametresFiltres['masque.type'] = $paramFiltre; |
} |
} |
private function filtrerProtocole() { |
// ces critère de tri des image à privilégier ne s'applique qu'à un protocole donné |
if (!isset($this->parametres['protocole']) || !is_numeric($this->parametres['protocole'])) { |
$this->parametresFiltres['protocole'] = $this->conteneur->getParametre('appli_img.protocole_defaut'); |
} else { |
$this->parametresFiltres['protocole'] = intval($this->parametres['protocole']); |
} |
} |
private function supprimerParametresFiltresInvalides() { |
// Suppression des NULL, FALSE et '', mais pas des 0, d'où l'utilisation de 'strlen'. |
// La fonction 'strlen' permet de supprimer les NULL, FALSE et chaines vides mais gardent les valeurs 0 (zéro). |
// Les valeurs spéciales contenant des tableaux (tag, _parametres_condition_or_) ne sont pas prise en compte |
foreach ($this->parametresFiltres as $cle => $valeur) { |
if (is_array($valeur) || strlen($valeur) !== 0) { |
$this->parametresFiltres[$cle] = $valeur; |
} |
} |
} |
} |
/branches/v1.7-oxygene/services/bibliotheque/Conteneur.php |
---|
New file |
0,0 → 1,179 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Le conteneur encapsule l'instanciation des classes ainsi que la récupération des paramètres depuis l'url ou |
* les fichiers de configuration |
* |
* @category DEL |
* @package Services |
* @package Bibliotheque |
* @version 0.1 |
* @author Mathias CHOUET <mathias@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @author Aurelien PERONNET <aurelien@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 1999-2014 Tela Botanica <accueil@tela-botanica.org> |
*/ |
//TODO : initialiser tous les objets dans le conteneur |
//TODO : créer un tableau de partage |
class Conteneur { |
protected $parametres; |
protected $partages = array(); |
/** |
* Constructeur de la classe |
* @param Array $parametres (optionnel) les paramètres additionnels à ajouter à ceux des fichiers de config |
* */ |
public function __construct(array $parametres = null) { |
$this->parametres = is_null($parametres) ? array() : $parametres; |
} |
/** |
* Obtenir un paramètre depuis le tableau de paramètres ou depuis le fichier de config |
* @param String $cle le nom du paramètre |
* @return la valeur du paramètre |
* */ |
public function getParametre($cle) { |
$valeur = isset($this->parametres[$cle]) ? $this->parametres[$cle] : Config::get($cle); |
return $valeur; |
} |
/** |
* Obtenir un paramètre depuis le tableau de paramètres ou depuis le fichier de config |
* et le transformer en tableau s'il est de la forme : "cle=valeur,cle=valeur,..." |
* @param String $cle le nom du paramètre |
* @return la valeur du paramètre |
*/ |
public function getParametreTableau($cle) { |
$tableau = array(); |
$parametre = $this->getParametre($cle); |
if (empty($parametre) === false) { |
$tableauPartiel = explode(',', $parametre); |
foreach ($tableauPartiel as $champ) { |
if (strpos($champ, '=') === false) { |
$tableau[] = trim($champ); |
} else { |
list($cle, $val) = explode('=', $champ); |
$tableau[trim($cle)] = trim($val); |
} |
} |
} |
return $tableau; |
} |
/** |
* Enregistrer la valeur d'un paramètre |
* */ |
public function setParametre($cle, $valeur) { |
$this->parametres[$cle] = $valeur; |
} |
//-------------------------------------------------------------------------------------------------------- |
// TODO : Supprimer le chargement de configuration présent dans des fichiers séparés. |
/** |
* Charger la configuration depuis un fichier .ini. |
* |
* @param String $fichier le nom du fichier de configuration |
* */ |
public function chargerConfiguration($fichier) { |
$cheminConfigurations = Config::get('chemin_configurations'); |
if ($cheminConfigurations == null || $cheminConfigurations == '') { |
$message = "Le parametre de configuration 'chemin_configurations' n'est pas défini."; |
$code = RestServeur::HTTP_CODE_ERREUR; |
throw new Exception($message, $code); |
} |
$cheminConfigService = $cheminConfigurations.$fichier; |
if (file_exists($cheminConfigService) === false) { |
$nomClasse = get_class($this); |
$message = "Classe $nomClasse : le fichier de configuration du service est introuvable : $cheminConfigService "; |
$code = RestServeur::HTTP_CODE_ERREUR; |
throw new Exception($message, $code); |
} |
Config::charger($cheminConfigService); |
} |
public function getBdd() { |
if (!isset($this->partages['Bdd'])){ |
$this->partages['Bdd'] = new Bdd(); |
} |
return $this->partages['Bdd']; |
} |
public function getRestClient() { |
if (!isset($this->partages['restClient'])){ |
$this->partages['restClient'] = new RestClient(); |
} |
return $this->partages['restClient']; |
} |
public function getUrl($base) { |
return new Url($base); |
} |
public function getControleAcces() { |
if (!isset($this->partages['controleAcces'])) { |
$this->partages['controleAcces'] = new ControleAcces($this); |
} |
return $this->partages['controleAcces']; |
} |
public function getNavigation() { |
if (!isset($this->partages['navigation'])) { |
$this->partages['navigation'] = new Navigation($this); |
} |
return $this->partages['navigation']; |
} |
public function getContexte() { |
if (!isset($this->partages['contexte'])) { |
$this->partages['contexte'] = new Contexte($this, $_SERVER, $_GET, $_POST, $_SESSION, $_COOKIE); |
} |
return $this->partages['contexte']; |
} |
public function getUtilisateur() { |
if (!isset($this->partages['utilisateur'])) { |
$this->partages['utilisateur'] = new GestionUtilisateur($this); |
} |
return $this->partages['utilisateur']; |
} |
public function getSyndicationOutils() { |
if (!isset($this->partages['syndicationOutils'])) { |
$this->partages['syndicationOutils'] = new SyndicationOutils($this); |
} |
return $this->partages['syndicationOutils']; |
} |
public function getParametresFiltrage() { |
if (!isset($this->partages['parametresFiltrage'])) { |
$this->partages['parametresFiltrage'] = new ParametresFiltrage($this); |
} |
return $this->partages['parametresFiltrage']; |
} |
public function getSql() { |
if (!isset($this->partages['sql'])) { |
$this->partages['sql'] = new Sql($this); |
} |
return $this->partages['sql']; |
} |
public function getSquelettePhp() { |
if (!isset($this->partages['SquelettePhp'])) { |
$this->partages['SquelettePhp'] = new SquelettePhp(); |
} |
return $this->partages['SquelettePhp']; |
} |
public function getMessagerie() { |
if (!isset($this->partages['Messagerie'])) { |
$this->partages['Messagerie'] = new TelaBotanica\Del\Commun\Messagerie($this); |
} |
return $this->partages['Messagerie']; |
} |
} |
/branches/v1.7-oxygene/services/bibliotheque/GestionUtilisateur.php |
---|
New file |
0,0 → 1,124 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Contient les méthodes permettant d'identifier l'utilisateur de l'application DEL. |
* |
* @category DEL |
* @package Services |
* @package Bibliotheque |
* @version 0.1 |
* @author Mathias CHOUET <mathias@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @author Aurelien PERONNET <aurelien@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 1999-2014 Tela Botanica <accueil@tela-botanica.org> |
*/ |
class GestionUtilisateur { |
private $conteneur; |
private $contexte; |
private $bdd; |
private $utilisateur = array(); |
public function __construct(Conteneur $conteneur) { |
$this->conteneur = $conteneur; |
$this->bdd = $this->conteneur->getBdd(); |
$this->contexte = $this->conteneur->getContexte(); |
$this->chargerUtilisateur(); |
} |
private function chargerUtilisateur() { |
$this->demarrerSession(); |
$infos = $this->getUtilisateurIdentifie(); |
$this->utilisateur = ($infos == null) ? $this->getUtilisateurAnonyme() : $infos; |
} |
private function demarrerSession() { |
if (session_id() == '') { |
// TODO : modifier ce test lors du passage en php 5.4 |
session_start(); |
} |
} |
public function getUtilisateurIdentifie() { |
$utilisateur = null; |
$delCourriel = $this->contexte->getCookie('del_courriel'); |
$delMdp = $this->contexte->getCookie('del_mot_de_passe'); |
if ($delCourriel != null && $delMdp != null) { |
$utilisateur = $this->identifierUtilisateurSansEncryptionMotDePasse($delCourriel, $delMdp); |
} |
if ($utilisateur != null) { |
$utilisateur['session_id'] = session_id(); |
} |
return $utilisateur; |
} |
public function getUtilisateurAnonyme() { |
return array( |
'connecte' => false, |
'id_utilisateur' => session_id(), |
'courriel' => '', |
'mot_de_passe' => '', |
'nom' => '', |
'prenom' => '', |
'admin' => '0', |
'session_id' => session_id() |
); |
} |
protected function identifierUtilisateur($login, $mot_de_passe) { |
return $this->recupererUtilisateurEnBdd($login, $mot_de_passe, 'MD5'); |
} |
protected function identifierUtilisateurSansEncryptionMotDePasse($login, $mot_de_passe) { |
return $this->recupererUtilisateurEnBdd($login, $mot_de_passe); |
} |
private function recupererUtilisateurEnBdd($login, $mot_de_passe, $cryptage = false) { |
$loginP = $this->bdd->proteger($login); |
$mdpP = $this->bdd->proteger($mot_de_passe); |
$mdpSql = $cryptage ? "$cryptage($mdpP)" : $mdpP; |
$requete = 'SELECT du.id_utilisateur, nom, prenom, courriel, mot_de_passe, dui.admin '. |
'FROM del_utilisateur AS du '. |
' LEFT JOIN del_utilisateur_infos AS dui ON (du.id_utilisateur = dui.id_utilisateur) '. |
"WHERE courriel = $loginP ". |
"AND mot_de_passe = $mdpSql ". |
' -- '.__FILE__.' : '.__LINE__; |
return $this->bdd->recuperer($requete); |
} |
protected function completerInfosUtilisateur($utilisateur) { |
$utilisateur['session_id'] = session_id(); |
$utilisateur['connecte'] = true; |
return $utilisateur; |
} |
protected function poserCookieUtilisateur($utilisateur) { |
$this->setPersistentCookie('del_courriel', $utilisateur['courriel'], 1); |
$this->setPersistentCookie('del_mot_de_passe', $utilisateur['mot_de_passe'], 1); |
} |
protected function setPersistentCookie($name, $value, $remember = 1) { |
setcookie($name, $value, time() + ($remember ? (60*60*24*100) : (60*60)),'/'); |
} |
protected function oublierUtilisateur() { |
setcookie('del_courriel', $this->contexte->getCookie('del_courriel'), time()-3600, '/'); |
setcookie('del_mot_de_passe', $this->contexte->getCookie('del_mot_de_passe'), time()-3600, '/'); |
$this->contexte->setCookie('del_courriel', null); |
$this->contexte->setCookie('del_mot_de_passe', null); |
} |
public function etreAdmin() { |
//TODO: déplacer ceci dans une classe utilitaire |
$idUtilisateurP = $this->bdd->proteger($this->utilisateur['id_utilisateur']); |
$requete = 'SELECT admin '. |
'FROM del_utilisateur_infos '. |
"WHERE id_utilisateur = $idUtilisateurP ". |
' -- '.__FILE__.' : '.__LINE__; |
$resultat = $this->bdd->recuperer($requete); |
return ($resultat && $resultat['admin'] == 1); |
} |
} |
/branches/v1.7-oxygene/services/bibliotheque/ControleAcces.php |
---|
New file |
0,0 → 1,203 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Classe de controle d'accès aux services de DEL. |
* |
* Cette classe propose des méthodes permettant : |
* - l'authentification http pour bloquer ou autoriser l'accès |
* - de déterminer les droits des utilisateurs |
* |
* @category DEL |
* @package Services |
* @package Bibliotheque |
* @version 0.1 |
* @author Mathias CHOUET <mathias@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @author Aurelien PERONNET <aurelien@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 1999-2014 Tela Botanica <accueil@tela-botanica.org> |
*/ |
class ControleAcces { |
private $conteneur; |
private $bdd; |
public function __construct($conteneur) { |
$this->conteneur = $conteneur; |
$this->bdd = $this->conteneur->getBdd(); |
} |
public function controlerIpAutorisees() { |
$ipsAutorisees = $this->conteneur->getParametreTableau('ip_autorisees'); |
$remoteIp = filter_input(INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP); |
$serverIp = filter_input(INPUT_SERVER, 'SERVER_ADDR', FILTER_VALIDATE_IP); |
if (in_array($remoteIp, $ipsAutorisees) == false) { |
if ($remoteIp != $serverIp) {// ATTENTION : maintenir ce test à l'intérieur du précédent |
$message = "Accès interdit. \n". |
"Vous n'êtes pas autorisé à accéder à ce service depuis '$remoteIp' !\n"; |
$code = RestServeur::HTTP_CODE_ACCES_NON_AUTORISE; |
throw new Exception($message, $code); |
} |
} |
return true; |
} |
public function demanderAuthentificationAdmin() { |
if (!$this->etreAdminAutoriseParHttp()) { |
$this->authentifierAdmin(); |
} |
} |
public function demanderAuthentificationUtilisateur() { |
if (!$this->etreUtilisateurAutoriseParHttp()) { |
$this->authentifierUtilisateur(); |
} |
} |
private function etreUtilisateurAutoriseParHttp() { |
$identifiant = $this->getAuthIdentifiant(); |
$mdp = $this->getAuthMotDePasse(); |
$existe = $this->obtenirUtilisateur($identifiant, $mdp); |
$autorisation = (isset($existe) && $existe) ? true :false; |
return $autorisation; |
} |
private function obtenirUtilisateur($login, $motDePasse) { |
$login = $this->bdd->proteger($login); |
$motDePasse = $this->bdd->proteger($motDePasse); |
$requete = 'SELECT id_utilisateur, nom, prenom, courriel, mot_de_passe '. |
'FROM del_utilisateur AS du '. |
"WHERE courriel = $login ". |
" AND mot_de_passe = MD5($motDePasse) ". |
' -- '.__FILE__.':'.__LINE__."\n"; |
$utilisateur = $this->bdd->recuperer($requete); |
return $utilisateur; |
} |
private function etreAdminAutoriseParHttp() { |
$identifiant = $this->getAuthIdentifiant(); |
$autorisation = ($this->etreAdmin($identifiant) && $this->etreUtilisateurAutorise()) ? true : false; |
return $autorisation; |
} |
private function etreAdmin($courriel) { |
$courriel = $this->bdd->proteger($courriel); |
$requete = 'SELECT dui.admin '. |
'FROM del_utilisateur AS du LEFT JOIN del_user_infos AS dui ON (du.id_utilisateur = dui.id_utilisateur) '. |
"WHERE du.courriel = $courriel ". |
' -- '.__FILE__.':'.__LINE__."\n"; |
$infoUtilisateur = $this->bdd->recuperer($requete); |
$etreAdmin = $this->verifierDroitAdmin($infoUtilisateur['admin']); |
return $etreAdmin; |
} |
private function verifierDroitAdmin($droit) { |
$droitAdmin = $this->conteneur->getParametre('droit_superadmin'); |
$etreAdmin = false; |
if (isset($droit) && $droit == $droitAdmin) { |
$etreAdmin = true; |
} |
return $etreAdmin; |
} |
private function getAuthIdentifiant() { |
$id = (isset($_SERVER['PHP_AUTH_USER'])) ? $_SERVER['PHP_AUTH_USER'] : null; |
return $id; |
} |
private function getAuthMotDePasse() { |
$mdp = (isset($_SERVER['PHP_AUTH_PW'])) ? $_SERVER['PHP_AUTH_PW'] : null; |
return $mdp; |
} |
//TODO: externaliser noms et adresses spécifiques à Tela Botanica |
private function authentifierAdmin() { |
$message_accueil = "Veuillez vous identifier avec votre compte administrateur Tela Botanica."; |
$message_echec = "Accès limité aux administrateurs de DEL.\n". |
"Votre tentative d'identification a échoué.\n". |
"Actualiser la page pour essayer à nouveau si vous êtes bien inscrit comme administrateur."; |
return $this->authentifier($message_accueil, $message_echec, 'Admin'); |
} |
private function authentifierUtilisateur() { |
$message_accueil = "Veuillez vous identifier avec votre compte Tela Botanica."; |
$message_echec = "Accès limité aux utilisateurs de DEL.\n". |
"Inscrivez vous http://www.tela-botanica.org/page:inscription pour le devenir.\n". |
"Votre tentative d'identification a échoué.\n". |
"Actualiser la page pour essayer à nouveau si vous êtes déjà inscrit ou contacter 'accueil@tela-botanica.org'."; |
return $this->authentifier($message_accueil, $message_echec, 'Utilisateur'); |
} |
private function authentifier($message_accueil, $message_echec, $type) { |
$id = $this->getAuthIdentifiant(); |
if (!isset($id)) { |
$this->envoyerAuth($message_accueil, $message_echec); |
} else { |
if ($type == 'Utilisateur' && $this->getAuthMotDePasse() == 'debug') { |
$autorisation = true; |
} else { |
$methodeAutorisation = "etre{$type}Autorise"; |
$autorisation = $this->$methodeAutorisation(); |
} |
if ($autorisation == false) { |
$this->envoyerAuth($message_accueil, $message_echec); |
} |
} |
return true; |
} |
public function etreUtilisateurAvecDroitAdmin() { |
$infos = $this->getInfosUtilisateurConnecte(); |
$etreAdmin = false; |
if (isset($infos['admin'])) { |
$etreAdmin = $this->verifierDroitAdmin($infos['admin']); |
} |
if ($etreAdmin == false) { |
$message = "Vous ne pouvez pas accéder à ce service car vous n'avez pas les droits d'administrateur !\n"; |
$code = RestServeur::HTTP_CODE_ACCES_NON_AUTORISE; |
throw new Exception($message, $code); |
} |
return $etreAdmin; |
} |
public function getInfosUtilisateurConnecte() { |
$utilisateur = array(); |
if (isset($_COOKIE['del_courriel'])) { |
$courriel = $_COOKIE['del_courriel']; |
$motDePasse = $_COOKIE['del_mot_de_passe']; |
$utilisateur = $this->obtenirUtilisateurSansEncryptionMdp($courriel, $motDePasse); |
} |
return $utilisateur; |
} |
private function obtenirUtilisateurSansEncryptionMdp($login, $motDePasseEncrypte) { |
$login = $this->bdd->proteger($login); |
$motDePasseEncrypte = $this->bdd->proteger($motDePasseEncrypte); |
$requete = 'SELECT du.*, admin, preferences, date_premiere_utilisation '. |
'FROM del_utilisateur AS du '. |
' LEFT JOIN del_utilisateur_infos AS dui ON (du.id_utilisateur = dui.id_utilisateur) '. |
"WHERE du.courriel = $login ". |
" AND du.mot_de_passe = $motDePasseEncrypte ". |
' -- '.__FILE__.':'.__LINE__."\n"; |
$utilisateur = $this->bdd->recuperer($requete); |
return $utilisateur; |
} |
public function getIdAnonymeTemporaire() { |
$this->demarrerSession(); |
return session_id(); |
} |
private function demarrerSession() { |
if (session_id() == '') { |
// TODO : modifier ce test lors du passage en php 5.4 |
session_start(); |
} |
} |
} |
/branches/v1.7-oxygene/services/bibliotheque/EnteteHttp.php |
---|
New file |
0,0 → 1,21 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Classe contenant le contenu par défaut de l'entête d'une réponse http par défaut. |
* |
* @category DEL |
* @package Services |
* @package Bibliotheque |
* @version 0.1 |
* @author Mathias CHOUET <mathias@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @author Aurelien PERONNET <aurelien@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 1999-2014 Tela Botanica <accueil@tela-botanica.org> |
*/ |
class EnteteHttp { |
public $code = RestServeur::HTTP_CODE_OK; |
public $encodage = 'utf-8'; |
public $mime = 'application/json'; |
} |
/branches/v1.7-oxygene/services/bibliotheque/ResultatService.php |
---|
New file |
0,0 → 1,21 |
<?php |
// declare(encoding='UTF-8'); |
/** |
* Classe contenant seulement le résultat d'un service. |
* |
* @category DEL |
* @package Services |
* @package Bibliotheque |
* @version 0.1 |
* @author Mathias CHOUET <mathias@tela-botanica.org> |
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org> |
* @author Aurelien PERONNET <aurelien@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 1999-2014 Tela Botanica <accueil@tela-botanica.org> |
*/ |
class ResultatService { |
public $mime = 'application/json'; |
public $encodage = 'utf-8'; |
public $corps = ''; |
} |
/branches/v1.7-oxygene/services/bibliotheque/SyndicationOutils.php |
---|
New file |
0,0 → 1,77 |
<?php |
/* |
* To change this license header, choose License Headers in Project Properties. |
* To change this template file, choose Tools | Templates |
* and open the template in the editor. |
*/ |
class SyndicationOutils { |
private $conteneur; |
private $contexte; |
public function __construct($conteneur) { |
$this->conteneur = $conteneur; |
$this->contexte = $this->conteneur->getContexte(); |
} |
/** |
* Verifier si le flux admin est demande |
*/ |
public function fluxAdminDemande() { |
return $this->contexte->getQS('admin') != null && $this->contexte->getQS('admin') == 1; |
} |
public function demanderAutorisationAdmin() { |
$verification = $this->conteneur->getControleAcces(); |
$verification->demanderAuthentificationAdmin(); |
} |
/** |
* Générer les métadonnées du flux (titre, dates, editeur etc.) |
* */ |
public function construireDonneesCommunesAuFlux($nomFlux, $dateDernierElement) { |
$donnees = array(); |
$donnees['guid'] = $this->creerUrlService(); |
$donnees['titre'] = $this->conteneur->getParametre("syndication.{$nomFlux}_titre"); |
$donnees['description'] = $this->conteneur->getParametre("syndication.{$nomFlux}_dsc"); |
$donnees['lien_service'] = $this->creerUrlService(); |
$donnees['lien_del'] = $this->conteneur->getParametre('img_appli_lien'); |
$donnees['editeur'] = $this->conteneur->getParametre('syndication.editeur'); |
$date_modification_timestamp = strtotime($dateDernierElement); |
$donnees['date_maj_RSS'] = date(DATE_RSS, $date_modification_timestamp); |
$donnees['date_maj_ATOM'] = date(DATE_ATOM, $date_modification_timestamp); |
$donnees['date_maj_W3C'] = date(DATE_W3C, $date_modification_timestamp); |
$donnees['annee_courante'] = date('Y'); |
$donnees['generateur'] = $this->conteneur->getParametre("syndication.generateur_nom"); |
$donnees['generateur_version'] = $this->conteneur->getParametre("syndication.generateur_version"); |
return $donnees; |
} |
public function creerUrlService() { |
$url = 'http://'. |
$this->contexte->getServer('SERVER_NAME'). |
$this->contexte->getServer('REQUEST_URI'); |
return htmlspecialchars($url); |
} |
public function getUrlImage($id, $format = 'L') { |
$url_tpl = $this->conteneur->getParametre('cel_img_url_tpl'); |
$url = sprintf($url_tpl, $id, $format); |
return $url; |
} |
public function convertirDateHeureMysqlEnTimestamp($date_heure_mysql){ |
$timestamp = 0; |
// Le date de 1970-01-01 pose problème dans certains lecteur de Flux, on met donc la date de création de Tela |
$date_heure_mysql = ($date_heure_mysql == '0000-00-00 00:00:00') ? '1999-12-14 00:00:00' : $date_heure_mysql; |
if ($date_heure_mysql != '0000-00-00 00:00:00') { |
$val = explode(' ', $date_heure_mysql); |
$date = explode('-', $val[0]); |
$heure = explode(':', $val[1]); |
$timestamp = mktime((int) $heure[0], (int) $heure[1], (int) $heure[2], (int) $date[1], (int) $date[2], (int) $date[0]); |
} |
return $timestamp; |
} |
} |