Rev 31 | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php
/**
*
* Classe principale du web service qui peut traiter des requetes provenant d'un navigateur web
* (stations dans bbox ou observations sur un point), ou d'un client SIG via appel au protocole/service WFS
* (demande d'observations par stations selon des filtres optionnels). Le web service analyse et verifie
* les parametres de l'URL de la requete qu'il recoit. S'ils sont tous valides, il va appeler une autre classe
* pour recuperer les informations demandees dans les differentes sources de donnees.
* Les donnees recuperees sont ensuite combinees si plusieurs sources sont demandees et mises en forme
* au format de sortie. Les formats de sortie utilises sont le GeoJSON (extension de JSON pour les donnees
* geographiques) en destination des navigateurs web et le GML adapte au service WFS pour les clients SIG.
* Dans le cas ou des erreurs sont levees, le web service renvoie un message d'erreur expliquant le probleme
* recnontre dans son fonctionnement.
*
*
* @package framework-0.4
* @author Alexandre GALIBERT <alexandre.galibert@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$
* @copyright 2013 Tela Botanica (accueil@tela-botanica.org)
*
*/
class Commun {
private $parametres = array();
private $ressources = array();
private $nomSource = '';
private $nomService = '';
private $verificateur = null;
private $parametresRecherche = null;
private $retour = array();
const MIME_WFS = 'text/xml';
public function consulter($ressources, $parametres) {
$this->recupererRessourcesEtParametres($ressources, $parametres);
$retour = null;
if (in_array("wfs", $ressources)) {
$retour = $this->traiterRequeteWfs();
} else {
$retour = $this->traiterRequeteNavigateur();
}
return $retour;
}
/*********************************************/
// Verification parametres URL non-WFS
private function traiterRequeteWfs() {
$retour = null;
try {
$this->parametresRecherche = new StdClass();
$this->traiterParametreOperation();
if ($this->parametresRecherche->operation != 'GetCapabilities') {
$this->traiterParametreSource();
}
if ($this->parametresRecherche->operation == 'GetFeature') {
$retour = $this->getFeature();
} else {
$formateurWfs = new FormateurWfs();
$nomMethode = 'formater'.$this->parametresRecherche->operation;
$parametre = isset($this->parametresRecherche->sources)
? $this->parametresRecherche->sources : null;
$retour = new ResultatService();
$retour->mime = self::MIME_WFS;
$retour->corps = $formateurWfs->$nomMethode($parametre);
}
} catch (Exception $erreur) {
$formateurWfs = new FormateurWfs();
$retour = new ResultatService();
$retour->mime = self::MIME_WFS;
$retour->corps = $formateurWfs->formaterException($erreur);
}
return $retour;
}
private function getFeature() {
if (array_key_exists('bbox', $this->parametres)) {
$this->traiterParametreBbox();
} elseif (array_key_exists('filter', $this->parametres)) {
$this->traiterParametreFilter();
}
$this->recupererStationsWfs();
$formateurWfs = new FormateurWfs();
$retour = new ResultatService();
$retour->mime = self::MIME_WFS;
$retour->corps = $formateurWfs->formaterGetFeature($this->retour, $this->parametresRecherche->sources);
return $retour;
}
private function traiterParametreOperation() {
if ($this->verifierExistenceParametre('request')) {
if (!$this->estOperationWfsAutorisee()) {
$message = "L'opération '".$this->parametres['request']."' n'est pas autorisée.\n".
"Les opérations suivantes sont permises par le service : ".Config::get('operations_wfs');
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
} else {
$this->parametresRecherche->operation = $this->parametres['request'];
}
}
}
private function verifierExistenceParametre($nomParametre) {
$estParametreExistant = false;
if (!array_key_exists($nomParametre, $this->parametres)) {
$message = "Le paramètre nom de l'opération '{$nomParametre}' ".
"n'a pas été trouvé dans la liste des paramètres.";
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
} else {
$estParametreExistant = true;
}
return $estParametreExistant;
}
private function estOperationWfsAutorisee() {
$operationsWfsService = explode(',' , Config::get('operations_wfs'));
return (in_array($this->parametres['request'], $operationsWfsService));
}
private function traiterParametreSource() {
// le parametre source (typename) est optionnel par defaut
if (array_key_exists('typename', $this->parametres)) {
$sources = explode(',', $this->parametres['typename']);
$estSourceValide = true;
foreach ($sources as $source) {
if (!$this->verifierExistenceSourcesDonnees($source)) {
$message = "Source de donnees '{$source}' indisponible. Les sources disponibles sont : ".
Config::get('sources_dispo');
$estSourceValide = false;
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
}
}
if ($estSourceValide) {
$this->parametresRecherche->sources = $sources;
}
}
}
private function traiterParametreBbox() {
$bboxVerifiee = $this->verifierCoordonneesBbox($this->parametres['bbox']);
if (is_array($bboxVerifiee) && count($bboxVerifiee) == 4) {
$this->parametresRecherche->bbox = array($bboxVerifiee);
}
}
private function verifierCoordonneesBbox($bbox) {
$bboxVerifiee = null;
// verifier que la chaine de caracteres $bbox est une serie de chaque nombre decimaux
// separes entre eux par une virgule
if (preg_match('/^(-?\d{1,3}(.\d+)?,){3}(-?\d{1,3}(.\d+)?)$/', $bbox) == 0) {
$message = "Format de saisie des coordonnees de la bounding box non valide. Le service ".
"n'accepte seulement qu'une serie de 4 nombre décimaux séparés par des virgules.";
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
} else {
$coordonnees = explode(',', $bbox);
$nomsIndexBbox = array("ouest", "sud", "est", "nord");
$bbox = array();
for ($i = 0; $i < count($coordonnees); $i ++) {
$bbox[$nomsIndexBbox[$i]] = $coordonnees[$i];
}
// verifier que les coordonnees de chaque bord de la bbox sont valides
if ($this->estUneBboxValide($bbox)) {
$bboxVerifiee = $bbox;
} else {
$message = "Certaines coordonnées de la bounding box sont situés en dehors des limites ".
"de notre monde";
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
}
}
return $bboxVerifiee;
}
private function estUneBboxValide($bbox) {
$monde = array(
'ouest' => floatval(Config::get('carte.limite_ouest')),
'est' => floatval(Config::get('carte.limite_est')),
'sud' => floatval(Config::get('carte.limite_sud')),
'nord' => floatval(Config::get('carte.limite_nord'))
);
return (floatval($bbox['ouest']) >= $monde['ouest'] && floatval($bbox['ouest']) <= $monde['est']
&& floatval($bbox['est']) >= $monde['ouest'] && floatval($bbox['est']) <= $monde['est']
&& floatval($bbox['nord']) >= $monde['sud'] && floatval($bbox['nord']) <= $monde['nord']
&& floatval($bbox['sud']) >= $monde['sud'] && floatval($bbox['sud']) <= $monde['nord']);
}
private function traiterParametreFilter() {
// la valeur du parametre filter est une chaine de texte qui compose en realite un document XML
// plus d'infos a l'URL suivante : http://mapserver.org/fr/ogc/filter_encoding.html
$filtreTexte = $this->recupererTexteParametreFilter();
$documentXML = new DomDocument();
$documentXML->loadXML($filtreTexte);
$filtres = $documentXML->documentElement->childNodes;
for ($index = 0; $index < $filtres->length; $index ++) {
$this->verifierFiltre($filtres->item($index));
}
}
private function recupererTexteParametreFilter() {
$parametresUrl = explode("&", $_SERVER['QUERY_STRING']);
$filtreTexte = '';
foreach ($parametresUrl as $parametre) {
list($cle, $valeur) = explode("=", $parametre);
if ($cle == 'filter') {
$filtreTexte = rawurldecode($valeur);
}
}
return $filtreTexte;
}
private function verifierFiltre($filtre) {
$operateursAcceptes = explode(',', Config::get('operateurs_wfs'));
$nomOperateur = $filtre->tagName;
if (!in_array($nomOperateur, $operateursAcceptes)) {
$message = "Le filtre '$nomOperateur' n'est pas pris en compte par le serrvice. ".
"Les opérateurs acceptés sont :".implode(', ', $operateursAcceptes);
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
} else {
if ($nomOperateur == 'BBOX') {
$bboxUrl = $filtre->lastChild->nodeValue;
$bboxVerifiee = $this->verifierCoordonneesBbox($bboxUrl);
$this->parametresRecherche->bbox = array($bboxVerifiee);
} else {
$this->traiterOperateurScalaire($filtre);
}
}
}
private function traiterOperateurScalaire($filtre) {
$nomOperateur = $filtre->tagName;
$champ = $filtre->childNodes->item(0)->nodeValue;
if ($champ != Config::get('champ_filtrage_wfs')) {
$message = "Le filtre ne peut pas être appliqué sur le champ '$champ'. ".
"Il est seulement accepté sur le champ '".Config::get('champ_filtrage_wfs')."'";
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
} else {
$valeur = $filtre->childNodes->item(1)->nodeValue;
$operateur = $nomOperateur == 'PropertyIsEqualTo' ? "=" : "LIKE";
$this->parametresRecherche->filtre = array("champ" => $champ, "operateur" => $operateur,
"valeur" => $valeur);
}
}
private function recupererStationsWfs() {
$this->nomMethode = $this->ressources[0];
foreach ($this->parametresRecherche->sources as $source) {
$source = trim($source);
$resultat = $this->traiterSource($source);
$this->ajouterResultat($resultat, $source);
}
}
/*********************************************/
// Verification parametres URL non-WFS
private function traiterRequeteNavigateur() {
$retour = null;
try {
if (!$this->estParametreSourceExistant()) {
$message = "Le paramètre source de données n'a pas été indiqué.";
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
} else {
$this->verifierParametres();
$listeSources = explode(',', $this->parametres['source']);
foreach ($listeSources as $source) {
$source = trim($source);
$resultat = $this->traiterSource($source);
$this->ajouterResultat($resultat, $source);
}
}
$formateur = new FormateurJson();
$nomMethode = 'formater'.ucfirst($this->ressources[0]);
$retour = new ResultatService();
$retour->corps = $formateur->$nomMethode($this->retour);
} catch (Exception $erreur) {
$retour = $erreur;
}
return $retour;
}
private function recupererRessourcesEtParametres($ressources, $parametres) {
$this->ressources = $ressources;
$this->parametres = array();
foreach ($parametres as $nomParametre => $valeur) {
$this->parametres[strtolower($nomParametre)] = $valeur;
}
}
private function estParametreSourceExistant() {
$parametreExiste = false;
if (isset($this->parametres['source'])) {
$parametreExiste = true;
}
return $parametreExiste;
}
private function verifierExistenceSourcesDonnees($source) {
$sourcesDisponibles = explode(',', Config::get('sources_dispo'));
$estDisponible = false;
if (in_array($source, $sourcesDisponibles)) {
$estDisponible = true;
}
return $estDisponible;
}
private function verifierParametres() {
$this->verificateur = new VerificateurParametres($this->parametres);
$this->verificateur->verifierParametres();
if ($this->verificateur->contientErreurs()) {
$this->verificateur->leverException();
} else {
$this->recupererParametresRecherche();
}
}
private function traiterSource($source) {
$retour = array();
if (!$this->verifierExistenceSourcesDonnees($source)) {
$message = "Source de donnees indisponible";
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
} else {
$this->chargerNomService($source);
$retour = $this->executerServicePourSource($source);
}
return $retour;
}
private function recupererParametresRecherche() {
$this->parametresRecherche = $this->verificateur->renvoyerResultatVerification();
}
private function chargerNomSource($source) {
if (isset($this->parametres['source'])) {
$this->nomSource = $this->parametres['source'];
} else {
$this->nomSource = Config::get('source_defaut');
}
}
private function chargerNomService($source) {
$this->nomService = ($source == 'floradata' ? 'Floradata' : 'Moissonnage').'Formateur';
Projets::chargerConfigurationSource($source);
}
private function executerServicePourSource($source) {
$objetTraitement = new $this->nomService($this->parametresRecherche, $source);
$methode = $this->genererNomMethodeAExecuter();
return $objetTraitement->$methode();
}
private function genererNomMethodeAExecuter() {
return 'recuperer' . ucfirst($this->ressources[0]);
}
private function ajouterResultat(& $resultat, $source) {
if (count($this->retour) > 0) {
if ($this->ressources[0] == 'stations' && count($resultat) > 0
&& $this->doitTransformerTypeDonnees($resultat)) {
$this->combinerResultats($resultat, $source);
} else {
$this->retour = array_merge($this->retour, $resultat);
}
} else {
$this->retour = array_merge($this->retour, $resultat);
}
}
private function doitTransformerTypeDonnees(& $resultat) {
return ($this->parametresRecherche->zoom <= Config::get('zoom_maximal_maillage') &&
(($resultat[0]['type_site'] == 'MAILLE' || $this->retour[0]['type_site'] == 'MAILLE')
|| ($resultat[0]['type_site'] != 'MAILLE' && $this->retour[0]['type_site'] != 'MAILLE'
&& count($resultat) + count($this->retour) > Config::get('seuil_maillage')))
);
}
private function combinerResultats(& $resultat, $source) {
$maillage = new Maillage($this->parametresRecherche->bbox, $this->parametresRecherche->zoom, $source);
$maillage->genererMaillesVides();
if ($resultat[0]['type_site'] == 'MAILLE') {
$maillage->ajouterMailles($resultat);
} else {
$maillage->ajouterStations($resultat);
}
if ($this->retour[0]['type_site'] == 'MAILLE') {
$maillage->ajouterMailles($this->retour);
} else {
$maillage->ajouterStations($this->retour);
}
$this->retour = $maillage->formaterSortie();
}
}
?>