Subversion Repositories eFlore/Applications.cel

Compare Revisions

No changes between revisions

Ignore whitespace Rev 3856 → Rev 3857

/branches/v3.01-serpe/jrest/services/CelWidgetMap.php
New file
0,0 → 1,828
<?php
// declare(encoding='UTF-8');
/**
* Service fournissant une carte dynamique (communes)des obsertions publiques du CEL.
*
* Cas d'utilisation :
* /CelWidgetMap/Carte/Utilisateur : carte des observations publiques d'un utilisateur.
* /CelWidgetMap/Carte/Utilisateur/Projet : carte des observations publiques d'un utilisateur pour un projet.
* /CelWidgetMap/Carte/Utilisateur/Projet/dept : carte des observations publiques d'un utilisateur pour un projet sur un département.
* /CelWidgetMap/Carte/Utilisateur/Projet/dept/num_taxon : carte des observations publiques d'un utilisateur pour un projet sur un département pour un taxon.
*
* Carte = Type de carte. Valeurs possible : defaut,
* Utilisateur = identifiant (= courriel) de l'utilisateur ou * pour tous les utilisateurs.
* Projet = mot-clé du projet
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Widget
* @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 : supprimer le TRIM quand les obs seront reliées correctements aux localisations (sur le code INSEE par exemple)
class CelWidgetMap extends Cel {
 
/**
* Méthode appelée avec une requête de type GET.
*/
public function getElement($ressources) {
$retour = null;
extract($this->parametres);
 
$action = array_shift($ressources);
if (isset($action)) {
$methode = $this->traiterNomMethodeGet($action);
if (method_exists($this, $methode)) {
$retour = $this->$methode($ressources);
} else {
$this->messages[] = "Ce type de ressource '$methode' n'est pas disponible.";
}
} else {
$this->messages[] = "Vous devez indiquer le type de ressource.";
}
 
if (is_null($retour)) {
$info = 'Un problème est survenu : '.print_r($this->messages, true);
$this->envoyer($info);
} else if (isset($retour['type']) && $retour['type'] == 'jsonVar') {
 
$this->envoyerJsonVar($retour['variable_js'], $retour['donnees']);
} else if (isset($retour['type']) && $retour['type'] == 'jsonP') {
$this->envoyerJsonp($retour['donnees']);
} else {
$this->envoyerJson($retour);
}
}
 
/**
* Les stations de la carte par défaut
*/
public function getStations($params) {
$json = null;
$requete = 'SELECT utm_secteur, utm_x, utm_y, wgs84_latitude AS latitude, wgs84_longitude AS longitude '.
'FROM cel_export AS co '.
' RIGHT JOIN cel_zones_geo AS zg '. // exclut les obs non localisées sur zone geo, pour obtenir un décompte cohérent
' ON (zg.id_zone_geo = co.ce_zone_geo) '.
"WHERE 1 ".
$this->construireWhereDept().
$this->construireWhereCommune().
$this->construireWherePhotosSeulement().
$this->construireWhereUtilisateur().
$this->construireWhereNumTaxon().
$this->construireWhereNomTaxon().
$this->construireWhereDate().
$this->construireWhereCommentaire().
$this->construireWhereProjet().
$this->construireWhereTag();
//die($requete);
$resultats = Cel::db()->requeter($requete);
 
// Traitement des résultats
$obs_nbre = $this->traiterNbreObs($resultats);
$stations = $this->traiterStations($resultats);
 
// Création des infos du widget
$json['donnees']['points'] = $stations;
$json['donnees']['stats']['communes'] = count($stations);
$json['donnees']['stats']['observations'] = $obs_nbre;
 
$json['type'] = (isset($this->formatRetour)) ? $this->formatRetour : 'jsonVar';
$json['variable_js'] = 'stations';
 
return $json;
}
 
private function traiterNbreObs($resultats) {
$obs_nbre = 0;
if ($resultats !== false) {
$obs_nbre = count($resultats);
}
return $obs_nbre;
}
 
private function traiterStations($resultats) {
$stations = array();
if ($resultats !== false) {
foreach ($resultats as $enrg) {
if ($enrg['latitude'] != null && $enrg['longitude'] != null) {
$id = $enrg['latitude'].'-'.$enrg['longitude'];
if (!isset($stations[$id])) {
$enrg['id'] = 'UTM:'.$enrg['utm_x'].'-'.$enrg['utm_y'].'-'.$enrg['utm_secteur'];
unset($enrg['utm_x']);
unset($enrg['utm_y']);
unset($enrg['utm_secteur']);
$stations[$id] = $enrg;
$stations[$id]['nbre'] = 1;
} else {
$stations[$id]['nbre']++;
}
}
}
$stations = array_values($stations);
}
return $stations;
}
 
/**
* Données pour l'affichage des obs d'une station
*/
public function getObservations($params) {
$resultats = array();
$total = 0;
if (!$this->etreNull($this->parametres['station'])) {
$requete = 'SELECT SQL_CALC_FOUND_ROWS id_observation, ce_utilisateur, courriel_utilisateur, '.
' nom_sel, nom_ret, nom_sel_nn, nom_ret_nn, nt, famille, '.
' lieudit, zone_geo, date_observation, milieu, commentaire, '.
' utm_secteur, utm_x, utm_y, id_zone_geo, date_transmission, nom_referentiel '.
'FROM cel_export AS co '.
' LEFT JOIN cel_zones_geo AS zg '.
" ON (zg.id_zone_geo = co.ce_zone_geo) ".
"WHERE 1 ".
$this->construireWhereCoordonnees().
$this->construireWherePhotosSeulement().
$this->construireWhereUtilisateur().
$this->construireWhereNumTaxon().
$this->construireWhereNomTaxon().
$this->construireWhereDate().
$this->construireWhereCommentaire().
$this->construireWhereProjet().
$this->construireWhereTag().
'ORDER BY nom_sel ASC '.
"LIMIT {$this->start},{$this->limit} ";
//die($requete);
$resultats = Cel::db()->requeter($requete, self::SQL_RETOUR_COMPLET, self::SQL_MODE_OBJET);
 
$requete = 'SELECT FOUND_ROWS()';
$total = (int) Cel::db()->requeter($requete, self::SQL_RETOUR_COLONNE);
}
 
// Post-traitement
$observations = $this->traiterObservations($resultats, $total);
$observations = $this->ajouterImagesAuxObs($observations);
$observations = $this->ajouterAuteursAuxObs($observations);
$observations = $this->supprimerIdDesObs($observations);
return $observations;
}
 
private function traiterObservations($donnees, $total) {
$observations = array('commune' => '', 'observations' => array(), 'observateurs' => array());
$observations['total'] = (isset($total)) ? $total : 0;
if (is_array($donnees) && count($donnees) > 0) {
foreach ($donnees as $donnee) {
$observation = array();
$observation['idObs'] = $donnee->id_observation;
$observation['nn'] = $this->etreNull($donnee->nom_sel_nn) ? null : $donnee->nom_sel_nn;
$observation['nomSci'] = $this->nettoyerTexte($donnee->nom_sel);
$observation['date'] = $this->formaterDate($donnee->date_observation, '%d/%m/%Y');
$observation['datePubli'] = $this->formaterDate($donnee->date_transmission);
$observation['lieu'] = $this->traiterLieu($donnee);
$observation['observateur'] = $donnee->courriel_utilisateur;
$observation['observateurId'] = $donnee->ce_utilisateur;
$observation['referentiel'] = $this->supprimerVersionDuReferentiel($donnee->nom_referentiel);
$observation['urlEflore'] = $this->getUrlEflore($donnee->nom_referentiel, $donnee->nom_sel_nn);
 
if (isset($donnee->zone_geo)) {
$observations['commune'] = $this->nettoyerTexte($donnee->zone_geo);
}
$observations['observations'][$donnee->id_observation] = $observation;
if (! array_key_exists($donnee->courriel_utilisateur, $observations['observateurs'])) {
$observations['observateurs'][$donnee->courriel_utilisateur] = $donnee->courriel_utilisateur;
}
}
}
return $observations;
}
 
private function traiterLieu($donnee) {
$lieu = array();
if (!$this->etreNull($donnee->lieudit)) {
$lieu[] = $donnee->lieudit;
}
if (!$this->etreNull($donnee->milieu)) {
$lieu[] = $donnee->milieu;
}
return implode(', ', $lieu);
}
 
private function chargerImages(Array $obs_ids) {
// Récupération des données au format Json
$service = 'CelImage/liste-ids?obsId='.implode(',', $obs_ids);
$url = sprintf($this->config['settings']['baseURLServicesCelTpl'], $service);
$json = $this->getRestClient()->consulter($url);
$donnees = json_decode($json);
 
// Post-traitement des données
$images = $this->traiterImages($donnees);
 
return $images;
}
 
private function traiterImages($donnees) {
$images = array();
if (count($donnees) > 0) {
foreach ($donnees as $id_obs => $id_images) {
foreach ($id_images as $id_img) {
$urls['idImg'] = $id_img;
$urls['guid'] = sprintf($this->config['settings']['guidImgTpl'], $id_img);
$urls['miniature'] = $this->getUrlImage($id_img, 'CXS');
$urls['normale'] = $this->getUrlImage($id_img, 'XL');
$images[$id_obs][] = $urls;
}
}
}
return $images;
}
 
private function ajouterImagesAuxObs($observations) {
$images = $this->chargerImages(array_keys($observations['observations']));
foreach ($observations['observations'] as $id => $infos) {
if(isset($images[$id])) {
$infos['images'] = $images[$id];
}
$observations['observations'][$id] = $infos;
}
return $observations;
}
 
private function ajouterAuteursAuxObs($observations) {
$observateurs = $this->recupererUtilisateursIdentite(array_keys($observations['observateurs']));
unset($observations['observateurs']);
foreach ($observations['observations'] as $id => $infos) {
$courriel = strtolower($infos['observateur']);
$infos['observateur'] = $observateurs[$courriel]['intitule'];
$infos['observateurId'] = $observateurs[$courriel]['id'];
$observations['observations'][$id] = $infos;
}
return $observations;
}
 
private function supprimerIdDesObs($observations) {
// Le tableau de sortie ne doit pas avoir les id des obs en clé car sinon Jquery Template ne fonctionne pas
$observationSansId = $observations;
unset($observationSansId['observations']);
foreach ($observations['observations'] as $id => $infos) {
$observationSansId['observations'][] = $infos;
}
return $observationSansId;
}
 
/**
* Liste des taxons présents sur la carte
*/
public function getTaxons($params) {
$json = null;
 
$requete = 'SELECT SQL_CALC_FOUND_ROWS DISTINCT nom_ret, nom_ret_nn, nt, famille '.
'FROM cel_export AS co '.
' LEFT JOIN cel_zones_geo AS zg '.
' ON (zg.id_zone_geo = co.ce_zone_geo) '.
"WHERE ".
" nom_ret != '' ".
$this->construireWhereDept().
$this->construireWhereCommune().
$this->construireWherePhotosSeulement().
$this->construireWhereUtilisateur().
$this->construireWhereNumTaxon().
$this->construireWhereNomTaxon().
$this->construireWhereDate().
$this->construireWhereCommentaire().
$this->construireWhereProjet().
$this->construireWhereTag();
'ORDER BY nom_ret ASC '.
"LIMIT {$this->start},{$this->limit} ";
//$this->debug[] = $requete;
//die($requete);
$resultats = Cel::db()->requeter($requete, self::SQL_RETOUR_COMPLET, self::SQL_MODE_OBJET);
 
$requete = 'SELECT FOUND_ROWS()';
$taxons['total'] = (int) Cel::db()->requeter($requete, self::SQL_RETOUR_COLONNE);
 
// Post-traitement
$taxons['taxons'] = $this->traiterTaxons($resultats);
 
return $taxons;
}
 
private function traiterTaxons($donnees) {
$taxons = array();
if (is_array($donnees) && count($donnees) > 0) {
foreach ($donnees as $donnee) {
if (!isset($taxons[$donnee->nt]) && ! $this->etreNull($donnee->nom_ret)) {
$taxon = array();
$taxon['nn'] = $donnee->nom_ret_nn;
$taxon['nt'] = $donnee->nt;
$taxon['nom'] = $this->nettoyerTexte($donnee->nom_ret);
$taxon['famille'] = $this->nettoyerTexte($donnee->famille);
$taxons[$donnee->nt] = $taxon;
}
}
}
$taxons = array_values($taxons);
return $taxons;
}
 
private function construireWhereCoordonnees() {
$sql = '';
// Récupération des coordonnées depuis l'id station
extract($this->decomposerParametreStation());
if (isset($type)) {
if ($type == 'UTM') {
$secteur = Cel::db()->proteger($secteur);
$utm_x = Cel::db()->proteger($utm_x);
$utm_y = Cel::db()->proteger($utm_y);
 
$sql = " AND (utm_secteur = $secteur AND utm_x = $utm_x AND utm_y = $utm_y ) ";
} else if ($type == 'LngLat') {
$latitude = Cel::db()->proteger($latitude);
$longitude = Cel::db()->proteger($longitude);
 
$sql = " AND (latitude = $latitude AND longitude = $longitude ) ";
}
}
return $sql;
}
 
private function construireWhereCommentaire() {
$sql = '';
list($type, $commentaire) = $this->decomposerParametreCommentaire();
if (!$this->etreNull($commentaire)) {
$commentaire = Cel::db()->proteger('%'.$commentaire.'%');
switch ($type) {
case '*' :
$sql = $this->obtenirConditionPourCommentaires($commentaire);
$sql = " AND (ci.commentaire LIKE $commentaire OR ($sql)) ";
break;
case 'observation' :
$sql = " AND co.commentaire LIKE $commentaire ";
break;
case 'photo' :
$sql = ' AND '.$this->obtenirConditionPourCommentaires($commentaire).' ';
break;
case 'photo.meta' :
$sql = ' AND '.$this->obtenirConditionPourCommentaireMeta($commentaire).' ';
break;
case 'photo.utilisateur' :
$sql = ' AND '.$this->obtenirConditionPourCommentaireUtilisateur($commentaire).' ';
break;
default:
$sql = " AND co.commentaire LIKE $commentaire ";
}
}
return $sql;
}
 
 
private function construireWhereNomTaxon() {
$sql = '';
list($type, $nom) = $this->decomposerParametreTaxon();
if (!$this->etreNull($nom)) {
$nom = Cel::db()->proteger($nom.'%');
switch ($type) {
case '*' :
$sql = " AND (nom_ret LIKE $nom OR nom_sel LIKE $nom OR famille LIKE $nom) ";
break;
case 'retenu' :
$sql = " AND nom_ret LIKE $nom ";
break;
case 'selectionne' :
$sql = " AND nom_sel LIKE $nom ";
break;
case 'famille' :
$sql = " AND famille LIKE $nom ";
break;
default:
$sql = " AND nom_ret LIKE $nom ";
}
}
return $sql;
}
 
private function construireWhereDate() {
$sql = '';
// Récupération des coordonnées depuis l'id station
list($type, $date) = $this->decomposerParametreDate();
 
if (!$this->etreNull($date)) {
$date = Cel::db()->proteger($date.'%');
switch ($type) {
case '*' :
$sql = " AND (
date_observation LIKE $date
OR date_creation LIKE $date
OR date_modification LIKE $date
OR date_transmission LIKE $date) ";
break;
case 'observation' :
$sql = " AND date_observation LIKE $date ";
break;
case 'creation' :
$sql = " AND date_creation LIKE $date ";
break;
case 'modification' :
$sql = " AND date_modification LIKE $date ";
break;
case 'transmission' :
$sql = " AND date_transmission LIKE $date ";
break;
case 'photo' :
$sql = $this->obtenirConditionPourDatePhoto($date);
break;
case 'ajout' :
$sql = $this->obtenirConditionPourDateAjout($date);
break;
case 'liaison' :
$sql = $this->obtenirConditionPourDateLiaison($date);
break;
default:
$sql = " AND date_observation LIKE $date ";
}
}
return $sql;
}
 
private function obtenirConditionPourDatePhoto($date) {
$observations = $this->obtenirObsLieesImg('date.photo', $date);
if (is_null($observations)) {
$this->debug[] = "Aucune observation n'est liée à une photo prise à la date : $date";
}
$sql = $this->assemblerObsEnConditionSql($observations);
return $sql;
}
 
private function obtenirConditionPourDateLiaison($date) {
$observations = $this->obtenirObsLieesImg('date.liaison', $date);
if (is_null($observations)) {
$this->debug[] = "Aucune observation n'a été liée à une image à à la date : $date";
}
$sql = $this->assemblerObsEnConditionSql($observations);
return $sql;
}
 
private function obtenirConditionPourDateAjout($date) {
$observations = $this->obtenirObsLieesImg('date.ajout', $date);
if (is_null($observations)) {
$this->debug[] = "Aucune observation n'est liée à une image ajoutée à la date : $date";
}
$sql = $this->assemblerObsEnConditionSql($observations);
return $sql;
}
 
private function obtenirConditionPourCommentaireMeta($commentaire) {
$observations = $this->obtenirObsLieesImg('commentaire.meta', $commentaire);
if (is_null($observations)) {
$this->debug[] = "Aucune observation n'est liée à une image dont le commentaire des méta-données correspond à : $commmentaire";
}
$operateur = '';
$sql = $this->assemblerObsEnConditionSql($observations, $operateur);
return $sql;
}
 
private function obtenirConditionPourCommentaireUtilisateur($commentaire) {
$observations = $this->obtenirObsLieesImg('commentaire.utilisateur', $commentaire);
if (is_null($observations)) {
$this->debug[] = "Aucune observation n'est liée à une image dont le commentaire des utilisateur correspond à : $commmentaire";
}
$operateur = '';
$sql = $this->assemblerObsEnConditionSql($observations, $operateur);
return $sql;
}
 
private function obtenirConditionPourCommentaires($commentaire) {
$observations = $this->obtenirObsLieesImg('commentaire.*', $commentaire);
if (is_null($observations)) {
$this->debug[] = "Aucune observation n'est liée à une image dont un des commentaires correspond à : $commmentaire";
}
$operateur = '';
$sql = $this->assemblerObsEnConditionSql($observations, $operateur);
return $sql;
}
 
/**
* Récupération des identifiant d'utilisateur et des ordres des observations correspondant à une date.
* Retour sous forme de tableau : array[identifiant] = array(ordre, ordre...);
*/
private function obtenirObsLieesImg($type, $param) {
// Construction de la requête
$requete = 'SELECT DISTINCT id_observation AS id_obs, co.ce_utilisateur AS utilisateur '.
'FROM cel_images_export AS ci'.
' INNER JOIN cel_export AS co '.
' ON ci.ce_observation = co.id_observation '.
' LEFT JOIN cel_zones_geo AS zg '.
' ON (zg.id_zone_geo = co.ce_zone_geo) '.
"WHERE '' ".
($type == 'date.photo' ? " AND (date_prise_de_vue LIKE ".str_replace('-', ':', $param).") " : '').
($type == 'date.ajout' ? " AND ci.date_creation LIKE $param " : '').
($type == 'date.liaison' ? " AND ci.date_liaison LIKE $param " : '').
// TODO: recherche sur le xml
//($type == 'commentaire.meta' ? " AND ci.commentaire LIKE $param " : '').
($type == 'commentaire.utilisateur' ? " AND ci.commentaire LIKE $param " : '').
($type == 'commentaire.*' ? " AND (ci.commentaire LIKE $param) " : '').
$this->construireWhereCoordonnees().
$this->construireWhereDept().
$this->construireWhereCommune().
$this->construireWhereUtilisateur().
$this->construireWhereNumTaxon().
$this->construireWhereNomTaxon().
$this->construireWhereProjet().
$this->construireWhereTag().
'ORDER BY utilisateur ASC, ordre ASC';
//$this->debug[] = $requete;
//die($requete);
$resultats = Cel::db()->requeter($requete);
 
$observations = null;
if ($resultats != false) {
$observations = array();
foreach ($resultats as $occurence) {
$utilisateur = $occurence['utilisateur'];
$id_obs = $occurence['id_obs'];
if (!array_key_exists($utilisateur, $observations)) {
$observations[$utilisateur] = array();
}
if (!array_key_exists($id_obs, $observations[$utilisateur])) {
$observations[$utilisateur][$id_obs] = $id_obs;
}
}
}
return $observations;
}
 
private function assemblerObsEnConditionSql($observations, $operateur = 'AND') {
$sql = '';
if ($observations != null) {
// Pré-construction du where de la requête
$tpl_where = "(id_observation IN (%s))";
foreach ($observations as $utilisateur => $ids_obs) {
$morceaux_requete[] = sprintf($tpl_where, implode(',', $ids_obs));
}
if (count($morceaux_requete) > 0) {
$sql = implode(" \nOR ", $morceaux_requete);
}
} else {
// Nous voulons que la requête ne retourne rien
$sql = "id_observation = ''";
}
$sql = " $operateur ($sql) ";
return $sql;
}
 
private function construireWhereDept() {
$sql = '';
// Récupération des coordonnées depuis l'id station
extract($this->parametres);
if (isset($dept) && !$this->etreNull($dept)) {
$valeurs_a_proteger = explode(',',trim($dept));
foreach ($valeurs_a_proteger as $valeur) {
$valeurs_protegees[] = '(ce_zone_geo LIKE '.Cel::db()->quote('INSEE-C:'.$valeur.'%').') ';
}
$valeurs = implode(' OR ', $valeurs_protegees);
$sql = " AND ($valeurs) ";
}
return $sql;
}
 
private function construireWhereCommune() {
$sql = '';
// Récupération des coordonnées depuis l'id station
extract($this->parametres);
if (isset($commune) && !$this->etreNull($commune)) {
$commune = Cel::db()->proteger($commune);
$sql = " AND zone_geo LIKE $commune ";
}
return $sql;
}
 
private function construireWherePhotosSeulement() {
$sql = '';
if (isset($this->parametres['photos']) && $this->parametres['photos'] == 1) {
$sql = 'AND co.id_observation IN (SELECT DISTINCT ce_observation FROM cel_images_export) ';
}
return $sql;
}
 
 
private function construireWhereUtilisateur() {
$sql = '';
// Récupération des coordonnées depuis l'id station
extract($this->parametres);
if (isset($utilisateur) && !$this->etreNull($utilisateur)) {
$utilisateur = Cel::db()->proteger($utilisateur);
$sql = " AND courriel_utilisateur = $utilisateur ";
}
return $sql;
}
 
private function construireWhereNumTaxon() {
$sql = '';
// Récupération des coordonnées depuis l'id station
extract($this->parametres);
if (isset($num_taxon) && !$this->etreNull($num_taxon)) {
$num_taxon = Cel::db()->proteger($num_taxon);
$sql = " AND nt = $num_taxon ";
}
return $sql;
}
 
private function construireWhereProjet() {
$sql = '';
// Récupération des coordonnées depuis l'id station
extract($this->parametres);
$projet_sql = isset($projet) ? $this->getSqlWhereProjet($projet) : null;
if (!$this->etreNull($projet_sql)) {
$sql = " AND ($projet_sql) ";
}
return $sql;
}
 
/**
* Traitement de $projet pour construction du filtre dans la requête
*/
private function getSqlWhereProjet($projet) {
$sql = null;
if (isset($projet) && !$this->etreNull($projet)) {
$sql = 'co.mots_cles_texte LIKE '.Cel::db()->proteger($projet);
}
return $sql;
}
 
private function construireWhereTag() {
$sql = '';
extract($this->parametres);
$tag_sql = isset($tag) ? $this->getSqlWhereObsAvecImagesTaguees($tag) : null;
if (!$this->etreNull($tag_sql)) {
$sql = " AND ($tag_sql) ";
}
return $sql;
}
 
/**
* Traitement de $tag pour construction du filtre dans la requête
*/
private function getSqlWhereObsAvecImagesTaguees($tag) {
$sql = null;
if (isset($tag) && !$this->etreNull($tag)) {
$tag_sql = $this->getSqlWhereMotsCles($tag);
// Construction de la requête
$requete = 'SELECT DISTINCT co.id_observation AS id_obs, ci.ce_utilisateur AS utilisateur '.
'FROM cel_images_export AS ci '.
' INNER JOIN cel_export AS co '.
' ON (ci.ce_observation = co.id_observation) '.
' LEFT JOIN cel_zones_geo AS zg '.
" ON (zg.id_zone_geo = co.ce_zone_geo) ".
"WHERE 1 ".
$this->construireWhereCoordonnees().
$this->construireWhereUtilisateur().
$this->construireWhereNumTaxon().
$this->construireWhereNomTaxon().
$this->construireWhereProjet().
(!$this->etreNull($tag_sql) ? "AND ($tag_sql) " : '').
'ORDER BY utilisateur ASC, ci.ordre ASC';
//$this->debug[] = $requete;
//die($requete);
$elements_tag = Cel::db()->requeter($requete);
 
$requete_tag = array();
if ($elements_tag != false && count($elements_tag) > 0) {
 
$filtres = array();
foreach ($elements_tag as $occurence) {
$utilisateur = $occurence['utilisateur'];
$id_obs = $occurence['id_obs'];
if (!array_key_exists($utilisateur, $filtres)) {
$filtres[$utilisateur] = array();
}
if (!array_key_exists($id_obs, $filtres[$utilisateur])) {
$filtres[$utilisateur][$id_obs] = $id_obs;
}
}
 
// Pré-construction du where de la requête
$tpl_where = "(id_observation IN (%s))";
foreach ($filtres as $utilisateur => $id_obs) {
$requete_tag[] = sprintf($tpl_where, implode(',', $id_obs));
}
 
} else {
$this->messages[] = "Aucune observation ne possède d'images avec ce mot-clé.";
}
if (count($requete_tag) > 0) {
$sql = implode(" \nOR ", $requete_tag);
}
}
return $sql;
}
 
/**
* Traitement de $tag pour construction du filtre dans la requête
*/
private function getSqlWhereMotsCles($tag) {
$sql = null;
$mots_cles = $this->decomposerParametreTag($tag);
$requete_projet = $this->getSqlWhereMotsClesImages($mots_cles);
$sql = $requete_projet;
//$this->debug[] = $sql;
return $sql;
}
 
/**
* Traitement de $tag pour construction du filtre dans la requête
*/
private function getSqlWhereMotsClesImages($mots_cles_encodes) {
$where_mots_cles_images = array();
foreach ($mots_cles_encodes['motsClesEncodesProteges'] as $mot_cle_encode) {
$where_mots_cles_images[] = "ci.mots_cles_texte LIKE $mot_cle_encode";
}
$where_mots_cles_images = implode(' '.$mots_cles_encodes['type'].' ', $where_mots_cles_images);
return $where_mots_cles_images;
}
 
private function decomposerParametreTag($tags) {
$mots_cles = array('type' => null, 'motsCles' => null, 'motsClesEncodesProteges' => null);
if (preg_match('/.+OU.+/', $tags)) {
$mots_cles['type'] = 'OR';
$mots_cles['motsCles'] = explode('OU', $tags);
} else if (preg_match('/.+ET.+/', $tags)) {
$mots_cles['type'] = 'AND';
$mots_cles['motsCles'] = explode('ET', $tags);
} else {
$mots_cles['motsCles'][] = $tags;
}
 
foreach ($mots_cles['motsCles'] as $mot) {
$mots_cles['motsClesEncodesProteges'][] = Cel::db()->quote('%'.$mot.'%');
}
$this->debug[] = $mots_cles;
return $mots_cles;
}
 
private function decomposerParametreStation() {
$station_infos = array();
if (isset($this->parametres['station'])) {
$station = $this->parametres['station'];
$this->debug[] = $station;
list($type, $coord) = explode(':', $station);
 
if ($type == 'UTM') {
list($utm_x, $utm_y, $secteur) = explode('-', $coord);
$station_infos = array('utm_x' => $utm_x, 'utm_y' => $utm_y, 'secteur' => $secteur);
} else if ($type == 'LngLat') {
list($longitude, $latitude) = explode('-', $coord);
$station_infos = array('longitude' => $longitude, 'latitude' => $latitude);
}
$station_infos['type'] = $type;
}
return $station_infos;
}
 
private function decomposerParametreDate() {
$date_infos = array(null,null);
if (isset($this->parametres['date'])) {
$date = $this->parametres['date'];
if (strpos($date, ':')) {
list($type, $date) = explode(':', $date);
} else {
$type = 'observation';
}
 
$date = str_replace('/', '-', $date);
if (preg_match('/(^[0-9]{2})-([0-9]{2})-([0-9]{4}$)/', $date, $matches)) {
$date = $matches[3].'-'.$matches[2].'-'.$matches[1];
}
 
$date_infos = array($type, $date);
}
return $date_infos;
}
 
private function decomposerParametreTaxon() {
$nom_infos = array(null, null);
if (isset($this->parametres['taxon'])) {
$taxon = $this->parametres['taxon'];
if (strpos($taxon, ':')) {
$nom_infos = explode(':', $taxon);
} else {
$nom_infos = array('retenu', $taxon);
}
}
return $nom_infos;
}
 
private function decomposerParametreCommentaire() {
$commentaire_infos = array(null, null);
if (isset($this->parametres['commentaire'])) {
$commentaire = $this->parametres['commentaire'];
if (strpos($commentaire, ':')) {
$commentaire_infos = explode(':', $commentaire);
} else {
$commentaire_infos = array('observation', $commentaire);
}
}
return $commentaire_infos;
}
}
/branches/v3.01-serpe/jrest/services/CelImage.php
New file
0,0 → 1,184
<?php
// declare(encoding='UTF-8');
/**
* Service générique permettant de manipuler les Images.
*
* Cas d'utilisation GET :
* /CelImage/liste-ids?obsId=[0-9]+ : ids des images liées à l'observation possédant l'identifiant 'obsId'.
*
* Cas d'utilisation DELETE :
*
* Sortie :
* Type de sortie : json (par défaut), HTML en cas d'erreur.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 CelImage extends Cel {
 
/**
* Méthode appelée avec une requête de type GET.
*/
public function getElement($params) {
$parametres = $this->traiterParametres(array('mode'), $params, false);
extract($parametres);
$contenu = '';
 
$retour = null;
if (isset($mode)) {
$methode = $this->traiterNomMethodeGet($mode);
if (method_exists($this, $methode)) {
$this->parametres = array_shift($params);
$retour = $this->$methode();
} else {
$service = get_class($this);
$this->messages[] = "Ce type de mode '$mode' pour le service '$service' n'est pas disponible.";
}
} else {
$this->messages[] = "Vous devez indiquer un type de mode d'interrogation.";
}
 
if (is_null($retour)) {
$this->messages[] = "Un problème est survenu lors de l'appel au service CelImage";
}
$this->envoyerJson($retour);
}
 
private function getImage() {
$image = null;
if (isset($_GET['imgId'])) {
$recherche = new RechercheImage($this->config);
$params = array('id_image' => $_GET['imgId'], 'transmission' => "1");
$image = $recherche->rechercherImages(null, $params, 0, 1);
if(!empty($image)) {
$image = $image[0];
}
}
return $image;
}
 
/**
* Service fournissant la liste des ids des images liées à une observation.
* Format de l'url du WS :
* /CelImage/liste-ids?obsId=[0-9]+ : ids des images liées à l'observation possédant l'identifiant 'obsId'.
*/
private function getListeIds() {
$ids = array();
 
if (isset($_GET['obsId'])) {
$observations = $this->traiterValeursMultiples($_GET['obsId']);
 
if (! is_null($observations)) {
$requete = 'SELECT occurrence_id as ce_observation, id as id_image '.
'FROM photo '.
"WHERE occurrence_id IN ($observations) ";
 
$resultats = Cel::db()->requeter($requete);
 
$infos = array();
if (is_array($resultats)) {
$infos = $resultats;
}
 
foreach ($infos as $info) {
if (is_numeric($info['id_image'])) {
$ids[$info['ce_observation']][] = (int) $info['id_image'];
}
}
}
}
return $ids;
}
 
/**
* Service permettant de recréer les miniatures pour des ids d'images
* fournis en entrée - @NOTE devrait peut-être être fait avec DELETE ?
*/
protected function getRegenererMiniatures() {
$idsImages = array();
$idsObs = array();
// par image
if (!empty($_GET['ids-img'])) {
$idsImages = explode(',', $_GET['ids-img']);
$idsImages = array_unique($idsImages);
} elseif (!empty($_GET['ids-obs'])) { // par obs
$idsObs = explode(',', $_GET['ids-obs']);
$idsObs = array_unique($idsObs);
// get id images selon id obs
$req = "SELECT DISTINCT id as id_image FROM photo WHERE occurrence_id IN (";
$req .= implode(',', $idsObs);
$req .= ");";
//var_dump($req);
$resultats = Cel::db()->requeter($req);
//var_dump($resultats);
$idsImages = array();
if ($resultats) {
foreach ($resultats as $res) {
$idsImages[] = $res["id_image"];
}
}
}
// a-t-on trouvé au moins une image ?
if (empty($idsImages)) {
$this->envoyerMessageErreur(500, "Erreur: aucune image trouvée - avez-vous bien fourni des valeurs corrected pour un des paramètres \"ids-img\" ou \"ids-obs\" ?");
return false; // aucun id fourni
}
//var_dump($idsImages);
 
$lib = new ImageRecreation($this->config);
foreach ($idsImages as $id) {
if (! is_numeric($id)) {
continue; // @TODO faire plutot un array_filter avant
}
$id = intval($id);
//echo "Regen [$id]\n";
$lib->regenererMiniaturesPourId(array($id));
}
return "ok"; // aucune garantie, c'est juste pour faire style
}
 
/**
* Méthode appelée avec une requête de type DELETE.
* Supprime les infos sur l'image et le fichier correspondant à l'ordre passé en parametre
* Supporte la suppression multiple en passant plusieurs numéros séparés par des virgules
*
* @param int uid[0] id utilisateur
* @param string uid[1] : ordre(s) image(s) obligatoire(s) séparés par des virgules
*
*/
public function deleteElement($uid){
$this->controlerAccessibiliteWs();
$this->controleAppelIpAutorisee();
 
$idImage = isset($uid[0]) ? $uid[0] : '';
$this->verifierIdentifiantImage($idImage);
$idsImages = explode(',', $idImage);
 
$gestionnaireImage = new GestionImage($this->config);
$suppressionImage = $gestionnaireImage->supprimerImage($idsImages);
 
if ($suppressionImage) {
$this->envoyer('OK');
} else {
$this->envoyer("Au moins une image « $idImage » n'a pu être supprimée");
}
}
 
private function verifierIdentifiantImage($chaine) {
$ok = preg_match('/^(?:[0-9]+,)*[0-9]+$/', $chaine);
if ($ok == false) {
$msg = "Indiquer un ou plusieurs identifiants d'image séparés par des virgules.";
$this->envoyerMessageErreur(412, $msg);// Precondition Failed
}
return $ok;
}
}
/branches/v3.01-serpe/jrest/services/NameSearch.php
New file
0,0 → 1,41
<?php
// declare(encoding='UTF-8');
/**
* Service de complétion du nom scientifique.
*
* Cas d'utilisation :
* 1 : L'application recoit un debut de nom scientifique ainsi qu'un code de référentiel
* 2 : Si le genre recu est >1, l'application retourne les 50 premieres genre commencant par ce prefixe
* 3 : Si l'espece est presente l'application retourne les 50 premieres genre+espece commencant par ce prefixe
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Auto-complétions
* @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 NameSearch extends Cel {
 
public function getRessource(){
//TODO: description du service à renvoyer
print '[]';
return;
}
 
public function getElement($uid){
$referentiel = isset($uid[0]) ? $uid[0] : null;
$genre = isset($uid[1]) ? $uid[1] : null;
$espece = isset($uid[2]) ? $uid[2] : null;
 
$chercheur_infos_taxon = new RechercheInfosTaxonBeta($this->config, $referentiel);
$liste_genre_espece = $chercheur_infos_taxon->rechercherGenreEspeceSurPrefixe($genre,$espece);
$this->envoyerJson($liste_genre_espece);
return true;
}
}
/branches/v3.01-serpe/jrest/services/CelObs.php
New file
0,0 → 1,218
<?php
// declare(encoding='UTF-8');
/**
* Service générique de modification des observations.
*
* Cas d'utilisation :
* GET /CelObs/[id] : oû id est l'identifiant d'une observation publique
* POST /CelObs/[id] : oû id est l'identifiant d'une observation publique
* si les data du POST contienent :
* - 1 données :
* - 'transmission' : publier ou dépublier une obs
* - 3 données :
* - 'id_observation', 'nom_sel_nn', 'nom_referentiel' : permet d'accepter une proposition (DEL)
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @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 CelObs extends Cel {
private $rechercheObs = null;
private $chpsEtendus = null;
private $donnees = null;
 
public function __construct($config) {
parent::__construct($config);
$this->rechercheObs = new RechercheObservationExport($config, array("standard"=>"0"));
$this->chpsEtendus = new GestionChampsEtendus($config, 'obs');
 
$this->chargerNomsTablesReferentiels();
}
 
private function chargerNomsTablesReferentiels() {
// Créé des attributs avec le code du référentiel : bdtfx, bdtxa, apd, isfan
foreach ( $this->config['referentiels'] as $referentiel => $table) {
$this->$referentiel = $table;
}
}
 
public function getElement($ressources){
$retour = false;
$idObs = $ressources[0];
if (isset($idObs) && preg_match('/^[0-9]+$/', $idObs)) {
 
$criteres = array('id_observation' => $idObs, 'transmission' => 1, 'standard' => 0);
$obsTrouvee = $this->rechercheObs->rechercherObservations(null, $criteres, 0, 1)->get();
 
$observation = array();
if (is_array($obsTrouvee) && count($obsTrouvee) > 0) {
$observation = $obsTrouvee[0];
}
$observation = $this->preparerChamps($observation);
$observation = $this->selectionnerChamps($observation);
$observation = $this->formaterClePourJs($observation);
 
$champsEtendus = $this->chpsEtendus->consulter($idObs);
if (is_array($champsEtendus) && count($champsEtendus) > 0) {
$champsEtendus = $this->preparerChampsEtendus($champsEtendus);
$observation['extension'] = $champsEtendus;
}
 
$this->envoyerJson($observation);
$retour = true;
}
return $retour;
}
 
private function preparerChamps($champs) {
if (isset($champs['date_observation'])) {
$date = explode(' ', $champs['date_observation']);
$champs['date_observation'] = $date[0];
}
return $champs;
}
 
private function selectionnerChamps($observation) {
$champs = array('id_observation', 'nom_sel', 'nom_ret', 'nom_ret_nn', 'nt', 'famille',
'nom_referentiel', 'ce_zone_geo', 'zone_geo', 'lieudit', 'station', 'milieu', 'latitude', 'longitude',
'geodatum', 'date_observation', 'mots_cles_texte', 'commentaire', 'date_creation', 'date_modification',
'date_transmission', 'code_insee_calcule', 'abondance', 'certitude', 'phenologie', 'altitude');
$selection = array();
foreach ($champs as $chp) {
if (isset($observation[$chp])) {
$selection[$chp] = $observation[$chp];
}
}
return $selection;
}
 
private function formaterClePourJs(Array $tableau) {
$tableauJs = array();
foreach ($tableau as $cle => $valeur) {
if ($cle == 'ce_zone_geo') {
$cle = 'codeZoneGeo';
} else {
$cle = str_replace(' ', '', ucwords(str_replace('_', ' ', $cle)));
$cle{0} = strtolower($cle{0});
}
$tableauJs[$cle] = $valeur;
}
return $tableauJs;
}
 
private function preparerChampsEtendus($champs) {
$retour = array();
foreach ($champs as $chp) {
$retour[$chp['cle']] = array('valeur' => $chp['valeur']);
}
return $retour;
}
 
/**
* Méthode appelée avec une requête de type POST et un identifiant d'observation.
* Modifie une observation en fonction des informations envoyées en POST.
* Utilisé par:
* - service:del:0.1/determinations/ : ValiderDetermination.php::modifierObservationParDetermination()
* - service:del:0.1/observations/#idObs [POST] : pour dépublier une observation
*
* @param $uid array $uid[0] (int) : identifiant observation
* @param pairs array tableau contenant les champs à modifier sous la forme : nom_du_champ=nouvelle_valeur
*/
public function updateElement($ressources, $donnees) {
$this->donnees = $donnees;
if ($this->controlerAccessibiliteWs()) {
if ($this->controleAppelIpAutorisee()) {
$idObs = isset($ressources[0]) ? $ressources[0] : '';
$this->verifierIdentifiantObs($idObs);
 
if (count($this->donnees) == 1) {
$donneesObligatoires = array('transmission');
if ($this->verifierDonneesObligatoires($donneesObligatoires)) {
$this->depublierObs($idObs);
}
} else if (count($this->donnees) == 3) {
$donneesObligatoires = array('id_observation', 'nom_sel_nn', 'nom_referentiel');
if ($this->verifierDonneesObligatoires($donneesObligatoires)) {
$this->accepterPropositionDEL($idObs);
}
} else {
$msg = "La modification complète d'une observation n'est pas implémentée.";
$this->envoyerMessageErreur(501, $msg);
}
 
$this->envoyer('ok');
}
}
return true;
}
 
private function verifierIdentifiantObs($chaine) {
$ok = preg_match('/^[0-9]+$/', $chaine);
if ($ok == false) {
$msg = "Indiquer un seul identifiant numérique d'observation.";
$this->envoyerMessageErreur(412, $msg);
}
return $ok;
}
 
private function verifierDonneesObligatoires($champsObligatoires) {
foreach ($champsObligatoires as $param) {
if (! isset($this->donnees[$param])) {
$msg = sprintf("Paramètre %s manquant (parmi %s)", $param, implode(', ', $champsObligatoires));
$this->envoyerMessageErreur(412, $msg);
}
}
return true;
}
 
private function depublierObs($idObs) {
$gestionnaireObs = new GestionObservation($this->config);
$depublication = $gestionnaireObs->modifierTransmissionObservation($idObs, false);
if ($depublication === false) {
$msg = "Un problème est survenu (voir log). L'observation « $idObs » n'a pas pu être dépubliée.";
$this->envoyerMessageErreur(304, $msg);
}
}
 
 
 
/**
* Modifie une observation aveec les infos d'une proposition :
* Nous complétons les données de la proposition acceptée ici car:
* 1) la table tb_del.del_commentaire ne contient pas toutes les informations nécessaires
* 2) la table tb_del.del_commentaire ne *devrait* pas contenir beaucoup plus que nom_sel et nom_sel_nn
* 3) la génération de ces données ici, au moment de l'UPDATE, est le meilleur garant de leur fiabilité
*/
private function accepterPropositionDEL($idObs) {
$gestion_observation = new GestionObservation($this->config);
$donnees = array_map('trim', $this->donnees);
$donneesAModifier = array(
'certitude' => 'certain',
'nom_referentiel' => $donnees['nom_referentiel'],
'nom_sel_nn' => $donnees['nom_sel_nn'],
);
 
$modification = $gestion_observation->modifierObservationPublique($idObs, $donneesAModifier);
 
if ($modification) {
// TODO: en modifiant bien la classe de gestion mots clés, on aurait peut être pas besoin de l'id
// utilisateur (car l'id de l'obs est déjà sans ambiguité)
$idUtilisateur = $this->rechercheObs->obtenirIdUtilisateurPourIdObs($idObs);
 
// supression des éventuelles liaison de l'obs avec le mot clé contenu dans obsKeywordDelete
$gestionMotsClesObs = new GestionMotsClesChemin($this->config, 'obs');
$supp_liaison_mot_cle = $gestionMotsClesObs->supprimerLiaisonPourMotCleEtIdElementLie('aDeterminer', $idObs, $idUtilisateur);
} else {
$msg = "Impossible de modifier l'observation associée à cet identifiant. Erreur mysql : " . mysql_error();
$this->envoyerMessageErreur(500, $msg);// Internal Server Error
}
}
}
/branches/v3.01-serpe/jrest/services/CelMessage.php
New file
0,0 → 1,100
<?php
// declare(encoding='UTF-8');
/**
* Service encapsulant l'envoie de courriel via le web service de l'annuaire.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Encapsulation
* @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 CelMessage extends Cel {
 
private $mode = 'obs';
 
/**
* Méthode appelée avec une requête de type POST avec un identifiant d'obs.
* Envoi un message à l'utilisateur ayant saisi l'observation
*
* @param int $uid[0] mode interrogation (obs ou image)
* @param int $uid[1] identifiant observation ou image suivant le mode
* @param pairs array tableau contenant les valeurs du formulaire de messagerie
* (même format que le web service messagerie utilisateur de l'annuaire)
*/
public function updateElement($uid,$pairs) {
$this->verifierParametresObligatoires($uid, $pairs);
if (isset($pairs['type_envoi'])) {
unset($pairs['type_envoi']);
}
 
if ($uid[0] != 'obs' && $uid[0] != 'image') {
$info = array();
$info = 'Aucun mode n\'a été indiqué ';
$this->envoyer($info, 'text/html', 'utf-8', false);
exit;
} else {
$this->mode = $uid[0];
$id = $uid[1];
 
$methode = 'obtenirCourrielUtilisateurPourId'.ucwords($this->mode);
$courriel_utilisateur = $this->$methode($id);
 
if ($courriel_utilisateur !== false) {
$resultat = $this->envoyerRequeteMessage($courriel_utilisateur, $pairs);
$this->envoyerJson($resultat);
exit;
} else {
$info = array();
$info = 'Impossible de trouver le courriel associé à cet identifiant ';
$this->envoyer($info, 'text/html', 'utf-8', false);
exit;
}
}
}
 
private function envoyerRequeteMessage($courriel_utilisateur, $pairs) {
$base_url = $this->config['settings']['baseURLServicesAnnuaireTpl'];
$rest_client = $this->getRestClient();
$url_messagerie = str_replace('%s', "utilisateur/".urlencode($courriel_utilisateur)."/message", $base_url);
$resultat_json = $rest_client->modifier($url_messagerie, $pairs);
$resultat = json_decode($resultat_json);
return $resultat;
}
 
private function verifierParametresObligatoires($uid ,$params) {
$params_obligatoires = array('sujet', 'message', 'utilisateur_courriel', 'destinataire_id');
$info = array();
 
if(!isset($uid[1]) || !is_numeric($uid[1])) {
$info .= 'l\' identifiant doit être un entier ';
}
 
foreach($params_obligatoires as $param) {
if(!isset($params[$param]) || trim($params[$param]) == "") {
$info = 'le paramètre '.$param.' doit exister et ne peut pas être vide ';
}
}
 
if(!empty($info)) {
$this->envoyer($info, 'text/html', 'utf-8', false);
exit;
}
}
 
private function obtenirCourrielUtilisateurPourIdObs($id_obs) {
$rechercheObservation = new RechercheObservation($this->config);
return $rechercheObservation->obtenirCourrielUtilisateurPourIdObs($id_obs);
}
 
private function obtenirCourrielUtilisateurPourIdImage($id_image) {
$rechercheImage = new RechercheImage($this->config);
return $rechercheImage->obtenirCourrielUtilisateurPourIdImage($id_image);
}
}
/branches/v3.01-serpe/jrest/services/InventoryTaxonPresent.php
New file
0,0 → 1,135
<?php
// declare(encoding='UTF-8');
/**
* Service vérifiant si un taxon a été signalé ou non dans une zone géographique donnée
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @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 InventoryTaxonPresent extends Cel {
private $source = "chorologie";
 
/**
* Renvoie les zones où le taxon a été observé
*
* uid[0] : référentiel
* uid[1] : numéro nomenclatural
*/
public function getElement($uid) {
// Référentiel et num nom obligatoires
if(count($uid) < 2) {
return null;
}
$referentiel = $uid[0];
$num_nom = intval($uid[1]);
$this->source = !empty($_GET['source']) ? $_GET['source'] : $this->source;
if(!empty($_GET['ce_zone_geo']) || !empty($_GET['pays'])) {
$zone_geo = !empty($_GET['ce_zone_geo']) ? $_GET['ce_zone_geo'] : null;
$pays = !empty($_GET['pays']) ? $_GET['pays'] : null;
if($this->source == "chorologie") {
$res = $this->taxonEstPresentDansZoneGeoChorologie($referentiel, $num_nom, $pays, $zone_geo);
} else if($this->source == "cel") {
$res = $this->taxonEstPresentDansZoneGeoCel($referentiel, $num_nom, $pays, $zone_geo);
}
} else {
$res = $this->obtenirZonesGeoTaxonPresentCel($referentiel, $num_nom);
}
$this->envoyerJson($res);
}
private function taxonEstPresentDansZoneGeoChorologie($referentiel, $num_nom, $pays, $zone_geo) {
$res = "";
// Pour le moment on ne gère que bdtfx, il suffira d'ajouter l'appel à d'autres ws de chorologies
// dès qu'on les obtiendra (on pourrait peut être déjà le faire avec les antilles)
switch($referentiel) {
case "bdtfx":
$dpt = $this->convertirZoneGeoVersDepartement($zone_geo);
$base_url_choro = $this->config['eflore']['url_service_chorologie_presence'];
$url_choro = str_replace('{num_nom}', $num_nom, $base_url_choro).'/'.$dpt;
$res = json_decode(file_get_contents($url_choro), true);
// Renvoyer un int "stringé" est bien plus pratique pour le parsing
$res = (string)intval(!empty($res) && $res['present']);
break;
default:
$res = "";
}
return $res;
}
private function convertirZoneGeoVersDepartement($zone_geo) {
return substr(str_replace('INSEE-C:', '', $zone_geo), 0, 2);
}
private function taxonEstPresentDansZoneGeoCel($referentiel, $num_nom, $pays = null, $zone_geo = null) {
$referentiel = Cel::db()->proteger($referentiel);
$num_nom = Cel::db()->proteger($num_nom);
$requete = "SELECT COUNT(id_observation) > 1 as present FROM cel_obs ".
"WHERE nom_referentiel = ".$referentiel." AND ".
"(nom_sel_nn = ".$num_nom." OR nom_ret_nn = ".$num_nom.") ".
($zone_geo != null ? " AND ce_zone_geo LIKE ".Cel::db()->proteger($zone_geo.'%') : '').
($pays != null ? " AND pays = ".Cel::db()->proteger($pays) : '');
$res = Cel::db()->requeter($requete);
 
return $res[0]['present'];
}
private function obtenirZonesGeoTaxonPresentCel($referentiel, $num_nom) {
$referentiel = Cel::db()->proteger($referentiel);
$num_nom = Cel::db()->proteger($num_nom);
$requete = "SELECT DISTINCT pays, ce_zone_geo FROM cel_obs WHERE nom_referentiel = ".$referentiel." AND ".
"(nom_sel_nn = ".$num_nom." OR nom_ret_nn = ".$num_nom.")";
$res = Cel::db()->requeter($requete);
return $this->formaterResultat($res);
}
private function formaterResultat($res) {
$res_fmt = array();
foreach($res as &$r) {
$pays = !empty($r['pays']) ? $r['pays'] : 'inconnu';
if($this->doitCreerIndexPaysZoneGeo($res_fmt, $r, $pays)) {
$res_fmt[$pays] = array();
}
if($this->estUneZoneGeoBienFormee($r)) {
$res_fmt[$pays][] = $r['ce_zone_geo'];
}
}
return $res_fmt;
}
private function doitCreerIndexPaysZoneGeo($res_fmt, $r, $pays) {
return !isset($res_fmt[$pays]) && $this->estUneZoneGeoBienFormee($r);
}
private function estUneZoneGeoBienFormee($r) {
return !empty($r['ce_zone_geo']) && $r['ce_zone_geo'] != "INSEE-C:";
}
}
?>
/branches/v3.01-serpe/jrest/services/CelWidgetExport.php
New file
0,0 → 1,381
<?php
// declare(encoding='UTF-8');
/**
* Service fournissant des exports des données publiques du CEL pour le widget.
*
* Format du service :
* /CelWidgetExport/format
* /CelWidgetExport/csv
*
* Les paramêtres :
* - "start" indique le numéro du premier item à afficher
* - "limit" nombre d'items à afficher
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Widget
* @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>
*/
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(dirname(realpath(__FILE__))) . '/lib');
// la sortie est binaire (xls), mais OLE n'est pas compatible E_ALL en PHP-5.4
error_reporting(error_reporting() & ~E_STRICT);
require_once 'lib/OLE.php';
require_once 'lib/Spreadsheet/Excel/Writer.php';
 
class CelWidgetExport extends Cel {
private $nom_fichier_export = 'cel_export';
// certains paramètres apparaissent plusieurs fois car ils ont des alias
// dans certains widgets
private $parametres_autorises = array(
'id_utilisateur' => 'ce_utilisateur',
'utilisateur' => 'courriel_utilisateur',
'courriel_utilisateur' => 'courriel_utilisateur',
'pays' => 'pays',
'commune' => 'zone_geo',
'zone_geo' => 'zone_geo',
'dept' => 'departement',
'departement' => 'departement',
'lieudit' => 'lieudit',
'station' => 'station',
'projet' => 'mots_cles',
'programme' => 'programme',
'num_taxon' => 'nt',
'certitude' => 'certitude',
'date_debut' => 'date_debut',
'date_fin' => 'date_fin',
'taxon' => 'taxon',
'identiplante' => 'validation_identiplante',
'validation_identiplante' => 'validation_identiplante',
'annee' => 'annee',
'mois' => 'mois',
'jour' => 'jour',
'recherche' => 'recherche',
'id_mots_cles' => 'id_mots_cles',
'mots_cles' => 'mots_cles',
'debut' => 'debut',
'limite' => 'limite',
'format' => 'format',
'colonnes' => 'colonnes',
'transmission' => 'transmission',
'obsids' => 'obsids',
'standard' => 'standard',
);
private $limite_decoupage_defaut = 9000;
private $format = 'csv';
public $id_utilisateur = null;
public $export_prive = false;
// un cache, initialisé par certaines fonctions de préchargement, à la manière
// de ce qui est fait par FormateurGroupeColonne
static $cache = Array();
public function getRessource() {
return $this->getElement(array());
}
/**
* Méthode appelée avec une requête de type GET.
*/
public function getElement($params = array()) {
switch(@strtolower($params[0])) {
case 'calcul':
$this->getCalcul();
break;
case 'export':
$this->getExport();
break;
default:
$this->getExport();
}
}
private function getCalcul() {
$criteres = $this->traiterParametresAutorises($_GET);
if (!isset($criteres['standard'])) {
$criteres['transmission'] = 1;
} else {
unset($criteres['transmission']);
}
// Définit si l'on exporte les obs privées ainsi que les champs étendus privés
$this->export_prive = $this->doitEtPeutExporterObsPrivees($criteres);
if($this->export_prive) {
unset($criteres['transmission']);
$this->id_utilisateur = $criteres['id_utilisateur'];
}
//if (isset($criteres['standard']) && $criteres['standard'] == 1) {
$chercheur_observations = new RechercheObservationExport($this->config);
/*} else {
$chercheur_observations = new RechercheObservation($this->config);
}*/
$numero_page = isset($criteres['debut']) ? $criteres['debut'] : 0;
$limite = isset($criteres['limite']) ? $criteres['limite'] : 0;
$colonnes = @FormateurGroupeColonne::colGroupsValidation($criteres['colonnes'], $criteres['programme']);
unset($criteres['limite']);
unset($criteres['debut']);
unset($criteres['format']);
unset($criteres['colonnes']);
$nb_observations = $chercheur_observations->compterObservations(null, $criteres);
$limite_decoupage = $this->calculerNbLignesMaxParFichier(explode(',', $colonnes));
$url_telechargements = array();
$intervalle = 0;
$params_url = $criteres;
unset($params_url['transmission']);
do {
$base_url = $this->config['settings']['baseURLAbsolu'].'CelWidgetExport/export';
$params_url['debut'] = $intervalle;
$params_url['limite'] = $limite_decoupage;
$url_telechargement_fichier = $base_url;
$url_telechargements[] = $base_url.'?'.http_build_query($params_url).'&format='.$this->format.'&colonnes='.$colonnes;
$intervalle += $limite_decoupage;
$nb_observations -= $limite_decoupage;
} while($nb_observations > 0);
$this->envoyerJson($url_telechargements);
}
private function calculerNbLignesMaxParFichier($colonnes) {
$limite = $this->limite_decoupage_defaut;
switch($this->format) {
case 'csv':
$limite = 20000;
break;
case 'xls':
$limite = 8000;
break;
case 'pdf':
$limite = 300;
break;
}
return $limite;
}
private function getExport() {
$criteres = $this->traiterParametresAutorises($_GET);
// ne pas faire de super-requête en cas d'absence de paramètres
// par exemple "format", au minimum, devrait être défini
if(!$criteres) die('erreur: pas de paramètre reçu');
if(!in_array($this->format, array('pdf','csv','xls'))) die('erreur: format invalide');
if (!isset($criteres['standard'])) {
$criteres['transmission'] = 1;
} else {
unset($criteres['transmission']);
}
// Définit si l'on exporte les obs privées ainsi que les champs étendus privés
$this->export_prive = $this->doitEtPeutExporterObsPrivees($criteres);
if($this->export_prive) {
unset($criteres['transmission']);
$this->id_utilisateur = $criteres['id_utilisateur'];
}
//if (isset($criteres['standard']) && $criteres['standard'] == 1) {
$chercheur_observations = new RechercheObservationExport($this->config);
/*} else {
$chercheur_observations = new RechercheObservation($this->config);
}*/
$debut = isset($criteres['debut']) ? intval($criteres['debut']) : 0;
$limite = isset($criteres['limite']) ? intval($criteres['limite']) : 0;
$groupes = @FormateurGroupeColonne::colGroupsValidation($criteres['colonnes']);
$groupes .= ',auteur';
if(!$groupes) die('erreur: Ne peut identifier les groupes de champs demandés.');
if(isset($criteres['obsids'])) {
$obsids = (is_array($criteres['obsids'])) ? implode(',', $criteres['obsids']) : $criteres['obsids'];
$criteres['sql_brut'] = sprintf('id_observation IN (%s)',
$obsids);
}
unset($criteres['limite']);
unset($criteres['debut']);
unset($criteres['format']);
unset($criteres['colonnes']);
unset($criteres['obsids']);
$observations = $chercheur_observations->rechercherObservations(null, $criteres, $debut, $limite, TRUE)->get();
$ids = array();
foreach($observations as &$obs) {
$ids[] = $obs['id_observation'];
}
if($this->format == 'pdf') {
$pdf = $this->convertirEnPdf($observations);
$pdf->pdf->Output('etiquettes.pdf', 'I');
exit;
}
// cas XLS et CSV: on peut avoir besoin des champs étendus, des noms communs et des champs baseflor:
// Obtention des colonnes correspondantes aux groupes de champs
$colonnes = FormateurGroupeColonne::nomEnsembleVersListeColonnes($groupes);
/*
Champs étendus et noms communs, si demandés.
* Pour "nom commun", "preload" retourne NULL, car c'est le cache statique de FormateurGroupeColonne
qu'il initialise et utilise en interne sans qu'un passage par paramètre dans le contexte de CelWidgetExport
ne soit nécessaire.
* Pour les champs étendus, c'est CelWidgetExport::$cache qui est utilisé, aussi bien pour les en-têtes que
pour les données préchargées, cf self::traiterLigneEtendue()
*/
self::$cache = FormateurGroupeColonne::preload($colonnes, $this, $ids);
// TODO: tous les champs étendus et les paramètres supplémentaires devraient être passés en un seul
// tableau (et chaque formateur csv, xls etc... pourrait également être dans une classe à part)
switch($this->format) {
case 'csv':
$csv = $this->convertirEnCsv($observations, $colonnes);
$this->envoyerCsv($csv);
break;
case 'xls':
$xls = $this->convertirEnXls($observations, $colonnes);
$this->envoyerXls($xls);
break;
default:
}
}
protected function traiterParametresAutorises(Array $parametres) {
$parametres_traites = array();
$this->format = (isset($parametres['format']) && $parametres['format'] != '') ? $parametres['format'] : $this->format;
foreach($parametres as $cle => $valeur) {
if(is_string($valeur) && !trim($valeur)) continue;
if(isset($this->parametres_autorises[$cle])) {
$parametres_traites[$this->parametres_autorises[$cle]] = $valeur;
}
}
return $parametres_traites;
}
private function envoyerCsv($csv) {
header('Content-Type: text/csv; charset=UTF-8');
header('Content-Disposition: attachment;filename='.$this->nom_fichier_export.'.csv');
echo $csv;
exit;
}
private function envoyerXls($workbook) {
$workbook->close();
exit;
}
private function convertirEnCsv(&$data, $colonnes) {
$chemin_temp = "php://temp";
$outstream = fopen($chemin_temp, 'r+');
$intitule_champs = array_merge(FormateurGroupeColonne::getIntitulesColonnes($colonnes));
// en premier car utilisé génériquement dans getLigneObservation()
if(isset($colonnes['baseflor'])) {
$intitule_champs = array_merge($intitule_champs, FormateurGroupeColonne::$baseflor_col);
}
// en second car manuellement appellé plus bas, TODO: utiliser l'API du FormateurGroupeColonne
if(isset($colonnes['etendu'])) {
$intitule_champs = array_merge($intitule_champs, array_values(self::$cache['etendu']['header']));
}
// header
fputcsv($outstream, $intitule_champs, ',', '"');
// lignes
foreach($data as &$ligne) {
$ligne = self::filtrerDonneesSensibles($ligne);
$ligne = FormateurGroupeColonne::getLigneObservation($ligne, $colonnes, $this);
fputcsv($outstream, $ligne, ',', '"');
}
rewind($outstream);
$csv = stream_get_contents($outstream);
fclose($outstream);
return $csv;
}
private function convertirEnXls(&$data, $colonnes) {
$this->extendSpreadsheetProductor = new SpreadsheetProductor();
$this->extendSpreadsheetProductor->initSpreadsheet();
$workbook = new Spreadsheet_Excel_Writer();
// avant la définition du titre de la worksheet !
$workbook->setVersion(8);
$worksheet = $workbook->addWorksheet('Liste');
$workbook->setTempDir($this->config['cel']['chemin_stockage_temp']);
$worksheet->setInputEncoding('utf-8');
$workbook->send($this->nom_fichier_export.'.xls');
$nb_lignes = 1;
$intitule_champs = array_merge(FormateurGroupeColonne::getIntitulesColonnes($colonnes));
// en premier car utilisé génériquement dans getLigneObservation()
if(isset($colonnes['baseflor'])) {
$intitule_champs = array_merge($intitule_champs, FormateurGroupeColonne::$baseflor_col);
}
// en second car manuellement appellé plus bas, TODO: utiliser l'API du FormateurGroupeColonne
if(isset($colonnes['etendu'])) {
$intitule_champs = array_merge($intitule_champs, array_values(self::$cache['etendu']['header']));
}
// header
$indice = 0;
foreach ($intitule_champs as &$intitule) {
$worksheet->write(0,$indice++,$intitule);
}
foreach($data as &$ligne) {
$ligne = self::filtrerDonneesSensibles($ligne);
$ligne = FormateurGroupeColonne::getLigneObservation($ligne, $colonnes, $this);
$indice = 0;
foreach($ligne as &$champ) {
$worksheet->write($nb_lignes,$indice++,$champ);
}
$nb_lignes++;
}
return $workbook;
}
private function convertirEnPdf(&$observations) {
if(count($observations) > 300) die('erreur: trop de données');
//require_once('GenerateurPDF.php');
$pdf = new GenerateurPDF();
$pdf->export($observations);
return $pdf;
}
static function filtrerDonneesSensibles($ligne) {
if(stripos($ligne['mots_cles_texte'], 'sensible') !== false) {
$ligne['latitude'] = '';
$ligne['longitude'] = '';
}
return $ligne;
}
private function doitEtPeutExporterObsPrivees($criteres) {
return isset($criteres['ce_utilisateur']) &&
$this->peutExporterObsPrivees($criteres['ce_utilisateur']);
}
private function peutExporterObsPrivees($id_utilisateur) {
$gestion_utilisateur = new GestionUtilisateur($this->config);
$utilisateur = $gestion_utilisateur->obtenirIdentiteConnectee();
return ! empty($utilisateur['id_utilisateur']) && $id_utilisateur == $utilisateur['id_utilisateur'];
}
 
}
?>
/branches/v3.01-serpe/jrest/services/ImageRDF.php
New file
0,0 → 1,102
<?php
// declare(encoding='UTF-8');
/**
* Retourne des infos au format RDF sur les imags.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 ImageRDF extends Cel {
 
/**
* Recherche des images associee au numero nomenclatural
* @param numeric $uid [0] : numero nomenclatural obligatoire , $uid[1] (optionnel) : taille image : S , M, L (default)
*/
public function getElement($uid){
$nomSelNnP = Cel::db()->proteger($uid[0]);
$taille = isset($uid[1]) ? $uid[1] : 'L';
 
// Recherche de toutes les observations transmises du taxon pour lesquelles une photo est associee.
$requete = 'SELECT co.id_observation, co.nom_sel, co.ordre, '.
' co.prenom_utilisateur, co.nom_utilisateur, co.courriel_utilisateur, '.
' co.zone_geo, .co.ce_zone_geo, co.date_observation, '.
' ci.id_image, ci.nom_original '.
'FROM cel_obs AS co INNER JOIN cel_images AS ci ON (co.id_observation = ci.ce_observation) '.
"WHERE co.nom_sel_nn = $nomSelNnP ".
'AND co.transmission = 1 '.
' -- '.__FILE__.':'.__LINE__;
//echo $requete;
$resultats = Cel::db()->requeter($requete);
 
$auteursEmails = array();
$donnees = array();
if ($resultats !== false && is_array($resultats)) {
$urlImgTpl = $this->config['settings']['celImgUrlTpl'];
foreach ($resultats as $picture) {
$id = sprintf('%09s', $picture['id_image']) ;
$dateObsTimestamp = $this->convertirDateHeureMysqlEnTimestamp($picture['date_observation']);
$auteursEmails[] = $picture['courriel_utilisateur'];
 
$data = array();
$data['url_img'] = sprintf($urlImgTpl, $id.$taille);
$data['id_image'] = $picture['id_image'];
$data['guid'] = 'urn:lsid:tela-botanica.org:celpic:'.$data['id_image'];
$data['nom_original'] = $picture['nom_original'];
$data['id_observation'] = $picture['id_observation'];
$data['nom_sel'] = $picture['nom_sel'];
$data['ordre'] = $picture['ordre'];
$data['zone_geo'] = utf8_decode($picture['zone_geo']);
$data['ce_zone_geo'] = $picture['ce_zone_geo'];
$data['ce_zone_geo'] = $picture['ce_zone_geo'];
$data['courriel_utilisateur'] = $picture['courriel_utilisateur'];
$data['date_observation'] = ($dateObsTimestamp != 0) ? date('d/m/Y', $dateObsTimestamp) : null;
$donnees[] = $data;
}
}
$auteursIntitules = $this->creerAuteurs($auteursEmails);
$xml = $this->formaterRdf($donnees, $auteursIntitules);
// Envoi du xml au navigateur
header("Content-Type: text/xml");
echo utf8_encode(str_replace(' & ', ' &#38; ', $xml));
}
 
private function formaterRdf($donnees, $auteurs) {
$xml = '<?xml version="1.0" encoding="utf-8"?>'."\n".
'<rdf:RDF'."\n".
' xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"'."\n".
' xmlns:dc="http://purl.org/dc/elements/1.1/"'."\n".
' xmlns:dcterms="http://purl.org/dc/terms">'."\n";
if (count($donnees) > 0) {
foreach ($donnees as $data) {
$intituleAuteur = $auteurs[$data['courriel_utilisateur']];
$xml .= ' <rdf:Description about="'.$data['url_img'].'"'."\n".
' dc:identifier="'.$data['guid'].'"'."\n".
' dc:title="'.$data['nom_sel'].'"'."\n".
' dc:description="'.$data['nom_sel'].' - '.
'[fichier_origine:'.$data['nom_original'].']'.
'[image_identifiant:'.$data['id_image'].']'.
'[image_ordre:'.$data['ordre'].']'.
'[observation_identifiant:'.$data['id_observation'].']'.
'[observation_ordre:'.$data['ordre'].']'.'"'."\n".
' dc:creator="'.$intituleAuteur.'"'."\n".
' dc:publisher="CEL"'."\n".
' dcterms:spatial="'.$data['zone_geo']." (".$data['ce_zone_geo'].")".'"'."\n";
if (isset($data['date_observation'])) {
$xml .= ' dcterms:created="'.$data['date_observation'].'"'."\n";
}
$xml .= ' dcterms:licence="CC BY-SA"/>'."\n";
}
}
$xml .= '</rdf:RDF>'."\n";
return $xml;
}
}
/branches/v3.01-serpe/jrest/services/InventoryImageLink.php
New file
0,0 → 1,198
<?php
// declare(encoding='UTF-8');
/**
* Service de liaisons d'images à des observations
* Cas d'utilisation :
* 2: Le service lie une ou plusieurs images à une observation
* 3: Le service renvoie l'observation liée à une image
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 InventoryImageLink extends Cel {
 
public function createElement($pairs) {
// Controle detournement utilisateur
$this->controleUtilisateur($pairs['ce_utilisateur']);
$id_utilisateur = $pairs['ce_utilisateur'];
 
if (!isset($pairs['id_image'])) {
die('err');
}
 
// filtrage des entiers
$ids_observations = self::filterInt($pairs['id_observation']);
$ids_images = self::filterInt($pairs['id_image']);
if (empty($ids_images) || empty($ids_observations)) {
die('err');
}
// filtrage des entiers à partir des ids existant réellement en DB
$ids_images_filtrees = $this->filtrerImgUtilisateur($ids_images, $id_utilisateur);
$infos_observations_filtrees = $this->filtrerObsUtilisateur($ids_observations, $id_utilisateur);
$ids_observations_filtrees = self::extraireValeurs($infos_observations_filtrees, 'id_observation');
if (empty($ids_images_filtrees) || empty($ids_observations_filtrees)) {
die('err');
}
 
$values = array();
foreach ($ids_images_filtrees as $id_img) {
foreach ($infos_observations_filtrees as $infos_obs) {
$id_obs = $infos_obs['id_observation'];
$dateTransmission = ($infos_obs['date_transmission'] != '') ? Cel::db()->proteger($infos_obs['date_transmission']) : 'NULL' ;
$transmission = $infos_obs['transmission'];
$values[] = "($id_img, $id_obs, NOW(), NOW(), $dateTransmission, $transmission)";
}
}
$clauseValues = implode(',', $values);
// ceci n'est pas un INSERT, c'est un UPDATE multiple en une seule requête
$requete = 'INSERT INTO cel_images (id_image, ce_observation, date_modification, date_liaison, date_transmission, transmission) '.
"VALUES $clauseValues ".
'ON DUPLICATE KEY UPDATE '.
' ce_observation = VALUES(ce_observation), '.
' date_modification = NOW(), '.
' date_liaison = NOW(), '.
' date_transmission = VALUES(date_transmission), '.
' transmission = VALUES(transmission) '.
' -- ' . __FILE__ . ':' . __LINE__;
$resultat = Cel::db()->executer($requete);
if ($resultat) {
// mise à jour de la date de modification de l'observation
$idsObsConcat = implode(', ', $ids_observations);
$requete = "UPDATE cel_obs SET date_modification = NOW() ".
"WHERE id_observation IN ($idsObsConcat) ".
' -- ' . __FILE__ . ':' . __LINE__;
$resultat = Cel::db()->executer($requete);
// @TODO faudrait faire une transaction et retourner false si l'UPDATE de cel_obs échoue
exit('OK');
}
exit(); // peut-être qu'aucune mise à jour n'a eu lieu (ON DUPLICATE KEY)
}
 
/**
* Retourne les identifiants des images liées à une observation ou l'identifiant de l'obs liée à une image, suivant le paramètre :
* uid[0] : utilisateur obligatoire
* uid[1] : id_observation=valeur ou bien id_image=valeur
*/
public function getElement($uid) {
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
if ($uid) {
$param = $uid[1] ;
//TODO utiliser le GET plutôt pour récuperer id image ou observation
list($field, $value) = explode('=', $param);
$valueP = Cel::db()->proteger($value);
 
if ($field == 'id_observation') {
$requete = 'SELECT id_image, hauteur , largeur '.
'FROM cel_images '.
"WHERE ce_observation = $valueP ".
' -- '.__FILE__.':'.__LINE__;
} else if ($field == 'id_image') {
$requete = 'SELECT co.* '.
'FROM cel_obs AS co INNER JOIN cel_images AS ci ON (co.id_observation = ci.ce_observation) '.
"WHERE id_image = $valueP ".
' -- '.__FILE__.':'.__LINE__;
}
}
$resultats = Cel::db()->requeter($requete);
 
$liaisons = array();
if (is_array($resultats) && count($resultats) > 0) {
$liaisons = $resultats;
if ($field == 'id_image') {
foreach ($liaisons as &$liaison) {
$liaison['ce_zone_geo'] = $this->convertirCodeZoneGeoVersCodeInsee($liaison['ce_zone_geo']);
}
}
}
$this->envoyerJson($liaisons);
return true;
}
 
public function updateElement($uid, $pairs) {
 
}
 
/**
* Supprimme une ou plusieurs liaisons entre images et observations
* uid[0] : utilisateur obligatoire
* uid[1] : identifiant(s) image(s) obligatoire(s)
* uid[2] : identifiant(s) observations
*/
public function deleteElement($uid) {
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
$id_utilisateur = $uid[0];
$ids_images = self::filterInt($uid[1]);
$ids_observations = self::filterInt($uid[2]);
if (empty($ids_images) || empty($ids_observations) || ! $id_utilisateur) {
die('err');
}
$ids_images_filtrees = $this->filtrerImgUtilisateur($ids_images, $id_utilisateur);
$infos_observations_filtrees = $this->filtrerObsUtilisateur($ids_observations, $id_utilisateur);
$ids_observations_filtrees = self::extraireValeurs($infos_observations_filtrees, 'id_observation');
if (empty($ids_images_filtrees) || empty($ids_observations_filtrees)) {
die('err');
}
 
$idsImgConcat = implode(',', $ids_images_filtrees);
$idsObsConcat = implode(',', $ids_observations_filtrees);
$requete = 'UPDATE cel_images '.
'SET ce_observation = NULL, date_liaison = NULL, date_transmission = NULL, transmission = 0 '.
"WHERE id_image IN ($idsImgConcat) AND ce_observation IN ($idsObsConcat)".
' -- '.__FILE__.':'.__LINE__;
$resultats = Cel::db()->executer($requete);
($resultats) ? exit('OK') : die('err');
}
 
private function filtrerImgUtilisateur($ids_images, $id_utilisateur) {
$idsImgConcat = implode(',', $ids_images);
$requete = 'SELECT id_image '.
'FROM cel_images '.
"WHERE id_image IN ($idsImgConcat) ".
"AND ce_utilisateur = $id_utilisateur ".
' -- '.__FILE__.':'.__LINE__;
$resultats = Cel::db()->requeter($requete);
return self::extraireValeurs($resultats, 'id_image');
}
 
private function filtrerObsUtilisateur($ids_observations, $id_utilisateur) {
$idsObsConcat = implode(',', $ids_observations);
$requete = 'SELECT id_observation, transmission, date_transmission '.
'FROM cel_obs '.
"WHERE id_observation IN ($idsObsConcat) ".
"AND ce_utilisateur = $id_utilisateur ".
' -- '.__FILE__.':'.__LINE__;
$resultats = Cel::db()->requeter($requete);
$valeurs = (is_array($resultats) && count($resultats) > 0) ? $resultats : array();
return $valeurs;
}
 
private static function filterInt($str_liste) {
return array_filter(array_map('intval', explode(',', $str_liste)));
}
 
/**
* Extrait les valeurs d'un champ donné. Utile pour renvoyer un tableau de simples valeurs
* à partir des résultats d'une requête effectuée sur un seul champ.
*/
private static function extraireValeurs($resultats, $champNom) {
$valeurs = array();
if (is_array($resultats) && count($resultats) > 0) {
foreach ($resultats as $infos) {
$valeurs[] = $infos[$champNom];
}
}
return $valeurs;
}
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/NameMap.php
New file
0,0 → 1,57
<?php
// declare(encoding='UTF-8');
/**
* Service recherche d'une carte de chorologie a partir d'un numero nomenclatural et d'un code de référentiel.
*
* Cas d'utilisation :
* 1: Le service recoit un référentiel et un numero nomenclatural
* 2: Le service recherche une carte disponible
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Cartes
* @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 NameMap extends Cel {
 
public function getElement($uid){
$retour = array('');
if (isset($uid[0]) && isset($uid[1])) {
$uid[0] = $uid[0] != '' ? $uid[0] : 'bdtfx';
$retour = $this->obtenirCarteChorologie($uid[0], $uid[1]);
}
$this->envoyerJson($retour);
return true;
}
 
private function obtenirCarteChorologie($referentiel_taxo, $nn) {
// TODO: gérer ici les cartes d'autres référentiels si celles si sont disponibles
$chercheur_infos_taxon = new RechercheInfosTaxonBeta($this->config, $referentiel_taxo);
$nt = $chercheur_infos_taxon->rechercherNumTaxSurNumNom($nn);
 
$retour = array('');
switch($referentiel_taxo) {
case 'bdtfx':
$url_service_chorologie = $this->config['eflore']['url_service_chorologie_carte'];
$url_service_chorologie = str_replace('{referentiel_choro}','chorodep',$url_service_chorologie);
$file = $url_service_chorologie.'/nt%3A'.$nt.'?retour.format=587&retour=image%2Fpng';
$retour = array($file);
break;
case 'bdtxa':
// En attendant mieux
$url_service_chorologie = $this->config['eflore']['url_service_chorologie_carte'];
$url_service_chorologie = str_replace('{referentiel_choro}','bdtxa',$url_service_chorologie);
$file = $url_service_chorologie.'/nt%3A'.$nt.'?retour.format=587&retour=image%2Fpng';
$retour = array($file);
break;
}
return $retour;
}
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/User.php
New file
0,0 → 1,46
<?php
// declare(encoding='UTF-8');
/**
* Service identification utilisateur.
*
* Cas d'utilisation :
*
* 1: Aucun identifiant ni mot de passe transmis
* 1: L'application retourne l'identifiant de session en cours
* 2: Une identification est toujours active, cette identification est retournee
*
* 1: L'application recoit un identifiant et un mot de passe
* 1 : On tente login
* 2 : Si reussi etat connecte, retour de l'identification obtenue
* 3 : sinon pas connecte, retour d'infos utilisateur anonyme
*
* 1: L'application recoit un identifiant et pas de mot de passe :
* 1 : Deconnection, retour d'infos utilisateur anonyme
*
* En resume :
* /User/ : retour infos utilisateur si connecté sinon infos utilisateur anonyme
* /User/login_utilisateur : logout retour infos utilisateur anonyme
* /User/login_utilisateur/password : login retour infos utilisateur si succès sinon infos utilisateur anonyme
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Utilisateurs
* @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 User extends Cel {
 
// TODO : controle systematique ....dans tous les services
public function getRessource() {
$gestion_utilisateur = new GestionUtilisateur($this->config);
$utilisateur = $gestion_utilisateur->obtenirIdentiteConnectee();
 
$this->envoyerJson($utilisateur);
}
}
/branches/v3.01-serpe/jrest/services/CelWidgetMapPoint.php
New file
0,0 → 1,1306
<?php
// declare(encoding='UTF-8');
/**
* Service fournissant une carte dynamique (communes + points) des obsertions publiques du CEL.
*
* Cas d'utilisation :
* /CelWidgetMap/Carte/Utilisateur : carte des observations publiques d'un utilisateur.
* /CelWidgetMap/Carte/Utilisateur/Projet : carte des observations publiques d'un utilisateur pour un projet.
* /CelWidgetMap/Carte/Utilisateur/Projet/dept : carte des observations publiques d'un utilisateur pour un projet sur un département.
* /CelWidgetMap/Carte/Utilisateur/Projet/dept/nt : carte des observations publiques d'un utilisateur pour un projet sur un département pour un taxon.
*
* Carte = Type de carte. Valeurs possible : defaut,
* Utilisateur = identifiant (= courriel) de l'utilisateur ou * pour tous les utilisateurs.
* Projet = mot-clé du projet
* Plusieurs mots-clés peuvent être spécifiés:
* machin ET bidule ET chose => observations ayant tous les mots-clés (intersection)
* machin OU bildule OU chose => observations ayant au moins un des mots-clés (union)
* ATTENTION
* machin ET bidule OU chose donne un résultat indéterminé pour l'instant
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Widget
* @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 : supprimer le TRIM quand les obs seront reliées correctements aux localisations (sur le code INSEE par exemple)
class CelWidgetMapPoint extends Cel {
const MARQUEUR_GROUPE = 'GROUPE';
const MARQUEUR_COMMUNE = 'COMMUNE';
const MARQUEUR_STATION = 'STATION';
private $standard = "1";
private $table_export = "cel_export";
/**
* Méthode appelée avec une requête de type GET.
*/
public function getElement($ressources) {
$retour = null;
if($this->parametres == null) {
$this->parametres = array();
}
extract($this->parametres);
//Chronometre::chrono("Avant groupage");
if (isset($this->parametres['standard']) && $this->parametres['standard'] == 0) {
$this->standard = "0";
$this->table_export = "cel_export_total";
}
$action = array_shift($ressources);
if (isset($action)) {
$methode = $this->traiterNomMethodeGet($action);
if (method_exists($this, $methode)) {
$retour = $this->$methode($ressources);
} else {
$this->messages[] = "Ce type de ressource '$methode' n'est pas disponible.";
}
} else {
$this->messages[] = "Vous devez indiquer le type de ressource.";
}
//Chronometre::chrono("Apres traitement");
//echo Chronometre::afficherChrono();
if (is_null($retour)) {
$info = 'Un problème est survenu : '.print_r($this->messages, true);
$this->envoyer($info);
} else if (isset($retour['type']) && $retour['type'] == 'jsonVar') {
$this->envoyerJsonVar($retour['variable_js'], $retour['donnees']);
} else if (isset($retour['type']) && $retour['type'] == 'jsonP') {
$this->envoyerJsonp($retour['donnees']);
} else if (isset($retour['type']) && $retour['type'] == 'png') {
header("Content-type: image/png");
imagepng($retour['img']);
imagedestroy($retour['img']);
} else {
$this->envoyerJson($retour);
}
}
/**
* Les icones des groupes de stations
*/
public function getIconeGroupe($params) {
extract($this->parametres);
$chemin_marqueur = sprintf($this->config['settings']['cheminCelMarkerObsTpl'], $type);
$img = imagecreatefrompng($chemin_marqueur);
$noir = imagecolorallocate($img, 0, 0, 0);
$texte = (String) $nbre;
$x = (imagesx($img) - 6.0 * strlen($texte)) / 2;
$y = (imagesy($img) - 16) / 2;
imagestring($img, 3, $x, $y, $texte, $noir);
imagealphablending($img, false);
imagesavealpha($img, true);
return array('type' => 'png', 'img' => $img);
}
public function getTout($params) {
$emplacements = null;
$concatenation_id = "CONCAT(IFNULL(latitude,''),IFNULL(longitude,'')) ";
$transmission = ( $this->standard == 0) ? "transmission = '1' AND " : "";
$requete = 'SELECT distinct ce_zone_geo, zone_geo, NULL as station, '.
"NULL as mots_cles_texte, ".
"latitude, ".
"wgs84_latitude, ".
"longitude, ".
"wgs84_longitude, ".
$concatenation_id." as id_coord ".
'FROM '.$this->table_export.' AS co left join cel_zones_geo on ce_zone_geo=code and (pays = "fr" or pays = "france" '.
"WHERE ".$transmission.
" (".
$this->construireWhereRectangleStationOR()." ".
$this->construireWhereRectangleCommuneOR().") ".
$this->construireWhereDept().
$this->construireWhereCommune().
$this->construireWherePays().
$this->construireWhereUtilisateur().
$this->construireWhereNumTaxonAvecSousTaxons().
$this->construireWhereNomTaxon().
$this->construireWhereReferentiel().
$this->construireWhereDate().
$this->construireWhereCommentaire().
$this->construireWherePhotosSeulement().
$this->construireWhereProjet().
$this->construireWhereTag().
$this->construireWhereNombreDeJours().
$this->construireWhereAnnee().
$this->construireWhereGroupeZoneGeo();
$resultats_emplacements = Cel::db()->requeter($requete);
$emplacements = $this->traiterEmplacements($resultats_emplacements, $this->compterObservations($params));
return $emplacements;
}
private function afficherRequeteFormatee($requete) {
$requete = str_replace(')',')<br />',$requete);
$requete = str_replace('(',' <br /> (',$requete);
echo '<pre>'.$requete.'</pre>';
exit;
}
private $nb_obs = 0;
private function compterObservations($params) {
$transmission = ( $this->standard == 0) ? "transmission = '1' AND " : "";
$requete = 'SELECT COUNT(*) as nb '.
'FROM '.$this->table_export.' AS co '.
"WHERE ".$transmission.
" (".
$this->construireWhereRectangleStationOR()." OR ".
$this->construireWhereRectangleCommuneOR().") ".
$this->construireWhereDept().
$this->construireWhereCommune().
$this->construireWherePays().
$this->construireWhereUtilisateur().
$this->construireWhereNumTaxonAvecSousTaxons().
$this->construireWhereNomTaxon().
$this->construireWhereReferentiel().
$this->construireWhereDate().
$this->construireWhereCommentaire().
$this->construireWherePhotosSeulement().
$this->construireWhereProjet().
$this->construireWhereTag().
$this->construireWhereNombreDeJours().
$this->construireWhereAnnee().
$this->construireWhereGroupeZoneGeo();
$resultats_nb_obs = Cel::db()->requeter($requete);
return $resultats_nb_obs[0]['nb'];
}
private function traiterEmplacements(&$emplacements, $nb_total_observation) {
$zoom = (int) array_key_exists('zoom', $this->parametres) ? $this->parametres['zoom'] : 11;
$distance = (int) array_key_exists('distance', $this->parametres) ? $this->parametres['distance'] : 20;
$marqueurs = array(
'stats' => array('stations' => 0, 'communes' => 0, 'observations' => 0),
'points' => null
);
if (isset($this->parametres['ne']) && $this->parametres['sw'] && ! $this->etreNull($this->parametres['ne']) && ! $this->etreNull($this->parametres['sw'])) {
$ne = $this->decomposerLatLng($this->parametres['ne']);
$sw = $this->decomposerLatLng($this->parametres['sw']);
$marqueurs['points'] = CartoGroupage::creerGroupesQuadtree($emplacements, $ne['lat'], $ne['lng'], $sw['lat'], $sw['lng'], $zoom);
// laisser la classe cartoGroupage compter les élements simplifie le comptage
// et permet de ne pas reparser le tableau pour compter les différents éléments
$nb_elements = CartoGroupage::getNbElements();
// les bornes servent à centrer la carte dans le cas ou l'on demande des paramètres précis
$marqueurs['stats']['coordmax'] = CartoGroupage::getBornes();
$marqueurs['stats']['stations'] = $nb_elements['stations'];
$marqueurs['stats']['communes'] = $nb_elements['communes'];
$marqueurs['stats']['observations'] = (int)$nb_total_observation;
} else {
$marqueurs['points'] = $emplacements;
}
return $marqueurs;
}
private function traiterStations($communes, $stations) {
$zoom = (int) array_key_exists('zoom', $this->parametres) ? $this->parametres['zoom'] : 11;
$distance = (int) array_key_exists('distance', $this->parametres) ? $this->parametres['distance'] : 20;
$marqueurs = array(
'stats' => array('stations' => 0, 'communes' => 0, 'observations' => 0),
'points' => null
);
$marqueurs['stats']['observations'] = $this->traiterNbreObs($communes) + $this->traiterNbreObs($stations);
$points = array();
if ($communes !== false) {
foreach ($communes as $commune) {
if (is_numeric($commune['lat']) && is_numeric($commune['lng'])) {
extract($commune);
$id = self::MARQUEUR_COMMUNE.':'.$lat.'|'.$lng;
$lata = round($lat, 5);
$lnga = round($lng, 5);
if (!isset($points[$id])) {
$points[$id]['id'] = $id;
$points[$id]['nom'] = $nom;
$points[$id]['lat'] = $lata;
$points[$id]['lng'] = $lnga;
$points[$id]['nbre'] = 1;
$marqueurs['stats']['communes']++;
} else {
$points[$id]['nbre']++;
}
}
}
}
if ($stations !== false) {
foreach ($stations as $station) {
if (is_numeric($station['lat']) && is_numeric($station['lng'])) {
extract($station);
$id = self::MARQUEUR_STATION.':'.$lat.'|'.$lng;
$lata = round($lat, 5);
$lnga = round($lng, 5);
$nom = $this->etreNull($nom) ? $lata.','.$lnga : $nom;
if (!isset($points[$id])) {
$points[$id]['id'] = $id;
$points[$id]['nom'] = $nom;
$points[$id]['lat'] = $lata;
$points[$id]['lng'] = $lnga;
$points[$id]['nbre'] = 1;
$marqueurs['stats']['stations']++;
} else {
$points[$id]['nbre']++;
}
}
}
}
if (isset($this->parametres['ne']) && $this->parametres['sw'] && ! $this->etreNull($this->parametres['ne']) && ! $this->etreNull($this->parametres['ne']) && ! $this->etreNull($this->parametres['sw'])) {
$ne = $this->decomposerLatLng($this->parametres['ne']);
$sw = $this->decomposerLatLng($this->parametres['sw']);
$marqueurs['points'] = CartoGroupage::creerGroupesQuadtree($points, $ne['lat'], $ne['lng'], $sw['lat'], $sw['lng'], $zoom);
} else {
$marqueurs['points'] = $points;
}
//$marqueurs['stats']['latDiff'] = abs($marqueurs['stats']['latMin'] - $marqueurs['stats']['latMax']);
//$marqueurs['stats']['lngDiff'] = abs($marqueurs['stats']['lngMin'] - $marqueurs['stats']['lngMax']);
return $marqueurs;
}
private function definirLatLngMaxMin(&$marqueurs, $lat, $lng) {
if ($lat != null && $lng != null) {
$marqueurs['stats']['latMin'] = $marqueurs['stats']['latMin'] > $lat ? $lat : $marqueurs['stats']['latMin'];
$marqueurs['stats']['lngMin'] = $marqueurs['stats']['lngMin'] > $lng ? $lng : $marqueurs['stats']['lngMin'];
$marqueurs['stats']['latMax'] = $marqueurs['stats']['latMax'] < $lat ? $lat : $marqueurs['stats']['latMax'];
$marqueurs['stats']['lngMax'] = $marqueurs['stats']['lngMax'] < $lng ? $lng : $marqueurs['stats']['lngMax'];
}
}
private function traiterNbreObs($resultats) {
$obs_nbre = 0;
if ($resultats !== false) {
$obs_nbre = count($resultats);
}
return $obs_nbre;
}
private function verifierLatLng($lat, $lng) {
$ok_lat = $this->etreLatitude($lat) ? true : false;
$ok_lng = $this->etreLongitude($lng) ? true : false;
$ok = $ok_lat && $ok_lng;
return $ok;
}
private function etreLatitude($lat) {
$ok = false;
//$format = preg_match('/^[-]?[0-9]+(?:[.][0-9]+|)$/', $lat) ? true : false;
$ok = ($lat >= -90 && $lat <= 90) ? true : false;
return $ok;
}
private function etreLongitude($lng) {
$ok = false;
//$format = preg_match('/^[-]?[0-9]+(?:[.][0-9]+|)$/', $lng) ? true : false;
$ok = ($lng >= -180 && $lng <= 180) ? true : false;
return $ok;
}
/* à changer pour localisation_floutage */
private function etreObsSensible($tags) {
$sensible = true;
if (stristr($tags, 'sensible') === FALSE) {
$sensible = false;
}
return $sensible;
}
private function communeEstDemandee() {
$station_infos = $this->decomposerParametreStation();
$commune_demandee = true;
if($station_infos['type'] == self::MARQUEUR_STATION) {
$commune_demandee = false;
}
return $commune_demandee;
}
/**
* Données pour l'affichage des obs d'une station
*/
public function getObservations($params) {
$resultats = array();
$total = 0;
$transmission = ( $this->standard == 0) ? "transmission = '1' " : " 1 ";
if (isset($this->parametres['station']) && !$this->etreNull($this->parametres['station'])) {
$requete = 'SELECT SQL_CALC_FOUND_ROWS id_observation, ce_utilisateur, courriel_utilisateur, pseudo_utilisateur as nom_utilisateur, "" as prenom_utilisateur, '.
' nom_sel, nom_ret, nom_sel_nn, nom_ret_nn, "" as nt, famille, '.
' lieudit, zone_geo, date_observation, milieu, commentaire, '.
' null as utm_secteur, null as utm_x, null as utm_y, ce_zone_geo as code, date_transmission, nom_referentiel '.
'FROM '.$this->table_export.' AS co '.
"WHERE ".$transmission.
(($this->communeEstDemandee()) ? $this->construireWhereCommuneSansCoordonneesAvecSensibles() : $this->construireWhereCoordonneesSansSensibles()).
$this->construireWhereDept().
$this->construireWherePays().
$this->construireWhereUtilisateur().
$this->construireWhereNumTaxonAvecSousTaxons().
$this->construireWhereNomTaxon().
$this->construireWhereReferentiel().
$this->construireWhereDate().
$this->construireWhereCommentaire().
$this->construireWherePhotosSeulement().
$this->construireWhereProjet().
$this->construireWhereTag().
$this->construireWhereNombreDeJours().
$this->construireWhereAnnee().
$this->construireWhereGroupeZoneGeo().
'ORDER BY nom_sel ASC '.
"LIMIT {$this->start},{$this->limit} ";
//echo $requete;exit;
$resultats = Cel::db()->requeter($requete, self::SQL_RETOUR_COMPLET, self::SQL_MODE_OBJET);
$requete = 'SELECT FOUND_ROWS()';
$total = (int) Cel::db()->requeter($requete, self::SQL_RETOUR_COLONNE);
}
// Post-traitement
$observations = $this->traiterObservations($resultats, $total);
$observations = $this->ajouterImagesAuxObs($observations);
$observations = $this->ajouterAuteursAuxObs($observations);
$observations = $this->supprimerIdDesObs($observations);
return $observations;
}
private function traiterObservations($donnees, $total) {
$observations = array('commune' => '', 'observations' => array(), 'observateurs' => array());
$observations['total'] = (isset($total)) ? $total : 0;
if (is_array($donnees) && count($donnees) > 0) {
foreach ($donnees as $donnee) {
//echo '<pre>'.print_r($donnee,true).'</pre>';exit;
$observation = array();
$observation['idObs'] = $donnee->id_observation;
$observation['nn'] = $this->etreNull($donnee->nom_sel_nn) ? null : $donnee->nom_sel_nn;
$observation['nomSci'] = $this->nettoyerTexte($donnee->nom_sel);
$observation['date'] = ($donnee->date_observation != '0000-00-00 00:00:00') ? $this->formaterDate($donnee->date_observation, '%d/%m/%Y') : '';
$observation['datePubli'] = $this->formaterDate($donnee->date_transmission);
$observation['lieu'] = $this->traiterLieu($donnee);
$observation['observateur'] = $donnee->courriel_utilisateur;
$observation['observateurId'] = $donnee->ce_utilisateur;
$observation['urlEflore'] = $this->getUrlEflore($donnee->nom_referentiel, $donnee->nom_sel_nn);
if (isset($donnee->zone_geo)) {
$observations['commune'] = $this->nettoyerTexte($donnee->zone_geo);
}
$observations['observations'][$donnee->id_observation] = $observation;
if (! array_key_exists($donnee->ce_utilisateur, $observations['observateurs'])) {
$observations['observateurs'][$donnee->courriel_utilisateur] = $donnee->courriel_utilisateur;
}
}
}
return $observations;
}
private function traiterLieu($donnee) {
$lieu = array();
if (!$this->etreNull($donnee->lieudit)) {
$lieu[] = $donnee->lieudit;
}
if (!$this->etreNull($donnee->milieu)) {
$lieu[] = $donnee->milieu;
}
return implode(', ', $lieu);
}
private function chargerImages(Array $obs_ids) {
// Récupération des données au format Json
$service = 'CelImage/liste-ids?obsId='.implode(',', $obs_ids);
$url = sprintf($this->config['settings']['baseURLServicesCelTpl'], $service);
$json = $this->getRestClient()->consulter($url);
$donnees = json_decode($json);
// Post-traitement des données
$images = $this->traiterImages($donnees);
return $images;
}
private function traiterImages($donnees) {
$images = array();
if (count($donnees) > 0) {
foreach ($donnees as $id_obs => $id_images) {
foreach ($id_images as $id_img) {
$urls['idImg'] = $id_img;
$urls['guid'] = sprintf($this->config['settings']['guidImgTpl'], $id_img);
$urls['miniature'] = $this->getUrlImage($id_img, 'CXS');
$urls['normale'] = $this->getUrlImage($id_img, 'XL');
$images[$id_obs][] = $urls;
}
}
}
return $images;
}
private function ajouterImagesAuxObs($observations) {
$images = $this->chargerImages(array_keys($observations['observations']));
foreach ($observations['observations'] as $id => $infos) {
if(isset($images[$id])) {
$infos['images'] = $images[$id];
$observations['observations'][$id] = $infos;
}
}
return $observations;
}
private function ajouterAuteursAuxObs($observations) {
$observateurs = $this->recupererUtilisateursIdentite(array_keys($observations['observateurs']));
unset($observations['observateurs']);
foreach ($observations['observations'] as $id => $infos) {
$courriel = strtolower($infos['observateur']);
if(isset($observateurs[$courriel])) {
$infos['observateur'] = $observateurs[$courriel]['intitule'];
$infos['observateurId'] = $observateurs[$courriel]['id'];
}
$observations['observations'][$id] = $infos;
}
return $observations;
}
private function supprimerIdDesObs($observations) {
// Le tableau de sortie ne doit pas avoir les id des obs en clé car sinon Jquery Template ne fonctionne pas
$observationSansId = $observations;
unset($observationSansId['observations']);
foreach ($observations['observations'] as $id => $infos) {
$observationSansId['observations'][] = $infos;
}
return $observationSansId;
}
/**
* Liste des taxons présents sur la carte
*/
public function getTaxons($params) {
$json = null;
$transmission = ( $this->standard == 0) ? "transmission = '1' AND " : "";
$requete = 'SELECT SQL_CALC_FOUND_ROWS DISTINCT nom_ret, nom_ret_nn, nt, famille '.
'FROM '.$this->table_export.' AS co '.
"WHERE ".$transmission.
" nom_ret != '' ".
$this->construireWhereDept().
$this->construireWhereCommune().
$this->construireWherePays().
$this->construireWhereUtilisateur().
$this->construireWhereNumTaxon().
$this->construireWhereNomTaxon().
$this->construireWhereReferentiel().
$this->construireWhereDate().
$this->construireWhereCommentaire().
$this->construireWherePhotosSeulement().
$this->construireWhereProjet().
$this->construireWhereTag().
$this->construireWhereNombreDeJours().
$this->construireWhereAnnee().
$this->construireWhereGroupeZoneGeo().
'ORDER BY nom_ret ASC '.
"LIMIT {$this->start},{$this->limit} ";
//$this->debug[] = $requete;
$resultats = Cel::db()->requeter($requete, self::SQL_RETOUR_COMPLET, self::SQL_MODE_OBJET);
//echo $requete;exit;
$requete = 'SELECT FOUND_ROWS()';
$taxons['total'] = (int) Cel::db()->requeter($requete, self::SQL_RETOUR_COLONNE);
// Post-traitement
$taxons['taxons'] = $this->traiterTaxons($resultats);
return $taxons;
}
private function traiterTaxons($donnees) {
$taxons = array();
if (is_array($donnees) && count($donnees) > 0) {
foreach ($donnees as $donnee) {
if (!isset($taxons[$donnee->nt]) && ! $this->etreNull($donnee->nom_ret)) {
$taxon = array();
$taxon['nn'] = $donnee->nom_ret_nn;
$taxon['nt'] = $donnee->nt;
$taxon['nom'] = $this->nettoyerTexte($donnee->nom_ret);
$taxon['famille'] = $this->nettoyerTexte($donnee->famille);
$taxons[$donnee->nt] = $taxon;
}
}
}
$taxons = array_values($taxons);
return $taxons;
}
private function construireWhereCoordonnees() {
$sql = '';
// Récupération des coordonnées depuis l'id station
extract($this->decomposerParametreStation());
if (isset($type)) {
if ($type == self::MARQUEUR_COMMUNE) {
$lat = Cel::db()->proteger($lat.'%');
$lng = Cel::db()->proteger($lng.'%');
//$sql = " AND wgs84_latitude LIKE $lat AND wgs84_longitude LIKE $lng ";
} else if ($type == self::MARQUEUR_STATION) {
$lat = Cel::db()->proteger($lat.'%');
$lng = Cel::db()->proteger($lng.'%');
$sql = " AND (latitude LIKE $lat AND longitude LIKE $lng) ";
}
}
return $sql;
}
private function construireWhereCoordonneesSansSensibles() {
$sql = '(';
// Récupération des coordonnées depuis l'id station
extract($this->decomposerParametreStation());
if (isset($type)) {
if ($type == self::MARQUEUR_COMMUNE) {
$lat = Cel::db()->proteger($lat);
$lng = Cel::db()->proteger($lng);
//$sql = " AND wgs84_latitude LIKE $lat AND wgs84_longitude LIKE $lng ";
} else if ($type == self::MARQUEUR_STATION) {
$lat = Cel::db()->proteger($lat.'%');
$lng = Cel::db()->proteger($lng.'%');
$sql = " AND (latitude LIKE $lat AND longitude LIKE $lng) ";
}
}
//$sql .= ' AND (localisation_floutage IS NULL OR localisation_floutage = "précise" ) ';
return $sql;
}
private function construireWhereCommentaire() {
$sql = '';
list($type, $commentaire) = $this->decomposerParametreCommentaire();
if (!$this->etreNull($commentaire)) {
$commentaire = Cel::db()->proteger('%'.$commentaire.'%');
switch ($type) {
case '*' :
$sql = $this->obtenirConditionPourCommentaires($commentaire);
$sql = " AND (commentaire LIKE $commentaire OR ($sql)) ";
break;
case 'observation' :
$sql = " AND commentaire LIKE $commentaire ";
break;
case 'photo' :
$sql = ' AND '.$this->obtenirConditionPourCommentaires($commentaire).' ';
break;
case 'photo.meta' :
$sql = ' AND '.$this->obtenirConditionPourCommentaireMeta($commentaire).' ';
break;
case 'photo.utilisateur' :
$sql = ' AND '.$this->obtenirConditionPourCommentaireUtilisateur($commentaire).' ';
break;
default:
$sql = " AND commentaire LIKE $commentaire ";
}
}
return $sql;
}
private function construireWhereNomTaxon() {
$sql = '';
list($type, $nom) = $this->decomposerParametreTaxon();
if (!$this->etreNull($nom)) {
$nom = Cel::db()->proteger($nom.'%');
switch ($type) {
case '*' :
$sql = " AND (nom_ret LIKE $nom OR nom_sel LIKE $nom OR famille LIKE $nom) ";
break;
case 'retenu' :
$sql = " AND nom_ret LIKE $nom ";
break;
case 'selectionne' :
$sql = " AND nom_sel LIKE $nom ";
break;
case 'famille' :
$sql = " AND famille LIKE $nom ";
break;
default:
$sql = " AND nom_ret LIKE $nom ";
}
}
return $sql;
}
private function construireWhereReferentiel() {
$sql = '';
extract($this->parametres);
if (isset($referentiel) && !$this->etreNull($referentiel)) {
$referentiel = Cel::db()->proteger($referentiel);
$sql = ' AND co.nom_referentiel = '.$referentiel.' ';
}
return $sql;
}
private function construireWhereDate() {
$sql = '';
// Récupération des coordonnées depuis l'id station
list($type, $date) = $this->decomposerParametreDate();
if (!$this->etreNull($date)) {
$date = Cel::db()->proteger($date.'%');
switch ($type) {
case '*' :
$sql = " AND (
date_observation LIKE $date
OR date_creation LIKE $date
OR date_modification LIKE $date
OR date_transmission LIKE $date) ";
break;
case 'observation' :
$sql = " AND date_observation LIKE $date ";
break;
case 'creation' :
$sql = " AND date_creation LIKE $date ";
break;
case 'modification' :
$sql = " AND date_modification LIKE $date ";
break;
case 'transmission' :
$sql = " AND date_transmission LIKE $date ";
break;
case 'photo' :
$sql = $this->obtenirConditionPourDatePhoto($date);
break;
case 'ajout' :
$sql = $this->obtenirConditionPourDateAjout($date);
break;
case 'liaison' :
$sql = $this->obtenirConditionPourDateLiaison($date);
break;
default:
$sql = " AND date_observation LIKE $date ";
}
}
return $sql;
}
private function obtenirConditionPourDatePhoto($date) {
$observations = $this->obtenirObsLieesImg('date.photo', $date);
if (is_null($observations)) {
$this->debug[] = "Aucune observation n'est liée à une photo prise à la date : $date";
}
$sql = $this->assemblerObsEnConditionSql($observations);
return $sql;
}
private function obtenirConditionPourDateLiaison($date) {
$observations = $this->obtenirObsLieesImg('date.liaison', $date);
if (is_null($observations)) {
$this->debug[] = "Aucune observation n'a été liée à une image à à la date : $date";
}
$sql = $this->assemblerObsEnConditionSql($observations);
return $sql;
}
private function obtenirConditionPourDateAjout($date) {
$observations = $this->obtenirObsLieesImg('date.ajout', $date);
if (is_null($observations)) {
$this->debug[] = "Aucune observation n'est liée à une image ajoutée à la date : $date";
}
$sql = $this->assemblerObsEnConditionSql($observations);
return $sql;
}
private function obtenirConditionPourCommentaireMeta($commentaire) {
$observations = $this->obtenirObsLieesImg('commentaire.meta', $commentaire);
if (is_null($observations)) {
$this->debug[] = "Aucune observation n'est liée à une image dont le commentaire des méta-données correspond à : $commmentaire";
}
$operateur = '';
$sql = $this->assemblerObsEnConditionSql($observations, $operateur);
return $sql;
}
private function obtenirConditionPourCommentaireUtilisateur($commentaire) {
$observations = $this->obtenirObsLieesImg('commentaire.utilisateur', $commentaire);
if (is_null($observations)) {
$this->debug[] = "Aucune observation n'est liée à une image dont le commentaire des utilisateur correspond à : $commmentaire";
}
$operateur = '';
$sql = $this->assemblerObsEnConditionSql($observations, $operateur);
return $sql;
}
private function obtenirConditionPourCommentaires($commentaire) {
$observations = $this->obtenirObsLieesImg('commentaire.*', $commentaire);
if (is_null($observations)) {
$this->debug[] = "Aucune observation n'est liée à une image dont un des commentaires correspond à : $commmentaire";
}
$operateur = '';
$sql = $this->assemblerObsEnConditionSql($observations, $operateur);
return $sql;
}
/**
* Récupération des identifiant d'utilisateur et des ordres des observations correspondant à une date.
* Retour sous forme de tableau : array[identifiant] = array(ordre, ordre...);
*/
private function obtenirObsLieesImg($type, $param) {
$transmission = ( $this->standard == 0) ? "transmission = '1' AND " : "";
// Construction de la requête
$requete = 'SELECT DISTINCT co.id_obs, co.ce_utilisateur AS utilisateur '.
'FROM '.$this->table_export.' AS co '.
' LEFT JOIN cel_zones_geo AS zg '.
' ON (zg.nom = co.zone_geo AND zg.code = co.ce_zone_geo) '.
"WHERE ".$transmission." co.images != null".
($type == 'date.creation' ? " AND co.date_creation LIKE $param " : '').
($type == 'commentaire.obs' ? " AND co.commentaire LIKE $param " : '').
($type == 'commentaire.*' ? " AND co.commentaire LIKE $param " : '').
$this->construireWhereCoordonnees().
$this->construireWhereDept().
$this->construireWhereCommune().
$this->construireWherePays().
$this->construireWhereUtilisateur().
$this->construireWhereNumTaxon().
$this->construireWhereNomTaxon().
$this->construireWhereReferentiel().
$this->construireWhereProjet().
$this->construireWhereTag().
$this->construireWhereGroupeZoneGeo().
'ORDER BY utilisateur ASC';
//$this->debug[] = $requete;
//die($requete);
$resultats = Cel::db()->requeter($requete);
$observations = null;
if ($resultats != false) {
$observations = array();
foreach ($resultats as $occurence) {
$utilisateur = $occurence['utilisateur'];
$ordre = $occurence['id_obs'];
if (!array_key_exists($utilisateur, $observations)) {
$observations[$utilisateur] = array();
}
if (!array_key_exists($ordre, $observations[$utilisateur])) {
$observations[$utilisateur][$ordre] = $ordre;
}
}
}
return $observations;
}
private function assemblerObsEnConditionSql($observations, $operateur = 'AND') {
$sql = '';
if ($observations != null) {
// Pré-construction du where de la requête
$tpl_where = "(identifiant = '%s' AND ordre IN (%s))";
foreach ($observations as $utilisateur => $ordres) {
$morceaux_requete[] = sprintf($tpl_where, $utilisateur, implode(',', $ordres));
}
if (count($morceaux_requete) > 0) {
$sql = implode(" \nOR ", $morceaux_requete);
}
} else {
// Nous voulons que la requête ne retourne rien
$sql = "identifiant = '' AND ordre = ''";
}
$sql = " $operateur ($sql) ";
return $sql;
}
private function construireWhereRectangleStation() {
$sql = '';
if (isset($this->parametres['ne']) && isset($this->parametres['sw']) && ! $this->etreNull($this->parametres['ne']) && ! $this->etreNull($this->parametres['sw'])) {
$ne = $this->decomposerLatLng($this->parametres['ne']);
$sw = $this->decomposerLatLng($this->parametres['sw']);
$latMin = $sw['lat'];
$lngMin = $sw['lng'];
$latMax = $ne['lat'];
$lngMax = $ne['lng'];
// ATTENTION : latitude correspond bien à la LATITUDE!
$sql = " AND (latitude != 0 AND longitude != 0) ".
" AND latitude > $latMin ".
" AND latitude < $latMax ".
" AND longitude > $lngMin ".
" AND longitude < $lngMax ";
}
return $sql;
}
private function construireWhereRectangleStationOR() {
$sql = '';
if (isset($this->parametres['ne']) && isset($this->parametres['sw']) && ! $this->etreNull($this->parametres['ne']) && ! $this->etreNull($this->parametres['sw'])) {
$ne = $this->decomposerLatLng($this->parametres['ne']);
$sw = $this->decomposerLatLng($this->parametres['sw']);
$latMin = $sw['lat'];
$lngMin = $sw['lng'];
$latMax = $ne['lat'];
$lngMax = $ne['lng'];
$sql = "( (latitude != 0 AND longitude != 0) ".
" AND latitude BETWEEN $latMin AND $latMax ".
" AND longitude BETWEEN $lngMin AND $lngMax )";
/*$sql = " MBRWithin(mon_point, GeomFromText('POLYGON((".$latMin.' '.$lngMin.','.
$latMax.' '.$lngMin.','.
$latMax.' '.$lngMax.','.
$latMax.' '.$lngMin.','.
$latMin.' '.$lngMin."))')) "; */
}
return $sql;
}
private function construireWhereRectangleCommune() {
$sql = '';
if (isset($this->parametres['ne']) && isset($this->parametres['sw']) && ! $this->etreNull($this->parametres['ne']) && ! $this->etreNull($this->parametres['sw'])) {
$ne = $this->decomposerLatLng($this->parametres['ne']);
$sw = $this->decomposerLatLng($this->parametres['sw']);
$latMin = $sw['lat'];
$lngMin = $sw['lng'];
$latMax = $ne['lat'];
$lngMax = $ne['lng'];
/*$sql = "AND wgs84_longitude != 0 AND wgs84_latitude != 0 ".
" AND wgs84_latitude BETWEEN $latMin AND $latMax ".
" AND wgs84_longitude BETWEEN $lngMin AND $lngMax ";*/
}
return $sql;
}
private function construireWhereRectangleCommuneOR() {
$sql = '';
if (isset($this->parametres['ne']) && isset($this->parametres['sw']) && ! $this->etreNull($this->parametres['ne']) && ! $this->etreNull($this->parametres['sw'])) {
$ne = $this->decomposerLatLng($this->parametres['ne']);
$sw = $this->decomposerLatLng($this->parametres['sw']);
$latMin = $sw['lat'];
$lngMin = $sw['lng'];
$latMax = $ne['lat'];
$lngMax = $ne['lng'];
/*$sql = "( wgs84_longitude != 0 AND wgs84_latitude != 0 ".
" AND wgs84_latitude BETWEEN $latMin AND $latMax ".
" AND wgs84_longitude BETWEEN $lngMin AND $lngMax )";*/
/*$sql = " MBRWithin(point_commune, GeomFromText('POLYGON((".$latMin.' '.$lngMin.','.
$latMax.' '.$lngMin.','.
$latMax.' '.$lngMax.','.
$latMax.' '.$lngMin.','.
$latMin.' '.$lngMin."))')) ";*/
}
return $sql;
}
private function construireWhereDept() {
$sql = '';
// Récupération des coordonnées depuis l'id station
extract($this->parametres);
if (isset($dept) && !$this->etreNull($dept)) {
$valeurs_a_proteger = explode(',',trim($dept));
foreach ($valeurs_a_proteger as $valeur) {
$valeurs_protegees[] = '(dept = '.Cel::db()->quote($valeur).') ';
}
$valeurs = implode(' OR ', $valeurs_protegees);
$sql = " AND ($valeurs) ";
}
return $sql;
}
private function construireWhereCommune() {
$sql = '';
// Récupération des coordonnées depuis l'id station
extract($this->parametres);
if (isset($this->parametres['commune']) && !$this->etreNull($commune)) {
$commune = Cel::db()->proteger($commune);
$sql = " AND zone_geo LIKE $commune";
}
if (isset($this->parametres['zonegeo']) && !$this->etreNull($zonegeo)) {
$zonegeo = Cel::db()->proteger($zonegeo);
$sql = " AND ce_zone_geo = $zonegeo";
}
return $sql;
}
private function construireWherePays() {
$sql = '';
extract($this->parametres);
if (isset($this->parametres['pays']) && !$this->etreNull($pays)) {
$pays = Cel::db()->proteger($pays);
$sql = " AND pays = $pays";
}
return $sql;
}
private function construireWhereCommuneSansCoordonneesAvecSensibles() {
$sql = '';
// Récupération des coordonnées depuis l'id station
extract($this->parametres);
if (isset($this->parametres['commune']) && !$this->etreNull($commune)) {
$commune = Cel::db()->proteger($commune);
$sql = " AND zone_geo LIKE $commune";
}
if (isset($this->parametres['zonegeo']) && !$this->etreNull($zonegeo)) {
$zonegeo = Cel::db()->proteger($zonegeo);
$sql = " AND ce_zone_geo = $zonegeo";
}
$sql .= " AND ".
"(".
"(".
"(latitude = '000null' OR latitude = '' OR latitude = 0 OR latitude IS NULL) AND ".
"(longitude = '000null' OR longitude = '' OR longitude = 0 OR longitude IS NULL) ".
')'.
' OR localisation_floutage IN ("localité", "10x10km")'.
') ';
return $sql;
}
private function construireWherePhotosSeulement() {
$sql = '';
if (isset($this->parametres['photos']) && $this->parametres['photos'] == 1) {
$sql = ' AND co.images is not null ';
}
return $sql;
}
private function construireWhereUtilisateur() {
$sql = '';
// TODO tester si l'on recoit un id, un mail ou bien un nom ou prenom
// pour en faire une fonction polyvalente
extract($this->parametres);
if (isset($this->parametres['utilisateur']) && !$this->etreNull($utilisateur)) {
$utilisateur = Cel::db()->proteger($utilisateur);
if (is_numeric($this->parametres['utilisateur'])) {
$sql = " AND co.ce_utilisateur = $utilisateur ";
} else {
$sql = " AND co.courriel_utilisateur = $utilisateur ";
}
}
return $sql;
}
private function construireWhereNumTaxon() {
$sql = '';
// Récupération des coordonnées depuis l'id station
extract($this->parametres);
if (isset($this->parametres['num_nom_ret']) && !$this->etreNull($num_nom_ret)) {
$num_nom_ret = Cel::db()->proteger($num_nom_ret);
$sql = " AND nom_ret_nn = $num_nom_ret ";
}
return $sql;
}
private function construireWhereNumTaxonAvecSousTaxons() {
$sql = '';
// Récupération des coordonnées depuis l'id station
extract($this->parametres);
if (isset($this->parametres['num_nom_ret']) && !$this->etreNull($num_nom_ret)) {
$sous_taxons = $this->obtenirSousTaxons($this->parametres['num_nom_ret']);
$num_nom_retenu = Cel::db()->proteger($num_nom_ret);
if(!empty($sous_taxons)) {
$sql_in_sous_tax = implode(',', $sous_taxons);
$sql = " AND (nom_sel_nn IN (".$num_nom_retenu.', '.$sql_in_sous_tax.") OR ".
"nom_ret_nn IN (".$num_nom_retenu.', '.$sql_in_sous_tax.") ".
") ";
}
else {
$sql = " AND nom_ret_nn = $num_nom_ret ";
}
}
return $sql;
}
private function obtenirSousTaxons($nt) {
$referentiel = 'bdtfx';
if(isset($this->parametres['referentiel']) && $this->parametres['referentiel'] != "" && $this->parametres['referentiel'] != '*') {
$referentiel = $this->parametres['referentiel'];
}
$nn_sous_taxons = array();
$sous_taxons = $this->obtenirSousTaxonsPourNn($referentiel, $nt);
foreach($sous_taxons as $sous_tax) {
$nn_sous_taxons[] = $sous_tax['num_nom'];
}
return $nn_sous_taxons;
}
private function construireWhereProjet() {
$sql = '';
extract($this->parametres);
$projet_sql = isset($projet) ? $this->getSqlWhereProjet($projet) : null;
if (!$this->etreNull($projet_sql)) {
$sql = " AND ($projet_sql) ";
}
return $sql;
}
/**
* Traitement de $projet pour construction du filtre dans la requête
*
* projet1 ET projet2 ET projet3 => intersection
* projet1 OU projet2 OU projet3 => union
* projet1 ET projet2 OU projet3 => ATTENTION indéfini
*/
private function getSqlWhereProjet($projet) {
$sql = null;
if (isset($projet) && !$this->etreNull($projet)) {
if (strpos($projet, ' ET ')) {
// intersection
$projets = explode(' ET ', $projet);
$clauses = array();
foreach ($projets as $proj) {
if ($proj != '') {
$clauses[] = 'co.mots_cles_texte LIKE '.Cel::db()->proteger('%'.$proj.'%');
}
}
$sql = implode($clauses, ' AND ');
} else if (strpos($projet, ' OU ')) {
// union
$projets = explode(' OU ', $projet);
$clauses = array();
foreach ($projets as $proj) {
if ($proj != '') {
$clauses[] = 'co.mots_cles_texte LIKE '.Cel::db()->proteger('%'.$proj.'%');
}
}
$sql = implode($clauses, ' OR ');
} else {
// simple
$sql = 'co.mots_cles_texte LIKE '.Cel::db()->proteger('%'.$projet.'%');
}
}
return $sql;
}
private function construireWhereTag() {
$sql = '';
extract($this->parametres);
$tag_sql = isset($tag) ? $this->getSqlWhereObsAvecImagesTaguees($tag) : null;
if (!$this->etreNull($tag_sql)) {
$sql = " AND ($tag_sql) ";
}
return $sql;
}
private function construireWhereNombreDeJours() {
$sql = null;
extract($this->parametres);
if (isset($nbjours) && !$this->etreNull($nbjours)) {
$sql = ' AND DATEDIFF(CURDATE(),co.date_creation) <= '.Cel::db()->proteger($nbjours).' ';
}
return $sql;
}
private function construireWhereAnnee() {
$sql = null;
extract($this->parametres);
if (isset($annee) && !$this->etreNull($annee)) {
$sql = ' AND YEAR(co.date_creation) = ' . Cel::db()->proteger($annee) . ' ';
}
return $sql;
}
private function construireWhereGroupeZoneGeo() {
$sql = null;
extract($this->parametres);
if (isset($groupe_zones_geo) && !$this->etreNull($groupe_zones_geo)) {
$req = "SELECT valeur FROM cel_groupes_zones WHERE id_groupe = ".Cel::db()->proteger($groupe_zones_geo);
$res = Cel::db()->requeter($req);
$zones = array();
foreach($res as &$r) {
$zones[] = Cel::db()->proteger($r['valeur']);
}
$sql = 'AND ce_zone_geo IN ('.implode(',', $zones).') ';
}
return $sql;
}
/**
* Traitement de $tag pour construction du filtre dans la requête
*/
private function getSqlWhereObsAvecImagesTaguees($tag) {
$sql = null;
$transmission = ( $this->standard == 0) ? "co.transmission = '1' " : " 1 ";
if (isset($tag) && !$this->etreNull($tag)) {
$tag_sql = $this->getSqlWhereMotsCles($tag);
// Construction de la requête
$requete = 'SELECT DISTINCT co.id_observation AS id_obs, co.ce_utilisateur AS utilisateur '.
'FROM cel_images_export ci'.
' INNER JOIN '.$this->table_export.' AS co '.
' ON (ci.ce_observation = co.id_observation) '.
' LEFT JOIN cel_zones_geo AS zg '.
" ON (zg.nom = co.zone_geo AND zg.code = co.ce_zone_geo) ".
"WHERE ".$transmission.
$this->construireWhereCoordonnees().
$this->construireWhereUtilisateur().
$this->construireWhereNumTaxon().
$this->construireWhereNomTaxon().
$this->construireWhereReferentiel().
$this->construireWhereProjet().
(!$this->etreNull($tag_sql) ? "AND ($tag_sql) " : '').
'ORDER BY utilisateur ASC';
//$this->debug[] = $requete;
//die($requete);
$elements_tag = Cel::db()->requeter($requete);
$requete_tag = array();
if ($elements_tag != false && count($elements_tag) > 0) {
$filtres = array();
foreach ($elements_tag as $occurence) {
$utilisateur = $occurence['utilisateur'];
$id_obs = $occurence['id_obs'];
if (!array_key_exists($utilisateur, $filtres)) {
$filtres[$utilisateur] = array();
}
if (!array_key_exists($id_obs, $filtres[$utilisateur])) {
$filtres[$utilisateur][$id_obs] = $id_obs;
}
}
// Pré-construction du where de la requête
$tpl_where = "(id_observation IN (%s))";
foreach ($filtres as $utilisateur => $id_obs) {
$requete_tag[] = sprintf($tpl_where, implode(',', $id_obs));
}
} else {
$this->messages[] = "Aucune observation ne possède d'images avec ce mot-clé.";
}
if (count($requete_tag) > 0) {
$sql = implode(" \nOR ", $requete_tag);
}
}
return $sql;
}
/**
* Traitement de $tag pour construction du filtre dans la requête
*/
private function getSqlWhereMotsCles($tag) {
$sql = null;
$mots_cles = $this->decomposerParametreTag($tag);
$requete_projet = $this->getSqlWhereMotsClesImages($mots_cles);
$sql = $requete_projet;
//$this->debug[] = $sql;
return $sql;
}
/**
* Traitement de $tag pour construction du filtre dans la requête
*/
private function getSqlWhereMotsClesImages($mots_cles_encodes) {
$where_mots_cles_images = array();
foreach ($mots_cles_encodes['motsClesEncodesProteges'] as $mot_cle_encode) {
$where_mots_cles_images[] = "ci.mots_cles_texte LIKE $mot_cle_encode";
}
$where_mots_cles_images = implode(' '.$mots_cles_encodes['type'].' ', $where_mots_cles_images);
return $where_mots_cles_images;
}
private function decomposerParametreTag($tags) {
$mots_cles = array('type' => null, 'motsCles' => null, 'motsClesEncodesProteges' => null);
if (preg_match('/.+OU.+/', $tags)) {
$mots_cles['type'] = 'OR';
$mots_cles['motsCles'] = explode('OU', $tags);
} else if (preg_match('/.+ET.+/', $tags)) {
$mots_cles['type'] = 'AND';
$mots_cles['motsCles'] = explode('ET', $tags);
} else {
$mots_cles['motsCles'][] = $tags;
}
foreach ($mots_cles['motsCles'] as $mot) {
$mots_cles['motsClesEncodesProteges'][] = Cel::db()->quote('%'.$mot.'%');
}
$this->debug[] = $mots_cles;
return $mots_cles;
}
private function decomposerLatLng($coord) {
$lat_lng = array();
if (isset($coord)) {
list($lat, $lng) = explode('|', $coord);
$lat_lng = array('lat' => $lat, 'lng' => $lng);
}
return $lat_lng;
}
private function decomposerParametreStation() {
$station_infos = array();
if (isset($this->parametres['station'])) {
$station = $this->parametres['station'];
$this->debug[] = $station;
@list($type, $coord) = explode(':', $station);
@list($lat, $lng) = explode('|', $coord);
$station_infos = array('type' => $type, 'lat' => $lat, 'lng' => $lng);
}
return $station_infos;
}
private function decomposerParametreDate() {
$date_infos = array(null,null);
if (isset($this->parametres['date'])) {
$date = $this->parametres['date'];
if (strpos($date, ':')) {
list($type, $date) = explode(':', $date);
} else {
$type = 'observation';
}
$date = str_replace('/', '-', $date);
if (preg_match('/(^[0-9]{2})-([0-9]{2})-([0-9]{4}$)/', $date, $matches)) {
$date = $matches[3].'-'.$matches[2].'-'.$matches[1];
}
$date_infos = array($type, $date);
}
return $date_infos;
}
private function decomposerParametreTaxon() {
$nom_infos = array(null,null);
if (isset($this->parametres['taxon'])) {
$taxon = $this->parametres['taxon'];
if (strpos($taxon, ':')) {
$nom_infos = explode(':', $taxon);
} else {
$nom_infos = array('retenu', $taxon);
}
}
return $nom_infos;
}
private function decomposerParametreCommentaire() {
$commentaire_infos = array(null,null);
if (isset($this->parametres['commentaire'])) {
$commentaire = $this->parametres['commentaire'];
if (strpos($commentaire, ':')) {
$commentaire_infos = explode(':', $commentaire);
} else {
$commentaire_infos = array('observation', $commentaire);
}
}
return $commentaire_infos;
}
}
?>
/branches/v3.01-serpe/jrest/services/CelImageFormat.php
New file
0,0 → 1,164
<?php
// declare(encoding='UTF-8');
/**
* Service fournissant permettant de visualiser ou télécharger des images du CEL.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 CelImageFormat {
 
private $config;
// @TODO tirer ça de la config
private $formats = array('CRX2S', 'CRXS', 'CXS', 'CS', 'CRS', 'XS', 'S', 'M', 'L', 'CRL', 'XL', 'X2L', 'X3L', 'O');
const METHODE_TELECHARGEMENT = 'telecharger';
const METHODE_AFFICHAGE = 'afficher';
 
// Pas besoin d'étendre Cel ici, surtout que le constructeur
// de la classe Cel instancie toujours une connexion à la bdd
// dont on a pas besoin ici. Ceci évite de planter le service
// quand la bdd est surchargée.
public function __construct($config) {
$this->config = $config;
}
 
public function getRessource() {
header('Content-Type: application/json');
echo json_encode($this->obtenirDescriptionService());
}
 
/**
* Méthode appelée avec une requête de type GET.
*/
public function getElement($params) {
// suppression des 0 non significatifs à gauche
$id = ltrim($params[0], '0');
$format = isset($_GET['format']) ? $_GET['format'] : 'M';
$methode_livraison = isset($_GET['methode']) ? $_GET['methode'] : self::METHODE_AFFICHAGE;
 
if($this->verifierParametres($id, $format, $methode_livraison)) {
$gestion_formats_images = new ImageRecreation($this->config);
$image_binaire = $gestion_formats_images->creerOuRenvoyerImage($params[0], $format);
 
if($image_binaire) {
$this->envoyerImage($id, $image_binaire, $format, $methode_livraison);
} else {
header("HTTP/1.0 404 Not Found");
echo 'Aucune image ne correspond à cet identifiant';
}
}
}
 
private function verifierParametres($id, $format, $methode_livraison) {
$ok = true;
$message = '';
if(!is_numeric($id)) {
$message .= "L'identifiant de format doit être un entier. ";
$ok = false;
}
 
if(!in_array($format, $this->formats)) {
$message .= "Le format d'image est inconnu, les formats acceptés sont ".implode(',', $this->formats).". ";
$ok = false;
}
 
$types_methode_livraison = array(self::METHODE_AFFICHAGE, self::METHODE_TELECHARGEMENT);
if (!in_array($methode_livraison, $types_methode_livraison)) {
$message .= "Le format de methode de livraison ".$methode_livraison." n'est pas acceptée par le service. ".
" Seuls les methodes suivantes sont gérés : ".implode(',', $types_methode_livraison);
$ok = false;
}
 
if(!empty($message)) {
header("HTTP/1.0 400 Bad Request");
echo $message;
}
return $ok;
}
 
private function envoyerImage($id, $image_binaire, $format, $methode) {
if ($methode == self::METHODE_AFFICHAGE) {
header('Content-Type: image/jpeg');
} else {
$this->envoyerHeadersTelechargement($id, $image_binaire, $format);
}
 
echo $image_binaire;
exit();
}
 
private function envoyerHeadersTelechargement($id, $image_binaire, $format) {
if (function_exists('mb_strlen')) {
$taille = mb_strlen($image_binaire, '8bit');
} else {
$taille = strlen($image_binaire);
}
 
// creation du format original
$id_avec_zeros = sprintf('%09s', $id) ;
$id_avec_zeros_underscores = wordwrap($id_avec_zeros, 3 , '_', true) ;
$nom_fichier = $id_avec_zeros_underscores.'_'.$format.'.jpg';
 
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$nom_fichier.'"');
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: '.$taille);
}
 
private function obtenirDescriptionService() {
$retour = array('description' => 'Ce service peut être appelé afin de visualiser ou bien télécharger les images du cel',
'formats' => $this->formats,
'utilisation' => 'http://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']."/{id} où {id} est l'identifiant numérique de l'image désirée",
'parametres' => array(
'methode' => "Valeurs : afficher, telecharger. Permet de préciser si l'image doit être affichée ou téléchargée",
'format' => "Valeurs : voir la liste ci dessous. Permet de demander un format précis de l'image parmi ceux disponibles ")
);
 
// ^^ c'est marrant non ?
$format_formates = array();
foreach ($this->formats as $format) {
if ($format == "O") {
$format_formates["O"] = array("hauteur" => "dépend de l'image originale",
"largeur" => "dépend de l'image originale",
"notes" => "Image dans son ratio et sa résolution originale (elle peut éventuellement avoir été compressée en qualité)"
);
} else {
$description = array();
if (strpos($format, 'R') !== false) {
$description[] = "Format carré, rogné pour ne garder que le centre de l'image.";
}
if (strpos($format, 'C') !== false) {
$description[] = "Format carré, si le format contient R, il est rogné, sinon des bandes blanches sont ajoutées pour conserver le ratio.";
}
 
if (empty($description)) {
$description[] = "Format standard, le ratio original de l'image est conservé";
}
 
$resolution = $this->config['cel']['format_'.$format];
$resolution = explode("_", $resolution);
$format_formates[$format] = array("hauteur" => $resolution[0],
"largeur" => $resolution[1],
"notes" => implode(' ', $description)
);
}
}
 
$retour['resolutions'] = $format_formates;
return $retour;
}
}
/branches/v3.01-serpe/jrest/services/Name.php
New file
0,0 → 1,37
<?php
// declare(encoding='UTF-8');
/**
* Service recherche nom retenu depuis un numero nomenclatural pour la BDNFF
*
* 1 : L'application recoit un numero nomenclatural
* 2 : L'application retourne le nom retenu associé
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @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 Name extends Cel {
 
public function getElement($uid){
$retour = array('null');
if (isset($uid[0])) {
$chercheurInfoTaxon = new RechercheInfosTaxonBeta($this->config);
$retour = $chercheurInfoTaxon->effectuerRequeteInfosComplementairesEtFormaterNom($uid[0]);
}
$this->envoyerJson($retour);
return true;
}
 
public function getRessource(){
print '["null"]';
return;
}
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/InventoryKeyWordImageLink.php
New file
0,0 → 1,49
<?php
// declare(encoding='UTF-8');
/**
* Service de liaisons de mots clés à des images.
* Le service lie une ou plusieurs mots clés à une ou plusieurs images.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 InventoryKeyWordImageLink extends Cel {
 
public function createElement($pairs) {
// Controle detournement utilisateur
$this->controleUtilisateur($pairs['ce_utilisateur']);
 
if (!isset($pairs['mots_cles']) || !isset($pairs['images']) || !isset($pairs['ce_utilisateur'])) {
return;
}
 
$ids_images = array_filter(explode(',', $pairs['images']));
$ids_mots_cles = array_filter(explode(',', $pairs['mots_cles']));
 
$gestion_mots_cles = new GestionMotsClesChemin($this->config,'images');
$liaison = true;
$liaison = $gestion_mots_cles->modifierLiaisonParTableaux($ids_mots_cles, $ids_images, true);
 
foreach ($ids_images as $id_element_lie) {
//TODO: que faire si la régénération d'index texte échoue ?
GestionMotsClesChemin::regenererIndexTexteMotCle($id_element_lie, 'images');
}
return $liaison;
}
 
public function deleteElement($uid){
// n'est jamais appelée car pour supprimer les mots clés d'une image
// on appelle createElement avec des mots clés vides
// car les mots clés images ne fonctionnent pas pareil que ceux des obs
// dans l'interface
}
}
/branches/v3.01-serpe/jrest/services/CelSyndicationObservation.php
New file
0,0 → 1,601
<?php
// declare(encoding='UTF-8');
/**
* Service fournissant des informations concernant le CEL au format RSS1, RSS2 ou ATOM.
* Encodage en entrée : utf8
* Encodage en sortie : utf8
* Format du service :
* /CelSyndicationObservation/liste-des-flux
* /CelSyndicationObservation/opml
* /CelSyndicationObservation/par-defaut/(rss1|rss2|atom)?start=0&limit=150
* /CelSyndicationObservation/pour-admin/(rss1|rss2|atom)?start=0&limit=150
* /CelSyndicationObservation/par-mots-cles/(rss1|rss2|atom)/mot-cle?start=0&limit=150
* /CelSyndicationObservation/par-commune/(rss1|rss2|atom)/nom-commune?start=0&limit=150
*
* Les paramêtres :
* - "start" indique le numéro du premier item à afficher
* - "limit" nombre d'items à afficher
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Syndication
* @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 CelSyndicationObservation extends Cel {
private $parametres_origines = null;
private $format = null;
private $service = null;
private $squelette = null;
private $squelette_dossier = null;
private $auteurs = array();
private $flux = array();
private $criteres = array(
'utilisateur' => 'courriel_utilisateur',
'commune' => 'zone_geo',
'dept' => 'ce_zone_geo',
'taxon' => 'nom_ret',
'num_taxon' => 'nt',
'commentaire' => 'commentaire',
'date' => 'date_observation',
'motcle' => 'tags',
'standard' => 'donnees_standard',
'projet' => 'mots-cles',
'groupe_zones_geo' => 'groupe_zones_geo');
private $catalogue_cles_labels_champs_etendus = array();
/**
* Méthode appelée avec une requête de type GET.
*/
public function getElement($params = array()) {
// Initialisation des variables
$this->parametres_origines = $params;
$info = array();
$contenu = '';
if (! $this->etreFluxAdmin() || $this->authentifierAdmin()) {
// Pré traitement des paramêtres
$pour_bdd = false;
$p = $this->traiterParametres(array('service', 'format'), $params, $pour_bdd);
extract($p);
$this->parametres = $params;
$this->squelette_dossier = dirname(__FILE__).DIRECTORY_SEPARATOR.'squelettes'.DIRECTORY_SEPARATOR;
// Récupération de la liste des flux
$this->chargerListeDesFlux();
// Chargement du bon type de service demandé
if (isset($service)) {
$this->service = $this->traiterNomService($service);
$methode = $this->getNomMethodeService();
if (method_exists($this, $methode)) {
if (isset($format) && preg_match('/^(?:rss1|rss2|atom)$/i', $format)) {
// Mise en minuscule de l'indication du format
$this->format = strtolower($format);
// Définition du fichier squelette demandé
$this->squelette = $this->squelette_dossier.$this->format.'.tpl.xml';
} else if (isset($this->flux[$this->service])) {
$this->format = '';
$this->messages[] = "Le service CEL Syndication nécessite d'indiquer en second paramètre le format : rss1, rss2 ou atom.";
}
if (!isset($this->flux[$this->service]) || isset($this->format)) {
// Suppression des paramêtres inutile pour le reste des méthodes
array_shift($this->parametres);
array_shift($this->parametres);
// Récupération du contenu à renvoyer
$contenu = $this->$methode();
}
} else {
$this->messages[] = "Le type d'information demandé '$this->service' n'est pas disponible.";
}
} else {
$this->messages[] = "Le service CEL Syndication Observation nécessite d'indiquer en premier paramètre le type d'information demandé.";
}
}
// Envoie sur la sortie standard
$encodage = 'utf-8';
$mime = $this->getTypeMime();
$formatage_json = $this->getFormatageJson();
$this->envoyer($contenu, $mime, $encodage, $formatage_json);
}
private function getUrlBase() {
$url_base = sprintf($this->config['settings']['baseURLAbsolu'], get_class($this).'/');
return $url_base;
}
private function getUrlServiceBase() {
$url_service = $this->getUrlBase().implode('/', $this->parametres_origines);
return $url_service;
}
private function traiterNomService($nom) {
$nom = strtolower($nom);
return $nom;
}
private function getNomMethodeService() {
$methode = '';
$service_formate = str_replace(' ', '', ucwords(implode(' ', explode('-', $this->service))));
$methode = 'getService'.$service_formate;
return $methode;
}
private function getTypeMime() {
$mime = '';
$test = isset($this->format) ? $this->format : $this->service;
switch ($test) {
case 'atom' :
$mime = 'application/atom+xml';
break;
case 'rss1' :
case 'rss2' :
$mime = 'application/rss+xml';
break;
case 'opml' :
$mime = 'text/x-opml';
break;
default:
$mime = 'text/html';
}
return $mime;
}
private function getFormatageJson() {
$json = false;
switch ($this->service) {
case 'liste-des-flux' :
$json = true;
break;
default:
$json = false;
}
return $json;
}
private function getFlux($nom) {
return isset($this->flux[$nom]) ? $this->flux[$nom] : array();
}
private function setFlux($nom, $titre, $description) {
$url_base = $this->getUrlBase();
$formats = array('atom', 'rss2', 'rss1');
$flux = array();
foreach ($formats as $format) {
$url = $url_base.$nom.'/'.$format;
$flux[$format] = $url;
}
$this->flux[$nom] = array('titre' => $titre, 'description' => $description, 'urls' => $flux);
}
private function chargerListeDesFlux() {
$this->setFlux('par-defaut', 'Flux de syndication des observations publiques du CEL',
'Ce flux fournit des informations sur les observations du CEL.');
$this->setFlux('multicriteres','Flux de syndication des nouvelles observations publiques du CEL '.
'filtrées par un ou plusieurs critères',
"Ce flux fournit des informations sur les nouvelles observations du CEL filtrées par ".
"auteur (mail), commune (nom), departement (code postal), taxon (nom scientifique), commentaire, projet ".
"et/ou date.");
}
private function getServiceListeDesFlux() {
return $this->flux;
}
private function getServiceOpml() {
$donnees = array();
$id = 1;
foreach ($this->flux as $flux_nom => $flux){
$info = array();
$info['type'] = 'atom';
$info['titre'] = $flux['titre'];
$info['texte'] = "CEL - Obs - $flux_nom";
$info['description'] = $flux['description'];
$info['url_xml'] = $this->getUrlBase().$flux_nom.'/atom';
$info['url_html'] = $this->config['settings']['aideCelUrl'].'FluxSyndication';
$donnees['liste_flux'][] = $info;
}
$this->squelette = $this->squelette_dossier.'opml.tpl.xml';
$contenu = Cel::traiterSquelettePhp($this->squelette, $donnees);
return $contenu;
}
private function getServiceParDefaut() {
// Construction de la requête
$requete = (isset($this->distinct) ? 'SELECT DISTINCT' : 'SELECT').' * '.
'FROM cel_export_total '.
(($this->etreFluxAdmin()) ? '' : 'WHERE transmission = 1 ').
'ORDER BY '.(isset($this->orderby) && (!is_null($this->orderby)) ? $this->orderby : 'date_modification DESC').' '.
"LIMIT $this->start,$this->limit ";
$elements = Cel::db()->requeter($requete);
// Création du contenu
$contenu = $this->executerService($elements);
return $contenu;
}
private function getServiceMultiCriteres() {
$contenu = '';
if (isset($_GET['debut'])) $this->start = Cel::db()->proteger($_GET['debut']);
if (isset($_GET['limite'])) $this->limit = Cel::db()->proteger($_GET['limite']);
$this->limit = ($this->limit < 1000) ? $this->limit : 1000;// Pour éviter les abus !
// Construction de la requête
$requete = (isset($this->distinct) ? 'SELECT DISTINCT' : 'SELECT').' * '.
'FROM cel_export_total '.
'WHERE 1 AND '.(($this->etreFluxAdmin()) ? '' : ' transmission = 1 AND ');
if ($this->estUneRechercheGenerale()) {
$chaine_requete = $_GET['recherche'];
$requete .= $this->creerSousRequeteRechercheGenerale($chaine_requete);
} else {
$criteres = $this->traiterCriteresMultiples($_GET) ;
if (!empty($criteres)) {
$requete .= $this->creerSousRequeteRechercheParCriteres($criteres);
}
}
$requete = rtrim($requete, 'AND ');
$requete .= ' ORDER BY '.(isset($this->orderby) && (!is_null($this->orderby)) ? $this->orderby :
'date_modification DESC, zone_geo ASC').' '.
"LIMIT $this->start,$this->limit ";
$elements = Cel::db()->requeter($requete);
// Création du contenu
if ($elements != false && count($elements) > 0) {
$contenu = $this->executerService($elements);
} else {
// déclenche une erreur 500 à tort; ne pas faire ça
//$this->messages[] = "Aucune observation disponible.";
}
return $contenu;
}
private function creerSousRequeteRechercheParCriteres($criteres) {
$requete = '';
foreach ($criteres as $pair) {
$nom_valeur = explode("=",$pair);
if (sizeof($nom_valeur) != 0) {
switch ($nom_valeur[0]) {
case "ci_limite" : $this->limit = Cel::db()->quote($nom_valeur[1]); break;
case "commentaire" : $mots_comment_liste = explode(" " , $nom_valeur[1]);
foreach($mots_comment_liste as $mot_comment) {
$mot_comment = trim($mot_comment) ;
$requete .= $nom_valeur[0].' LIKE '.Cel::db()->quote('%'.$mot_comment.'%').' AND ';
}
break;
case "date_observation" :
$nom_valeur[1] = str_replace('/', '-', $nom_valeur[1]);
if (preg_match('/(^[0-9]{2})-([0-9]{2})-([0-9]{4}$)/', $nom_valeur[1], $matches)) {
$nom_valeur[1] = $matches[3].'-'.$matches[2].'-'.$matches[1];
}
$requete .= $nom_valeur[0].'='.Cel::db()->quote($nom_valeur[1]).' AND '; break;
case "ce_zone_geo" :
$requete .= ' ('.$nom_valeur[0].' LIKE "'.$nom_valeur[1].'%") AND '; break;
case "nom_ret" :
if ($nom_valeur[1] == "indetermine") $nom_valeur[1] = 'null';
$requete .= ' ('.$nom_valeur[0].' LIKE "%'.$nom_valeur[1].'%" OR nom_sel LIKE "%'.
$nom_valeur[1].'%") AND '; break;
case "mots-cles" : $requete .= $this->creerSousRequeteMotsCles($nom_valeur[1]).' AND '; break;
case "tags" : $requete .= $this->creerSousRequeteTags($nom_valeur[1]).' AND '; break;
case "groupe_zones_geo" : $requete .= $this->creerSousRequeteGroupeZonesGeo($nom_valeur[1])." AND "; break;
default : $requete .= $nom_valeur[0].' = "'.$nom_valeur[1].'" AND '; break;
}
}
}
$requete = rtrim($requete,' AND ');
return $requete;
}
private function creerSousRequeteGroupeZonesGeo($groupe_zones_geo) {
$req = "SELECT valeur FROM cel_groupes_zones WHERE id_groupe = ".Cel::db()->proteger($groupe_zones_geo);
$res = Cel::db()->requeter($req);
$zones = array();
foreach($res as &$r) {
$zones[] = Cel::db()->proteger($r['valeur']);
}
$sql = '(ce_zone_geo IN ('.implode(',', $zones).')) ';
return $sql;
}
private function creerSousRequeteMotsCles($mot_cle) {
$requete = '';
if (preg_match('/.*OU.*/', $mot_cle)) {
$mots_cles_tab = explode('OU',$mot_cle);
foreach($mots_cles_tab as $mot_cle_item) {
$requete .= '(mots_cles_texte LIKE '.Cel::db()->proteger('%'.$mot_cle_item.'%').') OR ';
}
$requete = '('.rtrim($requete,'OR ').') ';
} else if (preg_match('/.*ET.*/', $mot_cle)) {
$mots_cles_tab = explode('ET',$mot_cle);
foreach($mots_cles_tab as $mot_cle_item) {
$requete .= '(mots_cles_texte LIKE '.Cel::db()->proteger('%'.$mot_cle_item.'%').') AND ';
}
$requete = '('.rtrim($requete, 'AND ').') ';
} else {
$requete = "(mots_cles_texte LIKE ".Cel::db()->proteger('%'.$mot_cle.'%').') ';
}
return $requete;
}
private function creerSousRequeteTags($tag) {
$requete = '(id_observation IN (SELECT ce_observation FROM cel_images ci WHERE ';
$where = '';
if (preg_match('/.*OU.*/', $tag)) {
$mots_cles_tab = explode('OU',$tag);
foreach($mots_cles_tab as $mot_cle_item) {
$where .= '(ci.mots_cles_texte LIKE '.Cel::db()->proteger('%'.$mot_cle_item.'%').') OR ';
}
$where .= '('.rtrim($where,'OR ').') ';
} else if (preg_match('/.*ET.*/', $tag)) {
$mots_cles_tab = explode('ET',$tag);
foreach($mots_cles_tab as $mot_cle_item) {
$where .= '(ci.mots_cles_texte LIKE '.Cel::db()->proteger('%'.$mot_cle_item.'%').') AND ';
}
$where .= '('.rtrim($where, 'AND ').') ';
} else {
$where .= "(ci.mots_cles_texte LIKE ".Cel::db()->proteger('%'.$tag.'%').') ';
}
$requete .= $where.' ))';
return $requete;
}
private function traiterCriteresMultiples($tableau_criteres) {
$tableau_criteres_pour_bdd = array();
foreach($tableau_criteres as $nom_critere => $valeur_critere) {
if (isset($this->criteres[$nom_critere])) {
//$valeur_critere = Cel::db()->proteger($valeur_critere);
$tableau_criteres_pour_bdd[] = $this->criteres[$nom_critere].'='.$valeur_critere;
}
}
return $tableau_criteres_pour_bdd;
}
private function creerSousRequeteRechercheGenerale($chaine_requete) {
$requete = '';
$chaine_requete = Cel::deb()->proteger($chaine_requete.'%');
if (trim($chaine_requete) != '') {
$chaine_requete = strtolower($chaine_requete);
$chaine_requete = str_replace(' ', '_', $chaine_requete);
$requete = ' ('.
'nom_ret LIKE '.$chaine_requete.
' OR '.
'nom_sel LIKE '.$chaine_requete.
' OR '.
'zone_geo LIKE '.$chaine_requete.
' OR '.
'ce_zone_geo LIKE '.$chaine_requete.
' OR '.
'ce_zone_geo LIKE '.$chaine_requete.
' OR '.
'courriel_utilisateur LIKE '.$chaine_requete.
' OR '.
'mots_cles_texte LIKE '.$chaine_requete.
') ';
}
return $requete;
}
private function estUneRechercheGenerale() {
return isset($_GET['recherche']);
}
private function executerService($elements) {
$contenu = '';
if (is_array($elements)) {
// Prétraitement des données
$donnees = $this->construireDonneesCommunesAuFlux($elements);
$ids_observations = array();
foreach ($elements as $element) {
$identifiants[$element['courriel_utilisateur']] = $element['courriel_utilisateur'];
$ids_observations[] = $element['id_observation'];
}
$gestion_obs_etendus = new GestionChampsEtendus($this->config, 'obs');
$gestion_champs_etendus = new GestionChampsEtendus2($this->config);
$champs_etendus = $gestion_obs_etendus->consulterParLots($ids_observations);
if(!empty($champs_etendus)) {
$this->catalogue_cles_labels_champs_etendus = $gestion_champs_etendus->consulterCatalogueChampsEtendusPredefinis(true);
// afin de simplifier les erreurs de majuscules et minuscules
$this->catalogue_cles_labels_champs_etendus = array_change_key_case($this->catalogue_cles_labels_champs_etendus);
}
$this->auteurs = $this->creerAuteurs($identifiants);
foreach ($elements as $element) {
$element['obs_etendue'] = isset($champs_etendus[$element['id_observation']]) ? $champs_etendus[$element['id_observation']] : array();
$donnees['items'][] = $this->construireDonneesCommunesAuxItems($element);
}
// Création du contenu à partir d'un template PHP
if (isset($this->squelette)) {
$contenu = Cel::traiterSquelettePhp($this->squelette, $donnees);
}
}
return $contenu;
}
private function construireDonneesCommunesAuFlux($observations) {
$donnees = $this->getFlux($this->service);
$donnees['guid'] = $this->getUrlServiceBase();
$donnees['titre'] = 'Flux des observations du CEL';
$donnees['lien_service'] = $this->creerUrlService();
$donnees['lien_cel'] = $this->config['settings']['baseURLAbsolu'];
$donnees['editeur'] = $this->config['settings']['editeur'];
$derniere_info_en_date = reset($observations);
$date_modification_timestamp = strtotime($derniere_info_en_date['date_modification']);
$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'] = 'CEL - Jrest - CelSyndicationObservation';
$donnees['generateur_version'] = (preg_match('/([0-9]+)/', '$Revision$', $match)) ? $match[1] : '0';
return $donnees;
}
private function construireDonneesCommunesAuxItems($observation) {
$item = array();
$date_modification_timestamp = $this->convertirDateHeureMysqlEnTimestamp($observation['date_modification']);
$item['date_maj_simple'] = strftime('%A %d %B %Y à %H:%M', $date_modification_timestamp);
$item['date_maj_RSS'] = date(DATE_RSS, $date_modification_timestamp);
$item['date_maj_ATOM'] = date(DATE_ATOM, $date_modification_timestamp);
$item['date_maj_W3C'] = date(DATE_W3C, $date_modification_timestamp);
$item['date_creation_simple'] = strftime('%A %d %B %Y à %H:%M', strtotime($observation['date_creation']));
$item['titre'] = $this->creerTitre($observation);
$item['guid'] = $this->creerGuidItem($observation);
$item['lien'] = $this->creerLienItem($observation);
$item['categorie'] = $this->creerCategorie($item);
$item['description'] = $this->creerDescription(Cel::protegerCaracteresHtmlDansChamps($observation), $item);
$item['description_encodee'] = htmlspecialchars($this->creerDescription($observation, $item));
$item['modifier_par'] = $this->nettoyerTexte($observation['id_observation']);
return $item;
}
private function creerTitre($obs) {
$date = ($obs['date_observation'] != '0000-00-00 00:00:00') ? 'le '.date("d/m/Y", strtotime($obs['date_observation'])) : '' ;
$nom_plante = $obs['nom_sel'].' [nn'.$obs['nom_sel_nn'].']';
$lieu = $this->formaterZoneGeoEtCodePourAffichage($obs);
$utilisateur = $this->getIntituleAuteur($obs['courriel_utilisateur']);
$titre = "$nom_plante à $lieu par $utilisateur $date";
$titre = $this->nettoyerTexte($titre);
return $titre;
}
private function creerGuidItem($element) {
$guid = sprintf($this->config['settings']['guidObsTpl'], $element['id_observation']);
return $guid;
}
private function creerLienItem($element) {
$lien = null;
if ($element['nom_sel_nn'] != 0) {
$lien = $this->getUrlEflore($element['nom_referentiel'], $element['nom_sel_nn'], 'cel');
}
return $lien;
}
private function creerDescription($obs, $item) {
$id_obs = $obs['id_observation'];
$famille = $obs['famille'];
$nom_saisi = $obs['nom_sel'];
$nom_retenu = $obs['nom_ret'];
$auteur = $this->getIntituleAuteur($obs['courriel_utilisateur']);
$auteur_mail = $obs['courriel_utilisateur'];
$mots_cles_obs = $obs['mots_cles_texte'];
$lien_correction = sprintf($this->config['settings']['phpEditUrlTpl'], $obs['id_observation']);
$lieu = $this->formaterZoneGeoEtCodePourAffichage($obs).' > '.$obs['lieudit'].' > '.$obs['station'];
$milieu = $obs['milieu'];
$coordonnees = ($this->etreNull($obs['latitude']) && $this->etreNull($obs['longitude'])) ? '' : $obs['latitude'].'/'.$obs['longitude'];
$commentaire = $obs['commentaire'];
$date_observation = ($obs['date_observation'] != '0000-00-00 00:00:00') ? $this->formaterDate($obs['date_observation'], '%A %d %B %Y') : '';
$date_transmission = $this->formaterDate($obs['date_transmission']);
$date_modification = $this->formaterDate($obs['date_modification']);
$date_creation = $this->formaterDate($obs['date_creation']);
$transmission = $obs['transmission'] == 1 ? "oui ($date_transmission)" : 'non';
$description = '<h2>'."Observation #$id_obs de $nom_saisi".'</h2>'.
'<ul>'.
'<li>'.'Famille : '.$famille.'</li>'.
'<li>'.'Nom saisi : '.$nom_saisi.'</li>'.
'<li>'.'Nom retenu : '.$nom_retenu.'</li>'.
'<li>'.'Observée le : '.$date_observation.'</li>'.
'<li>'.'Lieu : '.$lieu.'</li>'.
'<li>'.'Milieu : '.$milieu.'</li>'.
(($this->etreFluxAdmin()) ? '<li>Coordonnées (Lat/Long) : '.$coordonnees.'</li>' : '').
'<li>'.'Commentaire : '.$this->nePasInterpreterXml($commentaire).'</li>'.
'<li>'.'Mots-clés : '.$this->nePasInterpreterXml($mots_cles_obs).'</li>'.
(($this->etreFluxAdmin()) ? '<li>Transmis (= public) : '.$transmission.'</li>' : '').
'<li>Modifiée le : '.$date_modification.'</li>'.
'<li>Créée le : '.$date_creation.'</li>'.
'<li>'.'Par : '.
(($this->etreFluxAdmin()) ? '<a href="mailto:'.$auteur_mail.'">'.$auteur.'</a>' : $auteur).
'</li>'.
$this->creerDescriptionChampsEtendus($obs, $item).
(($this->etreFluxAdmin()) ? '<li><a href="'.$lien_correction.'">Corriger cette observation</a></li>' : '').
'</ul>';
$description = $this->nettoyerTexte($description);
return $description;
}
private function creerDescriptionChampsEtendus($obs, $item) {
$champs_etendus = '';
foreach($obs['obs_etendue'] as $cle => &$champ) {
if($this->doitAfficherChampEtendu($champ->cle, $this->catalogue_cles_labels_champs_etendus)) {
if(isset($this->catalogue_cles_labels_champs_etendus[$champ->cle])) {
$label = $this->catalogue_cles_labels_champs_etendus[$champ->cle]['label'];
} else {
$label = preg_replace("/(?<=\\w)(?=[A-Z])/"," $1", $champ->cle);
$label = trim($label);
$label = $label;
}
$champs_etendus .= '<li>'.$this->nePasInterpreterXml($label.' : '.$champ->valeur).' </li>';
}
}
if($champs_etendus != '') {
$champs_etendus = '<li> Champs supplémentaires : <ul>'.$champs_etendus.'</ul></li>';
}
return $champs_etendus;
}
private function doitAfficherChampEtendu($cle, $catalogue) {
// Suppression des nombres à la fin de la chaines dans le cas des clés
// "multiples" et mise en minuscule
$cle_simplifiee = preg_replace("/\d+$/","",$cle);
$cle_simplifiee = strtolower(rtrim($cle_simplifiee, ":"));
// Un champ est affichable s'il n'est pas au catalogue ou bien
// s'il n'est pas marqué privé dans celui-ci
$affichable = !isset($catalogue[$cle_simplifiee]) ||
$catalogue[$cle_simplifiee]['options']['prive'] != 1;
return $affichable;
}
private function creerCategorie($element) {
$categorie = '';
$categorie = 'Observation';
$categorie = $this->nettoyerTexte($categorie);
return $categorie;
}
private function etreFluxAdmin() {
return (isset($_GET['admin']) && $_GET['admin'] == '1') ? true : false;
}
private function creerUrlService() {
$url_service = $this->getUrlServiceBase();
if (count($_GET) > 0) {
$parametres_get = array();
foreach ($_GET as $cle => $valeur) {
$parametres_get[] = $cle.'='.$valeur;
}
$url_service .= '?'.implode('&amp;', $parametres_get);
}
return $url_service;
}
private function getIntituleAuteur($courriel) {
$courriel = strtolower($courriel);
if(isset($this->auteurs[$courriel])) {
$intitule = $this->auteurs[$courriel];
} else {
$intitule = $courriel;
}
return $intitule;
}
}
Property changes:
Added: svnkit:entry:sha1-checksum
+29045b1058a2dde75d8342b56a235d7a3c480f56
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/InventoryKeyWordObsLink.php
New file
0,0 → 1,61
<?php
// declare(encoding='UTF-8');
/**
* Service de liaisons de mots clés à des observations.
* Le service lie une ou plusieurs mots clés à une ou plusieurs observations.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 InventoryKeyWordObsLink extends Cel {
 
public function getElement($uid) { }
 
public function createElement($pairs) {
// Controle detournement utilisateur
$this->controleUtilisateur($pairs['ce_utilisateur']);
 
if (!isset($pairs['mots_cles']) || !isset($pairs['observations']) || !isset($pairs['ce_utilisateur'])) {
return;
}
 
$ids_obs = explode(',',$pairs['observations']);
$ids_mots_cles = explode(',',$pairs['mots_cles']);
 
$gestion_mots_cles = new GestionMotsClesChemin($this->config,'obs');
$liaison_mot_cle = $gestion_mots_cles->modifierLiaisonParTableaux($ids_mots_cles, $ids_obs, false);
 
foreach ($ids_obs as $id_element_lie) {
GestionMotsClesChemin::regenererIndexTexteMotCle($id_element_lie, 'obs');
}
return $liaison_mot_cle;
}
 
public function deleteElement($uid){
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
if (!isset($uid[0]) || !isset($uid[1]) || !isset($uid[2])) {
return false;
}
 
$id_utilisateur = $uid[0];
$ids_obs = explode(',', $uid[1]);
$ids_mots_cles = explode(',', GestionMotsClesChemin::nettoyerMotsClesAvantSuppression($uid[2]));
 
$gestion_mots_cles = new GestionMotsClesChemin($this->config, 'obs');
$suppression_liaisons = $gestion_mots_cles->supprimerLiaisonsMotsCles($ids_mots_cles, $ids_obs, $id_utilisateur);
foreach($ids_obs as $id_element_lie) {
GestionMotsClesChemin::regenererIndexTexteMotCle($id_element_lie, 'obs');
}
}
}
/branches/v3.01-serpe/jrest/services/InventoryImport.php
New file
0,0 → 1,33
<?php
// declare(encoding='UTF-8');
/**
* Service importation releve en cours :
* 1 : L'utilisateur à traiter est communique au service
* 2 : Les releves associés à la session en cours sont transferés à l'utilisateur identifié
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @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 InventoryImport extends Cel {
 
public function getElement($uid){
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
$gestionnaireObs = new GestionObservation($this->config);
$migration_compte_a_compte = $gestionnaireObs->migrerObservations(session_id(), $uid[0]);
 
$retour = ($migration_compte_a_compte) ? 'OK' : false;
echo $retour;
exit();
}
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/InventoryUserList.php
New file
0,0 → 1,67
<?php
// declare(encoding='UTF-8');
/**
* Liste des utilisateurs du cel, par défaut les 50 premiers ou bien commencant par la chaine fournie en paramètre
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @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 InventoryUserList extends Cel {
 
public function getElement($uid) {
$this->controleUtilisateur($uid[0]);
 
// Découplage de l'annuaire TB (suppression de la lecture dans cel_utilisateurs)
// @TODO vérifier que ça n'impacte que la liste d'usurpation d'identité pour les admins (on peut s'en passer)
$requete = 'SELECT DISTINCT ce_utilisateur as id_utilisateur, courriel_utilisateur as courriel '.
'FROM cel_obs '.
$this->construireRequeteConditionTableObs($uid).' '.
'LIMIT 0,50 '.
' -- '.__FILE__.':'.__LINE__;
$utilisateurs = Cel::db()->requeter($requete);
 
$liste_utilisateurs = array();
if ($utilisateurs) {
foreach ($utilisateurs as $utilisateur) {
$liste_utilisateurs[] = $utilisateur;
}
}
usort($liste_utilisateurs, array($this, 'trierUtilisateurs'));
 
$this->envoyerJson($liste_utilisateurs);
return true;
}
 
public function trierUtilisateurs($val1, $val2) {
if (strstr($val1['courriel'], '@')) {
if (strstr($val2['courriel'], '@')) {
return strcmp($val1['courriel'], $val2['courriel']);
} else {
return -1;
}
} else {
if (strstr($val2['courriel'], '@')) {
return 1;
} else {
return strcmp($val1['courriel'], $val2['courriel']);
}
}
}
 
private function construireRequeteConditionTableObs($params) {
$condition = '';
if (isset($params[1]) && $params[1] != null && $params[1] != '*') {
$condition .= ' WHERE courriel_utilisateur LIKE '.Cel::db()->proteger($params[1].'%');
}
return $condition;
}
}
/branches/v3.01-serpe/jrest/services/CelImageDoublon.php
New file
0,0 → 1,150
<?php
// declare(encoding='UTF-8');
/**
* Service fournissant une liste d'images doublon pour l'utilisateur qui s'authentifie.
*
* Cas d'utilisation :
* /CelImageDoublon/Sortie : images doublon de l'utilisateur authentifié.
*
* Sortie = Type de sortie : html ou json. Par défaut : html
*
* Utilisateur :
* identifiant (= courriel) de l'utilisateur récupéré via une identification HTTP.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 CelImageDoublon extends Cel {
 
/**
* Méthode appelée avec une requête de type GET.
*/
public function getElement($params) {
$parametres = $this->traiterParametres(array('mode', 'utilisateur'), $params, false);
extract($parametres);
$contenu = '';
 
if ($this->authentifierUtilisateur()) {
$retour = null;
 
if (isset($mode)) {
$methode = $this->traiterNomMethodeGet($mode);
if (method_exists($this, $methode)) {
$retour = $this->$methode($parametres);
} else {
$service = get_class($this);
$this->messages[] = "Ce type de mode '$mode' pour le service '$service' n'est pas disponible.";
}
} else {
$this->messages[] = "Vous devez indiquer un type de mode.";
}
 
if (is_null($retour)) {
$contenu = 'Un problème est survenu : '.print_r($this->messages, true);
} else {
if ($retour['type'] == 'widget') {
$squelette = dirname(__FILE__).DIRECTORY_SEPARATOR.'squelettes'.DIRECTORY_SEPARATOR.$retour['squelette'].'.tpl.html';
$contenu = $this->traiterSquelettePhp($squelette, $retour['donnees']);
} else if ($retour['type'] == 'json') {
$contenu = $retour['donnees'];
}
}
}
 
// Envoie sur la sortie standard
$encodage = 'UTF-8';
$mime = 'text/html';
$formatage_json = (isset($retour) && $retour['type'] == 'json') ? true : false;
$this->envoyer($contenu, $mime, $encodage, $formatage_json);
}
 
/**
* Carte par défaut
*/
private function getDoublonHtml($parametres) {
$widget = null;
$utilisateur_mail = Cel::getAuthIdentifiant();
$utilisateur_infos = new GestionUtilisateur($this->config);
$utilisateur = $utilisateur_infos->obtenirUtilisateurSiExiste($utilisateur_mail);
$utilisateur = $utilisateur['id_utilisateur'];
 
// Création des infos du widget
$widget['type'] = 'widget';
$widget['donnees']['utilisateur'] = $utilisateur_mail;
$widget['donnees']['doublons'] = $this->getImagesDoublon($utilisateur);
$widget['squelette'] = 'doublon_defaut';
 
return $widget;
}
 
/**
* Images en doublon d'un utilisateur
*/
private function getImagesDoublon($utilisateur) {
$doublons = null;
if (isset($utilisateur)) {
// Un utilisateur en particulier
$idUtilisateurP = Cel::db()->proteger($utilisateur);
$requete = 'SELECT id_image, ordre, nom_original, md5 '.
'FROM cel_images '.
"WHERE ce_utilisateur = $idUtilisateurP ".
' -- '.__FILE__.':'.__LINE__;
$images = Cel::db()->requeter($requete);
 
// Traitement
$doublons = array();
$images_doublons_id = array();
$md5 = array();
foreach ($images as $img) {
if (!isset($md5[$img['md5']])) {
$md5[$img['md5']] = array(
'url' => $this->getUrlImage($img['id_image'], 'CXS'),
'obs_ordre' => array(),
'img_ordre' => $img['ordre'],
'img_id' => $img['id_image']);
} else {
if (!isset($doublons[$img['md5']])) {
$id_img = $md5[$img['md5']]['img_id'];
$doublons[$img['md5']][$id_img] = $md5[$img['md5']];
$images_doublons_id[] = Cel::db()->proteger($id_img);
}
 
$doublons[$img['md5']][$img['id_image']] = array(
'url' => $this->getUrlImage($img['id_image'], 'CXS'),
'obs_ordre' => array(),
'img_ordre' => $img['ordre'],
'img_id' => $img['id_image']);
$images_doublons_id[] = Cel::db()->quote($img['id_image']);
}
}
 
if (count($images_doublons_id) > 0) {
$idsImgConcat = implode(',', $images_doublons_id);
$requete = 'SELECT cim.id_image, nom_original, md5, co.ordre AS ordre_obs '.
'FROM cel_images AS cim '.
' LEFT JOIN cel_obs AS co '.
' ON (cim.ce_observation = co.id_observation) '.
"WHERE cim.ce_utilisateur = $idUtilisateurP ".
"AND cim.id_image IN ($idsImgConcat) ".
' -- '.__FILE__.':'.__LINE__;
$infos = Cel::db()->requeter($requete);
 
foreach ($infos as $info) {
if (isset($doublons[$info['md5']][$info['id_image']]) && ! $this->etreNull($info['ordre_obs'])) {
$doublons[$info['md5']][$info['id_image']]['obs_ordre'][] = $info['ordre_obs'];
}
}
}
}
return $doublons;
}
}
/branches/v3.01-serpe/jrest/services/InventoryImportMail.php
New file
0,0 → 1,172
<?php
// declare(encoding='UTF-8');
/**
* Service d'import d'image à partir d'e-mails.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 InventoryImportMail extends Cel {
 
/**
* Appelée en mode client, lit le mail envoyé sur l'entrée stdin
* et le stocke dans le dossier temporaire en attendant
* qu'une tache périodique associée traite les mails en attente
*
* @param array $params les paramètres du script client, l'utilisateur est indiqué avec le paramètre -s
*/
public function stockerMailCli($params) {
$contenu_mail = file_get_contents('php://stdin');
$parametres_ajout = array();
$parametres_ajout['mail_utilisateur'] = $params['-s'];
 
$stockage = $this->stockerMailTemporaire($parametres_ajout, $contenu_mail);
if ($stockage) {
$message_attente = 'Votre messsage a été reçu, et est en attente de traitement, '.
'vous recevrez un message lorsque celui-ci aura été effectué';
mail($parametres_ajout['mail_utilisateur'],'Votre message est en attente de traitement',$message_attente);
} else {
$message_echec = 'Votre messsage a été reçu, mais il n\'a pas pu être stocké';
mail($parametres_ajout['mail_utilisateur'],'Problème lors de reception du message',$message_echec);
}
exit();
}
 
private function stockerMailTemporaire($parametres_ajout, $contenu_mail) {
$expediteur = $parametres_ajout['mail_utilisateur'];
$nom_fichier_temp = $this->fabriquerNomTemporaireStockageMail($expediteur);
$dossier_stockage_temp = $this->config['chemin_stockage_temp'];
$chemin_stockage_image_temp = $dossier_stockage_temp.'/mails/';
 
return file_put_contents($chemin_stockage_image_temp.$nom_fichier_temp, $contenu_mail);
}
 
/**
* Appelée en mode client, lit le mail envoyé sur l'entrée stdin
* extrait les images en pièces jointes, et les ajoute au cel de l'utilisateur
* expediteur
*
* @param array $params les paramètres du script client, l'utilisateur est indiqué avec le paramètre -s
*/
public function traiterMailCli($params) {
$contenu_mail = file_get_contents('php://stdin');
$parametres_ajout = array();
$parametres_ajout['mail_utilisateur'] = $params['-s'];
$ids_stockage = $this->traiterMail($parametres_ajout, $contenu_mail);
 
foreach ($ids_stockage as $nom_image => $id_stockage) {
if ($id_stockage) {
$sujet = "Votre image a été ajoutée au Carnet en ligne";
$msg = "Votre image $nom_image a été ajoutée avec succès";
mail($parametres_ajout['mail_utilisateur'], $sujet, $msg);
} else {
$sujet = "Problème lors de l'ajout au Carnet en ligne";
$msg = "Votre image $nom_image n'a pas pu être ajoutée";
mail($parametres_ajout['mail_utilisateur'], $sujet, $msg);
}
}
exit();
}
 
/**
* Traite le mail fourni en paramètre extrait les images en pièces jointes,
* et les ajoute au cel de l'utilisateur expediteur
*
* @param array $params les paramètres du script client, l'utilisateur est indiqué dans la case 'identifiant'
*/
public function traiterMail($params, $contenu_mail) {
$pieces_jointes = $this->extrairePiecesJointes($contenu_mail);
$stockeur_image = new InventoryImage($this->config);
$ids = array();
$infos_utilisateur = $this->getInfosComplementairesUtilisateurPourMail($params['mail_utilisateur']);
$params['ce_utilisateur'] = $infos_utilisateur['id_utilisateur'];
foreach ($pieces_jointes as $piece_jointe) {
$nouvel_id_image = $stockeur_image->ajouterImageSurDdEtBdd($params, $piece_jointe);
 
if($nouvel_id_image) {
$ids[$piece_jointe['name']] = $nouvel_id_image;
} else {
$ids[$piece_jointe['name']] = false;
}
}
 
// TODO: permettre la création d'observations liées aux images à partir du mail
// et d'une syntaxe simple à définir
return $ids;
}
 
/**
* Appelée en mode client, parse le dossier ou sont stockés les mails
* extrait les images en pièces jointes, et les ajoute au cel de l'utilisateur
*
*/
public function parserDossierMail() {
$dossier_stockage_temp = $this->config['chemin_stockage_temp'];
$chemin_stockage_image_temp = $dossier_stockage_temp.'/mails/';
foreach (new DirectoryIterator($chemin_stockage_image_temp) as $fichier_a_stocker) {
if ($fichier_ou_dossier->isDot()) {
continue;
}
$nom_fichier = $fichier_ou_dossier->getFilename();
$expediteur_mail = $this->obtenirExpediteurPourNomTemporaireMail($nom_fichier);
$parametres = array('courriel_utilisateur' => $expediteur_mail);
$chemin_fichier = $fichier_a_stocker->getPathname();
$contenu_mail = file_get_contents($chemin_fichier);
$this->traiterMail($parametres, $contenu_mail);
unlink($chemin_fichier);
}
}
 
private function extrairePiecesJointes($mail) {
$args['include_bodies'] = true;
$args['decode_bodies'] = true;
$args['decode_headers'] = true;
$args['input'] = $mail;
$dossier_stockage_temp = $this->config['chemin_stockage_temp'];
 
$pieces_jointes = array();
$tableau_mail_decode = Mail_mimeDecode::decode($args);
foreach ($tableau_mail_decode->parts as $partie) {
if ($partie->ctype_primary == 'image' && $partie->ctype_secondary == 'jpeg') {
$nom_original = $partie->ctype_parameters['name'];
$fichier = $partie->body;
$hash = md5(time());
$chemin_temp = $dossier_stockage_temp.'/images/'.$hash.'.jpg';
 
$temp = fopen($chemin_temp,'w+');
fwrite($temp,$fichier);
fclose($temp);
chmod($chemin_temp, 0777);
 
$pieces_jointes[] = array(
'tmp_name' => $chemin_temp,
'name' => $nom_original,
'type' => 'image/jpeg',
'size' => filesize($chemin_temp));
}
}
return $pieces_jointes;
}
 
private function fabriquerNomTemporaireStockageMail($expediteur) {
return time().'_'.$expediteur;
}
 
private function obtenirExpediteurPourNomTemporaireMail($nom_temp) {
$chaine_separee = explode('_', $nom_temp,1);
$nom_expediteur = false;
if ($chaine_separee && count($chaine_separee) > 1) {
$nom_expediteur = $chaine_separee[1];
}
return $nom_expediteur;
}
}
/branches/v3.01-serpe/jrest/services/CoordSearch.php
New file
0,0 → 1,96
<?php
// declare(encoding='UTF-8');
/**
* Service recherche de zone par coordonnées et vice versa.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Cartes
* @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 CoordSearch extends Cel {
 
public function getRessource() {
return $this->getElement(array());
}
 
public function getElement($uid){
$header = '';
$retour = [];
 
$params = $this->traiterParametres();
$recherche_zones_geo = new RechercheInfosZoneGeo($this->config);
 
if( !empty($params)) {
if ($this->estUneRequeteReverseGeocoding($params)) {
$informations = $recherche_zones_geo->obtenirInfosPourCoordonnees([
'latitude' => $params['lat'],
'longitude' => $params['lon'],
]);
} elseif ($this->estUneRequeteGeocodingCodeInseeCommune($params)) {
$informations = $recherche_zones_geo->obtenirInfosPourCodeInseeCommune($params['code']);
} elseif ($this->estUneRequeteGeocoding($params)) {
$informations = $recherche_zones_geo->obtenirInfosPourNom(
$params['zone'],
$params['pays'],
$params['code']
);
} elseif ($this->estUneRequeteGeocodingGroupe($params)) {
// renvoie des infos sur un groupes de zones géographiques, si celui-ci
// est décrit dans la table cel_groupes_zones_geo
$informations = $recherche_zones_geo->obtenirInfosPourGroupeZonesFrance($params['groupe_zones']);
}
 
$altitude = $recherche_zones_geo->obtenirAltitude($informations);
$informations = array_merge($informations, $altitude);
 
$header = 'Content-Type: application/json; charset=UTF-8';
$retour = json_encode($informations);
 
} else {
$header = 'HTTP/1.0 400 Bad Request';
$retour = 'zone ou Coordonnées ou code INSEE non spécifié.e';
}
 
header($header);
echo $retour;
}
 
protected function traiterParametres() {
$params = array('lon', 'lat', 'zone', 'groupe_zones', 'code', 'pays');
$parametresTraites = array();
 
foreach($params as $p) {
$val = ''; // @TODO plutôt null ?
if (!empty($_REQUEST[$p])) {
$val = $_REQUEST[$p];
}
$parametresTraites[$p] = $val;
}
 
return $parametresTraites;
}
 
protected function estUneRequeteReverseGeocoding($params) {
return ($params['lat'] != '' && $params['lon'] != '');
}
 
protected function estUneRequeteGeocoding($params) {
return ($params['zone'] != '');
}
 
protected function estUneRequeteGeocodingCodeInseeCommune($params) {
return ($params['code'] != '' && 5 === strlen($params['code']));
}
 
protected function estUneRequeteGeocodingGroupe($params) {
return ($params['groupe_zones'] != '');
}
}
/branches/v3.01-serpe/jrest/services/ImageProvider.php
New file
0,0 → 1,50
<?php
// declare(encoding='UTF-8');
/**
* Service fournissant des images au format demandé ou bien aux dimensions demandées.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 ImageProvider extends Cel {
 
public function getElement($uid){
if (!isset($uid[0])) {
return;
}
$id_image = $uid[0];
 
$format = 'temp';
if (isset($_GET['format'])) {
$format = $_GET['format'];
}
 
if (isset($_GET['dimensions'])) {
$dimensions = $_GET['dimensions'];
} else if (isset($this->config['cel']['format_'.$format])) {
$dimensions = $this->config['cel']['format_'.$format];
}
$this->config['cel']['format_'.$format] = $dimensions;
 
$generateur_image = new ImageRecreation($this->config);
$infos_image = $generateur_image->obtenirImageEtInfosPourId($id_image);
if (!$infos_image) {
header('HTTP/1.0 404 Not Found');
exit();
} else {
$image_generee = $generateur_image->creerMiniatureImageSelonFormat($infos_image, $format);
header('Content-type: image/jpeg');
imagejpeg($image_generee);
exit();
}
}
}
/branches/v3.01-serpe/jrest/services/LocationSearch.php
New file
0,0 → 1,47
<?php
// declare(encoding='UTF-8');
/**
* Service gérant la completion des noms de lieux.
*
* Cas d'utilisation :
* Service completion nom de commune (plus tard de lieu en général)
*
* 1 : L'application recoit un debut de nom de lieu
* 2 : Si la longueur du prefixe est > 2, l'application retourne les 50 premieres lieux commencant par ce prefixe
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Auto-complétions
* @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 LocationSearch extends Cel {
 
public function getElement($uid){
$retour = array();
 
if (isset($uid[0])) {
$retour = $this->executerRequeteLieu($uid[0]);
}
 
$this->envoyerJson($retour);
return true;
}
 
public function getRessource() {
print '[]';
return;
}
 
private function executerRequeteLieu($lieu) {
$recherche_infos_zone_geo = new RechercheInfosZoneGeo($this->config);
return $recherche_infos_zone_geo->obtenirListeInfosPourNom($lieu);
}
}
/branches/v3.01-serpe/jrest/services/InventoryExport.php
New file
0,0 → 1,140
<?php
// declare(encoding='UTF-8');
/**
* Service d'export vers feuille de calcul d'une sélection de relevés.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @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>
*/
 
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(dirname(realpath(__FILE__))) . '/lib');
// la sortie est binaire (xls), mais OLE n'est pas compatible E_ALL en PHP-5.4
error_reporting(error_reporting() ^ E_STRICT);
require_once 'lib/OLE.php';
require_once 'lib/Spreadsheet/Excel/Writer.php';
 
class InventoryExport extends Cel {
 
private $extendSpreadsheetProductor;
 
public function __construct($config) {
parent::__construct($config);
 
$this->extendSpreadsheetProductor = new SpreadsheetProductor();
$this->extendSpreadsheetProductor->initSpreadsheet();
}
 
public function getElement($uid){
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
$criteres = $_GET;
$chercheur_observations = new RechercheObservation($this->config);
 
// Creating a workbook
$workbook = new Spreadsheet_Excel_Writer();
$workbook->setVersion(8);
$workbook->send('liste.xls');
 
// Creating a worksheet
$worksheet = $workbook->addWorksheet('Liste');
$worksheet->setInputEncoding('utf-8');
$worksheet->write(0,0,'Espece');
$worksheet->write(0,1,'Numero nomenclatural');
$worksheet->write(0,2,'Nom retenu');
$worksheet->write(0,3,'Numero nomenclatural nom retenu');
$worksheet->write(0,4,'Numero taxonomique');
$worksheet->write(0,5,'Famille');
$worksheet->write(0,6,'Referentiel taxonomique');
$worksheet->write(0,7,'Commune');
$worksheet->write(0,8,'Identifiant Commune');
$worksheet->write(0,9,'Date');
$worksheet->write(0,10,'Lieu-dit');
$worksheet->write(0,11,'Station');
$worksheet->write(0,12,'Milieu');
$worksheet->write(0,13,'Notes');
$worksheet->write(0,14,'Latitude');
$worksheet->write(0,15,'Longitude');
$worksheet->write(0,16,'Referentiel Geographique');
$worksheet->write(0,17,'Ordre');
$worksheet->write(0,18,'Identifiant');
 
$numero_page = isset($criteres['numero_page']) ? $criteres['numero_page'] : 0;
$limite = isset($criteres['limite']) ? $criteres['limite'] : 0;
 
$observations = $chercheur_observations->rechercherObservations($uid[0], $criteres, $numero_page, $limite)->get();
if (!$observations) {
header('HTTP/1.0 204 No Content');
exit;
}
 
$ids_obs = array();
$indices_lignes_obs = array();
 
$i = 1;
foreach ($observations as &$obs) {
$obs = $this->denullifierTableauValeurCel($obs);
$ids_obs[] = $obs['id_observation'];
$indices_lignes_obs[$obs['id_observation']] = $i;
 
if ($obs['date_observation'] != '0000-00-00 00:00:00') {
$obs['date_observation'] = $this->formaterDate($obs['date_observation']);
} else {
$obs['date_observation'] = '00/00/0000';
}
 
$worksheet->write($i,0,$obs['nom_sel']);
$worksheet->write($i,1,$obs['nom_sel_nn']);
$worksheet->write($i,2,$obs['nom_ret']);
$worksheet->write($i,3,$obs['nom_ret_nn']);
$worksheet->write($i,4,$obs['nt']);
$worksheet->write($i,5,$obs['famille']);
$worksheet->write($i,6,$obs['nom_referentiel']);
$worksheet->write($i,7,$obs['zone_geo']);
$worksheet->write($i,8,$this->convertirCodeZoneGeoVersDepartement($obs['ce_zone_geo']));
$worksheet->write($i,9,$obs['date_observation']);
$worksheet->write($i,10,$obs['lieudit']);
$worksheet->write($i,11,$obs['station']);
$worksheet->write($i,12,$obs['milieu']);
$worksheet->write($i,13,$obs['commentaire']);
$worksheet->write($i,14,$obs['latitude']);
$worksheet->write($i,15,$obs['longitude']);
$worksheet->write($i,16,$obs['geodatum']);
$worksheet->write($i,17,$obs['ordre']);
$worksheet->write($i,18,$obs['id_observation']);
$i++;
}
 
$indice_dernier_champ_supp = 19;
$indices_champs_supp = array();
$gestion_champs_etendus = new GestionChampsEtendus($this->config, 'obs');
$champs_supp_par_obs = $gestion_champs_etendus->consulterParLots($ids_obs);
 
foreach ($champs_supp_par_obs as $id_obs => &$champs_supp) {
foreach ($champs_supp as &$champ_etendu) {
$cle = $champ_etendu->cle;
$label = $champ_etendu->label;
$valeur = $champ_etendu->valeur;
if(!isset($indices_champs_supp[$cle])) {
$indices_champs_supp[$cle] = $indice_dernier_champ_supp;
$worksheet->write(0, $indice_dernier_champ_supp, utf8_decode($label));
$indice_dernier_champ_supp++;
}
$num_ligne_obs = $indices_lignes_obs[$id_obs];
$worksheet->write($num_ligne_obs,$indices_champs_supp[$cle],utf8_decode($valeur));
}
}
 
$workbook->close();
exit();
}
}
/branches/v3.01-serpe/jrest/services/Resume.php
New file
0,0 → 1,94
<?php
// declare(encoding='UTF-8');
/**
* Service renvoyant au format JSON les dernières observations publiques d'un utilisateur.
* Utilisée par l'annuaire appelant les web services résumé de chaque application.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @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 Resume extends Cel {
 
public function getElement($uid){
$idUtilisateurP = Cel::db()->proteger($uid[1]);
$requete = 'SELECT co.*, ci.id_image, ci.nom_original, ci.largeur, ci.hauteur '.
'FROM cel_obs AS co INNER JOIN cel_images AS ci ON (id_observation = ce_observation) '.
"WHERE co.ce_utilisateur = $idUtilisateurP ".
'ORDER BY co.date_modification DESC '.
'LIMIT 0,5 '.
' -- '.__FILE__.':'.__LINE__;
$resultats = Cel::db()->requeter($requete);
 
$urlImgTpl = $this->config['settings']['celImgUrlTpl'];
$urlAppliCel = $this->config['settings']['celAppliUrl'];
$resume = array(
'titre' => 'Vos dernières observations avec photos publiées',
'lien_appli' => '<a href="'.$urlAppliCel.'"> Accéder au carnet en ligne </a>');
 
if ($resultats !== false && is_array($resultats) && count($resultats) == 0) {
$resume['message'] = 'Aucune observation saisie pour le moment';
} else if ($resultats !== false && is_array($resultats) && count($resultats) > 0) {
 
foreach ($resultats as $obs) {
$obs = array_filter($obs, array($this, 'nettoyerObs'));
 
$nomRetenu = isset($obs['nom_ret']) ? $obs['nom_ret'] : 'Indéterminé';
$date = 'Datée du '.$obs['date_modification'];
$idZoneGeo = $this->convertirCodeZoneGeoVersDepartement($obs['ce_zone_geo']);
$lieuMorceaux = array();
$lieuMorceaux[] = $obs['zone_geo'].(!empty($idZoneGeo) ? " ($idZoneGeo)" : '');
$lieuMorceaux[] = isset($obs['station']) ? $obs['station'] : null;
$lieuMorceaux[] = isset($obs['lieudit']) ? $obs['lieudit'] : null;
$lieu = 'Lieu : '.implode(', ', $lieuMorceaux);
$nomOriginal = htmlspecialchars($obs['nom_original']);
list($largeur, $hauteur) = $this->calculerDimensions($obs['largeur'], $obs['hauteur']);
$idImg = sprintf('%09s', $obs['id_image']);
$urlImgL = sprintf($urlImgTpl, "{$idImg}L");
$urlImgM = sprintf($urlImgTpl, "{$idImg}M");
$baliseImg = '<img src="'.$urlImgM.'" alt="'.$nomOriginal.'" height="'.$hauteur.'" width="'.$largeur.'" />';
 
$resume['elements'][] = array(
'element' => "$nomRetenu<br />$date<br />$lieu<br />",
'lien' => $urlImgL,
'image' => $baliseImg);
}
}
$this->envoyerJson($resume);
return true;
}
 
protected function nettoyerObs($valeur) {
return ($valeur == '000null') ? '' : trim($valeur);
}
 
private function calculerDimensions($largeur, $hauteur) {
$tailleOr = 75 ;
if ($hauteur == 0) {
$hauteur = $tailleOr;
}
if ($largeur == 0) {
$largeur = $tailleOr;
}
$maxTaille = max($hauteur, $largeur);
 
if ($maxTaille == $hauteur) {
$rapport = $hauteur / $largeur;
$hauteur = 75;
$largeur = round($hauteur / $rapport, 0);
} else {
$rapport = $largeur / $hauteur;
$largeur = 75;
$hauteur = round($largeur / $rapport, 0);
}
return array($largeur, $hauteur);
}
}
/branches/v3.01-serpe/jrest/services/CelWidgetManager.php
New file
0,0 → 1,243
<?php
// declare(encoding='UTF-8');
/**
* Service fournissant des informations sur les widgets existants et permettant d'en créer d'autres.
*
* Format du service :
* /CelWidgetExport/format
* /CelWidgetExport/csv
*
* Les paramêtres :
* - "start" indique le numéro du premier item à afficher
* - "limit" nombre d'items à afficher
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Widget
* @version 0.1
* @author Delphine CAUQUIL <delphine@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-2017 Tela Botanica <accueil@tela-botanica.org>
*/
 
 
class CelWidgetManager extends Cel {
 
// correspondance entre les champs de l'interface et les champs de la BD (format 2018 / 2019)
private $parametres_autorises = array(
'projet' => 'project',
'type' => 'type',
'esttype' => 'is_type',
'langue' => 'language',
'order' => 'order'
);
private $correspondance_config_widget= array(
'projet' => 'project',
'langue' => 'language',
'titre' => 'title',
'logo' => 'logo',
'description' => 'description',
'type' => 'type',
'est_type' => 'is_type',
'style_css' => 'css_style',
'image_fond' => 'image_font',
'date_creation' => 'date_created',
'type_especes' => 'taxo_restriction_type',
'referentiel' => 'taxo_restriction_value',
'type_localisation' => 'location_type',
'localisation' => 'location',
'milieux' => 'environment',
'motscles' => 'project_tag_name',
'info' => 'info',
'id_projet' => 'project_id'
);
private $correspondance_champs_etendus = array(
"key" => "field_id",
"element" => "data_type",
"mandatory" => "is_mandatory",
"unit" => "unit"
);
private $correspondance_champs_etendus_trad = array(
"key" => "extended_field_id",
"name" => "label",
"description" => "description",
"fieldValues" => "default_value",
"help" => "help"
);
 
public function getRessource() {
return $this->getElement(array());
}
 
/**
* Méthode appelée avec une requête de type GET.
*/
public function getElement($params = array()) {
switch(@strtolower($params[0])) {
case 'widget':
$this->getWidget();
break;
case 'champsetendus';
$this->getChampsEtendus();
break;
default:
$this->getWidget();
}
}
public function createElement($requeteDonnees) {
unset($requeteDonnees['signup_submit']);
if (isset($requeteDonnees['champs-supp'])) {
$gestionchamps = new GestionChampsEtendus2($this->config);
$champs = $this->traiterCorrespondanceChampsEtendusInterfaceBD($requeteDonnees); //var_dump($champs);exit;
$liste = $gestionchamps->ajouterParProjet($champs);
unset($requeteDonnees['champs-supp']);
}
$requeteDonnees['est_type'] = (isset($requeteDonnees['est_type']) && $requeteDonnees['est_type']== "on") ? 1 : 0;
$manager = new GestionWidget($this->config);
$requeteDonnees = $this->traiterCorresponceConfigWidgetInterfaceBD($requeteDonnees);
$retour = $manager->ajouterWidget($requeteDonnees);
 
$this->envoyerJson($retour);
 
}
public function updateElement($uid,$params) {
$retour = "";
if (isset($params['projet']) && isset($params['langue'])) {
$manager = new GestionWidget($this->config);
$params['est_type'] = (isset($params['est_type']) && $params['est_type']== "on") ? 1 : 0;
$requeteDonnees = $this->traiterCorresponceConfigWidgetInterfaceBD($params);
$retour = $manager->modifierWidget($params['projet'], $params['langue'], $requeteDonnees);
}
$this->envoyerJson($retour);
return "ff";
}
 
private function getWidget() {
$criteres = $this->traiterParametresAutorises($_GET);
$manager = new GestionWidget($this->config);
$liste = $manager->obtenirWidget($criteres);
$liste = $this->traiterCorresponceConfigWidgetBDInterface($liste);
 
$this->envoyerJson($liste);
}
private function getChampsEtendus() {
$champs = new GestionChampsEtendus2($this->config);
$projet = (isset($_GET['projet'])) ? $_GET['projet'] : "";
$langue = (isset($_GET['langue'])) ? $_GET['langue'] : "fr";
$liste = $champs->consulterProjetChampsEtendus($projet, $langue);
$liste = $this->traiterCorrespondanceChampsEtendusBDInterface($liste, $projet);
$this->envoyerJson($liste);
}
 
 
protected function traiterParametresAutorises(Array $parametres) {
$parametres_traites = array();
foreach($parametres as $cle => $valeur) {
if(is_string($valeur) && !trim($valeur)) continue;
if(isset($this->parametres_autorises[$cle])) {
$parametres_traites[$this->parametres_autorises[$cle]] = $valeur;
}
}
return $parametres_traites;
}
protected function traiterCorresponceConfigWidgetBDInterface(Array $widgets) {
$parametres_traites = array();
$corresp = array_flip($this->correspondance_config_widget);
foreach($widgets as $id => $widget) {
foreach($widget as $cle => $valeur) {
if(is_string($valeur) && !trim($valeur)) continue;
if(isset($corresp[$cle])) {
$parametres_traites[$id][$corresp[$cle]] = $valeur;
}
}
}
return $parametres_traites;
}
protected function traiterCorresponceConfigWidgetInterfaceBD(Array $parametres) {
$parametres_traites = array();
$corresp = $this->correspondance_config_widget;
foreach($parametres as $cle => $valeur) {
if(is_string($valeur) && !trim($valeur)) $valeur=NULL;
if(isset($corresp[$cle])) {
$parametres_traites[$corresp[$cle]] = $valeur;
}
}
return $parametres_traites;
}
protected function traiterCorrespondanceChampsEtendusInterfaceBD(Array $champsinterface) {
$champsrequete = array(); $i = 0;
$champssupp = json_decode($champsinterface['champs-supp'], true);
// pour chaque champs-supp, mettre correspondance extended field et extended field trad
foreach ($champssupp as $champ) {
$champsrequete['ce'][$i]['project'] = $champsrequete['cet'][$i]['project'] = $champsinterface['projet'];
$champsrequete['cet'][$i]['language_iso_code'] = $champsinterface['langue'];
// pour la table extended fiels champs interface => champs bd
foreach ($this->correspondance_champs_etendus as $ci => $ce) {
if (isset($champ[$ci]) && $champ[$ci] != "") {
$champsrequete['ce'][$i][$ce] = $champ[$ci];
} else {
if ($ci == "mandatory") {
$champsrequete['ce'][$i][$ce] = "0";
} else {
$champsrequete['ce'][$i][$ce] = "";
}
}
}
// pour la table extended fiels trad champs interface => champs bd
foreach ($this->correspondance_champs_etendus_trad as $cit => $cr) {
if (isset($champ[$cit]) && is_array($champ[$cit])) {
$champsrequete['cet'][$i][$cr] = json_encode($champ[$cit]);
} elseif (isset($champ[$cit]) && $champ[$cit] != "") {
$champsrequete['cet'][$i][$cr] = $champ[$cit];
} else {
$champsrequete['cet'][$i][$cr] = "";
}
}
$i++;
}
return $champsrequete;
}
protected function traiterCorrespondanceChampsEtendusBDInterface(Array $champsrequete, $projet = "null") {
$champssupp = array(); $i = 0;
foreach ($champsrequete as $champ) {
$champssupp[$projet]['projet'] = $champ['project'];
$champssupp[$projet]['langue'] = $champ['language_iso_code'];
// pour la table extended fiels champs interface => champs bd
foreach ($this->correspondance_champs_etendus as $ci => $ce) {
if (isset($champ[$ce]) && $champ[$ce] != "") {
$champssupp[$projet]['champs-supp'][$i][$ci] = $champ[$ce];
} else {
$champssupp[$projet]['champs-supp'][$i][$ci]= "";
}
}
// pour la table extended fiels trad champs interface => champs bd
foreach ($this->correspondance_champs_etendus_trad as $cet => $cr) {
if (isset($champ[$cr]) && $champ[$cr] != "") {
$champssupp[$projet]['champs-supp'][$i][$cet]= $champ[$cr];
} else {
$champssupp[$projet]['champs-supp'][$i][$cet]="";
}
}$i++;
}
return $champssupp;
}
 
 
}
?>
/branches/v3.01-serpe/jrest/services/CelStatistique.php
New file
0,0 → 1,972
<?php
// declare(encoding='UTF-8');
/**
* Service fournissant des urls vers des images de graphiques sur les statistiques de l'application CEL.
* Encodage en entrée : utf8
* Encodage en sortie : utf8
*
* Cas d'utilisation :
* /CelStatistique/TypeDeGraph : retourne le graphique demandé
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Statistiques
* @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 CelStatistique extends Cel {
 
/**
* Méthode appelée avec une requête de type GET.
*/
public function getElement($param) {
$graph = null;
 
if (isset($param[0])) {
$graph_demande = array_shift($param);
$methode = 'get'.$graph_demande;
if (method_exists($this, $methode)) {
$graph = $this->$methode($param);
} else {
$this->messages[] = "Ce type de graphique '$graph_demande' n'est pas disponible.";
}
} else {
$this->messages[] = "Le premier paramêtre du service CEL Statistique doit correspondre au type de graphique.";
}
 
if (!is_null($graph)) {
$url = "http://chart.apis.google.com/chart";
$contexte = stream_context_create(
array('http' => array(
'method' => 'POST',
'content' => http_build_query($graph),
'header' => 'Content-Type: application/x-www-form-urlencoded')));
$image = file_get_contents($url, false, $contexte);
$this->envoyer($image, 'image/png', null, false);
} else {
$info = 'Un problème est survenu : '.print_r($this->messages, true);
$this->envoyer($info);
}
}
 
private function getEvolImgLieesParMois($param) {
$utilisateur = isset($_GET['utilisateur']) ? Cel::db()->quote($_GET['utilisateur']) : null;
 
// Récupération des données
$requete = "SELECT DATE_FORMAT(date_creation, '%Y%m') AS periode, COUNT(id_image) AS nbre ".
"FROM cel_images_export ".
"WHERE date_creation != '0000-00-00 00:00:00' ".
' AND ce_observation IS NOT NULL AND ce_observation != 0 '.
((isset($utilisateur)) ? " AND courriel_utilisateur = $utilisateur " : '').
'GROUP BY periode '.
'ORDER BY periode ';
 
$resulats = Cel::db()->requeter($requete);
 
$img_totale = array();
foreach ($resulats as $info) {
$img_totale[$info['periode']] = $info['nbre'];
}
 
// Trie des dates pour les étiquettes des axes
$dates = array();
$annees = array();
$les_mois = array();
$pas = 1; // intervalle de mois entre deux étiquettes
$periode = 0;
$cumul = 0;
$img_totale_cumul = array();
foreach ($img_totale as $annee_mois => $nbre) {
$annee = substr($annee_mois, 0, 4);
$mois = substr($annee_mois, 4, 2);
$mois_fmt_B = strftime('%b', strtotime("0000-$mois-01"));
$cumul += $nbre;
$img_totale_cumul[$annee_mois] = $cumul;
 
if (!isset($dates[$annee][$mois])) {
$annees[] = (!isset($dates[$annee]) ? $annee : '');
$les_mois[] = is_int($periode++ / $pas) ? $mois_fmt_B : '';
// Ajouter au tableau dates tjrs à la fin
$dates[$annee][$mois] = 1;
}
}
 
// Post traitement des données
$titre = "Évolution des images liées aux observations par mois";
$valeurs_y = implode(',', $img_totale);
$valeurs_r = implode(',', $img_totale_cumul);
$valeurs_max_y = max($img_totale);
$valeurs_max_r = max($img_totale_cumul);
$y_val_fin = $valeurs_max_y;
$y_pas = 200;
$r_val_fin = $valeurs_max_r;
$r_pas = 1000;
$etiquettes_x1 = implode('|', $les_mois);
$etiquettes_x2 = implode('|', $annees);
$etiquettes_y = 'Images';
 
// Construire de l'url de l'image
$graph = array('cht' => 'lc',
'chtt' => $titre,
'chs' => '600x200',
'chco' => '007F00,99CC00',
'chd' => 't:'.$valeurs_y.'|'.$valeurs_r,
'chds' => "0,$valeurs_max_y,0,$valeurs_max_r",
'chxt' => 'y,y,x,x,r',
'chxl' => '1:|'.$etiquettes_y.'|3:|'.$etiquettes_x2.'|2:|'.$etiquettes_x1.'',
'chxp' => '1,50|3,0',
'chxr' => "0,0,$y_val_fin,$y_pas|4,0,$r_val_fin,$r_pas",
'chm' => 'N ** ,000000,0,-1,8,1.0,ht',
'chxs' => '0,007F00|4,99CC00');
return $graph;
}
 
private function getEvolImgParMois($param) {
$utilisateur = isset($_GET['utilisateur']) ? Cel::db()->quote($_GET['utilisateur']) : null;
 
// Récupération des données
$requete = "SELECT DATE_FORMAT(date_creation, '%Y%m') AS periode, COUNT(id_image) AS nbre ".
"FROM cel_images_export ".
"WHERE date_creation != '0000-00-00 00:00:00' ".
((isset($utilisateur)) ? " AND courriel_utilisateur = $utilisateur " : '').
'GROUP BY periode '.
'ORDER BY periode ';
 
$resulats = Cel::db()->requeter($requete);
 
$img_totale = array();
foreach ($resulats as $info) {
$img_totale[$info['periode']] = $info['nbre'];
}
 
// Trie des dates pour les étiquettes des axes
$dates = array();
$annees = array();
$les_mois = array();
$pas = 1; // intervalle de mois entre deux étiquettes
$periode = 0;
$cumul = 0;
$img_totale_cumul = array();
foreach ($img_totale as $annee_mois => $nbre) {
$annee = substr($annee_mois, 0, 4);
$mois = substr($annee_mois, 4, 2);
$mois_fmt_B = strftime('%b', strtotime("0000-$mois-01"));
$cumul += $nbre;
$img_totale_cumul[$annee_mois] = $cumul;
 
if (!isset($dates[$annee][$mois])) {
$annees[] = (!isset($dates[$annee]) ? $annee : '');
$les_mois[] = is_int($periode++ / $pas) ? $mois_fmt_B : '';
// Ajouter au tableau dates tjrs à la fin
$dates[$annee][$mois] = 1;
}
}
 
// Post traitement des données
$titre = "Évolution du dépôt d'images par mois";
$valeurs_y = implode(',', $img_totale);
$valeurs_r = implode(',', $img_totale_cumul);
$valeurs_max_y = max($img_totale);
$valeurs_max_r = max($img_totale_cumul);
$y_val_fin = $valeurs_max_y;
$y_pas = 500;
$r_val_fin = $valeurs_max_r;
$r_pas = 1000;
$etiquettes_x1 = implode('|', $les_mois);
$etiquettes_x2 = implode('|', $annees);
$etiquettes_y = 'Images';
 
// Construire de l'url de l'image
$graph = array('cht' => 'lc',
'chtt' => $titre,
'chs' => '600x200',
'chco' => '007F00,99CC00',
'chd' => 't:'.$valeurs_y.'|'.$valeurs_r,
'chds' => "0,$valeurs_max_y,0,$valeurs_max_r",
'chxt' => 'y,y,x,x,r',
'chxl' => '1:|'.$etiquettes_y.'|3:|'.$etiquettes_x2.'|2:|'.$etiquettes_x1.'',
'chxp' => '1,50|3,0',
'chxr' => "0,0,$y_val_fin,$y_pas|4,0,$r_val_fin,$r_pas",
'chm' => 'h,C3C3C3,0,0.5,1,-1|N ** ,000000,0,-1,8,1.0,ht',
'chxs' => '0,007F00|4,99CC00');
return $graph;
}
 
private function getEvolUtilisateurParMois($param) {
// Récupération des données
$requete = 'SELECT DISTINCT courriel_utilisateur , '.
' MIN(date_creation) AS date_min, MAX(date_creation) AS date_max, '.
' COUNT(id_observation) AS obs_nbre '.
'FROM cel_export_total '.
"WHERE date_creation != '0000-00-00 00:00:00' ".
" AND courriel_utilisateur LIKE '%@%' ".
'GROUP BY courriel_utilisateur '.
'ORDER BY date_min ASC ';
$resultats = Cel::db()->requeter($requete);
 
// Trie des données et des dates pour les étiquettes des axes
$dates = array();
$annees = array();
$utilisateurs = array();
$les_mois = array();
$pas = 2; // intervalle de mois entre deux étiquettes
$periode = 0;
foreach ($resultats as $enrg) {
$annee = substr($enrg['date_min'], 0, 4);
$mois = substr($enrg['date_min'], 5, 2);
$mois_fmt_B = strftime('%b', strtotime("0000-$mois-01"));
 
if (!isset($dates[$annee][$mois])) {
$annees[] = (!isset($dates[$annee]) ? $annee : '');
$les_mois[] = is_int($periode++ / $pas) ? $mois_fmt_B : '';
$utilisateurs["$annee-$mois"] = 1;
// Ajouter au tableau dates tjrs à la fin
$dates[$annee][$mois] = 1;
} else {
$utilisateurs["$annee-$mois"]++;
}
}
 
// Post traitement des données
$titre = 'Évolution des utilisateurs par mois';
$valeurs = implode(',', $utilisateurs);
$valeurs_max = max($utilisateurs);
$y_val_fin = $valeurs_max;
$y_pas = 5;
$etiquettes_x1 = implode('|', $les_mois);
$etiquettes_x2 = implode('|', $annees);
$etiquettes_y = 'Utilisateurs';
 
// Construire de l'url de l'image
$graph = array('cht' => 'lc',
'chtt' => $titre,
'chs' => '600x200',
'chco' => '0000FF',//4D89F9
'chd' => 't:'.$valeurs,
'chds' => '0,'.$valeurs_max,
'chxt' => 'y,y,x,x',
'chxl' => '1:|'.$etiquettes_y.'|3:|'.$etiquettes_x2.'|2:|'.$etiquettes_x1.'',
'chxp' => '1,50|3,0',
'chxr' => "0,0,$y_val_fin,$y_pas",
'chm' => 'h,C3C3C3,0,0.5,1,-1|N ** ,000000,0,2::2,8,1.0,ht',
'chxs' => '0,0000FF|1,0000FF');
return $graph;
}
 
private function getEvolObsParMoisGlissant($param) {
// Récupération des données
$format_date = '%Y%m%d';
$where = 'date_creation > DATE_SUB(NOW(), INTERVAL 31 DAY)';
$obs_totale = $this->executerRequeteEvol('cel_export_total', 'id_observation', $format_date, $where);
 
// Tri des dates pour les étiquettes des axes
$dates = array();
$annees = array();
$annees_mois = array();
$jours = array();
foreach ($obs_totale as $annee_mois_jours => $nbre) {
$annee = substr($annee_mois_jours, 0, 4);
$mois = substr($annee_mois_jours, 4, 2);
$jour = substr($annee_mois_jours, 6, 2);
$annee_mois_fmt_B = strftime('%B %Y', mktime(0, 0, 0, $mois, 1, $annee));
 
if (!isset($dates[$annee][$mois][$jour])) {
$annees_mois[] = (!isset($dates[$annee][$mois]) ? $annee_mois_fmt_B : '');
$jours[] = $jour;
// Ajouter au tableau dates tjrs à la fin
$dates[$annee][$mois][$jour] = 1;
}
}
 
// Post traitement des données
$titre = 'Évolution des observations sur un mois glissant';
$valeurs_max = max($obs_totale);
$valeurs = implode(',', $obs_totale);
$y_val_fin = $valeurs_max;
$y_pas = round($valeurs_max / 6);
$etiquettes_x1 = implode('|', $jours);
$etiquettes_x2 = implode('|', $annees_mois);
$etiquettes_y2 = 'Observations';
 
// Construire de l'url de l'image
$graph = array('cht' => 'lc',
'chtt' => $titre,
'chs' => '600x200',
'chco' => '822013',
'chd' => 't:'.$valeurs,
'chds' => '0,'.$valeurs_max,
'chxt' => 'y,y,x,x',
'chxl' => '1:|'.$etiquettes_y2.'|2:|'.$etiquettes_x1.'|3:|'.$etiquettes_x2,
'chxp' => '0,0|1,50',
'chxr' => "0,0,$y_val_fin,$y_pas",
'chm' => 'h,C3C3C3,0,0.5,1,-1|N,000000,0,1::1,8,1.0,ht',
'chxs' => '0,822013|1,822013');
 
return $graph;
}
 
private function getEvolObsParMois($param) {
// Récupération des données
$obs_totale = $this->executerRequeteEvol('cel_export_total', 'id_observation');
 
// Trie des dates pour les étiquettes des axes
$dates = array();
$annees = array();
$les_mois = array();
$pas = 3; // intervalle de mois entre deux étiquettes
$periode = 0;
$cumul = 0;
$obs_totale_cumul = array();
foreach ($obs_totale as $annee_mois => $nbre) {
$annee = substr($annee_mois, 0, 4);
$mois = substr($annee_mois, 4, 2);
$mois_fmt_B = strftime('%b', strtotime("0000-$mois-01"));
$cumul += $nbre;
$obs_totale_cumul[$annee_mois] = $cumul;
 
if (!isset($dates[$annee][$mois])) {
$annees[] = (!isset($dates[$annee]) ? $annee : '');
$les_mois[] = is_int($periode++ / $pas) ? $mois_fmt_B : '';
// Ajouter au tableau dates tjrs à la fin
$dates[$annee][$mois] = 1;
}
}
 
// Post traitement des données
$titre = 'Évolution des observations par mois';
$valeurs_y = implode(',', $obs_totale);
$valeurs_r = implode(',', $obs_totale_cumul);
$valeurs_max_y = max($obs_totale);
$valeurs_max_r = max($obs_totale_cumul);
$y_val_fin = $valeurs_max_y;
$y_pas = round(($valeurs_max_y / 6), 0);
$r_val_fin = $valeurs_max_r;
$r_pas = round(($valeurs_max_r / 6), 0);
$etiquettes_x1 = implode('|', $les_mois);
$etiquettes_x2 = implode('|', $annees);
$etiquettes_y2 = 'Observations';
$etiquettes_r2 = 'Cumul obs.';
 
// Construire de l'url de l'image
$graph = array('cht' => 'lc',
'chtt' => $titre,
'chs' => '600x200',
'chco' => '822013,F1841D',
'chd' => 't:'.$valeurs_y.'|'.$valeurs_r,
'chds' => "0,$valeurs_max_y,0,$valeurs_max_r",
'chxt' => 'y,y,x,x,r,r',
'chxl' => '1:|'.$etiquettes_y2.'|2:|'.$etiquettes_x1.'|3:|'.$etiquettes_x2.'|5:|'.$etiquettes_r2.'',
'chxp' => '1,50|3,0|5,50',
'chxr' => "0,0,$y_val_fin,$y_pas|4,0,$r_val_fin,$r_pas",
'chm' => 'N ** ,000000,0,2::2,8,1.0,ht',
'chxs' => '0,822013|1,822013|4,F1841D|5,F1841D');
return $graph;
}
 
private function getEvolObsParAn($param) {
// Récupération des données
$obs_totale = $this->executerRequeteEvol('cel_export_total', 'id_observation', '%Y');
 
// Trie des dates pour les étiquettes des axes
$dates = array();
$annees = array();
foreach ($obs_totale as $annee => $nbre) {
if (!isset($dates[$annee])) {
$annees[] = $annee;
$dates[$annee] = 1;
}
}
 
// Post traitement des données
$titre = 'Évolution des observations par année';
$valeurs = implode(',', $obs_totale);
$valeurs_max = max($obs_totale);
$valeurs_min = min($obs_totale);
$y_val_deb = preg_replace('/[0-9]{2}$/', '00', $valeurs_min);
$y_val_fin = $valeurs_max;
$y_pas = round(($valeurs_max / 6), 0);
$etiquettes_x = implode('|', $annees);;
$etiquettes_y = 'Observations';
 
// Construire de l'url de l'image
$graph = array('cht' => 'lc',
'chtt' => $titre,
'chs' => '600x200',
'chco' => '822013',
'chd' => 't:'.$valeurs,
'chds' => "$valeurs_min,$valeurs_max",
'chxt' => 'y,y,x',
'chxl' => '1:|'.$etiquettes_y.'|2:|'.$etiquettes_x.'',
'chxp' => '0,0|1,50|2,0',
'chxr' => "0,$y_val_deb,$y_val_fin,$y_pas",
'chm' => 'h,C3C3C3,0,0.5,1,-1|N,000000,0,1::1,8,1.0,ht',
'chxs' => '0,822013|1,822013');
return $graph;
}
 
private function getEvolObsHisto($param) {
// Récupération des données
$obs_totale = $this->executerRequeteEvol('cel_export_total', 'id_observation');
$obs_identifiee = $this->executerRequeteEvol('cel_export_total', 'id_observation', "courriel_utilisateur LIKE '%@%' ");
$lignes = array('total', 'obs. identifiée');
 
// Post traitement des données
$titre = 'Évolution des observations';
$valeurs = implode(',', $obs_totale).'|'.implode(',', $obs_identifiee);
$valeurs_max = max($obs_totale);
$etiquettes = implode('|', array_keys($lignes));
 
// Construire de l'url de l'image
$graph = array('cht' => 'lc',
'chtt' => $titre,
'chs' => '500x300',
'chco' => 'FF0000,00FF00',
'chd' => 't:'.$valeurs,
'chds' => "0,$valeurs_max",
'chxt' => 'y',
'chxl' => '0:|'.$etiquettes.'',
'chm' => 'N,000000,0,-1,10');
return $graph;
}
 
private function getNbreObsIdVsTest($param) {
// Récupération des données
$obs_totale = $this->executerRequeteNombre('cel_export_total', 'id_observation');
$obs_identifiee = $this->executerRequeteNombre('cel_export_total', 'id_observation', "courriel_utilisateur LIKE '%@%' ");
$obs_test = $obs_totale - $obs_identifiee;
$pourcent_identifiee = round(($obs_identifiee / ($obs_totale / 100)), 2).'%';
$pourcent_anonyme = round(($obs_test / ($obs_totale / 100)), 2).'%';
 
// Post traitement des données de la base de données
$titre = "Nombre d'observations|tests vs. identifiées";
$etiquette_obs_test = "tests ($obs_test - $pourcent_anonyme)";
$etiquette_obs_id = "identifiées ($obs_identifiee - $pourcent_identifiee)";
$donnees = array($etiquette_obs_test => $obs_test, $etiquette_obs_id => $obs_identifiee);
$valeurs = implode(',', $donnees);
$etiquettes = implode('|', array_keys($donnees));
 
// Construire les paramêtres de l'url de l'image
$graph = array('cht' => 'p3',
'chtt' => $titre,
'chs' => '250x200',
'chco' => 'FF0000,00FF00',
'chd' => 't:'.$valeurs,
'chds' => "0,$obs_totale",
'chdl' => $etiquettes,
'chdlp' => 'bv|r',
'chts' => '000000,12');
return $graph;
}
 
private function getNbreObsPublicVsPrivee($param) {
// Récupération des données
$obs_totale = $this->executerRequeteNombre('cel_export_total', 'id_observation');
$obs_public = $this->executerRequeteNombre('cel_export_total', 'id_observation', 'transmission = 1');
$obs_privee = $obs_totale - $obs_public;
$pourcent_privee = round(($obs_privee / ($obs_totale / 100)), 2).'%';
$pourcent_public = round(($obs_public / ($obs_totale / 100)), 2).'%';
 
// Post traitement des données de la base de données
$titre = "Nombre d'observations|publiques vs. privées";
$etiquette_obs_public = "publiques ($obs_public - $pourcent_public)";
$etiquette_obs_privee = "privées ($obs_privee - $pourcent_privee)";
$donnees = array($etiquette_obs_privee => $obs_privee, $etiquette_obs_public => $obs_public);
$valeurs = implode(',', $donnees);
$etiquettes = implode('|', array_keys($donnees));
 
// Construire les paramêtres du graph
$graph = array('cht' => 'p3',
'chtt' => $titre,
'chs' => '250x200',
'chco' => 'FF0000,00FF00',
'chd' => 't:'.$valeurs,
'chds' => "0,$obs_totale",
'chdl' => $etiquettes,
'chdlp' => 'bv|r',
'chts' => '000000,12');
return $graph;
}
 
private function getNbreObsDetermineeVsInconnue($param) {
// Récupération des données
$obs_totale = $this->executerRequeteNombre('cel_export_total', 'id_observation');
$obs_determinee = $this->executerRequeteNombre('cel_export_total', 'id_observation', 'nom_sel_nn != 0');
$obs_inconnue = $obs_totale - $obs_determinee;
$pourcent_determinee = round(($obs_determinee / ($obs_totale / 100)), 2).'%';
$pourcent_inconnue = round(($obs_inconnue / ($obs_totale / 100)), 2).'%';
 
// Post traitement des données de la base de données
$titre = "Nombre d'observations|determinées vs. inconnues";
$etiquette_obs_determinee = "determinées ($obs_determinee - $pourcent_determinee)";
$etiquette_obs_inconnue = "non déterminées ($obs_inconnue - $pourcent_inconnue)";
$donnees = array($etiquette_obs_inconnue => $obs_inconnue, $etiquette_obs_determinee => $obs_determinee);
$valeurs = implode(',', $donnees);
$etiquettes = implode('|', array_keys($donnees));
 
// Construire les paramêtres du graph
$graph = array('cht' => 'p3',
'chtt' => $titre,
'chs' => '250x200',
'chco' => 'FF0000,00FF00',
'chd' => 't:'.$valeurs,
'chds' => "0,$obs_totale",
'chdl' => $etiquettes,
'chdlp' => 'bv|r',
'chts' => '000000,12');
return $graph;
}
 
private function getNbreObsAvecIndicationGeo($param) {
// Récupération des données
$total = $this->executerRequeteNombre('cel_export_total', 'id_observation');
$where_commune = $this->creerWhereIndicationGeo('zone_geo');
$obs['commune'] = $this->executerRequeteNombre('cel_export_total', 'id_observation', $where_commune);
$where_commune_id = $this->creerWhereIndicationGeo('ce_zone_geo');
$obs['commune identifiée'] = $this->executerRequeteNombre('cel_export_total', 'id_observation', $where_commune_id);
$where_lieudit = $this->creerWhereIndicationGeo('lieudit');
$obs['lieu-dit'] = $this->executerRequeteNombre('cel_export_total', 'id_observation', $where_lieudit);
$where_station = $this->creerWhereIndicationGeo('station');
$obs['station'] = $this->executerRequeteNombre('cel_export_total', 'id_observation', $where_station);
$where_milieu = $this->creerWhereIndicationGeo('milieu');
$obs['milieu'] = $this->executerRequeteNombre('cel_export_total', 'id_observation', $where_milieu);
$where_xy = $this->creerWhereIndicationGeo('latitude').' AND '.$this->creerWhereIndicationGeo('longitude');
$obs['coordonnée'] = $this->executerRequeteNombre('cel_export_total', 'id_observation', $where_xy);
 
$donnees = array();
$num = 1;
foreach ($obs as $etiquette => $nbre) {
$pourcent = round(($obs[$etiquette] / ($total / 100)), 1).'%';
$legende = "$num : $etiquette ($nbre - $pourcent)";
$donnees['valeurs'][] = $nbre;
$donnees['etiquettes'][] = $num++;
$donnees['legendes'][] = $legende;
}
 
 
// Post traitement des données de la base de données
$titre = "Nombre d'observations|avec indications géographiques";
$valeurs = implode(',', $donnees['valeurs']);
$etiquettes = implode('|', $donnees['etiquettes']);
$legendes = implode('|', $donnees['legendes']);
 
// Construire les paramètres du graphe
$graph = array('cht' => 'rs',
'chtt' => $titre,
'chs' => '600x300',
'chco' => 'FFFFFF',
'chd' => 't:'.$valeurs,
'chds' => "0,$total",
'chdl' => $legendes,
'chxt' => 'x',
'chxl' => "0:|$etiquettes",
//'chxp' => '1,0,20,40,60,80,100',// Grille sous forme de cible
'chm' => 'B,FF000080,0,1.0,5.0');
return $graph;
}
 
private function creerWhereIndicationGeo($champ) {
$where = null;
if (isset($champ)) {
$where = "$champ != '000null' ".
"AND $champ != '' ".
"AND $champ IS NOT NULL ";
}
return $where;
}
 
private function getUtilisationJournaliere($param) {
// Sur quel jour, voulons nous estimer l'utilisation
$aujourdhui = date('Y-m-d');
if (isset($param[0]) && preg_match('/^[0-9]{4}(?:-[0-9]{2}){2}$/', $param[0])) {
$aujourdhui = $param[0];
}
$aujourdhui_fmt = strftime('%d %b %Y', strtotime($aujourdhui));
 
// Récupération des données
$max_obs = array();
$max_obs[] = $this->executerRequeteEvol('cel_export_total', 'id_observation', '%Y%m%d',
"date_creation NOT LIKE '$aujourdhui%' ", 'date_creation');
$max_obs[] = $this->executerRequeteEvol('cel_export_total', 'id_observation', '%Y%m%d',
"date_modification NOT LIKE '$aujourdhui%' ", 'date_modification');
$max_obs[] = $this->executerRequeteEvol('cel_export_total', 'id_observation', '%Y%m%d',
"date_transmission NOT LIKE '$aujourdhui%' ", 'date_transmission');
$obs_aujourdhui = $this->executerRequeteNombre('cel_export_total', 'id_observation',
"(date_creation LIKE '$aujourdhui%'
OR date_modification LIKE '$aujourdhui%'
OR date_transmission LIKE '$aujourdhui%') ");
 
// Cummul des obs crées, modifiées, transmises par jour
$donnees = array();
foreach ($max_obs as $obs_par_jour) {
foreach ($obs_par_jour as $annee_mois_jour => $nbre) {
if (!isset($donnees[$annee_mois_jour])) {
$donnees[$annee_mois_jour] = $nbre;
} else {
$donnees[$annee_mois_jour] += $nbre;
}
}
}
 
// Post traitement des données
$valeur = $obs_aujourdhui;
$valeur_max = 400;
if ($valeur > $valeur_max) {
$pourcentage = 100;
} else {
$pourcentage = round(($valeur / ($valeur_max / 100)), 0);
}
$etiquettes_x = $aujourdhui_fmt;
$etiquettes_y = "faible|moyenne|forte";
$titre = "Intensité d'utilisation pour le $aujourdhui_fmt";
$legende = "$valeur changements";
 
// Construire de l'url de l'image
$graph = array('cht' => 'gom',
'chtt' => $titre,
'chdl' => "$legende",
'chdlp' => 'b',
'chs' => '350x200',
'chco' => 'FFFF00,0A7318',
'chls' => '3|10',
'chma' => '0,0,0,0|300,40',
'chd' => 't:'.$pourcentage,
'chxt' => 'x,y',
'chxl' => '0:|'.$etiquettes_x.'|1:|'.$etiquettes_y.'',
'chxp' => '0,50');
return $graph;
}
 
private function getNbreObsParUtilisateur($param) {
// Récupération des données
$requete = 'SELECT courriel_utilisateur, COUNT(id_observation) AS nbre '.
'FROM cel_export_total '.
'GROUP BY courriel_utilisateur ';
$utilisateurs = Cel::db()->requeter($requete);
 
// Création des classes d'utilisateurs
$classes = array('00->10' => 0, '11->50' => 0, '51->100' => 0, '101->500' => 0, '500->∞' => 0);
$donnees['Utilisateurs'] = $classes;
$valeur_max = 0;
foreach ($utilisateurs as $utilisateur) {
$id = $utilisateur['courriel_utilisateur'];
$nbre = $utilisateur['nbre'];
 
// Détermination de la classe
$classe = '';
if (0 < $nbre && $nbre <= 10) {
$classe = '00->10';
} else if (10 < $nbre && $nbre <= 50) {
$classe = '11->50';
} else if (50 < $nbre && $nbre <= 100) {
$classe = '51->100';
} else if (100 < $nbre && $nbre <= 500) {
$classe = '101->500';
} else if (500 < $nbre) {
$classe = '500->∞';
}
 
// Détermination du type d'utilisateur
if (strstr($id, '@')) {
$type = 'Utilisateurs';
// Incrémentation du tableau de données et récupration de la valeur max
$donnees[$type][$classe]++;
if ($donnees[$type][$classe] > $valeur_max) {
$valeur_max = $donnees[$type][$classe];
}
}
}
 
// Post traitement des données
$titre = "Nombre d'observations par utilisateur";
$y1_val_fin = $valeur_max;
$y1_pas = '100';
$valeurs = implode(',', $donnees['Utilisateurs']);
$etiquettes_x1 = implode('|', array_keys($classes));
$etiquettes_x2 = 'Observations';
$etiquettes_y2 = 'Utilisateurs';
$legendes = implode('|', array_keys($donnees));
 
// Construire de l'url de l'image
$graph = array('cht' => 'bvg',
'chtt' => $titre,
'chs' => '400x200',
'chco' => '00FF00,FF0000',
'chbh' => 'r,0.3,1',
'chd' => 't:'.$valeurs,
'chds' => "0,$valeur_max",
'chxt' => 'x,x,y,y',
'chxl' => '0:|'.$etiquettes_x1.'|1:|'.$etiquettes_x2.'|3:|'.$etiquettes_y2.'',
'chxp' => '1,100|3,100',
'chxr' => "2,0,$y1_val_fin,$y1_pas",
'chm' => 'h,C3C3C3,0,0.5,1,-1|N,000000,0,0::1,8,1.0,e');
//echo '<pre>'.print_r($graph,true).'</pre>';
return $graph;
}
 
private function getNbreObsParUtilisateurEtTest($param) {
// Récupération des données
$requete = 'SELECT courriel_utilisateur, COUNT(id_observation) AS nbre '.
'FROM cel_export_total '.
'GROUP BY courriel_utilisateur ';
$utilisateurs = Cel::db()->requeter($requete);
 
// Création des classes d'utilisateurs
$classes = array('00->10' => 0, '11->50' => 0, '51->100' => 0, '101->500' => 0, '500->∞' => 0);
$donnees['Utilisateurs'] = $classes;
$donnees['Tests'] = $classes;
$valeur_max = 0;
foreach ($utilisateurs as $utilisateur) {
$id = $utilisateur['courriel_utilisateur'];
$nbre = $utilisateur['nbre'];
 
// Détermination de la classe
$classe = '';
if (0 < $nbre && $nbre <= 10) {
$classe = '00->10';
} else if (10 < $nbre && $nbre <= 50) {
$classe = '11->50';
} else if (50 < $nbre && $nbre <= 100) {
$classe = '51->100';
} else if (100 < $nbre && $nbre <= 500) {
$classe = '101->500';
} else if (500 < $nbre) {
$classe = '500->∞';
}
 
// Détermination du type d'utilisateur
if (strstr($id, '@')) {
$type = 'Utilisateurs';
} else {
$type = 'Tests';
}
 
// Incrémentation du tableau de données et récupration de la valeur max
$donnees[$type][$classe]++;
if ($donnees[$type][$classe] > $valeur_max) {
$valeur_max = $donnees[$type][$classe];
}
}
 
// Post traitement des données
$titre = "Nombre d'observations par utilisateur et test";
$y1_val_fin = $valeur_max;
$y1_pas = '100';
$valeurs = implode(',', $donnees['Utilisateurs']).'|'.implode(',', $donnees['Tests']);
$etiquettes_x1 = implode('|', array_keys($classes));
$etiquettes_x2 = 'Observations';
$etiquettes_y2 = 'Utilisateurs';
$legendes = implode('|', array_keys($donnees));
 
// Construire de l'url de l'image
$graph = array('cht' => 'bvg',
'chtt' => $titre,
'chs' => '400x200',
'chco' => '00FF00,FF0000',
'chbh' => 'r,0.3,1',
'chd' => 't:'.$valeurs,
'chds' => "0,$valeur_max",
'chxt' => 'x,x,y,y',
'chxl' => '0:|'.$etiquettes_x1.'|1:|'.$etiquettes_x2.'|3:|'.$etiquettes_y2.'',
'chxp' => '1,100|3,100',
'chxr' => "2,0,$y1_val_fin,$y1_pas",
'chm' => 'h,C3C3C3,0,0.5,1,-1|N,000000,0,0::1,8,1.0,e|N,000000,1,0::1,8,1.0,e',
'chdl' => $legendes,
'chdlp' => 'b');
//echo '<pre>'.print_r($graph,true).'</pre>';
return $graph;
}
 
private function getNuagePointsObsParHeureEtJourSemaine($param) {
$utilisateur = isset($_GET['utilisateur']) ? Cel::db()->quote($_GET['utilisateur']) : false;
 
// Récupération des données de la base
$requete = 'SELECT courriel_utilisateur, DATE_FORMAT(date_creation, "%w-%H") AS periode, (ROUND(LOG10(COUNT(id_observation))) + 1) AS nbre '.
'FROM cel_export_total '.
'WHERE date_creation != "0000-00-00 00:00:00" '.
' AND courriel_utilisateur '.($utilisateur ? "= $utilisateur " : 'LIKE "%@%" ').
'GROUP BY periode, courriel_utilisateur ';
$infos = Cel::db()->requeter($requete);
 
// Traitement résulat requête
$observations = array();
foreach ($infos as $info) {
if (isset($observations[$info['periode']])) {
$observations[$info['periode']] += $info['nbre'];
} else {
$observations[$info['periode']] = $info['nbre'];
}
}
 
// Postraitement des données
// Jour de la semaine
$donnees['joursSemaine'] = array();
for ($njs = 0; $njs < 7; $njs++) {
$donnees['joursSemaine'][] = strftime('%A', strtotime('2010-05-'.(16+$njs)));
}
// Heure
$donnees['heures'] = array();
for ($h = 0; $h < 24; $h++) {
$heure_fmt = sprintf('%02s', $h);// Format numérique 00
$donnees['heures'][] = strftime('%H', strtotime("0000-00-00 $heure_fmt:00:00"));
}
// Nbre
$valeur_max = max($observations);
for ($njs = 0; $njs < 7; $njs++) {
for ($h = 0; $h < 24; $h++) {
$hfmt = sprintf('%02s', $h);// Format numérique 00
$periode = $njs.'-'.$hfmt;
$donnees['valeurs_x'][] = round(($h + 1) * (100 / 24), 0);
$donnees['valeurs_y'][] = round(($njs + 1) * (100 / 7), 0);
$ps = 0;
if (isset($observations[$periode])) {
$ps = round($observations[$periode] * (100 / $valeur_max), 0);
}
$donnees['valeurs_ps'][] = $ps;
}
}
//echo '<pre>'.print_r($donnees,true).'</pre>';
// Préparation des paramêtres du graph
$titre = "Nombre de création d'observation|par heure et jour de la semaine";
$valeurs = implode(',', $donnees['valeurs_x'])."|".implode(',', $donnees['valeurs_y'])."|".implode(',', $donnees['valeurs_ps']);
$etiquettes_x1 = '|'.implode('|', $donnees['heures']);
$etiquettes_x2 = 'Heures';
$etiquettes_y1 = '|'.implode('|', $donnees['joursSemaine']);
$x_axis_step_size = str_replace(',', '.', (100 / 24));
$y_axis_step_size = str_replace(',', '.', (100 / 7));
 
// Construction du tableau des paramêtres du graph
$graph = array('cht' => 's',
'chtt' => $titre,
'chs' => '400x200',
'chco' => '00FF00',
'chd' => 't:'.$valeurs,
'chxt' => 'x,x,y',
'chxr' => "0,-1,23,1|2,-1,6,1",
'chxp' => '1,100',
'chxl' => '0:|'.$etiquettes_x1.'|1:|'.$etiquettes_x2.'|2:|'.$etiquettes_y1.'',
'chg' => "$x_axis_step_size,$y_axis_step_size,1,5");
//echo '<pre>'.print_r($graph,true).'</pre>';
return $graph;
}
 
private function getNuagePointsObsAnciennete($param) {
// Récupération des données de la base
$requete = 'SELECT DISTINCT courriel_utilisateur , '.
' MIN(date_creation) AS date_min, MAX(date_creation) AS date_max, '.
' COUNT(id_observation) AS obs_nbre '.
'FROM cel_export_total '.
"WHERE date_creation != '0000-00-00 00:00:00' ".
" AND courriel_utilisateur LIKE '%@%' ".
'GROUP BY courriel_utilisateur '.
'ORDER BY date_min ASC ';
$resultats = Cel::db()->requeter($requete);
 
// Trie des données
$max_obs = 0;
$max_obs_log = 0;
$max_anciennete = 0;
$donnees = array();
foreach ($resultats as $enrg) {
$tps_deb = strtotime($enrg['date_min']);
$tps_fin = strtotime($enrg['date_max']);
 
$donnee = array();
if (($tps_fin - $tps_deb) == 0) {
$donnee['anciennete'] = 1;
} else {
$donnee['anciennete'] = round((($tps_fin - $tps_deb) / 86400), 0);
}
$donnee['obs'] = $enrg['obs_nbre'];
$donnee['obs_log'] = log10($enrg['obs_nbre']);
$donnees[] = $donnee;
 
$max_obs_log = ($donnee['obs_log'] > $max_obs_log) ? $donnee['obs_log'] : $max_obs_log;
$max_obs = ($donnee['obs'] > $max_obs) ? $donnee['obs'] : $max_obs;
$max_anciennete = ($donnee['anciennete'] > $max_anciennete) ? $donnee['anciennete'] : $max_anciennete;
}
 
// Postraitement des données
foreach ($donnees as $donnee) {
$donnees['valeurs_x'][] = round($donnee['anciennete'] * (100 / $max_anciennete), 0);
$donnees['valeurs_y'][] = round($donnee['obs_log'] * (100 / $max_obs_log), 0);
$donnees['valeurs_ps'][] = 20;
}
 
// Échelle log des obs
$donnees['echelle_y1'] = array();
$pas = $max_obs_log / 100 ;
for ($i = 0 ; $i < 5 ; $i++) {
$donnees['echelle_y1'][] = round(pow(10, (($i*20) * $pas)), 0);
}
$donnees['echelle_y1'][] = $max_obs;
 
//echo '<pre>'.print_r($donnees['valeurs_x'],true).'</pre>';
// Préparation des paramêtres du graph
$titre = "Répartition des utilisateurs en fonction|du nombre d'observations et de l'ancienneté";
$valeurs = implode(',', $donnees['valeurs_x'])."|".implode(',', $donnees['valeurs_y'])."|".implode(',', $donnees['valeurs_ps']);
$etiquettes_x2 = 'Ancienneté en jours';
$etiquettes_y1 = implode('|', $donnees['echelle_y1']);
$etiquettes_y2 = 'Observations';
$x_axis_step_size = $max_anciennete;
 
// Construction du tableau des paramêtres du graph
$graph = array('cht' => 's',
'chtt' => $titre,
'chs' => '400x200',
'chco' => '0000FF',
'chxt' => 'x,x,y,y',
'chd' => 't:'.$valeurs,
'chxr' => "0,0,$x_axis_step_size|2,0,$max_obs",//|2,0,$y_axis_step_size,$pas
'chxp' => '1,100|3,100',
'chm' => 'h,C3C3C3,0,-0.2,0.2,-1',
'chxl' => '1:|'.$etiquettes_x2.'|2:|'.$etiquettes_y1.'|3:|'.$etiquettes_y2.'');//
//echo '<pre>'.print_r($graph,true).'</pre>';
return $graph;
}
 
private function executerRequeteEvol($table, $champ, $format_date = '%Y%m', $where = null, $champ_date = 'date_creation', $order_by = null, $limit = null) {
$utilisateur = isset($_GET['utilisateur']) ? Cel::db()->quote($_GET['utilisateur']) : false;
 
$requete = "SELECT DATE_FORMAT($champ_date, '$format_date') AS periode, COUNT($champ) AS nbre ".
"FROM $table ".
"WHERE $champ_date != '0000-00-00 00:00:00' ".
(($utilisateur != false) ? " AND courriel_utilisateur = $utilisateur " : '').
((is_null($where)) ? '' : " AND $where ").
'GROUP BY periode '.
((is_null($order_by)) ? '' : "ORDER BY $order_by ");
((is_null($limit)) ? '' : "LIMIT $limit ");
 
$evolution = Cel::db()->requeter($requete);
 
// Traitement du tableau
$donnees_traitees = array();
foreach ($evolution as $info) {
$donnees_traitees[$info['periode']] = $info['nbre'];
}
 
return $donnees_traitees;
}
 
private function executerRequeteNombre($table, $champ, $where = null) {
$utilisateur = null;
if (isset($_GET['utilisateur'])) {
$utilisateur = Cel::db()->quote($_GET['utilisateur']);
$where = isset($where) ? $where.' AND ' : '';
$where .= "courriel_utilisateur = $utilisateur ";
}
 
$requete = "SELECT COUNT($champ) AS nbre ".
"FROM $table ".
((isset($where)) ? "WHERE $where " : '');
 
$nbre = Cel::db()->requeterValeurUnique($requete);
return $nbre;
}
}
?>
/branches/v3.01-serpe/jrest/services/CelWidgetUploadImageTemp.php
New file
0,0 → 1,135
<?php
// declare(encoding='UTF-8');
/**
* Service permettant d'enregistrer dans le répertoire temporaire les images envoyées depuis le widget Saisie
*
* Cas d'utilisation :
* POST /CelWidgetUploadImageTemp : écriture d'une image dans le répertoire temporaire
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Widget
* @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 CelWidgetUploadImageTemp extends Cel {
 
public function createElement($donnees) {
$image = $_FILES['fichier']; // chaudrépare
$retour = $this->enregistrerImageTemporaire($image);
$this->formaterRetourAvecSquelette($retour);
}
 
private function formaterRetourAvecSquelette($retour) {
$codeRetour = true;
if (is_array($retour)) {
$squelette = 'services/squelettes/image_temp.tpl.xml';
$contenu = $this->traiterSquelettePhp($squelette, $retour);
$mime = 'text/xml';
} else {
$contenu = 'Un problème est survenu : '.print_r($retour['message'], true);
$codeRetour = false;
}
if ($codeRetour) {
$this->envoyer($contenu, $mime);
exit; // pour éviter que JRest renvoie des headers après le contenu - supporté par agathis (nginx) mais pas apache (sequoia)
} else {
return false;
}
}
 
// enregistre l'image envoyée dans le chemin de stockage temporaire, puis
// renvoie le XML attendu par le widget de saisie du CEL
public function enregistrerImageTemporaire($image) {
$retour = array(
'urlMiniature' => '',
'imageNom' => '',
'message' => '',
'debogage' => '');
$message = '';
$debogage = '';
if ($image['error'] == UPLOAD_ERR_OK) {
if (is_uploaded_file($image['tmp_name'])) {
if ($this->verifierFormatJpeg($image['tmp_name'])) {
$dossierStockage = $this->config['cel']['chemin_stockage_temp'];
 
$nomFichierOriginal = preg_replace('/[.](jpeg|jpg)$/i', '.jpg', strtolower($image['name']));
$originalChemin = $dossierStockage.'/'.$nomFichierOriginal;
$deplacementOk = move_uploaded_file($image['tmp_name'], $originalChemin);
 
if ($deplacementOk === true) {
$miniatureFichier = str_replace('.jpg', '_min.jpg', $nomFichierOriginal);
$miniatureChemin = $dossierStockage.'/'.$miniatureFichier;
 
// Parametres
$largeurIdeale = 100;
$hauteurIdeale = 100;
$qualite = 85;
 
// Calcul de la hauteur et de la largeur optimale de la miniature
$taillesImgOriginale = getimagesize($originalChemin);
$largeurOrigine = $taillesImgOriginale[0];
$hauteurOrigine = $taillesImgOriginale[1];
 
$largeurMin = $largeurIdeale;
$hauteurMin = (int) ($hauteurOrigine * ($largeurIdeale / $largeurOrigine));
if ($hauteurMin > $hauteurIdeale) {
$hauteurMin = $hauteurIdeale;
$largeurMin = (int)($largeurOrigine * ($hauteurMin / $hauteurOrigine));
}
 
// Création de la miniature
$imageOriginale = imagecreatefromjpeg($originalChemin);
$imageMiniature = imagecreatetruecolor($largeurMin, $hauteurMin);
$couleurFond = imagecolorallocate($imageMiniature, 255, 255, 255);
imagefill($imageMiniature, 0, 0, $couleurFond);
imagecopyresized($imageMiniature, $imageOriginale, 0, 0, 0, 0, $largeurMin, $hauteurMin, $largeurOrigine, $hauteurOrigine);
imagejpeg($imageMiniature, $miniatureChemin, $qualite);
imagedestroy($imageMiniature);
imagedestroy($imageOriginale);
 
// Retour des infos
$retour['urlMiniature'] = sprintf($this->config['cel']['images_temp_url'], $miniatureFichier);
$retour['imageNom'] = $nomFichierOriginal;
} else {
$message = "L'image n'a pu être déplacé sur le serveur.";
}
} else {
$message = "L'image n'est pas au format JPEG.";
}
} else {
$message = "L'image n'a pu être téléversée.";
$debogage = $message.print_r($image, true);
}
} else {
if ($image['error'] == UPLOAD_ERR_FORM_SIZE) {
$message = "L'image téléversée excède la taille maximum autorisée.".
"Veuillez modifier votre image avant de la téléverser à nouveau.";
} else {
$message = "Une erreur de transfert a eu lieu (téléversement interrompu).";
}
$debogage = "Code erreur : {$image['error']}. ".
"Voir : http://php.net/manual/fr/features.file-upload.errors.php";
}
// Retour des infos
$retour['message'] = $message;
$retour['debogage'] = $debogage;
return $retour;
}
 
// Il ne faut pas utiliser l'index type du tableau files pour tester
// si une image est en jpeg car le type renvoyé par les navigateurs
// peut varier (ex. sous ie qui renvoie image/pjpeg
private function verifierFormatJpeg($chemin) {
// get imagesize renvoie un résultat consistant par contre
$infos = getimagesize($chemin, $infos);
return (isset($infos['mime']) && $infos['mime'] == 'image/jpeg');
}
}
?>
/branches/v3.01-serpe/jrest/services/CelWidgetSaisie.php
New file
0,0 → 1,867
<?php
// declare(encoding='UTF-8');
/**
* Service permettant d'insérer les informations fournie par le widget Saisie dans le CEL.
*
* Cas d'utilisation :
* PUT /CelWidgetSaisie : ajout de données en les passant via $_POST
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Widget
* @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 CelWidgetSaisie extends Cel {
 
private $projet = null;
private $projetId = null;
private $projetTags = array();
private $tagsObs = null;
private $tagsImg = null;
private $userId = null;
private $userEmail = null;
private $userIntitule = null;
private $isPlantnetPull = false;
private $isSauvages = false;
const DUREE_DE_VIE_IMG = 86400;// 3600 * 24 = 86 400 (1 journée)
const ARRET_SERVICE = false;// Permet de bloquer le service en cas de problème sur le serveur
 
private $correspondanceIdImgTags = array();
private $gestionMotsClesObs = null;
private $gestionMotsClesImages = null;
 
public function createElement($requeteDonnees) {
if (self::ARRET_SERVICE) {
$this->messages[] = "Désactivation temporaire du service d'envoi des données au CEL.";
} else if (array_key_exists('projet', $requeteDonnees)) {
$this->debug[] = 'Projet : '.$requeteDonnees['projet'];
if ($requeteDonnees['projet'] != "base") {
$this->projet = $requeteDonnees['projet'] ?? null;
$this->projetId = $requeteDonnees['id_projet'] ?? null;
}
 
// Si c'est une obs Pl@ntNet
if (! empty($requeteDonnees['tag-obs']) && strpos(strtolower($requeteDonnees['tag-obs']), 'plantnet') !== false) {
if (isset($requeteDonnees['origin']) && 'pullPlantnet' === $requeteDonnees['origin']) {
// on traite les obs PN qui viennent du script de pull
$this->isPlantnetPull = true;
} else {
// fake ID pour les obs PN provenant de PlantNet V1
$retour = (object) [
'msg' => 'observation Pl@ntNet non sauvegardée',
'id' => 'fake-' . uniqid(),
'images' => []
];
$this->envoyerJson($retour);
exit; // envoyerJson() ne termine pas le script !
}
}
// Si c'est une obs Sauvages de ma rue
if (! empty($requeteDonnees['tag-obs']) && strpos(strtolower($requeteDonnees['tag-obs']), 'mobileSauvages') !== false) {
$this->isSauvages = true;
}
 
// Traitements des tags multiples de projet
$this->traiterProjetTags();
 
// Traitement des tags spécifiques aux obs
$this->traiterTagObs($requeteDonnees);
 
// Traitement des tags spécifiques aux images
$this->traiterTagImg($requeteDonnees);
 
// Traitement des observations et des images
if (isset($requeteDonnees['utilisateur']['courriel']) && filter_var($requeteDonnees['utilisateur']['courriel'], FILTER_VALIDATE_EMAIL)) {
$this->debug[] = 'Utilisateur : '.print_r($requeteDonnees['utilisateur'], true);
$utilisateur = $requeteDonnees['utilisateur'];
 
// hop on récupère les infos de l'utilisateur
$infosUtilisateur = $this->infosInscritTela($utilisateur['courriel']);
if ($infosUtilisateur) {
$this->userId = $infosUtilisateur['id'];
$this->userIntitule = $infosUtilisateur['intitule'];
} else {
$this->userId = 0;
$this->userIntitule = $utilisateur['prenom'] . ' ' . $utilisateur['nom'];
}
$this->userEmail = $utilisateur['courriel'];
 
$this->debug[] = 'Courriel : ' . $this->userEmail;
$requeteDonnees = $this->supprimerSlashesProfond($requeteDonnees);
// Triage et manipulation des données
$observations = array();
foreach ($requeteDonnees as $cle => $obs) {
if (preg_match('/^obsId[0-9]+$/', $cle)) {
$this->debug[] = 'commune_nom : '.$obs['commune_nom'];
$this->debug[] = 'commune_code_insee : '. (isset($obs['commune_code_insee']) ? $obs['commune_code_insee'] : 'n/a');
 
$obsAAjouter = array();
$obsAAjouter['user_id'] = $this->userId;
$obsAAjouter['user_email'] = $this->userEmail;
$obsAAjouter['user_pseudo'] = $this->userIntitule;
 
$obsAAjouter['user_sci_name'] = isset($obs['nom_sel']) ? $obs['nom_sel'] : null;
$obsAAjouter['user_sci_name_id'] = isset($obs['num_nom_sel']) && '' !== $obs['num_nom_sel'] ? $obs['num_nom_sel'] : null;
$obsAAjouter['accepted_sci_name'] = isset($obs['nom_ret']) ? $obs['nom_ret'] : null;
$obsAAjouter['accepted_sci_name_id'] = isset($obs['num_nom_ret']) && '' !== $obs['num_nom_ret'] ? $obs['num_nom_ret'] : null;
$obsAAjouter['family'] = isset($obs['famille']) ? $obs['famille'] : null;
$obsAAjouter['taxo_repo'] = isset($obs['referentiel']) ? ($obs['referentiel'] == 'bdtfxr') ? 'bdtfx' : $obs['referentiel'] : null;
 
$obsAAjouter['date_observed'] = $this->transormerDateFrVersMysql($obs['date']);
$obsAAjouter['annotation'] = isset($obs['notes']) && trim($obs['notes']) !== "" ? $obs['notes'] : null;
 
// Pays est pour le moment sur un varchar(2) dans la base
// alors qu'il est envoyé complet par le script WidgetSaisie
$obsAAjouter['osm_country'] = (isset($obs['pays'])) ? $obs['pays'] : null;
$obsAAjouter['osm_postcode'] = (isset($obs['code_postal'])) ? $obs['code_postal'] : null;
$obsAAjouter['locality'] = isset($obs['commune_nom']) && trim($obs['commune_nom']) !== "" ? $obs['commune_nom'] : null;
$obsAAjouter['locality_insee_code'] = isset($obs['commune_code_insee']) && trim($obs['commune_code_insee']) !== "" ? $obs['commune_code_insee'] : null;
$obsAAjouter['sublocality'] = isset($obs['lieudit']) && trim($obs['lieudit']) !== "" ? $obs['lieudit'] : null;
$obsAAjouter['station'] = isset($obs['station']) && trim($obs['station']) !== "" ? $obs['station'] : null;
$obsAAjouter['environment'] = isset($obs['milieu']) && trim($obs['milieu']) !== "" ? $obs['milieu'] : null;
$obsAAjouter['elevation'] = (! empty($obs['altitude'])) ? $obs['altitude'] : null;
$obsAAjouter['geometry'] = $obs['geometry'] ?? json_encode([
'type' => 'Point',
'coordinates' => [
round((float)str_replace(',', '.', $obs['longitude']), 6),
round((float)str_replace(',', '.', $obs['latitude']), 6)
]
]); // CONCAT('{\"type\":\"Point\",\"coordinates\":[', longitude, ',', latitude,']}'),
$obsAAjouter['geodatum'] = 'WGS84';
$obsAAjouter['published_location'] = ($this->tagsObs != null && in_array('sensible', $this->tagsObs) == true) ?
"localité" : "précise";
 
$obsAAjouter['phenology'] = isset($obs['phenologie']) ? $obs['phenologie'] : null;
$obsAAjouter['coef'] = isset($obs['abondance']) ? $obs['abondance'] : null;
 
$obsAAjouter['is_public'] = '1';
$obsAAjouter['date_created'] = date('Y-m-d H:i:s');
$obsAAjouter['date_updated'] = $obsAAjouter['date_created'];
$obsAAjouter['date_published'] = $obsAAjouter['date_created'];
 
$obsAAjouter['image_nom'] = $obs['image_nom'] ?? null;
$obsAAjouter['image_b64'] = $obs['image_b64'] ?? null;
 
$obsAAjouter['certainty'] = null;
if (isset($obs['certitude'])) {
switch ($obs['certitude']) {
case 'certaine':
$obsAAjouter['certainty'] = 'certain';
break;
case 'douteuse':
$obsAAjouter['certainty'] = 'douteux';
break;
default:
$obsAAjouter['certainty'] = $obs['certitude'];
break;
}
}
$obsAAjouter['certainty'] = ($this->projet == "aDeterminer") ? 'à déterminer' : $obsAAjouter['certainty'];
$obsAAjouter['input_source'] = 'widget';
$obsAAjouter['project_id'] = $this->projetId;
// racommodage en attendant mieux
$obsAAjouter['project'] = ($this->projetId == null || $this->projetId == 3) ? null : ($this->projetId == 53) ? "missions-flore" : $this->projet ;
if ($this->isPlantnetPull) {
$obsAAjouter['input_source'] = 'PlantNet';
$obsAAjouter['plantnet_id'] = $obs['obs_id'];
}
if ($this->isSauvages) {
$obsAAjouter['input_source'] = 'autre';
$obsAAjouter['project'] = 'sauvages';
}
 
$obsAAjouter['obs_etendue'] = isset($obs['obs_etendue']) ? $obs['obs_etendue'] : array();
 
// Tentative d'enrichissement des données taxonomiques
// @TODO attention aux perfs, aux timeouts de WS etc.
$this->enrichirDonneesTaxonomiques($obsAAjouter);
 
$observations[] = $obsAAjouter;
}
}
$this->debug[] = 'Nbre obs ajoutée : '.count($observations);
$this->debug[] = 'projet : '.$this->projet;
$this->debug[] = 'tagsObs : '.print_r($this->tagsObs, true);
$this->debug[] = 'tagsImg : '.print_r($this->tagsImg, true);
 
// début transaction car si insertions par le même utilisateur en parallèle,
// De plus, ça permet de ne pas conserver les données d'obs si l'image provoque une erreur
//Cel::db()->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
Cel::db()->beginTransaction();
$erreursDurantTraitement = false;
$nomsOriginauxImagesTemp = array();
 
// Insertion dans la base
$obs_a_taguer_ids = array();
$img_a_taguer_ids_noms = array();
$champsEtendusObs = array();
foreach ($observations as $obs) {
$fullObs = $obs;
unset($obs['obs_etendue']);
unset($obs['image_nom']);
unset($obs['image_b64']);
 
$obs = $this->protegerTableau($obs);
 
$champs = implode(', ', array_keys($obs));
$valeurs = implode(', ', $obs);
$requete = "INSERT INTO occurrence ($champs) VALUES ($valeurs) ";
 
if (Cel::db()->executer($requete) === false) {
$erreursDurantTraitement = true;
$this->messages[] = "Un problème est survenu lors de l'insertion de l'obs dans la base de données.";
}
 
// récupérer l'id de l'obs nouvellement insérée
$idNouvelleObs = Cel::db()->obtenirDernierId();
$obs_a_taguer_ids[] = $idNouvelleObs;
$champsEtendusObs[$idNouvelleObs] = $fullObs['obs_etendue'];
 
$imgAAjouter = null;
if (isset($fullObs['image_nom'])) {
$imgAAjouter = $this->traiterImagesALierAObs($idNouvelleObs, $fullObs);
foreach ($imgAAjouter as $uneImgAAjouter) {
$nomsOriginauxImagesTemp[] = $uneImgAAjouter['nom'];
}
}
 
// si le formulaire contient une image on la traite
if (!empty($imgAAjouter)) {
$this->nettoyerImagesUploades();
$img_a_taguer_ids_noms = $this->stockerImagesEtLierAObs($idNouvelleObs, $imgAAjouter);
if (empty($img_a_taguer_ids_noms)) {
$erreursDurantTraitement = true;
$this->messages[] = "Au moins une des images n'a pas pu être enregistrée.";
} else {
$cmd = sprintf($this->config['cel']['commande_script_images'],implode(',', array_keys($img_a_taguer_ids_noms)));
pclose(popen($cmd,"r"));
}
}
}
 
$this->gestionMotsClesObs = new GestionMotsClesChemin($this->config,'obs');
$this->gestionMotsClesImages = new GestionMotsClesChemin($this->config,'images');
 
$this->taguerObs($obs_a_taguer_ids);
if (!empty($img_a_taguer_ids_noms)) {
$this->taguerImg(array_keys($img_a_taguer_ids_noms));
}
 
// Les champs taggés sont des champs supplémentaires stockés sous forme de clé => valeur
$this->ajouterChampsEtendusObs($obs_a_taguer_ids, $champsEtendusObs);
// Fin de la transaction - on considère que commit() et rollback() ne ratent jamais
if ($erreursDurantTraitement === false) {
// Suppression des fichiers images temporaires
$this->nettoyerImagesUploades($nomsOriginauxImagesTemp);
Cel::db()->commit();
} else {
// On annule l'écriture des images enregistrées sur le disque dur - la transaction
// se charge de les retirer de la base de données
if ($img_a_taguer_ids_noms !== false) {
foreach (array_keys($img_a_taguer_ids_noms) as $idImageASupprimer) {
$this->effacerImageDuDd($idImageASupprimer);
}
}
Cel::db()->rollBack();
}
} else {
$this->messages[] = '[' . $requeteDonnees['utilisateur']['courriel'] . "] n'est pas une adresse email valide.";
}
} else {
$this->messages[] = "Les informations concernant le projet coopératif n'ont pas été transmises.";
}
if (count($this->messages) > 0) {
$this->debug[] = print_r($this->messages, true);
}
if (count($this->messages) > 0) {
$msg = 'erreur';
$idNouvelleObs = null;
} else {
$msg = 'ok';
}
// renvoi des infos d'images (id, nom) ordonnées, en plus des infos obs.
$infosImages = array();
if (! empty($img_a_taguer_ids_noms)) {
foreach ($img_a_taguer_ids_noms as $id => $nom) {
$infosImages[] = array(
'id' => $id,
'nom' => $nom
);
}
}
$retour = (object) array(
'msg' => $msg,
'id' => $idNouvelleObs,
'images' => $infosImages
);
$this->envoyerJson($retour);
exit;
}
 
/**
* Retourne les infos du compte correspondant à $courriel
* si présent dans l'annuaire Tela,
* false sinon
*/
protected function infosInscritTela($courriel) {
if (empty($courriel)) {
return false;
}
// interrogation de l'annuaire
$url = sprintf($this->config['settings']['baseURLServicesAnnuaireTpl'], 'utilisateur/identite-par-courriel/' . $courriel);
$retour = file_get_contents($url);
if (! $retour) {
return false;
}
try {
$retour = json_decode($retour, true);
} catch (Exception $e) {
return false;
}
if (isset($retour['error'])) {
return false;
}
// le service annuaire a retourné qqch de valide
return array_shift($retour);
}
 
/**
* Retourne true si les champs suivants sont présents dans le tableau :
* - obsId1[user_sci_name]
* - obsId1[latitude]' : obs.geoloc.lat || '',
'obsId1[longitude]' : obs.geoloc.lon || '',
* mot-clé "pn:referentiel"
*/
protected function estUneDonneeQualifiee($donnees) {
// vérifier date et géoloc
// lancer enrichirDonneesTaxonomiques et vérifier si ça a retrouvé un nn
}
 
/**
* Si les données taxonomiques sont incomplètes dans $obs
* (clefs 'nom_sel_nn', 'user_sci_name', 'taxo_repo', 'accepted_sci_name_id',
* 'accepted_sci_name', 'family'), tente d'en récupérer un maximum à l'aide des
* services eFlore, à condition que soient mentionnés au moins :
* - un nom de référentiel
* - un nom_sel_nn OU un user_sci_name
*/
protected function enrichirDonneesTaxonomiques(&$obs) {
// sans référentiel, on ne peut rien faire
if (! empty($obs['taxo_repo'])) {
// copies locales pour ne pas abimer les données d'entrée
$nn = $obs['user_sci_name_id'];
$ref = $obs['taxo_repo'];
$ns = $obs['user_sci_name'];
$nr = $obs['accepted_sci_name'];
$nnr = $obs['accepted_sci_name_id'];
$fam = $obs['family'];
 
// si j'ai un nn, tentative de retrouver le nnr, le user_sci_name,
// le accepted_sci_name et la famille, s'ils ne sont pas déjà présents (on
// pourrait les écraser systématiquement mais l'appel au service
// dégrade les perfs)
if ((! empty($nn) && is_numeric($nn))
// omission du test sur 'accepted_sci_name' car le service eFlore noms ne le retourne que sans auteur (pas bon)
&& (empty($ns) || empty($nnr) || empty($fam) /*|| empty($nr)*/)) {
// go
$this->enrichirDonneesTaxonomiquesParNN($ref, $nn, $obs);
} else {
// si j'ai un nom complet, avec un peu de bol il sera dans le référentiel
if ((! empty($ns))
&& (empty($nn) || empty($nnr) || empty($fam) /*|| empty($nr)*/)) {
// go
$this->enrichirDonneesTaxonomiquesParNS($ref, $ns, $obs);
}
} // sinon fuque
 
}
}
 
/**
* Enrichit le tableau $obs destiné à être inséré dans le BDD, en
* interrogeant le service eFlore/noms par référentiel + nom scientifique
* avec auteur
*/
protected function enrichirDonneesTaxonomiquesParNS($ref, $ns, &$obs) {
$url_nom = $this->config['eflore']['url_service_nom'];
$url_nom = str_replace('{referentiel}', $ref, $url_nom);
$url_nom .= '?recherche=etendue&ns.structure=au&masque=' . urlencode($ns);
// un horrible @ car les erreurs de file_get_contents() ne sont pas try/catchables
// @TODO mettre du cURL à l'occase
$infos_nom = @file_get_contents($url_nom);
if ($infos_nom != NULL) {
try {
$infos_nom = json_decode($infos_nom, true);
if (count($infos_nom['resultat']) > 0) {
$nn_trouve = null;
$ret_trouve = false;
// on prend le nom avec auteur correspondant exactement;
// s'il y en a plusieurs on prend le premier qui est retenu
foreach($infos_nom['resultat'] as $n => $nom) {
if (! $ret_trouve) {
if ($nom['nom_sci_complet'] == $ns) {
if ($nn_trouve == null || $nom['retenu'] == 'true') {
$nn_trouve = $n;
$ret_trouve = ($nom['retenu'] == 'true');
}
}
}
}
if ($nn_trouve != null) {
// gagné !
$obs['user_sci_name_id'] = $nn_trouve;
// et maintenant on recolle ce qu'on peut à partir du nn
$this->enrichirDonneesTaxonomiquesParNN($ref, $nn_trouve, $obs);
}
}
} catch(Exception $e) {
// échec silencieux
}
}
}
 
/**
* Enrichit le tableau $obs destiné à être inséré dans le BDD, en
* interrogeant le service eFlore/noms par référentiel + nn
*/
protected function enrichirDonneesTaxonomiquesParNN($ref, $nn, &$obs) {
$url_nom = $this->config['eflore']['url_service_nom'];
$url_nom = str_replace('{referentiel}', $ref, $url_nom);
$url_nom .= '/' . $nn . '?ns.structure=au,an';
// un horrible @ car les erreurs de file_get_contents() ne sont pas try/catchables
// @TODO mettre du cURL à l'occase
$infos_nom = @file_get_contents($url_nom);
if ($infos_nom != NULL) {
try {
$infos_nom = json_decode($infos_nom, true);
// une fois qu'on a les infos, on écrase tout
if ($infos_nom['nom_sci_complet'] != null) {
$obs['user_sci_name'] = $infos_nom['nom_sci_complet'];
}
if ($infos_nom['nom_retenu_complet'] != null) {
$obs['accepted_sci_name'] = $infos_nom['nom_retenu_complet'];
}
if ($infos_nom['nom_retenu.id'] != null) {
$obs['accepted_sci_name_id'] = $infos_nom['nom_retenu.id'];
}
if ($infos_nom['famille'] != null) {
$obs['family'] = $infos_nom['famille'];
}
} catch(Exception $e) {
// échec silencieux
}
}
}
 
private function traiterProjetTags() {
if (strpos($this->projet, ',') === false) {
$this->projetTags = array('Projets coopératifs>'.$this->projet);
} else {
$projetTagsTxt = explode(',', $this->projet);
foreach ($projetTagsTxt as $tag) {
$this->projetTags[] = 'Projets coopératifs>'.$tag;
}
}
}
 
private function traiterTagObs($requeteDonnees) {
if (array_key_exists('tag-obs', $requeteDonnees) && $requeteDonnees['tag-obs'] != '') {
$this->tagsObs = explode(',', $requeteDonnees['tag-obs']);
}
foreach ($this->projetTags as $tag) {
$this->tagsObs[] = $tag;
}
}
 
private function traiterTagImg($requeteDonnees) {
if (array_key_exists('tag-img', $requeteDonnees) && $requeteDonnees['tag-img'] != '') {
$this->tagsImg = explode(',', $requeteDonnees['tag-img']);
}
foreach ($this->projetTags as $tag) {
$this->tagsImg[] = $tag;
}
}
 
private function ajouterChampsEtendusObs($obs_ids, $obs_a_champs_etendus) {
$champs_etendus_obs = array();
$gestionChampsEtendus = new GestionChampsEtendus($this->config, 'obs');
 
foreach ($obs_ids as $id_obs) {
$champs = array_shift($obs_a_champs_etendus);
if ($champs != null && is_array($champs)) {
foreach ($champs as $infosChamp) {
$cle = isset($infosChamp['cle']) ? $infosChamp['cle'] : '';
$valeur = isset($infosChamp['valeur']) ? $infosChamp['valeur'] : '';
 
if (!empty($cle) && $valeur !== '') {
$champEtendu = new ObsEtendue();
$champEtendu->id = $id_obs;
$champEtendu->cle = $cle;
$champEtendu->valeur = $valeur;
 
$champs_etendus_obs[] = $champEtendu;
}
}
}
}
 
if(! $champs_etendus_obs) return TRUE;
 
return $gestionChampsEtendus->ajouterParLots($champs_etendus_obs, $this->projet);
}
 
private function traiterImagesALierAObs($idObs, $obs) {
$imgAAjouter = array();
if (is_array($obs['image_nom'])) {
foreach ($obs['image_nom'] as $index => $nom_image) {
$image = array();
$image['id_utilisateur'] = $this->userId;
$image['id_obs'] = $idObs;
$image['nom'] = $nom_image;
// on suppose que les b64 des images sont envoyés dans le même ordre que leurs noms
// TODO: indexer le tableau avec le nom des images
$image['b64'] = (is_array($obs['image_b64']) && isset($obs['image_b64'][$index])) ? $obs['image_b64'][$index] : null;
$this->debug[] = 'Contient B64 : '.(isset($obs['image_b64']) ? 'oui' : 'non');
$imgAAjouter[] = $image;
}
} else {
$image = array();
$image['id_utilisateur'] = $this->userId;
$image['id_obs'] = $idObs;
$image['nom'] = $obs['image_nom'];
$image['b64'] = $obs['image_b64'] ?? null;
$this->debug[] = 'Contient B64 : '.(isset($obs['image_b64']) ? 'oui' : 'non');
$imgAAjouter[] = $image;
}
 
return $imgAAjouter;
}
 
protected function stockerImagesEtLierAObs($id_obs, $img) {
$img_a_taguer_ids_noms = array();
foreach ($img as $image) {
$image['nom'] = trim(rtrim($image['nom'], "'"), "'");
$nomFichierImg = $this->traiterNomFichierImage($image['nom']);
$cheminImage = $this->config['cel']['chemin_stockage_temp']."/$nomFichierImg";
// Si l'image est transmise en base 64
if (isset($image['b64'])) {
$this->transformerBase64enFichier($cheminImage, $image['b64']);
}
 
$this->debug[] = 'Nom fichier img debut :'.$nomFichierImg;
$idImg = $this->ajouterImageSurDdEtBdd($id_obs, $cheminImage, $nomFichierImg);
if ($idImg !== false) {
$img_a_taguer_ids_noms[$idImg] = $nomFichierImg;
if (isset($image['tags'])) {
$this->correspondanceIdImgTags[$idImg] = $image['tags'];
}
} else {
// L'image n'a pas pu être écrite.
// On annule l'écriture des précédentes et on s'arrête là - la transaction
// se chargera de les retirer de la base de données
foreach (array_keys($img_a_taguer_ids_noms) as $idImageASupprimer) {
$this->effacerImageDuDd($idImageASupprimer);
}
$img_a_taguer_ids_noms = array();
break;
}
}
return $img_a_taguer_ids_noms;
}
 
private function supprimerSlashesProfond($valeur) {
$valeur = is_array($valeur) ? array_map(array($this, 'supprimerSlashesProfond'), $valeur) : stripslashes($valeur);
return $valeur;
}
 
/**
* Transforme une date au format français (jj/mm/aaaa) dans un format Mysql (aaaa-mm-jj).
* @param string $dateFr date au format français (jj/mm/aaaa)
* @return string date au format Mysql (aaaa-mm-jj)
*/
private function transormerDateFrVersMysql($dateFr) {
$dateMysql = '0000-00-00';
$morceauxDate = explode('/', $dateFr);
if (count($morceauxDate) == 3) {
$dateMysql = implode('-', array_reverse($morceauxDate));
}
return $dateMysql;
}
 
private function taguerObs($obs_a_taguer_ids) {
if (count($obs_a_taguer_ids) > 0) {
foreach ($this->tagsObs as $hierarchieTag) {
$tagsALier = explode('>', $hierarchieTag);
$liaisonOk = $this->lierObsAMotsCles($obs_a_taguer_ids, $tagsALier);
if ($liaisonOk === false) {
$e = "Toutes les observations n'ont pas pu être liées aux mots-clés : $hierarchieTag";
$this->messages[] = $e;
}
}
}
}
 
private function lierObsAMotsCles($observations_ids, $tags) {
// pas de mots clés pour les non-inscrits
if ($this->userId == null) {
$this->userId = 0;
}
 
$chemin_parent = '/';
$listeIdsTags = array();
foreach ($tags as $tag) {
$tag = $this->nettoyerTag($tag);
if ($tag != '') {
$id_mot_cle = $this->gestionMotsClesObs->insererParCheminSiInexistant($tag, $chemin_parent, $this->userId);
if ($id_mot_cle !== false) {
$listeIdsTags[] = $id_mot_cle;
$chemin_parent .= $tag."/";
}
}
}
 
$liaison_ok = $this->gestionMotsClesObs->lierParTableaux($listeIdsTags, $observations_ids);
return $liaison_ok;
}
 
private function taguerImg($img_a_taguer_ids) {
if (count($img_a_taguer_ids) > 0) {
$this->debug[] = "Tags img : ".print_r($this->tagsImg, true);
foreach ($this->tagsImg as $hierarchieTag) {
$tagsALier = explode('>', $hierarchieTag);
$liaisonOk = $this->lierImgAMotsCles($img_a_taguer_ids, $tagsALier);
if ($liaisonOk === false) {
$e = "Toutes les images n'ont pas pu être liées aux mots-clés : $hierarchieTag";
$this->messages[] = $e;
}
}
}
// Liaison des tags spécifiques à chaque image s'il y en a
if (count($this->correspondanceIdImgTags) > 0) {
foreach ($this->correspondanceIdImgTags as $id_img => $tags) {
if ($tags != null && !empty($tags)) {
$this->lierImgAMotsCles(array($id_img), $tags);
}
}
}
}
 
private function lierImgAMotsCles($images_ids, $tags) {
// pas de mots clés pour les non-inscrits
if ($this->userId == null) {
$this->userId = 0;
}
 
$chemin_parent = "/";
$listeIdsTags = array();
foreach ($tags as $tag) {
$tag = $this->nettoyerTag($tag);
if ($tag != '') {
$id_mot_cle = $this->gestionMotsClesImages->insererParCheminSiInexistant($tag, $chemin_parent, $this->userId);
if ($id_mot_cle !== false) {
$listeIdsTags[] = $id_mot_cle;
$chemin_parent .= $tag."/";
}
}
}
$liaison_ok = $this->gestionMotsClesImages->lierParTableaux($listeIdsTags, $images_ids);
return $liaison_ok;
}
 
private function nettoyerTag($tag) {
$tag = trim($tag);
$tag = preg_replace('/(?:\s+|[,]+)/', ' ', $tag);
return $tag;
}
 
private function traiterNomFichierImage($fichierNom) {
$fichierNom = preg_replace('/[.](jpeg|jpg)$/i', '.jpg', strtolower(trim($fichierNom)));
return $fichierNom;
}
 
/**
* Décode l'image en base64,enregistre celle-ci sous forme de fichier du type de l'image
* dans un dossier temporaire.
*/
private function transformerBase64enFichier($cheminImage, $imageInfosB64) {
// Enleve la partie data:image qui permet la previsalisation pour firefox de l'image en base64
$imageBase64 = explode(';', $imageInfosB64);
$dataBase64 = explode(',',$imageBase64[1]);
$dataImg = base64_decode($dataBase64[1]);
 
$imageRessource = fopen($cheminImage, 'wb');
fwrite($imageRessource, $dataImg);
fclose($imageRessource);
 
if (file_exists($cheminImage) == false) {
$this->messages[] = "Erreur lors de la création du fichier";
}
}
 
/**
* Supprime toutes les images temporaires dont :
* - l'ancienneté est supérieure à DUREE_DE_VIE_IMG (si $nomsDeFichiers est vide, par défaut)
* - le nom correspond à un des éléments du tableau $nomsDeFichiers (s'il est spécifié et non vide)
*/
protected function nettoyerImagesUploades($nomsDeFichiers = array()) {
$dossierStockage = $this->config['cel']['chemin_stockage_temp'].'/';
if (is_dir($dossierStockage)) {
$objets = scandir($dossierStockage);
if (is_array($objets)) {
foreach ($objets as $objet) {
$chemin = $dossierStockage . $objet;
if (is_file($chemin)) {
// critère de suppression
if (count($nomsDeFichiers) > 0) {
$suppression = in_array($objet, $nomsDeFichiers);
} else {
$filemtime = @filemtime($chemin);
if ($filemtime !== false) {
$suppression = (time() - $filemtime >= self::DUREE_DE_VIE_IMG) ? true : false;
}
}
// suppression
if ($suppression === true) {
unlink($chemin);
}
}
}
}
}
}
 
/**
* Ajoute une image dans la base de données et stocke le fichier en fabriquant les miniatures,
* renvoie le nouvel id d'image en cas de succès
*
* @param string $id_obs l'id de l'obs
* @param string $cheminImage le chemin vers le fichier original de l'image
* @param string $nomFichierImage le nom du fichier original de l'image
*/
public function ajouterImageSurDdEtBdd($id_obs, $cheminImage, $nomFichierImage) {
$idImage = false;
if (file_exists($cheminImage)) {
$extracteurMetadonnees = new ExtracteurMetadonnees();
$metadonnees = $extracteurMetadonnees->extraireMetadonnees($cheminImage);
if ($metadonnees !== false) {
$infosImage = array();
$infosImage['date_shot'] = $metadonnees['date_shot'];
$infosImage['size'] = $metadonnees['size'];
$infosImage['occurrence_id'] = $id_obs;
$infosImage['original_name'] = $nomFichierImage;
$infosImage['user_id'] = $this->userId;
$infosImage['user_email'] = $this->userEmail;
$infosImage['user_pseudo'] = $this->userIntitule;
$infosImage['content_url'] = $cheminImage;
$infosImage['mime_type'] = mime_content_type($cheminImage);
// $infosImage['md5'] = md5_file($cheminImage);
$infosImage['date_created'] = 'NOW()';
$infosImage['date_updated'] = 'NOW()';
$infosImage['date_linked_to_occurrence'] = 'NOW()';
$this->debug[] = 'Nom fichier img meta :'.$nomFichierImage;
$requete = $this->construireRequeteInsertionImage($infosImage);
$resultat = Cel::db()->executer($requete);
if ($resultat !== false) {
$idImage = $this->traiterEtRecupererIdImage($nomFichierImage, $id_obs);
if ($idImage !== false) {
$infosImage['url'] = 'https://api.tela-botanica.org/img:'.str_pad($idImage, 9, '0', STR_PAD_LEFT).'O';
 
$manipulateurImage = new ImageRecreation($this->config);
// Stocke le fichier en conservant les fichiers temporaires, ce qui permet de réessayer
// de les traiter en cas d'échec de la totalité du processus de traitement de l'obs
$stockageOk = $manipulateurImage->stockerFichierOriginal($cheminImage, $idImage, true);
if ($stockageOk) {
$miniatureChemin = str_replace('.jpg', '_min.jpg', $cheminImage);
if (file_exists($miniatureChemin)) {
if (@unlink($miniatureChemin) === false) {
$this->messages[] = "La miniature de l'image n'a pu être supprimée.";
}
}
 
} else {
$this->messages[] = "Une erreur s'est produite lors du stockage du fichier.";
// Remise à zéro d'idImage pour que l'erreur ne soit pas ignorée par l'appelant
$idImage = false;
}
} else {
$this->messages[] = "Impossible d'obtenir le nouvel identifiant de l'image";
}
} else {
$this->messages[] = "Echec de l'insertion dans la base de donnees des informations de l'image.";
}
} else {
$this->messages[] = "Erreur lors de l'extraction des metadonnées.";
}
} else {
$this->messages[] = "L'image originale est introuvable sur le serveur.";
}
return $idImage;
}
 
/**
* Supprime une image du disque dur. Ne touche pas à la base de données, on considère
* que c'est le rôle de la transaction d'annuler les écritures en cas de problème
*
* @param Integer $idImageASupprimer
* @return boolean $ok true si la suppression s'est bien passée, false s'il reste au moins un fichier
*/
protected function effacerImageDuDd($idImageASupprimer) {
$manipulateurImage = new ImageRecreation($this->config);
$ok = $manipulateurImage->detruireImageSurDisque($idImageASupprimer);
 
return $ok;
}
 
private function traiterEtRecupererIdImage($original_name, $id_obs) {
$original_name = Cel::db()->proteger($original_name);
$id_obs = Cel::db()->proteger($id_obs);
$requete = 'SELECT id '.
'FROM photo '.
"WHERE occurrence_id = ".$id_obs.
" AND original_name = $original_name ";
$resultat = Cel::db()->requeter($requete);
$id_image = $resultat[0]['id'] ?? false;
 
if ($id_image) {
$full_id_image = str_pad($id_image, 9, '0', STR_PAD_LEFT) . 'O';
$image_url = sprintf($this->config['settings']['celImgUrlTpl'], $full_id_image);
$requete = 'UPDATE photo'
. ' SET url = ' . Cel::db()->proteger($image_url)
. ' WHERE id = ' . Cel::db()->proteger($id_image);
$resultat = Cel::db()->requeter($requete);
}
 
return $id_image;
 
}
 
private function construireRequeteInsertionImage($informations) {
$champs = array();
$valeurs = array();
foreach ($informations as $champ => $valeur) {
$champs[] = $champ;
if (is_null($valeur)) {
$valeurs[$champ] = 'NULL';
} else if ($valeur === 'NOW()') {
$valeurs[$champ] = $valeur;
} else {
$valeurs[$champ] = Cel::db()->proteger($valeur);
}
}
$champsConcat = implode(', ', $champs);
$valeursConcat = implode(', ', $valeurs);
 
$requete = "INSERT INTO photo ($champsConcat) VALUES ($valeursConcat) ".
' -- '.__FILE__.':'.__LINE__;
return $requete;
}
}
/branches/v3.01-serpe/jrest/services/InventoryObservationList.php
New file
0,0 → 1,139
<?php
// declare(encoding='UTF-8');
/**
* Cas d'utilisation :
* GET : Service recherche d'observations a partir de divers critères
* a: Le service recherche les observations correspondant aux critères demandés
* b: Le service renvoie la liste des observations correspondantes
*
* POST : Service modification en masse d'observations
* a: Le service recherche les observations correspondant aux identifiants donnés
* b: Le service modifie les observations correspondantes avec les infos données en paramètres
*
* DELETE : Service de suppression d'observations en masse
* a: Le service recherche les observations correspondant aux critères demandés
* b: Le service supprime la liste des observations correspondantes
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Mots-clés
* @version 0.1
* @author Mathias CHOUET <mathias@tela-botanica.org>
* @author Raphaël Droz <raphael@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 InventoryObservationList extends Cel {
 
/**
* Renvoie les observations correspondant au critères de filtrage
*
* uid[0] : utilisateur obligatoire
* uid[1] : criteres de filtrage de la forme critere1=valeur1&critere2=valeur2
*/
public function getElement($uid) {
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
$chercheur_observations = new RechercheObservation($this->config);
 
$numero_page = 0;
$taille_page = 50;
$criteres = array();
 
$criteres = $_GET ;
if (isset($criteres['numero_page']) && isset($criteres['limite'])) {
$numero_page = $criteres['numero_page'];
unset($criteres['numero_page']);
$taille_page = $criteres['limite'];
unset($criteres['limite']);
}
 
$debut = $taille_page*$numero_page ;
 
$retour = $chercheur_observations->rechercherObservations($uid[0], $criteres, $debut, $taille_page)->get();
$retour_formate = $chercheur_observations->formaterPourEnvoiCel($retour);
 
$this->envoyerJson($retour_formate);
return true;
}
 
/**
* met à jour les métadonnées d'une liste d'observations
*
* uid[0] : utilisateur obligatoire
* uid[1] : ordres des observations à modifier séparés par des virgules
* pairs : données à mettre à jour sous la forme de clés => valeurs
*/
public function updateElement($uid,$pairs) {
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
if (!isset($uid[1])) {
//TODO: envoyer un message d'erreur
return;
}
 
$obs = array_filter(explode(',', $uid[1]), 'is_numeric');
if (count($obs) == 0) {
return;
}
 
$gestionnaire_observation = new GestionObservation($this->config);
if (count($obs) == 1) {
return $gestionnaire_observation->modifierObservation($uid[0], $obs[0], $pairs);
}
 
// cas de mise à jour de multiples observations:
$ret = $gestionnaire_observation->modifierMultiplesObservation($uid[0], $obs, $pairs);
if ($ret === false) {
return false; // JRest::badRequest();
}
if ($ret === 0) {
header('HTTP/1.0 304 Not Modified');
} else {
header('HTTP/1.0 200 OK'); // et non pas une 201 !
}
die();
}
 
/**
* Supprime une liste d'observations
*
* uid[0] : utilisateur obligatoire
* uid[1] : ordres des observations à supprimer séparés par des virgules
*/
public function deleteElement($uid) {
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
if (!isset($uid[1])) {
//TODO: envoyer un message d'erreur
return;
}
$uid[1] = rtrim($uid[1], ',');
 
$gestionnaireObs = new GestionObservation($this->config);
$tableau_ordres = explode(',', $uid[1]);
foreach ($tableau_ordres as $ordre) {
$ids_obs[] = $gestionnaireObs->renvoyerIdPourOrdre($uid[0], $ordre);
}
 
$suppression_observations = $gestionnaireObs->supprimerObservation($uid[0], $uid[1]);
 
$gestionnaireChampsEtendus = new GestionChampsEtendus($this->config, 'obs');
$gestionnaireChampsEtendus->viderParLots($ids_obs);
$gestionnaire_images = new GestionImage($this->config);
$gestionnaire_images->modifierTransmissionParObs($ids_obs, false);
 
if ($suppression_observations) {
echo 'OK';
}
exit() ;
}
}
/branches/v3.01-serpe/jrest/services/Modification.php
New file
0,0 → 1,59
<?php
/**
* PHP Version 5
*
* @category PHP
* @package cel
* @author aurelien <aurelien@tela-botanica.org>
* @copyright 2015 Tela-Botanica
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
* @version SVN: <svn_id>
*/
 
/**
* Migre les observations et les images d'un utilisateur, lorsqu'il change d'adresse email
* (ou les migre d'un utilisateur à l'autre)
*
* Utilisation : http://domain/service:cel/Modification/?mail=oldemail@example.fr&nouveau_mail=newemail@example.fr
*/
class Modification extends Cel {
 
public $table_image = "photo";
public $table_obs = "occurrence";
 
public function getRessource() {
return $this->getElement(array());
}
 
public function getElement($uid) {
 
$ancien_mail = (isset($_GET['mail'])) ? $_GET['mail'] : false;
$nouveau_mail = (isset($_GET['nouveau_mail'])) ? $_GET['nouveau_mail'] : false;
 
if(!$ancien_mail) {
$this->envoyer("false");
return;
}
 
// si le mail n'a pas changé, on ne change rien
if($ancien_mail == $nouveau_mail) {
$this->envoyer("OK");
return;
}
 
// Sinon on doit changer des trucs dans les obs et les images
 
$requete_maj_mail_obs = "UPDATE ".$this->table_obs." SET user_email = ".Cel::db()->proteger($nouveau_mail)." ".
"WHERE user_email = ".Cel::db()->proteger($ancien_mail);
 
Cel::db()->executer($requete_maj_mail_obs);
 
$requete_maj_mail_img = "UPDATE ".$this->table_image." SET user_email = ".Cel::db()->proteger($nouveau_mail)." ".
"WHERE user_email = ".Cel::db()->proteger($ancien_mail);
 
Cel::db()->executer($requete_maj_mail_img);
 
$this->envoyer("OK");
return;
}
}
/branches/v3.01-serpe/jrest/services/ExportXLS.php
New file
0,0 → 1,300
<?php
// declare(encoding='UTF-8');
/**
* Service d'export de données d'observation du CEL au format XLS.
*
* Format du service :
* POST /ExportXLS
* POST /ExportXLS/<Utilisateur>
* TODO: GET /ExportXLS/<Utilisateur> [ sans "range" ? ]
*
* Les données POST acceptées sont:
* range (obligatoire): un range d'id_observation sous la forme d'entier ou d'intervalles d'entiers
* séparés par des virgules ou bien '*' (pour toutes)
* TODO: limit
* TODO: départ
* TODO: sets (ou colonnes, ou extended)
* TODO: + les critères supportés par fabriquerSousRequeteRecherche()
*
* Si <Utilisateur> est fourni, celui-ci doit être authentifié
* TODO: export des données public et non-sensible d'un utilisateur
*
* Si <Utilisateur> est fourni, le observations seront le résultat de l'intersection des 2 contraintes
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @version 0.1
* @author Mathias CHOUET <mathias@tela-botanica.org>
* @author Raphaël Droz <raphael@tela-botania.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>
*/
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(dirname(realpath(__FILE__))) . '/lib');
ini_set('html_errors', 0);
ini_set('xdebug.cli_color', 2);
require_once 'lib/PHPExcel/Classes/PHPExcel.php';
require_once 'lib/FormateurGroupeColonne.php';
 
class ExportXLS extends Cel {
 
private $id_utilisateur = NULL;
private $parametres_defaut = array('range' => '*', 'format' => 'CSV');
 
private $filtres_autorises = array(
'id_utilisateur' => 'id_utilisateur',
'utilisateur' => 'courriel_utilisateur',
'commune' => 'zone_geo',
'dept' => 'departement',
'projet' => 'mots_cles',
'num_taxon' => 'nt',
'date_debut' => 'date_debut',
'date_fin' => 'date_fin',
'taxon' => 'taxon'
);
 
public function __construct($config) {
parent::__construct($config);
}
 
public function getRessource() {
return $this->getElement(array());
}
 
public function getElement($uid) {
$parametres_format = $this->traiterParametresFormat($uid, $_GET);
$filtres = $this->traiterFiltres($_GET);
$this->export($parametres_format, $filtres);
exit();
}
 
private function traiterParametresFormat($uid, $params) {
$parametres = $this->parametres_defaut;
if (isset($params['format'])) {
if($params['format'] == 'csv') $parametres['format'] = 'CSV';
if($params['format'] == 'xls') $parametres['format'] = 'Excel5';
if($params['format'] == 'xlsx') $parametres['format'] = 'Excel2007';
if($params['format'] == 'pdf') $parametres['format'] = 'pdf';
}
// TODO: $params['part'] pour le multi-part
$parametres['widget'] = isset($params['widget']) ? $params['widget'] : 'CEL';
$parametres['debut'] = isset($params['debut']) ? intval($params['debut']) : 0;
$parametres['limite'] = isset($params['limite']) ? intval($params['limite']) : 0;
$parametres['id_utilisateur'] = $this->traiterIdUtilisateur($uid);
$parametres['groupe_champs'] = isset($params['colonnes']) ? $params['colonnes'] : 'standard,avance';
 
return $parametres;
}
 
private function traiterIdUtilisateur($uid) {
$id_utilisateur = null;
// TODO: controleUtilisateur()
if (isset($uid[0])) {
$id_utilisateur = intval($uid[0]);
}
return $id_utilisateur;
}
 
private function traiterFiltres($params) {
$obs_ids = $this->traiterObsIds($params);
$filtres = array();
if (!$obs_ids || count($obs_ids) == 1 && $obs_ids[0] == '*') {
unset($filtres['sql_brut']);
} else {
$filtres = Array('sql_brut' =>
sprintf('id_observation IN (%s)', implode(',', $obs_ids)));
}
foreach ($params as $cle => $valeur) {
if (trim($valeur) != '' && isset($this->filtres_autorises[$cle])) {
$filtres[$this->filtres_autorises[$cle]] = $valeur;
}
}
return $filtres;
}
 
private function traiterObsIds($params) {
$obs_ids = Array('*');
if (isset($params['range']) && trim($params['range']) != '*') {
// trim() car: `POST http://url<<<"range=*"`
$obs_ids = self::rangeToList(trim($params['range']));
}
return $obs_ids;
}
 
/*
* $param: Tableau associatif, indexes supportés:
* - widget: le nom du widget d'origine (utilisé pour les méta-données du tableur)
*
*/
private function export(Array $parametres_format = Array(),Array $filtres = array()) {
$chercheur_observations = new RechercheObservation($this->config);
 
$observations = $chercheur_observations
->rechercherObservations($parametres_format['id_utilisateur'], $filtres, $parametres_format['debut'], $parametres_format['limite'], TRUE)
->get();
// debug //echo ($chercheur_observations->requete_selection_observations);
// XXX: malheureusement l'instance de JRest n'est pas accessible ici
if (!$observations) {
header('HTTP/1.0 204 No Content');
exit();
}
 
if ($parametres_format['format'] == 'pdf') {
if (count($observations) > 300) {
die('too much');
}
require_once('GenerateurPDF.php');
 
$pdf = new GenerateurPDF();
$pdf->export($observations);
//$pdf->export1($observations);
//$pdf->export2($observations);
$pdf->pdf->Output('etiquettes.pdf', 'I');
die();
}
 
$colonnes = FormateurGroupeColonne::nomEnsembleVersListeColonnes($parametres_format['groupe_champs']);
// $colonne_abbrev = array_keys($colonnes);
$objPHPExcel = $this->gerenerFeuilleImportFormatee($parametres_format);
$feuille = $objPHPExcel->setActiveSheetIndex(0);
// attention formaterColonnesFeuille prend ses 2 premiers paramètres par référence
$this->formaterColonnesFeuille($feuille, $colonnes, $parametres_format);
$objPHPExcel->getActiveSheet()->getDefaultColumnDimension()->setWidth(12);
 
$no_ligne = 2;
foreach ($observations as $obs) {
// attention traiterLigneObservation prend ses 3 premiers paramètres par référence
$this->traiterLigneObservation($obs, $colonnes, $feuille, $no_ligne);
$no_ligne++;
}
 
$this->envoyerFeuille($objPHPExcel, $parametres_format);
}
 
private function envoyerFeuille($objPHPExcel, $parametres_format) {
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment; filename="liste.xls"; charset=utf-8');
header('Cache-Control: max-age=0');
 
// csv|xls|xlsx => CSV|Excel5|Excel2007
// Note: le format Excel2007 utilise un fichier temporaire
$generateur = PHPExcel_IOFactory::createWriter($objPHPExcel, $parametres_format['format']);
$generateur->save('php://output');exit;
}
 
private function traiterLigneObservation(&$obs, &$colonnes, &$feuille, $no_ligne) {
$no_colonne = 0;
foreach ($colonnes as $abbrev => $colonne) {
$valeur = null;
if ($colonne['extra'] == 2 || ! is_null($colonne['dyna'])) {
continue;
}
 
// valeur direct depuis cel_obs ?
if (isset($obs[$abbrev])) {
$valeur = $obs[$abbrev];
}
 
// pré-processeur de la champs
if (function_exists($colonne['fonction'])) {
$valeur = $colonne['fonction']($valeur);
} else if (method_exists('FormateurGroupeColonne', $colonne['fonction'])) {
$valeur = call_user_func(array('FormateurGroupeColonne', $colonne['fonction']), $valeur);
} else if (method_exists(__CLASS__, $colonne['fonction'])) {
$valeur = call_user_func(array(__CLASS__, $colonne['fonction']), $valeur);
} else if ($colonne['fonction']) {
die("méthode {$colonne['fonction']} introuvable");
} else if (function_exists($colonne['fonction_data'])) { // fonction pour obtenir des champs (étendus)
$valeur = $colonne['fonction_data']($obs);
} else if (method_exists(__CLASS__, $colonne['fonction_data'])) {
$valeur = call_user_func(array(__CLASS__, $colonne['fonction_data']), $obs);
}
 
// // cette section devrait être vide:
// // cas particuliers ingérable avec l'architecture actuelle:
if (false && $abbrev == 'date_observation' && $valeur == "0000-00-00") {
/* blah */
}
if ($abbrev == 'images') {
$valeur = FormateurGroupeColonne::getImages($obs, $this->id_utilisateur, $this);
}
if ($abbrev == 'nom-commun') {
$valeur = FormateurGroupeColonne::getNomCommun_v4($obs, $this);
}
 
// // fin de section "cas particuliers"
$feuille->setCellValueByColumnAndRow($no_colonne, $no_ligne, $valeur);
$no_colonne++;
}
}
 
private function gerenerFeuilleImportFormatee($parametres_format) {
$objPHPExcel = new PHPExcel();
 
$objPHPExcel->getProperties()->setCreator($parametres_format['widget']) // ou $uid ?
->setLastModifiedBy("XX") // TODO: $uid
->setTitle("Export des observation du carnet en ligne") // TODO
->setSubject("Export") // TODO
->setDescription("Export");
 
$objPHPExcel->getActiveSheet()->setTitle("Observations");
return $objPHPExcel;
}
 
private function formaterColonnesFeuille(&$feuille, &$colonnes, $parametres_format) {
$colid = 0;
foreach ($colonnes as $colonne) {
if ($colonne['extra'] == 2) {
continue;
}
 
$feuille->setCellValueByColumnAndRow($colid, 1, $colonne['nom']);
if ($colonne['extra'] == 1) {
$feuille->getStyleByColumnAndRow($colid, 1)->getBorders()->applyFromArray(
array(
'allborders' => array(
'style' => PHPExcel_Style_Border::BORDER_DASHDOT,
'color' => array('rgb' => PHPExcel_Style_Color::COLOR_BLUE)
)
)
);
}
if (! $colonne['importable']) {
$feuille->getStyleByColumnAndRow($colid, 1)->getFill()->applyFromArray(
array(
'type' => PHPExcel_Style_Fill::FILL_SOLID,
'color' => array('rgb' => PHPExcel_Style_Color::COLOR_YELLOW)
)
);
}
$colid++;
}
}
 
/*
* @param $fieldSets: un range, eg: 1-5,8,32,58-101
* @return un tableau trié, eg: 1,2,3,4,5,8,32,58,...,101
* http://stackoverflow.com/questions/7698664/converting-a-range-or-partial-array-in-the-form-3-6-or-3-6-12-into-an-arra
*/
static function rangeToList($in = '') {
$inSets = explode(',', $in);
$outSets = array();
 
foreach ($inSets as $inSet) {
list($start,$end) = explode('-', $inSet . '-' . $inSet);
// ignore les ranges trop importants
if ($start > 10000000 || $end > 10000000 || abs($start-$end) > 10000) {
continue;
}
$outSets = array_merge($outSets,range($start,$end));
}
$outSets = array_unique($outSets);
$outSets = array_filter($outSets, 'is_numeric');
sort($outSets);
return $outSets;
}
}
/branches/v3.01-serpe/jrest/services/CelRadiusPoints.php
New file
0,0 → 1,97
<?php
// declare(encoding='UTF-8');
/**
* Service renvoyant les observations présentent au sein d'un cercle de rayon donné.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Cartes
* @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 CelRadiusPoints extends Cel {
 
private $champs_max = array('id_observation', 'nom_sel', 'latitude', 'longitude', 'COUNT(id_observation) AS nb_obs', 'GROUP_CONCAT(id_observation) as ids_obs');
private $champs_min = array('latitude', 'longitude');
 
private $champs_mode = null;
 
/**
* Méthode appelée avec une requête de type GET.
*/
public function getRessource() {
$this->champs_mode = $this->champs_min;
return $this->getElement(array());
}
 
/**
* Méthode appelée avec une requête de type GET.
*/
public function getElement($params) {
$lat_centre = str_replace(',', '.', round(floatval($_GET['lat']), 3));
$lon_centre = str_replace(',', '.', round(floatval($_GET['lon']), 3));
$radius = str_replace(',', '.', floatval($_GET['radius']/1000));
if (isset($_GET['format'])) {
if ($_GET['format'] == 'max') {
$this->champs_mode = $this->champs_max;
} else if($_GET['format'] == 'min') {
$this->champs_mode = $this->champs_min;
}
}
 
$retour = array();
 
$retour['points'] = $this->obtenirPointsPourCentreEtRadius($lat_centre, $lon_centre, $radius);
if (empty($retour['points'])) {
$retour['plus_proche'] = $this->obtenirPointPlusProche($lat_centre, $lon_centre);
}
$this->envoyerJson($retour);
}
 
public function obtenirPointsPourCentreEtRadius($lat_centre, $lon_centre, $radius) {
$requete = 'SELECT '.implode(', ', $this->champs_mode).' '.
'FROM cel_obs '.
'WHERE latitude != 0 AND longitude != 0 '.
'AND '.$this->renvoyerDistanceSql($lat_centre, $lon_centre)." < $radius ".
'GROUP BY latitude, longitude '.
' -- '.__FILE__.':'.__LINE__;
$points = Cel::db()->requeter($requete);
return $points;
}
 
private function renvoyerDistanceSql($lat_centre, $lon_centre) {
$sous_requete =
"( ".
"6371 * acos ( ".
"cos ( radians($lat_centre) ) ".
"* cos( radians( latitude ) ) ".
"* cos( radians( longitude ) - radians($lon_centre) ) ".
"+ sin ( radians($lat_centre) ) ".
"* sin( radians( latitude ) ) ".
") ".
") ";
return $sous_requete;
}
 
public function obtenirPointPlusProche($lat_centre, $lon_centre) {
// TODO: faire moins moche et plus efficace
$requete = 'SELECT '.
implode(", ", $this->champs_mode).", ".$this->renvoyerDistanceSql($lat_centre, $lon_centre)." AS distance ".
'FROM cel_obs '.
'WHERE latitude != 0 AND longitude != 0 '.
'GROUP BY latitude, longitude '.
'ORDER BY distance '.
'LIMIT 1 '.
' -- '.__FILE__.':'.__LINE__;
$point = Cel::db()->requeterLigne($requete);
return $point;
}
}
/branches/v3.01-serpe/jrest/services/squelettes/rss1.tpl.xml
New file
0,0 → 1,45
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'."\n";?>
 
<!DOCTYPE rdf:RDF [
<!ENTITY % HTMLlat1 PUBLIC
"-//W3C//ENTITIES Latin 1 for XHTML//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">
%HTMLlat1;
]>
 
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns="http://purl.org/rss/1.0/">
 
<channel rdf:about="<?=$guid?>">
<title><?=$titre?></title>
<link><?=$lien_cel?></link>
<description><?=$description?></description>
<dc:publisher><?=$editeur?></dc:publisher>
<dc:date><?=$date_maj_W3C?></dc:date>
<?php if (isset($items)) : ?>
<items>
<rdf:Seq>
<?php foreach ($items as $item) : ?>
<rdf:li resource="<?=$item['guid']?>" />
<?php endforeach; ?>
</rdf:Seq>
</items>
<?php endif; ?>
 
</channel>
<?php if (isset($items)) : ?>
<?php foreach ($items as $item) : ?>
<item rdf:about="<?=$item['guid']?>">
<title><?=$item['titre']?></title>
<link><?=(isset($item['lien'])) ? $item['lien'] : 'http://www.tela-botanica.org/'?></link>
<description><?=$item['description_encodee']?></description>
<dc:date><?=$item['date_maj_W3C']?></dc:date>
</item>
<?php endforeach; ?>
<?php endif; ?>
</rdf:RDF>
/branches/v3.01-serpe/jrest/services/squelettes/rss2.tpl.xml
New file
0,0 → 1,25
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'."\n";?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title><?=$titre?></title>
<link><?=$lien_cel?></link>
<atom:link href="<?=$lien_service?>" rel="self" type="application/rss+xml" />
<description><?=$description?></description>
<?php if (isset($items)) : ?>
<?php foreach ($items as $item) : ?>
<item>
<guid><?=$item['guid']?></guid>
<title><?=$item['titre']?></title>
<? if (isset($item['lien'])) : ?>
<link><?=$item['lien']?></link>
<? endif; ?>
<description><?=$item['description_encodee']?></description>
<category><?= $item['categorie'] ?></category>
<pubDate><?=$item['date_maj_RSS']?></pubDate>
</item>
<?php endforeach; ?>
<?php endif; ?>
</channel>
</rss>
/branches/v3.01-serpe/jrest/services/squelettes/doublon_defaut.tpl.html
New file
0,0 → 1,52
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Images en doublon - <?=$utilisateur?></title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<style type="text/css">
html, body{
margin:0;
padding:0;
height: 100%;
font-family: Arial;
font-size: 12px;
}
ul{
list-style-type:none;
}
.doublon{
float:left;
}
.doublon-liste{
clear:left;
}
</style>
<!-- JavaScript -->
<script type="text/javascript" src="http://www.tela-botanica.org/commun/jquery/1.4.4/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="http://www.tela-botanica.org/commun/jquery/lazyload/1.5.0/jquery.lazyload.mini.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("img").lazyload();
});
</script>
</head>
 
<body>
<h1><?=count($doublons)?> images en doublon - <?=$utilisateur?></h1>
<ul>
<?php foreach ($doublons as $doublon) : ?>
<li class="doublon-liste">
<?php foreach ($doublon as $img) : ?>
<ul class="doublon">
<li>Image : <?=$img['img_ordre']?></li>
<li>Observation(s) : <?=implode(', ', $img['obs_ordre'])?></li>
<li><img src="<?=$img['url']?>" alt="Id #<?=$img['img_id']?>"/></li>
</ul>
<?php endforeach; ?>
</li>
<?php endforeach; ?>
</ul>
</body>
</html>
/branches/v3.01-serpe/jrest/services/squelettes/modele_import_description_florileges.txt
New file
0,0 → 1,23
Milieu = Milieux dans lesquels l'espèce est présente sur le site, séparés par des virgules <br />("chemin", "fissures", "haie", "mur", "pelouse", "pied d'arbre", "plate bande")
adresse = Adresse du site étudié
dateArretTraitementPhyto = Date d'arrêt des traitements (au format jj/mm/aaaa)
dateDerniereIntervention = Dernière intervention ("inconnue", "plus de 3 ans", "entre 1 et 3 ans", "moins d'1 an", "au cours du dernier semestre",<br /> "au cours du dernier trimestre", "au cours des 30 derniers jours", "au cours des 7 derniers jours")
hauteurBatimentAvoisinant = Hauteur des bâtiments avoisinants en mètres ("0", "1", "2", "3", "4", "5 et +")
hauteurPlante = Hauteur max. (en cm) de la plante
intensiteGestion = Intensité de gestion ("extensive", "intermédiaire", "intensive")
itineraireGestion = Description de l'itinéraire de gestion
latitudeDebutRue = Latitude de début de parcours
latitudeFinRue = Longitude de début de parcours
longitudeDebutRue = Latitude de fin de parcours
longitudeFinRue = Latitude de fin de parcours
perceptionRiverainMauvaise = Mauvaise perception par les riverains ? ("oui", "non", "inconnue")
perceptionTechnicien = Perception globale de l'espèce par l'équipe technique ("inconnue", "discrète", "esthétique", "gênante", "envahissante")
periodiciteTraitementPhyto = Utilisation de produits phytosanitaires ("régulière", "occasionnelle", "rare", "jamais")
personneFonction = Fonction de l'observateur
personneService = Service de l'observateur
personneStructure = Structure de l'observateur
presenceZoneVegetalise = Présence de zones végétalisés ("nulle", "faible", "moyenne", "importante")
resistanceTraitementPhyto = Résistance/résilience de l'espèce face aux traitements utilisés sur ce site <br /> ("faible", "intermédiaire", "forte", "très forte", "pas de traitement")
revetementSol = Revêtement au sol ("asphalte et enrobés", "pavés", "stabilisés, aires sablées", "graviers", "terre")
typoUrbaine = Typologie Urbaine ("centre ville", "faubourg", "quartier résidentiel", "zone commerciale", "zone d'activités")
vitesseCroissance = Vitesse de croissance de l'espèce sur ce site ("nulle", "lente", "moyenne", "rapide", "trop rapide")
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/squelettes/atom.tpl.xml
New file
0,0 → 1,35
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'."\n";?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
<title><?=$titre?></title>
<link href="<?=$lien_cel?>" rel="alternate" type="text/html" hreflang="fr" />
<link href="<?=$lien_service?>" rel="self" type="application/atom+xml"/>
<updated><?=$date_maj_ATOM?></updated>
<author>
<name><?=$editeur?></name>
</author>
<id><?=$guid?></id>
<rights>Copyright (c) <?=$annee_courante?>, <?=$editeur?></rights>
<generator uri="<?=$lien_service?>" version="<?=$generateur_version?>"><?=$generateur?></generator>
 
 
<?php if (isset($items)) : ?>
<?php foreach ($items as $item) : ?>
<entry>
<id><?=$item['guid']?></id>
<title><?=$item['titre']?></title>
<?php if (isset($item['lien'])) : ?>
<link href="<?=$item['lien']?>"/>
<?php endif; ?>
<updated><?=$item['date_maj_ATOM']?></updated>
<author><name><?=$item['modifier_par']?></name></author>
<content type="xhtml" xml:lang="fr">
<div xmlns="http://www.w3.org/1999/xhtml">
<?=$item['description'];?>
</div>
</content>
</entry>
<?php endforeach; ?>
<?php endif; ?>
 
</feed>
Property changes:
Added: svnkit:entry:sha1-checksum
+f58b0505ab3a8706e54d9b231afe375e4d9c93d4
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/squelettes/modele_import_description_sauvages.txt
New file
0,0 → 1,7
Station = Nom de la rue étudiée
coteRue = le (ou les) côté(s) de la rue étudiée ("pair", "impair", "2cotes")
adresse = Nom de la rue étudiée
latitudeDebutRue = Latitude de début de rue
latitudeFinRue = Longitude de début de rue
longitudeDebutRue = Latitude de fin de rue
longitudeFinRue = Latitude de fin de rue
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/squelettes/modele_import_description.txt
New file
0,0 → 1,18
Espèce = Nom scientifique de l'espèce <br />ou bien chaine au format referentiel:nn:num_tax <br />ou referentiel:nt:num_nom <br />(Ex.: "bdtfx:nn:182")
Referentiel taxonomique = Code du référentiel taxonomique (bdtfx, isfan, apd, etc...)
Commune = Nom de la commune
Identifiant Commune = Code INSEE de la commune (uniquement pour les communes françaises)
Date = date de l'observation au format jj/mm/aaaa
Lieu-dit = Toponyme plus précis que la commune, utilisé localement et se trouvant souvent sur les cartes au 1/25 000
Station = Station associée à l'observation
Milieu = Milieu de l'observation (Ex. : "pelouse", "prairie humide")
Notes = Texte libre
Latitude = En décimal système WGS84, exemple : 45.666
Longitude = En décimal système WGS84, exemple : 3.55
Altitude = Altitude en mètres
Mots Clés = Mots clés à associer à l'observation, séparés par des virgules
Transmis = 0 ou 1 pour indiquer si l'observation est privée ou publique
Abondance = Abondance de l'espèce observée (selon l'échelle d'abondance-dominance BRAUN-BLANQUET et al. ou bien texte libre)
Certitude = Certitude de la détermination ("certain", "douteux", "aDeterminer" ou bien texte libre)
Phénologie = Stade phénologique de l'espèce observée (code BBCH ou bien texte libre)
Image(s) = Noms des images préalablement chargées dans le CEL à associer à l'observation, séparés par des virgules
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/squelettes/modele_import_description_arbres-tetards.txt
New file
0,0 → 1,12
milieu = Situations correspondants au site, séparées par des virgules <br /> ("séparation de parcelle", "proximité de bâtiment", "plein champ", "jardin de particulier", "bord de cours d'eau",<br /> "bord de chemin", "intégré à une haie", "en forêt", "en zone humide")
arbreTetardAligneNbre = Nombre d'arbres têtards alignés
arbreTetardClasseCirconferenceA1m = Classe de circonférence à 1 m du sol (en m) ("0-0,5", "0,5-2", "2-3", "+3")
arbreTetardEntretientCoupe = Type d’entretien de l'arbre, en précisant la périodicité des coupes ("récente", "ancienne", "non entretenu")
arbreTetardEtatSanitaire = État sanitaire de l'arbre têtard ("mort", "dépérissant", "bon")
arbreTetardFormation = Type de formation de l'arbre ou des arbres têtards ("alignement", "isolé")
arbreTetardHauteurTete = Hauteur de la tête (en m) ("0-1,5", "1,5-3", "+3")
arbreTetardPresenceCavite = Présence ou non de cavités sur l'arbre ("aucune", "petite", "grande")
arbreTetardPresenceSp = Présence d'espèces sur l'arbre<br />Vous pouvez éventuellement indiquer des informations du type : Champignons ; Lierre ; Mousses ; Lichens ; Autre plante...<br /> Larve d'insecte saproxylique ; Galerie dans le bois ; Pelote de réjection ; Nid ; Crotte ; Trou
arbreTetardTailleType = Type de taille ("trogne", "tête de chat", "émonde" ou bien texte libre)
coordonneelambert93x = Coordonnée x de l'espèce observée au format lambert 93
coordonneelambert93y = Coordonnée y de l'espèce observée au format lambert 93
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/squelettes/image_temp.tpl.xml
New file
0,0 → 1,7
<?='<?xml version="1.0" encoding="UTF-8"?>'."\n";?>
<root>
<miniature-url><?=$urlMiniature?></miniature-url>
<image-nom><?=$imageNom?></image-nom>
<message><?=$message?></message>
<debogage><?=$debogage?></debogage>
</root>
/branches/v3.01-serpe/jrest/services/squelettes/modele_import.xls
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/branches/v3.01-serpe/jrest/services/squelettes/modele_import.xls
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/squelettes/opml.tpl.xml
New file
0,0 → 1,18
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'."\n";?>
<opml version="1.0">
<head>
<text/>
</head>
<body>
<outline text="CEL">
<?php foreach ($liste_flux as $flux) : ?>
<outline title="<?=$flux['titre']?>"
description="<?=$flux['description']?>"
htmlUrl="<?=$flux['url_html']?>"
xmlUrl="<?=$flux['url_xml']?>"
type="<?=$flux['type']?>"
text="<?=$flux['texte']?>"/>
<?php endforeach; ?>
</outline>
</body>
</opml>
/branches/v3.01-serpe/jrest/services/InventoryImageCount.php
New file
0,0 → 1,45
<?php
// declare(encoding='UTF-8');
/**
* Service recherche du nombre d'images à partir de divers critères.
*
* Cas d'utilisation :
* 2: Le service recherche le nombre d'images correspondant aux critères demandés
* 3: Le service renvoie le nombre calculé
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 InventoryImageCount extends Cel {
 
/**
* Renvoie le nombre d'images correspondant aux criteres
* uid[0] : utilisateur obligatoire
*/
public function getElement($uid) {
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
$chercheurImages = new RechercheImage($this->config);
$retour = $chercheurImages->compterImages($uid[0], $_GET);
 
$retour_encode = json_encode($retour);
$retour_encode = $this->nettoyerCaracteresNuls($retour_encode);
header('content-type: application/json');
print $retour_encode ;
exit() ;
}
 
private function nettoyerCaracteresNuls($chaine) {
return str_replace('\u0000','',$chaine);
}
}
/branches/v3.01-serpe/jrest/services/CelWidgetImage.php
New file
0,0 → 1,104
<?php
// declare(encoding='UTF-8');
/**
* Service recherche d'images publique a partir de divers critères.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 CelWidgetImage extends Cel {
 
const start_defaut = 0;
const limit_defaut = 100;
const tri_defaut = 'ci.date_creation';
const dir_defaut = 'DESC';
 
public function getRessource() {
 
}
 
public function getElement($uid) {
// restriction aux observations publiques
$criteres = array('transmission' => '1');
 
if ($uid[0] != '*' && empty($_GET)) {
header("content-type: application/json");
$images_json = json_encode(array());
print $images_json;
exit();
}
 
$this->start = isset($_GET['start']) ? $_GET['start'] : self::start_defaut;
$this->limit = isset($_GET['limit']) ? $_GET['limit'] : self::limit_defaut;
 
$criteres['recherche'] = isset($_GET['recherche']) ? $_GET['recherche'] : null;
$criteres['taxon'] = isset($_GET['taxon']) ? $_GET['taxon'] : null;
$criteres['referentiel'] = isset($_GET['referentiel']) ? $_GET['referentiel'] : null;
$criteres['taxon'] = isset($_GET['taxon']) ? $_GET['taxon'] : null;
// date debut - fin
$criteres['zone_geo'] = isset($_GET['commune']) ? $_GET['commune'] : null;
$criteres['ce_zone_geo'] = isset($_GET['dept']) ? $_GET['dept'] : null; // separe par ,
$criteres['pays'] = isset($_GET['pays']) ? $_GET['pays'] : null;
$criteres['auteur'] = isset($_GET['auteur']) ? $_GET['auteur'] : null;
$criteres['programme'] = isset($_GET['programme']) ? $_GET['programme'] : null;
$criteres['mots_cles'] = isset($_GET['tag']) ? $_GET['tag'] : null;
$criteres['famille'] = isset($_GET['famille']) ? $_GET['famille'] : null;
$criteres['standard'] = isset($_GET['standard']) ? $_GET['standard'] : 1;
$criteres['tri'] = isset($_GET['tri']) ? $_GET['tri'] : self::tri_defaut;
$criteres['dir'] = isset($_GET['dir']) ? $_GET['dir'] : self::dir_defaut;
 
$chercheur_images = new RechercheImage($this->config);
$total = $chercheur_images->compterImages(null, $criteres);
$images = $chercheur_images->rechercherImagesJoinObservation(null, $criteres, $this->start, $this->limit);
$images = $this->mettreEnForme($images);
$resultat = array('total' => $total,'images' => $images);
$images_json = json_encode($resultat);
$images_json = str_replace('\u0000','',$images_json);
 
header("content-type: application/json");
print $images_json;
exit();
}
public function mettreEnForme($images) {
$retour = array();
foreach ($images as $id => $image) {
$retour[$id]['id_photo'] = $image['id_photo'];
unset($image['id_photo']);
$retour[$id]['guid'] = $image['guid'];
unset($image['guid']);
$retour[$id]['nom_original'] = $image['nom_original'];
unset($image['nom_original']);
$retour[$id]['date_photo'] = $image['date_photo'];
unset($image['date_photo']);
$retour[$id]['licence'] = $image['licence'];
unset($image['licence']);
$retour[$id]['attribution'] = $image['attribution'];
unset($image['attribution']);
$retour[$id]['url_photo'] = $image['url_photo'];
unset($image['url_photo']);
$retour[$id]['tags_photo'] = $image['tags_photo'];
unset($image['tags_photo']);
$retour[$id]["utilisateur"]['id_utilisateur'] = $image['id_utilisateur'];
unset($image['id_utilisateur']);
$retour[$id]["utilisateur"]['mail_utilisateur'] = $image['mail_utilisateur'];
unset($image['mail_utilisateur']);
$retour[$id]["utilisateur"]['nom_utilisateur'] = $image['nom_utilisateur'];
unset($image['nom_utilisateur']);
$retour[$id]['obs'] = $image;
}
return $retour;
}
}
/branches/v3.01-serpe/jrest/services/CelSyndicationImage.php
New file
0,0 → 1,731
<?php
// declare(encoding='UTF-8');
/**
* Service fournissant des informations concernant les images du CEL au format RSS1, RSS2 ou ATOM.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Syndication
* @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 CelSyndicationImage extends Cel {
private $parametres_origines = null;
private $format = null;
private $service = null;
private $squelette = null;
private $squelette_dossier = null;
private $auteurs = array();
private $flux = array();
private $format_image = 'XL';
private $criteres = array(
'utilisateur' => 'b.courriel_utilisateur',
'commune' => 'b.zone_geo',
'dept' => 'b.dept',
'taxon' => 'b.nom_ret',
'num_taxon' => 'b.nt',
'num_nom' => 'b.nom_sel_nn',
'commentaire' => 'c.commentaire',
'date' => 'c.date_prise_de_vue',
'tag' => 'tag',
'motcle' => 'tag',
'projet' => 'projet',
'referentiel' => 'referentiel',
'groupe_zones_geo' => 'groupe_zones_geo'
);
/**
* Méthode appelée avec une requête de type GET.
*/
public function getElement($params = array()) {
// Initialisation des variables
$this->parametres_origines = $params;
$info = array();
$contenu = '';
if (! $this->etreFluxAdmin() || $this->authentifierAdmin()) {
// Pré traitement des paramêtres
$pour_bdd = false;
$p = $this->traiterParametres(array('service', 'format'), $params, $pour_bdd);
extract($p);
$this->parametres = $params;
$this->squelette_dossier = dirname(__FILE__).DIRECTORY_SEPARATOR.'squelettes'.DIRECTORY_SEPARATOR;
// Récupération de la liste des flux
$this->chargerListeDesFlux();
// Chargement du bon type de service demandé
if (isset($service)) {
$this->service = $this->traiterNomService($service);
$methode = $this->getNomMethodeService();
if (method_exists($this, $methode)) {
if (isset($format) && preg_match('/^(?:rss1|rss2|atom)$/i', $format)) {
// Mise en minuscule de l'indication du format
$this->format = strtolower($format);
// Définition du fichier squelette demandé
$this->squelette = $this->squelette_dossier.$this->format.'.tpl.xml';
} else if (isset($this->flux[$this->service])) {
$this->format = '';
$this->messages[] = "Le service CEL Syndication nécessite d'indiquer en second paramètre le format : rss1, rss2 ou atom.";
}
if (!isset($this->flux[$this->service]) || isset($this->format)) {
// Suppression des deux premiers paramètres (service et format) pour le reste des méthodes
array_shift($this->parametres);
array_shift($this->parametres);
// Récupération du contenu à renvoyer
$contenu = $this->$methode();
}
} else {
$this->messages[] = "Le type d'information demandé '$this->service' n'est pas disponible.";
}
} else {
$this->messages[] = "Le service CEL Syndication Image nécessite d'indiquer en premier paramètre le type d'information demandé.";
}
}
// Envoie sur la sortie standard
$encodage = 'utf-8';
$mime = $this->getTypeMime();
$formatage_json = $this->getFormatageJson();
$this->envoyer($contenu, $mime, $encodage, $formatage_json);
}
private function chargerListeDesFlux() {
$this->setFlux('simple', 'Nouvelles images liées à une observation dans le CEL',
"Ce flux fournit l'url des nouvelles images du CEL liées à une observation.");
$this->setFlux('complet', 'Nouvelles images liées à une observation dans le CEL (détails)',
"Ce flux fournit les informations sur les nouvelles images du CEL liées à une observation.");
$this->setFlux('par-mots-cles', 'Flux de syndication obsolète',
"Ce flux est désormais accessible via le flux multicriteres/atom/M?tag='mot-cle'.");
$this->setFlux('par-commune','Flux de syndication obsolète',
"Ce flux est désormais accessible via le flux multicriteres/atom/M?commune='commune'.");
$this->setFlux('multicriteres','Flux de syndication des nouvelles images liées à une observation publique du CEL '.
'filtrées par un ou plusieurs critères',
"Ce flux fournit des informations sur les nouvelles images liées à une observation du CEL filtrées par ".
"auteur (mail), commune (nom), departement (code postal), taxon (nom scientifique), commentaire, tag ".
"et/ou date.");
}
private function setFlux($nom, $titre, $description) {
$url_base = $this->config['settings']['baseURLAbsoluDyn'].'CelSyndicationImage/';
$formats = array('atom', 'rss2', 'rss1');
$flux = array();
foreach ($formats as $format) {
$url = $url_base.$nom.'/'.$format;
$flux[$format] = $url;
}
$this->flux[$nom] = array('titre' => $titre, 'description' => $description, 'urls' => $flux);
}
private function getFlux($nom) {
return isset($this->flux[$nom]) ? $this->flux[$nom] : array();
}
private function traiterNomService($nom) {
$nom = strtolower($nom);
return $nom;
}
private function getNomMethodeService() {
$methode = '';
$service_formate = str_replace(' ', '', ucwords(implode(' ', explode('-', $this->service))));
$methode = 'getService'.$service_formate;
return $methode;
}
private function getUrlBase() {
$url_base = sprintf($this->config['settings']['baseURLAbsolu'], get_class($this).'/');
return $url_base;
}
private function getUrlServiceBase() {
$url_service = $this->getUrlBase().implode('/', $this->parametres_origines);
return $url_service;
}
private function getTypeMime() {
$mime = '';
switch ($this->format) {
case 'atom' :
$mime = 'application/atom+xml';
break;
case 'rss1' :
case 'rss2' :
$mime = 'application/rss+xml';
break;
case 'opml' :
$mime = 'text/x-opml';
break;
default:
$mime = 'text/html';
}
return $mime;
}
private function getFormatageJson() {
$json = false;
switch ($this->service) {
case 'liste-des-flux' :
$json = true;
break;
default:
$json = false;
}
return $json;
}
private function creerCategorie($element) {
$categorie = '';
$categorie = 'Image';
$categorie = $this->nettoyerTexte($categorie);
return $categorie;
}
private function etreFluxAdmin() {
return (isset($_GET['admin']) && $_GET['admin'] == '1') ? true : false;
}
private function creerUrlService() {
$url_service = $this->getUrlServiceBase();
if (count($_GET) > 0) {
$parametres_get = array();
foreach ($_GET as $cle => $valeur) {
$parametres_get[] = $cle.'='.$valeur;
}
$url_service .= '?'.implode('&amp;', $parametres_get);
}
return $url_service;
}
protected function executerRequete($requete, $retour = 'All', $mode = PDO::FETCH_ASSOC) {
$infos = null;
try {
$infos = Cel::db()->query($requete)->fetchAll(PDO::FETCH_ASSOC);
if ($infos === false) {
$this->messages[] = "La requête suivante n'a retourné aucun résultat :\n$requete";
}
} catch (PDOException $e) {
$msgTpl = 'Requête echec. Fichier : "%s". Ligne : "%s". Message : %s';
$this->messages[] = sprintf($msgTpl, $e->getFile(), $e->getLine(), $e->getMessage());
}
return $infos;
}
private function executerService($elements) {
// Prétraitement des données
$donnees = $this->construireDonneesCommunesAuFlux($elements);
foreach ($elements as $element) {
$identifiants[$element['courriel_utilisateur']] = $element['courriel_utilisateur'];
}
$this->auteurs = $this->creerAuteurs($identifiants);
foreach ($elements as $element) {
$donnees['items'][] = $this->construireDonneesCommunesAuxItems($element);
}
// Création du contenu à partir d'un template PHP
$contenu = Cel::traiterSquelettePhp($this->squelette, $donnees);
return $contenu;
}
private function construireDonneesCommunesAuFlux($infos) {
$donnees = $this->getFlux($this->service);
$donnees['guid'] = $this->getUrlServiceBase();
$donnees['lien_service'] = $this->creerUrlService();
$donnees['lien_cel'] = (isset($infos['nom_sel_nn']) && $infos['nom_sel_nn'] != '' && $infos['nom_sel_nn'] != 0) ?
$this->getUrlEflore($infos['nom_referentiel'], $infos['nom_sel_nn']) : '';
$donnees['editeur'] = $this->config['settings']['editeur'];
$derniere_info_en_date = reset($infos);
$date_modification_timestamp = strtotime($derniere_info_en_date['date_creation']);
$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'] = 'CEL - Jrest - CelSyndicationImage';
$donnees['generateur_version'] = (preg_match('/([0-9]+)/', '$Revision$', $match)) ? $match[1] : '0';
return $donnees;
}
private function construireDonneesCommunesAuxItems($info) {
$item = array();
$date_modification_timestamp = $this->convertirDateHeureMysqlEnTimestamp($info['date_creation']);
$item['date_maj_simple'] = strftime('%A %d %B %Y à %H:%M', $date_modification_timestamp);
$item['date_maj_RSS'] = date(DATE_RSS, $date_modification_timestamp);
$item['date_maj_ATOM'] = date(DATE_ATOM, $date_modification_timestamp);
$item['date_maj_W3C'] = date(DATE_W3C, $date_modification_timestamp);
$item['titre'] = $this->creerTitre($info);
$item['guid'] = $this->creerGuidItem($info);
$item['lien'] = $this->creerLienItem($info);
$item['categorie'] = $this->creerCategorie($item);
$item['description'] = $this->creerDescription(Cel::protegerCaracteresHtmlDansChamps($info), $item);
$item['description_encodee'] = htmlspecialchars($this->creerDescription($info, $item));
$item['modifier_par'] = $this->nettoyerTexte($this->getIntituleAuteur($info['courriel_utilisateur']));
return $item;
}
private function creerGuidItem($element) {
$guid = $this->getUrlImage($element['id_image']);
return $guid;
}
private function creerTitre($element) {
$methode = 'creerTitre'.$this->service;
$methode = (method_exists($this, $methode)) ? $methode : 'creerTitreSimple';
$titre = $this->$methode($element);
$titre = $this->nettoyerTexte($titre);
return $titre;
}
private function creerDescription($donnees, $item) {
$methode = 'creerDescription'.$this->service;
$methode = (method_exists($this, $methode)) ? $methode : 'creerDescriptionComplet';
$description = $this->$methode($donnees, $item);
$description = $this->nettoyerTexte($description);
return $description;
}
private function creerLienItem($element) {
if ($this->etreNull($element['id_observation'])) {
// Lien vers image grand format
$lien = $this->getUrlImage($element['id_image'], $this->format_image);
} else {
// Lien vers fiche eFlore onglet Illustration
$lien = $this->getUrlEflore($element['nom_referentiel'], $element['nom_sel_nn'], 'illustration');
}
return $lien;
}
private function getServiceListeDesFlux() {
return $this->flux;
}
private function getServiceOpml() {
$donnees = array();
$id = 1;
foreach ($this->flux as $flux_nom => $flux){
$info = array();
$info['type'] = 'atom';
$info['titre'] = $flux['titre'];
$info['texte'] = "CEL - Images - $flux_nom";
$info['description'] = $flux['description'];
$info['url_xml'] = $this->getUrlBase().$flux_nom.'/atom';
$info['url_html'] = $this->config['settings']['aideCelUrl'].'FluxSyndication';
$donnees['liste_flux'][] = $info;
}
$this->squelette = $this->squelette_dossier.'opml.tpl.xml';
$contenu = Cel::traiterSquelettePhp($this->squelette, $donnees);
return $contenu;
}
private function getServiceSimple() {
if (isset($this->parametres[0])) {
$this->format_image = $this->parametres[0];
}
// Construction de la requête
$requete = (isset($this->distinct) ? 'SELECT DISTINCT' : 'SELECT').' co.*, '.
' ci.id_image, co.ce_utilisateur, nom_original, ci.date_creation, ci.mots_cles_texte AS mots_cles_texte_images, '.
' co.mots_cles_texte AS mots_cles_texte_images_obs, "" as commentaire, "" as note_qualite, nom_referentiel '.
'FROM cel_export_total AS co JOIN cel_images_export AS ci ON (co.id_observation = ci.ce_observation) '.
'WHERE co.transmission = 1 '.
' AND co.ce_utilisateur = ci.ce_utilisateur '.
'ORDER BY '.(isset($this->orderby) && (!is_null($this->orderby)) ? $this->orderby : 'ci.date_creation DESC').' '.
"LIMIT $this->start, $this->limit ";
$elements = $this->executerRequete($requete);
// Création du contenu
$contenu = $this->executerService($elements);
return $contenu;
}
private function creerTitreSimple($element) {
$date = $element['date_observation'];
$date = date("d/m/Y", strtotime($date));
if ($this->etreNull($element['nom_sel']) && $this->etreNull($element['nom_sel_nn'])) {
$titre = "Ajout d'une photo par ".$this->getIntituleAuteur($element['courriel_utilisateur']).' le '.$date;
} else {
$titre = $element['nom_sel'].' [nn'.$element['nom_sel_nn'].'] par '.$this->getIntituleAuteur($element['courriel_utilisateur']).' le '.$date;
}
$zoneGeo = $element['zone_geo'];
if ($zoneGeo) {
$titre .= " - $zoneGeo";
}
return $titre;
}
private function creerDescriptionSimple($donnees, $item) {
$description = $this->getUrlEflore($element['nom_referentiel'], $element['nom_sel_nn'], 'illustration');
return $description;
}
private function getServiceComplet() {
// Construction de la requête
$requete = (isset($this->distinct) ? 'SELECT DISTINCT' : 'SELECT').' co.*, '.
' ci.id_image, co.ce_utilisateur, nom_original, ci.date_creation, ci.mots_cles_texte AS mots_cles_texte_images, '.
' co.mots_cles_texte AS mots_cles_texte_obs, ci.commentaire AS commentaire_img, note_qualite, nom_referentiel, '.
' co.commentaire AS commentaire_obs '.
'FROM cel_images_export AS ci '.
' JOIN cel_export AS co '.
' ON (ci.ce_observation = co.id_observation) '.
(($this->etreFluxAdmin()) ? '' : 'WHERE co.transmission = 1 ').
'ORDER BY '.(isset($this->orderby) && (!is_null($this->orderby)) ? $this->orderby : 'ci.date_creation DESC').' '.
"LIMIT $this->start, $this->limit ";
//echo $requete;
$elements = $this->executerRequete($requete);
// Création du contenu
if ($elements != false && count($elements) > 0) {
$contenu = $this->executerService($elements);
} else {
// ne pas faire ça, car ça déclenche une erreur 500 à tort !
//$this->messages[] = "Aucune image disponible.";
$contenu = array();
}
return $contenu;
}
private function getServiceMultiCriteres() {
$contenu = '';
if (isset($_GET['debut'])) $this->start = Cel::db()->proteger($_GET['debut']);
if (isset($_GET['limite'])) $this->limit = Cel::db()->proteger($_GET['limite']);
$this->limit = ($this->limit < 1000) ? $this->limit : 1000;// Pour éviter les abus !
if ($this->parametresSontDemandes()) {
$requete = $this->creerRequeteAvecParametres();
} else {
$requete = $this->creerRequeteSansParametres();
}
$elements = $this->executerRequete($requete);
// Création du contenu
if ($elements != false && count($elements) > 0) {
$contenu = $this->executerService($elements);
} else {
// ne pas faire ça, car ça déclenche une erreur 500 à tort !
//$this->messages[] = "Aucune image disponible.";
}
return $contenu;
}
private function parametresSontDemandes() {
$criteres = $this->traiterCriteresMultiples($_GET) ;
return (isset($_GET['recherche']) && $_GET['recherche'] != '') || !empty($criteres);
}
private function creerRequeteSansParametres() {
// Construction de la requête
$requete = 'SELECT *, b.mots_cles_texte AS mots_cles_texte_obs, c.mots_cles_texte AS mots_cles_texte_images, '.
' b.commentaire AS commentaire_obs, "" AS commentaire_img, nom_referentiel '.
'FROM cel_images_export c '.
' JOIN cel_export AS b '.
' ON (c.ce_observation = b.id_observation) ';
$requete .= ' ORDER BY '.(isset($this->orderby) && (!is_null($this->orderby)) ? $this->orderby : 'c.date_creation DESC').' '.
"LIMIT $this->start,$this->limit ";
//echo $requete;
return $requete;
}
private function creerRequeteAvecParametres() {
// Construction de la requête
$requete = 'SELECT *, b.mots_cles_texte as mots_cles_texte_obs, c.mots_cles_texte as mots_cles_texte_images, '.
' b.commentaire as commentaire_obs, "" as commentaire_img, nom_referentiel '.
'FROM cel_images_export AS c '.
' JOIN cel_export_total AS b '.
' ON (c.ce_observation = b.id_observation) '.
'WHERE '.
(($this->etreFluxAdmin()) ? '' : ' b.transmission = 1 ').
' AND ';
if ($this->estUneRechercheGenerale()) {
$chaine_requete = $_GET['recherche'];
$requete .= "donnees_standard = 1 AND ".$this->creerSousRequeteRechercheGenerale($chaine_requete);
} else {
$criteres = $this->traiterCriteresMultiples($_GET) ;
if (!isset($_GET["standard"])) {
$requete .= "donnees_standard = 1 AND ";
} elseif ($_GET["standard"] = 1) {
$requete .= "donnees_standard = 1 AND ";
}
if (!empty($criteres)) {
$requete .= $this->creerSousRequeteRechercheParCriteres($criteres);
}
}
$requete = str_replace(' AND ) ',' ', $requete);
$requete = rtrim($requete, 'AND ');
$requete .= ' ORDER BY '.(isset($this->orderby) && (!is_null($this->orderby)) ? $this->orderby :
'c.date_creation DESC').' '."LIMIT $this->start,$this->limit ";
return $requete;
}
private function creerSousRequeteRechercheParCriteres($criteres) {
$requete = '';
foreach ($criteres as $pair) {
$nom_valeur = explode("=",$pair);
if (sizeof($nom_valeur) != 0) {
switch ($nom_valeur[0]) {
case "ci_limite" : $this->limit = Cel::db()->quote($nom_valeur[1]); break;
case "c.ci_numero_page" : $this->limit*Cel::db()->quote($nom_valeur[1]); break;
case "c.commentaire" : $mots_comment_liste = explode(" " , $nom_valeur[1]);
foreach($mots_comment_liste as $mot_comment) {
$mot_comment = trim($mot_comment) ;
$requete .= $nom_valeur[0].' LIKE '.Cel::db()->quote('%'.$mot_comment.'%').' AND ';
}
break;
case "c.date_prise_de_vue" :
$nom_valeur[1] = str_replace('/', '-', $nom_valeur[1]);
if (preg_match('/(^[0-9]{2})-([0-9]{2})-([0-9]{4}$)/', $nom_valeur[1], $matches)) {
$nom_valeur[1] = $matches[3].'-'.$matches[2].'-'.$matches[1];
}
$requete .= $nom_valeur[0].' LIKE '.Cel::db()->quote($nom_valeur[1]."%").' AND '; break;
case "b.ce_zone_geo" :
$requete .= ' ('.$nom_valeur[0].' LIKE "%'.$nom_valeur[1].'%") AND '; break;
case "b.nom_ret" :
if ($nom_valeur[1] == "indetermine") $nom_valeur[1] = 'null';
$requete .= ' ('.$nom_valeur[0].' LIKE "%'.$nom_valeur[1].'%" OR b.nom_sel LIKE "%'.
$nom_valeur[1].'%") AND '; break;
case "tag" : $requete .= $this->creerSousRequeteMotsCles($nom_valeur[1]).' AND '; break;
case "projet" : $requete .= $this->creerSousRequeteProjet($nom_valeur[1]).' AND '; break;
case "referentiel" : $requete .= $this->creerSousRequeteReferentiel($nom_valeur[1]).' AND '; break;
case "groupe_zones_geo" : $requete .= $this->creerSousRequeteGroupeZonesGeo($nom_valeur[1])." AND "; break;
default : $requete .= $nom_valeur[0].' = "'.$nom_valeur[1].'" AND '; break;
}
}
}
$requete = rtrim($requete,' AND ');
return $requete;
}
private function creerSousRequeteGroupeZonesGeo($groupe_zones_geo) {
$req = "SELECT valeur FROM cel_groupes_zones WHERE id_groupe = ".Cel::db()->proteger($groupe_zones_geo);
$res = Cel::db()->requeter($req);
$zones = array();
foreach($res as &$r) {
$zones[] = Cel::db()->proteger($r['valeur']);
}
$sql = '(b.ce_zone_geo IN ('.implode(',', $zones).')) ';
return $sql;
}
private function creerSousRequeteMotsCles($mot_cle) {
$requete = '';
if (preg_match('/.*OU.*/', $mot_cle)) {
$mots_cles_tab = explode('OU',$mot_cle);
foreach($mots_cles_tab as $mot_cle_item) {
$requete .= '(c.mots_cles_texte LIKE '.Cel::db()->proteger('%'.$mot_cle_item.'%').') OR ';
}
$requete = '('.rtrim($requete,'OR ').')';
} else if (preg_match('/.*ET.*/', $mot_cle)) {
$mots_cles_tab = explode('ET',$mot_cle);
foreach($mots_cles_tab as $mot_cle_item) {
$requete .= '(c.mots_cles_texte LIKE '.Cel::db()->proteger('%'.$mot_cle_item.'%').') AND ';
}
$requete = '('.rtrim($requete, 'AND ').') ';
} else {
$requete = "(c.mots_cles_texte LIKE ".Cel::db()->proteger('%'.$mot_cle.'%').') ';
}
return $requete;
}
private function creerSousRequeteProjet($mot_cle) {
$requete = '';
if (preg_match('/.*OU.*/', $mot_cle)) {
$mots_cles_tab = explode('OU',$mot_cle);
foreach($mots_cles_tab as $mot_cle_item) {
$requete .= '(b.mots_cles_texte LIKE '.Cel::db()->proteger('%'.$mot_cle_item.'%').') OR ';
}
$requete = '('.rtrim($requete,'OR ').')';
} else if (preg_match('/.*ET.*/', $mot_cle)) {
$mots_cles_tab = explode('ET',$mot_cle);
foreach($mots_cles_tab as $mot_cle_item) {
$requete .= '(b.mots_cles_texte LIKE '.Cel::db()->proteger('%'.$mot_cle_item.'%').') AND ';
}
$requete = '('.rtrim($requete, 'AND ').') ';
} else {
$requete = "(b.mots_cles_texte LIKE ".Cel::db()->proteger('%'.$mot_cle.'%').') ';
}
return $requete;
}
private function creerSousRequeteReferentiel($referentiel) {
$requete = "b.nom_referentiel LIKE '$referentiel%'";
return $requete;
}
private function creerSousRequeteRechercheGenerale($chaine_requete) {
$requete = '';
$chaine_requete = Cel::deb()->proteger($chaine_requete.'%');
if (trim($chaine_requete) != '') {
$chaine_requete = strtolower($chaine_requete);
$chaine_requete = str_replace(' ', '_', $chaine_requete);
$requete = ' ('.
'b.nom_ret LIKE '.$chaine_requete.
' OR '.
'b.nom_sel LIKE '.$chaine_requete.
' OR '.
'b.zone_geo LIKE '.$chaine_requete.
' OR '.
'b.ce_zone_geo LIKE INSEE-C:'.$chaine_requete.
' OR '.
'b.ce_zone_geo LIKE '.$chaine_requete.
' OR '.
'b.ce_utilisateur LIKE '.$chaine_requete.
' OR '.
'b.courriel_utilisateur LIKE '.$chaine_requete.
' OR '.
'b.mots_cles_texte LIKE '.$chaine_requete.
') ';
}
return $requete;
}
private function estUneRechercheGenerale() {
return isset($_GET['recherche']);
}
private function traiterCriteresMultiples($tableau_criteres) {
$tableau_criteres_pour_bdd = array();
foreach($tableau_criteres as $nom_critere => $valeur_critere) {
if (isset($this->criteres[$nom_critere])) {
//$valeur_critere = Cel::db()->proteger($valeur_critere);
$tableau_criteres_pour_bdd[] = $this->criteres[$nom_critere].'='.$valeur_critere;
}
}
return $tableau_criteres_pour_bdd;
}
private function creerDescriptionComplet($donnees, $item) {
$auteur = $this->getIntituleAuteur($donnees['courriel_utilisateur']);
$auteur_mail = $donnees['courriel_utilisateur'];
$id_img = $donnees['id_image'];
$nom_fichier = $donnees['nom_original'];
$url_img = $this->getUrlImage($donnees['id_image'], 'CS');
$url_img_normale = $this->getUrlImage($donnees['id_image'], 'XL');
//
$mots_cles_image = $donnees['mots_cles_texte_images'];
$note = ($donnees['note_qualite'] +1).'/5';
$commentaire_img = $donnees['commentaire_img'];
$id_obs = $donnees['id_observation'];
$famille = $donnees['famille'];
$nom_saisi = $donnees['nom_sel'];
$nom_retenu = $donnees['nom_ret'];
//
$mots_cles_obs = $donnees['mots_cles_texte_obs'];
$lieu = $this->formaterZoneGeoEtCodePourAffichage($donnees).' > '.$donnees['lieudit'].' > '.$donnees['station'];
$milieu = $donnees['milieu'];
$coordonnees = ($this->etreNull($donnees['latitude']) && $this->etreNull($donnees['longitude'])) ? '' : $donnees['latitude'].'/'.$donnees['longitude'];
$commentaire_obs = $donnees['commentaire_obs'];
$date_observation = $this->formaterDate($donnees['date_observation'], '%A %d %B %Y');
$date_transmission = $this->formaterDate($donnees['date_transmission']);
$date_modification = $this->formaterDate($donnees['date_modification']);
$date_creation = $this->formaterDate($donnees['date_creation']);
$transmission = $donnees['transmission'] == 1 ? "oui ($date_transmission)" : 'non';
$description = '<style>.champ{color:grey} .gauche{float:left;padding:0 20px 0 0;} ul{list-style-type:none;padding:0;}</style>'.
'<h2>'.(!$this->etreNull($id_obs) ? "Image #$id_img liée à l'observation #$id_obs" : "Image #$id_img non liée à une observation.").'</h2>'.
'<a href="'.$url_img_normale.'"><img class="gauche" src="'.$url_img.'" alt="'.$nom_fichier.'" /></a>'.
'<div class="gauche">'.
'<h3>'.'Image'.'</h3>'.
'<ul>'.
'<li>'.'<span class="champ">URL :</span> <a href="'.$url_img_normale.'.jpg" onclick="javascript:window.open(this.href);return false;">'.$url_img_normale.'</a></li>'.
'<li>'.'<span class="champ">Importée le :</span> '.$item['date_maj_simple'].'</li>'.
'<li>'.'<span class="champ">Par :</span> '.
(($this->etreFluxAdmin()) ? '<a href="mailto:'.$auteur_mail.'">'.$auteur.'</a>' : $auteur).
'</li>'.
'<li>'.'<span class="champ">Nom du fichier :</span> '.$this->nePasInterpreterXml($nom_fichier).'</li>'.
'<li>'.'<span class="champ">Note qualité :</span> '.$note.'</li>'.
'<li>'.'<span class="champ">Commentaires :</span> '.$this->nePasInterpreterXml($commentaire_img).'</li>'.
'<li>'.'<span class="champ">Mots-clés :</span> '.$this->nePasInterpreterXml($mots_cles_image).'</li>'.
'</ul>'.
'</div>';
// TODO : ajouter le champ commentaire EXIF.
if (! $this->etreNull($id_obs)) {
$description .=
'<div class="gauche">'.
'<h3>'.'Observation'.'</h3>'.
'<ul>'.
'<li>'.'<span class="champ">Famille :</span> '.$famille.'</li>'.
'<li>'.'<span class="champ">Nom saisi :</span> '.$nom_saisi.'</li>'.
'<li>'.'<span class="champ">Nom retenu :</span> '.$nom_retenu.'</li>'.
'<li>'.'<span class="champ">Observée le :</span> '.$date_observation.'</li>'.
'<li>'.'<span class="champ">Lieu :</span> '.$lieu.'</li>'.
'<li>'.'<span class="champ">Milieu :</span> '.$milieu.'</li>'.
(($this->etreFluxAdmin()) ? '<li><span class="champ">Coordonnées (Lat/Long) :</span> '.$coordonnees.'</li>' : '').
'<li>'.'<span class="champ">Commentaire :</span> '.$this->nePasInterpreterXml($commentaire_obs).'</li>'.
'<li>'.'<span class="champ">Mots-clés :</span> '.$this->nePasInterpreterXml($mots_cles_obs).'</li>'.
(($this->etreFluxAdmin()) ? '<li><span class="champ">Transmis (= public) :</span> '.$transmission.'</li>' : '').
'<li><span class="champ">Modifiée le :</span> '.$date_modification.'</li>'.
'<li><span class="champ">Créée le :</span> '.$date_creation.'</li>'.
'</ul>'.
'</div>';
}
$description = $this->nettoyerTexte($description);
return $description;
}
private function getServiceParMotsCles() {
$infos=array();
$infos[0]['nom_sel_nn'] = '';
$infos[0]['date_creation'] = '2011-06-28';
$donnees = $this->construireDonneesCommunesAuFlux($infos);
$donnees['items'][0]['guid'] = 0;
$donnees['items'][0]['description'] = 'Ce flux est devenu obsolète. Veuillez utiliser le flux '.
'<b>http://www.tela-botanica.org/eflore/cel2/jrest/CelSyndicationImage/multicriteres/atom?tag=';
if (isset($this->parametres[0])) {
$donnees['items'][0]['description'] .= $this->parametres[0].'</b>';
} else {
$donnees['items'][0]['description'] .= '</b>';
}
$donnees['items'][0]['titre'] = '';
$contenu = Cel::traiterSquelettePhp($this->squelette, $donnees);
return $contenu;
}
private function getServiceParCommune() {
$infos=array();
$infos[0]['nom_sel_nn'] = '';
$infos[0]['date_creation'] = '2011-06-28';
$donnees = $this->construireDonneesCommunesAuFlux($infos);
$donnees['items'][0]['guid'] = 0;
$donnees['items'][0]['description'] = 'Ce flux est devenu obsolète. Veuillez utiliser le flux '.
'<b>http://www.tela-botanica.org/eflore/cel2/jrest/CelSyndicationImage/multicriteres/atom?commune=';
if (isset($this->parametres[0])) {
$donnees['items'][0]['description'] .= $this->parametres[0].'</b>';
} else {
$donnees['items'][0]['description'] .= '</b>';
}
$donnees['items'][0]['titre'] = '';
$contenu = Cel::traiterSquelettePhp($this->squelette, $donnees);
return $contenu;
}
private function getIntituleAuteur($courriel) {
$courriel = strtolower($courriel);
$intitule = $this->auteurs[$courriel];
return $intitule;
}
}
Property changes:
Added: svnkit:entry:sha1-checksum
+fa20e6a48864ce5bd735373255bf3791ac58bdb3
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/ImageDateList.php
New file
0,0 → 1,82
<?php
// declare(encoding='UTF-8');
/**
* Liste les date des images par utilisateur.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 ImageDateList extends Cel {
 
private $correspondance_fonction = array(1 => 'year', 2 => 'month', 3 => 'day');
 
/**
* uid[0] : utilisateur obligatoire
* uid[1] : si absent : valeur 'all' (annee)
* uid[2] : si absent : valeur 'all' (mois)
* uid[3] : si absent : valeur 'all' (jour)
*/
public function getElement($uid){
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
if (!is_numeric($uid[0])) {
return;
}
 
$conditions = $this->traiterParametresEtConstruireRequete($uid);
 
$requete_liste_dates = 'SELECT DISTINCT date_prise_de_vue AS id '.
'FROM cel_images '.
"WHERE $conditions ".
'ORDER BY date_prise_de_vue '.
' -- '.__FILE__.':'.__LINE__;
 
$liste_dates = Cel::db()->requeter($requete_liste_dates);
$liste_dates = $this->formaterListeResultats($liste_dates);
$this->envoyerJson($liste_dates);
return true;
}
 
private function formaterListeResultats($liste_dates) {
if (!$liste_dates) {
$liste_dates = array();
}
 
foreach($liste_dates as &$date) {
if ($date['id'] == null || trim($date['id']) == '' || $date['id'] == 'null') {
$date = '0000-00-00';
} else {
$date_heures = explode(' ',$date['id']);
$date = (count($date_heures) > 1) ? $date_heures[0] : $date['id'];
}
}
return $liste_dates;
}
 
private function traiterParametresEtConstruireRequete($params) {
$conditions = ' ce_utilisateur = '.Cel::db()->proteger($params[0]);
 
$taille_tableau_parametres = count($params);
for ($i = 1; $i < $taille_tableau_parametres; $i++) {
if ($this->estUnParametreDate($params[$i])) {
$fonction_date = $this->correspondance_fonction[$i];
$conditions .= ' AND '.$fonction_date.'(date_prise_de_vue) = '.Cel::db()->proteger($params[$i]);
}
}
return $conditions;
}
 
private function estUnParametreDate($valeur) {
return is_numeric($valeur) && $valeur != 'all';
}
}
/branches/v3.01-serpe/jrest/services/CelStreets.php
New file
0,0 → 1,341
<?php
class CelStreets extends Cel {
 
/**
* Méthode appelée avec une requête de type GET.
*/
public function getRessource() {
$this->getStreetGeom();
}
private function getStreetGeom() {
$erreurs = $this->verifierParametres();
if(!empty($erreurs)) {
$this->envoyerMessageErreur(400, implode("\n", $erreurs));
exit;
}
$latitude_debut = $_GET['latitude_debut'];
$longitude_debut = $_GET['longitude_debut'];
$latitude_fin = $_GET['latitude_fin'];
$longitude_fin = $_GET['longitude_fin'];
$dist_max = round(self::haversineGreatCircleDistance($latitude_debut, $longitude_debut, $latitude_fin, $longitude_fin)/2);
 
$url_tpl = $this->getUrlRequeteOverPass().urlencode($this->getRequetePasLoin($latitude_debut, $longitude_debut, $latitude_fin, $longitude_fin, $dist_max));
$json = file_get_contents($url_tpl);
$infos = json_decode($json, true);
$this->filtrerNoeuds($infos, $latitude_debut, $longitude_debut, $latitude_fin, $longitude_fin);
header('Content-type: application/json');
echo json_encode($infos); exit;
}
private function verifierParametres() {
$parametres_obligatoires = array('latitude_debut', 'longitude_debut', 'latitude_fin', 'longitude_fin');
$erreurs = array();
foreach($parametres_obligatoires as $param) {
if(empty($_GET[$param]) || !is_numeric($_GET[$param])) {
$erreurs[] = "Le paramètre $param est obligatoire et doit être un flottant";
}
}
return $erreurs;
}
function getUrlRequeteOverPass() {
return $this->config['cel']['url_service_rue'];
}
function getRequetePasLoin($latitude_debut, $longitude_debut, $latitude_fin, $longitude_fin, $dist = 50) {
$req = 'way["highway"]
(around:'.$dist.','.$latitude_debut.','.$longitude_debut.')
(around:'.$dist.','.$latitude_fin.','.$longitude_fin.')
;
(
._;
>;
);
out geom;';
return $req;
}
function getRequete($nord, $sud, $est, $ouest) {
return '(
way["highway"]
('.$sud.','.$ouest.','.$nord.','.$est.');
>;
);out geom;';
}
function filtrerNoeuds(&$infos, $latitude_debut, $longitude_debut, $latitude_fin, $longitude_fin) {
$distances_debut = array();
$distances_fin = array();
foreach($infos['elements'] as $index_e => &$element) {
if(empty($element['geometry'])) {
unset($infos['elements'][$index_e]);
} else {
$index_fin_tableau = count($element['geometry']) - 1;
$distances_debut[$index_e] = -1;
$distances_fin[$index_e] = -1;
$index_point_plus_proche_debut = 0;
$dist_point_plus_proche_debut = 999999999;
$index_point_plus_proche_fin = $index_fin_tableau;
$dist_point_plus_proche_fin = 9999999999;
$index_debut = array(0, 1);
$index_fin = array($index_fin_tableau -1, $index_fin_tableau);
$element['geometryOrig'] = $element['geometry'];
foreach($element['geometry'] as $index_g => &$geometry) {
// Calcul de la plus petite distance de la droite de rue au point
// pour sélectionner la rue la plus proche des deux points
if($index_g + 1 < count($element['geometry'])) {
$geom_next = $element['geometry'][$index_g + 1];
$this->stockerDistancePlusCourte($distances_debut, $index_debut, $index_e, $index_g, $geometry, $geom_next, $latitude_debut, $longitude_debut);
$this->stockerDistancePlusCourte($distances_fin, $index_fin, $index_e, $index_g, $geometry, $geom_next, $latitude_fin, $longitude_fin);
}
$dist_debut= self::haversineGreatCircleDistance($latitude_debut, $longitude_debut, $geometry['lat'], $geometry['lon']);
$dist_fin = self::haversineGreatCircleDistance($latitude_fin, $longitude_fin, $geometry['lat'], $geometry['lon']);
if($dist_point_plus_proche_debut > $dist_debut) {
$dist_point_plus_proche_debut = $dist_debut;
$index_point_plus_proche_debut = $index_g;
}
if($dist_point_plus_proche_fin > $dist_fin) {
$dist_point_plus_proche_fin = $dist_fin;
$index_point_plus_proche_fin = $index_g;
}
}
$index_min = min($index_point_plus_proche_debut, $index_point_plus_proche_fin);
$index_max = max($index_point_plus_proche_debut, $index_point_plus_proche_fin);
$infos_debut = array('lat' => (float)$latitude_debut, 'lon' => (float)$longitude_debut);
$infos_fin = array('lat' => (float)$latitude_fin, 'lon' => (float)$longitude_fin);
// Inversion des points de début et de fin si le début donné par l'utilisateur est plus
// proche de la fin
if($index_min != $index_point_plus_proche_debut) {
$tmp = $infos_debut;
$infos_debut = $infos_fin;
$infos_fin = $tmp;
}
// Projection des points de début et d'arrivée sur le segment de rue
if($index_min < $index_fin_tableau) {
$proj_debut = $this->getOrthoPoint($element['geometry'][$index_min], $element['geometry'][$index_min+1], $infos_debut);
$index_insertion_point_debut = $this->getIndexInsertionDebut($element, $index_min, $infos_debut);
} else {
$proj_debut = $infos_debut;
$index_insertion_point_debut = 0;
}
if($index_max > 0) {
$proj_fin = $this->getOrthoPoint($element['geometry'][$index_max], $element['geometry'][$index_max-1], $infos_fin);
$index_insertion_point_fin = $this->getIndexInsertionFin($element, $index_max, $infos_fin);
} else {
$proj_fin = $infos_fin;
$index_insertion_point_fin = $index_fin_tableau;
}
 
$index_insertion_point_debut = $index_insertion_point_debut < 0 ? 0 : $index_insertion_point_debut;
$index_insertion_point_fin = $index_insertion_point_fin > $index_fin_tableau ? $index_fin_tableau : $index_insertion_point_fin;
$rd = array();
for($ii = $index_insertion_point_debut+1; $ii <= $index_insertion_point_fin; $ii++) {
$rd[] = $element['geometry'][$ii];
}
$proj_debut = $infos_debut;
$proj_fin = $infos_fin;
// Insertion des points utilisateurs en début et fin de tableau
array_unshift($rd, $proj_debut);
array_push($rd, $proj_fin);
$element['geometry'] = $rd;
}
}
if(!empty($distances_debut)) {
asort($distances_debut);
reset($distances_debut);
$cle_plus_courte_debut = key($distances_debut);
}
if(!empty($distances_fin)) {
asort($distances_fin);
reset($distances_fin);
$cle_plus_courte_fin = key($distances_fin);
}
if(!empty($distances_fin)) {
$cle_choisie = $this->choisirIndexRuePlusProchePourDebutEtFin($cle_plus_courte_debut, $cle_plus_courte_fin, $distances_debut, $distances_fin);
$rue_plus_proche = $distances_fin[$cle_choisie];
unset($distances_fin[$cle_choisie]);
$distances_fin = array($cle_choisie => $rue_plus_proche) + $distances_fin;
}
$elements_fmt = array();
foreach($distances_fin as $index => $distance) {
//echo '<pre>'.print_r($infos['elements'][$index], true).'</pre>';exit;
$rue_proche = $infos['elements'][$index];
$rue_proche['dist_min'] = $distance;
$elements_fmt[] = $rue_proche;
}
$infos['elements'] = $elements_fmt;
}
function choisirIndexRuePlusProchePourDebutEtFin($cle_plus_courte_debut, $cle_plus_courte_fin, $distances_debut, $distances_fin) {
$cle_choisie = $cle_plus_courte_fin;
// Si la rue la plus proche n'est pas la même pour les deux points
if($cle_plus_courte_debut != $cle_plus_courte_fin) {
// on calcule celle qui est la mieux positionnée en moyenne
$index_debut_tab_debut = array_search($cle_plus_courte_debut, array_keys($distances_debut));
$index_debut_tab_fin = array_search($cle_plus_courte_debut, array_keys($distances_fin));
$index_fin_tab_debut = array_search($cle_plus_courte_fin, array_keys($distances_debut));
$index_fin_tab_fin = array_search($cle_plus_courte_fin, array_keys($distances_fin));
$moy_index_debut = ($index_debut_tab_debut + $index_debut_tab_fin)/2;
$moy_index_fin = ($index_fin_tab_debut + $index_fin_tab_fin)/2;
$cle_choisie = ($moy_index_debut < $moy_index_fin) ? $cle_plus_courte_debut : $cle_plus_courte_fin;
// Si ça ne suffit pas on prend celle qui a la distance moyenne la plus courte aux deux points
if ($moy_index_debut == $moy_index_fin) {
$moyenne_dist_cle_debut = ($distances_debut[$cle_plus_courte_debut] + $distances_fin[$cle_plus_courte_debut])/2;
$moyenne_dist_cle_fin = ($distances_debut[$cle_plus_courte_fin] + $distances_fin[$cle_plus_courte_fin])/2;
$cle_choisie = ($moyenne_dist_cle_debut < $moyenne_dist_cle_fin) ? $cle_plus_courte_debut : $cle_plus_courte_fin;
}
}
return $cle_choisie;
}
function getIndexInsertionDebut($element, $index_min, $debut) {
// le point de début est situé entre $index_min et $index_min + 1
$proj_debut = $this->getOrthoPoint($element['geometry'][$index_min], $element['geometry'][$index_min+1], $debut);
$point_deb = $element['geometry'][$index_min];
$point_deb_plus_un = $element['geometry'][$index_min+1];
$distance_point_deb_plus_un_proj = self::haversineGreatCircleDistance($point_deb_plus_un['lat'], $point_deb_plus_un['lon'], $proj_debut['lat'], $proj_debut['lon']);
$distance_point_deb_deb_plus_un = self::haversineGreatCircleDistance($point_deb['lat'], $point_deb['lon'], $point_deb_plus_un['lat'], $point_deb_plus_un['lon']);
if($distance_point_deb_plus_un_proj < $distance_point_deb_deb_plus_un) {
// le point le plus proche doit être éliminé
return $index_min + 1;
} else {
// il doit être gardé
return $index_min;
}
}
function getIndexInsertionFin($element, $index_max, $fin) {
$proj_fin = $this->getOrthoPoint($element['geometry'][$index_max], $element['geometry'][$index_max-1], $fin);
$point_fin = $element['geometry'][$index_max];
$point_fin_moins_un = $element['geometry'][$index_max-1];
$distance_point_fin_moins_un_proj = self::haversineGreatCircleDistance($point_fin_moins_un['lat'], $point_fin_moins_un['lon'], $proj_fin['lat'], $proj_fin['lon']);
$distance_point_fin_fin_moins_un = self::haversineGreatCircleDistance($point_fin['lat'], $point_fin['lon'], $point_fin_moins_un['lat'], $point_fin_moins_un['lon']);
if($distance_point_fin_moins_un_proj < $distance_point_fin_fin_moins_un) {
// le point le plus proche doit être éliminé
return $index_max - 1;
} else {
// il doit être gardé
return $index_max;
}
}
function stockerDistancePlusCourte(&$distances, &$infos_index_position_point, $index_e, $index_g, $geometry, $geom_next, $latitude_point, $longitude_point) {
$a = $geometry['lat'];
$b = $geometry['lon'];
$c = $geom_next['lat'];
$d = $geom_next['lon'];
$x = $latitude_point ;
$y = $longitude_point ;
$dist = $this->getShortestDistance($a, $b, $c, $d, $x, $y);
if($distances[$index_e] == -1 || $dist < $distances[$index_e]) {
$distances[$index_e] = $dist;
$infos_index_position_point = array($index_g, $index_g+1);
}
}
// projette le point C sur le segment AB
function getOrthoPoint($a, $b, $c) {
$x1 = $a['lat'];
$y1 = $a['lon'];
$x2 = $b['lat'];
$y2 = $b['lon'];
$x3 = $c['lat'];
$y3 = $c['lon'];
$px = $x2-$x1;
$py = $y2-$y1;
$dAB = $px*$px + $py*$py;
$u = (($x3 - $x1) * $px + ($y3 - $y1) * $py) / $dAB;
$x = $x1 + $u * $px;
$y = $y1 + $u * $py;
return array('lat' => $x, 'lon' => $y);
}
function getShortestDistance($a, $b, $c, $d, $x, $y) {
//Coordinates are (a,b) and (c,d)
//the point (x,y) is the required point.
//echo 'nagi ';
//echo $c.' - '.$a." = ".($c-$a).'<br />';
if(($c-$a) == 0) {
return 56465465456485;
}
$m=($d-$b)/($c-$a);
//echo $m."\n";
//echo $y-($m*$x)-$b+($m*$a)."\n";
$distance=abs($y-($m*$x)-$b+($m*$a))/sqrt(1+($m*$m));
return $distance;
}
function haversineGreatCircleDistance(
$latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo, $earthRadius = 6371000)
{
// convert from degrees to radians
$latFrom = deg2rad($latitudeFrom);
$lonFrom = deg2rad($longitudeFrom);
$latTo = deg2rad($latitudeTo);
$lonTo = deg2rad($longitudeTo);
$latDelta = $latTo - $latFrom;
$lonDelta = $lonTo - $lonFrom;
$angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
return $angle * $earthRadius;
}
public static function vincentyGreatCircleDistance($latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo, $earthRadius = 6371000)
{
// convert from degrees to radians
$latFrom = deg2rad($latitudeFrom);
$lonFrom = deg2rad($longitudeFrom);
$latTo = deg2rad($latitudeTo);
$lonTo = deg2rad($longitudeTo);
$lonDelta = $lonTo - $lonFrom;
$a = pow(cos($latTo) * sin($lonDelta), 2) +
pow(cos($latFrom) * sin($latTo) - sin($latFrom) * cos($latTo) * cos($lonDelta), 2);
$b = sin($latFrom) * sin($latTo) + cos($latFrom) * cos($latTo) * cos($lonDelta);
$angle = atan2(sqrt($a), $b);
return $angle * $earthRadius;
}
}
?>
/branches/v3.01-serpe/jrest/services/InventoryTransmit.php
New file
0,0 → 1,100
<?php
// declare(encoding='UTF-8');
/**
* Service rendant publique une observation.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @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 InventoryTransmit extends Cel {
 
private $idUtilisateur = null;
private $ordres = null;
 
public function updateElement($ressources, $data) {
$this->verifierRessources($ressources);
$this->verifierData($data);
 
$transmission = intval($data['transmission']) == 1 ? true : false;
$idsObs = $this->getIdsObs();
 
$gestionnaireObs = new GestionObservation($this->config);
$resultatObs = $gestionnaireObs->modifierTransmissionObservation($idsObs, $transmission);
if ($resultatObs === false) {
$idsObsConcat = implode(', ', $idsObs);
$msg = "Un problème est survenu (voir log). Les observations « $idsObsConcat » n'ont pas pu être dépubliées.";
$this->envoyerMessageErreur(304, $msg);
}
 
$gestionnaireImg = new GestionImage($this->config);
$resultatImg = $gestionnaireImg->modifierTransmissionParObs($idsObs, $transmission);
if ($resultatImg === false) {
$idsObsConcat = implode(', ', $idsObs);
$msg = "Un problème est survenu (voir log). Les images liées aux obs « $idsObsConcat » n'ont pas pu être dépubliées.";
$this->envoyerMessageErreur(304, $msg);
}
 
return ($resultatObs != 0 && $resultatImg != 0);
}
 
private function verifierRessources($ressources) {
if (!isset($ressources[0])) {
return false;
} else {
$this->controleUtilisateur($ressources[0]);
$this->idUtilisateur = $ressources[0];
}
if (!isset($ressources[1])) {
return false;
} else {
$this->ordres = $ressources[1];
}
}
 
private function verifierData($data) {
$transmission = (int) $data['transmission'];
if ($transmission != 0 && $transmission != 1) {
return false;
}
}
 
private function getIdsObs() {
$idUtilisateurP = Cel::db()->proteger($this->idUtilisateur);
$ordres = $this->nettoyerOrdres();
$ordreConcat = implode(',', $ordres);
 
$requete = 'SELECT id_observation '.
'FROM cel_obs '.
"WHERE ce_utilisateur = $idUtilisateurP ".
"AND ordre IN ($ordreConcat) ".
' -- '.__FILE__.':'.__LINE__;
$resultats = Cel::db()->requeter($requete);
$idsObs = array();
if ($resultats && is_array($resultats)) {
foreach ($resultats as $infos) {
$idsObs[] = $infos['id_observation'];
}
}
return $idsObs;
}
 
private function nettoyerOrdres() {
$ordres = explode(',', $this->ordres);
$ordresNettoyes = array();
foreach ($ordres as $ordre) {
if (preg_match('/^\d+$/', $ordre)) {
$ordresNettoyes[] = $ordre;
}
}
return $ordresNettoyes;
}
}
Property changes:
Added: svnkit:entry:sha1-checksum
+fd2a35dcbfc45ca8609a23242b84a35322fa7a91
\ No newline at end of property
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/SelfRefList.php
New file
0,0 → 1,95
<?php
// declare(encoding='UTF-8');
/**
* Fournit une liste d'auto-complétions (=référentiel) relative à l'utilisateur sur l'un des champs demandés.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Auto-complétions
* @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 SelfRefList extends Cel {
 
private $referentiels = array('station', 'lieudit', 'milieu');
 
/**
* Suivant le type de référentiel donné en paramètre, renvoie les liste de ses éléments
*
* uid[0] : utilisateur obligatoire
* uid[1] : referentiel demandé (obligatoire)
* $_GET["start"] et $GET_["limit"] : selection intervalle
* $_GET["recherche"] : cherche les noms qui commmencent selon la valeur
*
*/
public function getElement($uid){
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
if (!$this->paramObligatoiresSontPresents($uid)) {
return;
}
 
if ($_GET['recherche'] == '*') {
$_GET['recherche'] = '%';
}
 
$referentiel_demande = $uid[1];
$idUtilisateurP = Cel::db()->proteger($uid[0]);
 
$filtreSql = '';
if ($this->filtreRechercheEstDemande()) {
$rechercheP = Cel::db()->proteger($_GET['recherche'].'%');
$filtreSql = "AND $referentiel_demande LIKE $rechercheP ";
}
 
$limiteSql = '';
if ($this->limiteEstDemandee()) {
$start = intval($_GET['start']);
$limit = intval($_GET['limit']);
$limite = "LIMIT $start,$limit ";
}
 
$requete = "SELECT DISTINCT $referentiel_demande " .
'FROM cel_obs '.
"WHERE ce_utilisateur = $idUtilisateurP ".
$filtreSql.
"ORDER BY $referentiel_demande ".
$limiteSql.
' -- '.__FILE__.':'.__LINE__;
$resultat = Cel::db()->requeter($requete);
 
$referentiel = array();
if (is_array($resultat)) {
foreach ($resultat as $cle => $valeur) {
if ($this->estUneValeurValide($valeur[$referentiel_demande])) {
$referentiel[] = $valeur[$referentiel_demande];
}
}
}
$this->envoyerJson($referentiel);
return true;
}
 
private function paramObligatoiresSontPresents($uid) {
return (isset($uid[1]) && in_array($uid[1], $this->referentiels) && (isset($uid[0]) && $uid[0] != ''));
}
 
private function filtreRechercheEstDemande() {
return (isset($_GET['recherche']) && trim($_GET['recherche']) != '');
}
 
private function limiteEstDemandee() {
return isset($_GET['start']) && is_numeric($_GET['start']) && isset($_GET['limit']) && is_numeric($_GET['limit']);
}
 
private function estUneValeurValide($chaine) {
return ($chaine != null && $chaine != '000null' && trim($chaine) != '');
}
}
Property changes:
Added: svnkit:entry:sha1-checksum
+3cf82d4f4dd79608a8b682a0abbc1d314fd668bb
\ No newline at end of property
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/InventoryObservationCount.php
New file
0,0 → 1,37
<?php
// declare(encoding='UTF-8');
/**
* Service recherche du nombre a partir de divers critères
*
* 2: Le service recherche le nombre d'observations correspondant aux critères demandés
* 3: Le service renvoie le nombre calcule
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @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 InventoryObservationCount extends Cel {
 
/**
* Renvoie le nombre d' observations correspondant aux critères
* uid[0] : utilisateur obligatoire
* uid[1] : criteres de filtrage de la forme critere1=valeur1&critere2=valeur2
*/
public function getElement($uid) {
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
$chercheurObs = new RechercheObservation($this->config);
$retour = $chercheurObs->compterObservations($uid[0], $_GET);
$this->envoyerJson($retour);
return true;
}
}
/branches/v3.01-serpe/jrest/services/InventoryLocationList.php
New file
0,0 → 1,36
<?php
// declare(encoding='UTF-8');
/**
* Service de listage des zones géographiques d'un utilisateur
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @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 InventoryLocationList extends Cel {
 
public function getElement($uid) {
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
$idUtilisateurP = Cel::db()->proteger($uid[0]);
 
$requete = 'SELECT DISTINCT pays, ce_zone_geo, zone_geo, lieudit, station '.
'FROM cel_obs '.
"WHERE ce_utilisateur = $idUtilisateurP ".
'ORDER BY pays ASC, ce_zone_geo ASC, zone_geo ASC, lieudit ASC, station ASC '.
' -- '.__FILE__.':'.__LINE__;
$resultats = Cel::db()->requeter($requete);
 
$retour = (is_array($resultats)) ? $resultats : array();
$this->envoyerJson($retour);
return true;
}
}
/branches/v3.01-serpe/jrest/services/InventoryKeywordTree.php
New file
0,0 → 1,103
<?php
// declare(encoding='UTF-8');
/**
* Service permettant de créer l'arbre des mots-clés.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Mots-clés
* @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 InventoryKeywordTree extends Cel {
 
//TODO : verifications des paramètres
public static $gestion_mots_cles = null;
 
public function getElement($uid) {
// Controle detournement utilisateur
$id_utilisateur = $uid[1] ;
$this->controleUtilisateur($uid[1]);
 
$arbre = $this->getGestionMotsCles($uid[0])->obtenirArbre($id_utilisateur);
 
$this->envoyerJson($arbre);
return TRUE; // compat: pourquoi renvoyer true si vide ?
}
 
private function getGestionMotsCles($mode) {
if (self::$gestion_mots_cles == null) {
self::$gestion_mots_cles = new GestionMotsClesChemin($this->config, $mode);
}
return self::$gestion_mots_cles;
}
 
public function updateElement($uid, $pairs) {
$id_utilisateur = $uid[1];
$this->controleUtilisateur($uid[1]);
 
$id_mot_cle = $pairs['id'];
$action = $pairs['action'];
 
if ($action == 'modification') {
$nouveau_nom = $pairs['motcle'];
$modification = $this->getGestionMotsCles($uid[0])->renommerMotCle($id_mot_cle, $nouveau_nom);
} else if ($action == 'deplacement') {
$id_pere = $pairs['parent'];
$modification = $this->getGestionMotsCles($uid[0])->deplacerMotCle($id_mot_cle, $id_pere, $id_utilisateur);
}
 
$modification = ($modification !== false);
if ($modification) {
$this->envoyer('OK');
}
return $modification;
}
 
public function createElement($pairs) {
// Controle detournement utilisateur
$this->controleUtilisateur($pairs['identifiant']);
 
$mode = $pairs['mode'];
if ($mode != 'obs' && $mode != 'images') {
return;
}
 
$id_utilisateur = $pairs['identifiant'];
$mot_cle = $pairs['motcle'];
$id_parent = $pairs['parent'];
$id_nouveau_mot_cle = $this->getGestionMotsCles($mode)->insererParIdParent($mot_cle, $id_parent, $id_utilisateur);
 
if ($id_nouveau_mot_cle !== false) {
// on sort de self::createElement ==> JRest::(get|post) ==> JRest->created() qui fait header().
// or si nous dépassons ini_get(output_buffering) nous ne pouvons plus réécrire le code de retour
// HTTP, de plus, si ini_get(output_buffering) == off, nous enverrions un warning.
// d'où ce clone de JRest::created();
header('HTTP/1.0 201 Created');
echo $id_nouveau_mot_cle;
exit();
} else {
// cf ci-dessus: JRest::badRequest
header('HTTP/1.0 400 Bad Request');
exit();
}
}
 
public function deleteElement($uid) {
$mode = $uid[0];
$id_utilisateur = $uid[1];
$id_mot_cle = $uid[2];
 
$suppression = $this->getGestionMotsCles($mode)->supprimerMotCleParId($id_mot_cle, $id_utilisateur);
 
if ($suppression) {
$this->envoyer('OK');
}
}
}
/branches/v3.01-serpe/jrest/services/ImageContribution.php
New file
0,0 → 1,92
<?php
// declare(encoding='UTF-8');
/**
* Service renvoyant une liste HTML très succinte des images (et infos sur l'obs liée) d'un utilisateur.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 ImageContribution extends Cel {
 
/**
* Renvoi un petit bout de html contenant les dernières obs liées à
* une image d'un utilisateur
*
* @param string $uid[0] mail de l'utilisateur
* @param string $uid[1] identifiant numérique de l'utilisateur
*/
function getElement($uid){
$idUtilisateurP = Cel::db()->proteger($uid[1]);
$requete = 'SELECT co.*, ci.id_image, ci.nom_original, ci.largeur, ci.hauteur '.
'FROM cel_obs AS co INNER JOIN cel_images AS ci ON (id_observation = ce_observation) '.
"WHERE co.ce_utilisateur = $idUtilisateurP ".
'ORDER BY co.date_modification DESC '.
'LIMIT 0,5 '.
' -- '.__FILE__.':'.__LINE__;
$resultats = Cel::db()->requeter($requete);
 
$html = '<div id="resume_cel">';
if ($resultats !== false && is_array($resultats)) {
$urlImgTpl = $this->config['settings']['celImgUrlTpl'];
foreach ($resultats as $obs) {
$nom_ret = (!empty($obs['nom_ret'])) ? $obs['nom_ret'] : 'Indéterminée';
$obs['nom_original'] = htmlspecialchars($obs['nom_original']);
$obs['id_image'] = htmlspecialchars($obs['id_image']);
$obs['zone_geo'] = trim($obs['zone_geo'],'000null');
$obs['ce_zone_geo'] = trim($obs['ce_zone_geo'],'000null');
$obs['station'] = trim($obs['station'],'000null');
$obs['lieudit'] = trim($obs['lieudit'],'000null');
$id = $obs['id_image'];
 
list($largeur, $hauteur) = $this->calculerDimensions($obs['largeur'], $obs['hauteur']);
$id = sprintf('%09s', $id);
$urlImgL = sprintf($urlImgTpl, "{$id}L");
$urlImgS = sprintf($urlImgTpl, "{$id}S");
 
$html .= '<div class="item_resume_cel">'.
'<h4><a href="'.$urlImgL.'">'.$nom_ret.'</a></h4>'.
'<img src="'.$urlImgS.'" alt="'.$obs['nom_original'].'" height="'.$hauteur.'px" width="'.$largeur.'px" /><br/>'.
'<span>Datée du '.$obs['date_modification'].'<br/>'.
'Lieu : '.$obs['zone_geo'].' ('.$obs['ce_zone_geo'].') '.$obs['station'].' '.$obs['lieudit'].'<br/></p>'.
'</span>'.
'</div>';
}
}
$html .= '</div>';
 
header("Content-Type: text/html; charset=UTF-8");
print $html;
exit;
}
 
private function calculerDimensions($largeur, $hauteur) {
$tailleOr = 75 ;
if ($hauteur == 0) {
$hauteur = $tailleOr;
}
if ($largeur == 0) {
$largeur = $tailleOr;
}
$maxTaille = max($hauteur, $largeur);
 
if ($maxTaille == $hauteur) {
$rapport = $hauteur / $largeur;
$hauteur = 75;
$largeur = round($hauteur / $rapport, 0);
} else {
$rapport = $largeur / $hauteur;
$largeur = 75;
$hauteur = round($largeur / $rapport, 0);
}
return array($largeur, $hauteur);
}
}
/branches/v3.01-serpe/jrest/services/NameImage.php
New file
0,0 → 1,62
<?php
// declare(encoding='UTF-8');
/**
* Service recherche d'image a partir d'un numero nomenclatural.
*
* Cas d'utilisation :
* 1: Le service recoit un numero nomenclatural
* 2: Le service calcul le numero taxonomique associe
* 3: Le service recherche une image disponible pour ce numero taxonomique
* 4: Le service redimensionne l'image et la renvoie
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 NameImage extends Cel {
 
public function getElement($uid){
$image = array('', '');
if (isset($uid[0]) && isset($uid[1])) {
$uid[0] = $uid[0] != '' ? $uid[0] : 'bdtfx';
$image = $this->obtenirIllustration($uid[0], $uid[1]);
}
 
$this->envoyerJson($image);
return true;
}
 
private function obtenirIllustration($referentiel_taxo, $nn) {
// TODO: gérer ici les images d'autres référentiels si celles si sont disponibles
$retour = array('', '');
if ($referentiel_taxo == 'bdtfx') {
$retour = $this->effectuerRequetePhotoFlora($nn);
}
return $retour;
}
 
private function effectuerRequetePhotoFlora($nn) {
$url_photoflora = $this->config['eflore']['url_service_photoflora'];
$url = $url_photoflora.'?masque.nn='.$nn.'&navigation.limite=1';
$resultat = @file_get_contents($url);
$resultat = json_decode($resultat);
if (is_object($resultat) && isset($resultat->resultats)) {
$element = (array)$resultat->resultats;
$element = array_pop($element);
if(is_object($element)) {
$image = array($element->{'binaire.href'}, $element->{'binaire.hrefmax'});
} else {
$image = array('', '');
}
}
return $image;
}
}
/branches/v3.01-serpe/jrest/services/InventoryPDF.php
New file
0,0 → 1,209
<?php
// declare(encoding='UTF-8');
/**
* Service générant un PDF d'export des observations pour réaliser des étiquettes d'herbier.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Export
* @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>
*/
 
/** Constante stockant l'URL de la page d'accueil de Photoflora.*/
define('EF_URL_PHOTOFLORA', 'http://photoflora.free.fr/');
/** Constante stockant l'URL de la page de Photoflora affichant toutes les images d'un taxon donn.es.*/
define('EF_URL_PHOTOFLORA_TAXON', EF_URL_PHOTOFLORA.'FiTax.php?NumTaxon=%s');
/** Constante stockant l'URL du dossier de photoflora contenant les images miniatures.*/
define('EF_URL_PHOTOFLORA_IMG_MIN', 'http://www.tela-botanica.org/~photoflo/photos/%s/min/%s');
/** Constante stockant l'URL du dossier de photoflora contenant les images normale.*/
define('EF_URL_PHOTOFLORA_IMG_MAX', 'http://www.tela-botanica.org/~photoflo/photos/%s/max/%s');
/** Constante stockant l'expression r.guli.re r.cup.rant l'abr.viation du photographe et le nom du fichier.*/
define('EF_URL_PHOTOFLORA_REGEXP', '/\/photos\/([^\/]+)\/max\/(.+)$/');
/** Constante stockant l'URL du service XML de Photoflora.*/
define('EF_URL_PHOTOFLORA_SERVICE', EF_URL_PHOTOFLORA.'ef_photoflora.php?nt=%s');
 
class InventoryPDF extends Cel {
 
var $extendPDFProductor;
 
public function __construct($config) {
parent::__construct($config);
 
$this->config = $config;
// Pas d'heritage multiple en php :(
$this->extendPDFProductor = new PDFProductor();
$this->extendPDFProductor->initPDF();
}
 
/**
* uid[0] : utilisateur obligatoire
* uid[1] : si absent : valeur 'all' (commune)
* uid[2] : si absent : valeur 'all' (date)
* uid[3] : si absent : valeur 'all' (recherche libre)
* uid[4] : si absent : valeur 'all' (station)
*/
public function getElement($uid){
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
if (!isset($uid[1]) || $uid[1] == '' || $uid[1] == 'all' ) {
$uid[1] = 'all';
$requete_location = '';
} else {
$requete_location = ' AND location= '.Cel::db()->proteger($uid[1]).' ';
}
 
if (!isset($uid[2]) || $uid[2] == '' || $uid[2] == 'all') {
$uid[2] = 'all';
$requete_date = '';
} else {
$requete_date = ' AND date_observation= '.Cel::db()->proteger($uid[2]).' ';
}
 
if (!isset($uid[3]) || $uid[3] == '' || $uid[3] == 'all') {
$uid[3] = 'all';
$requete_libre = '';
} else {
$requete_libre = ' AND (nom_sel LIKE '.Cel::db()->proteger('%'.$uid[3].'%').
' OR nom_ret LIKE '.Cel::db()->proteger('%'.$uid[3].'%').
' OR station LIKE '.Cel::db()->proteger('%'.$uid[3].'%').
' OR commentaire LIKE '.Cel::db()->proteger('%'.$uid[3].'%');
}
 
if (!isset($uid[4]) || $uid[4] == '' || $uid[4] == 'all') {
$uid[4] = 'all';
$requete_station ='';
} else {
$requete_station = ' AND station= '.Cel::db()->proteger($uid[4]).' ';
}
 
$value = array();
$requete = 'SELECT ce_utilisateur, ordre, nom_sel, nom_sel_nn, nom_ret, nom_ret_nn, nt, famille, zone_geo, date_observation, '.
'station, commentaire, transmission '.
'FROM cel_obs '.
'WHERE ce_utilisateur = '.Cel::db()->proteger($uid[0]).' '.
$requete_location.
$requete_date.
$requete_libre.
$requete_station.' '.
'ORDER BY ordre '.
' -- '.__FILE__.':'.__LINE__;
$resultat = Cel::db()->requeter($requete);
 
$observations = array();;
if (is_array($resultat)) {
$observations = $resultat;
}
 
// Set up the pdf object.
$pdf = &File_PDF::factory(array('orientation' => 'P', 'format' => 'A4'));
// DesActivate compression.
$pdf->setCompression(false);
$pdf->setMargins(0, 0);
// Enable automatic page breaks.
$pdf->setAutoPageBreak(true);
// Start the document.
$pdf->open();
// Start a page.
$pdf->addPage();
$pdf->setFont('Times', '' , 12);
 
$i = 1;
$tempfn = tempnam('', '');
 
foreach ($observations as $obs) {
// Denullifiage
foreach($obs as $k=>$v) {
if (($v == 'null') || ($v == '000null')) {
$obs[$k] = '';
} else {
$obs[$k] = utf8_decode($v);
}
}
 
if ($obs['date_observation'] != '0000-00-00 00:00:00') {
list($year,$month,$day)= explode('-', $obs['date_observation']);
list($day)= explode(' ', $day);
$obs['date_observation'] = "$day/$month/$year";
} else {
$obs['date_observation'] = '00/00/0000';
}
 
$text = $obs['nom_sel']." ".$obs['nom_sel_nn']." ".$obs['nom_ret']." ".$obs['nom_ret_nn']." ".$obs['nt']." ".
$obs['famille']." ".$obs['zone_geo']." ".$obs['ce_zone_geo']." ".$obs['date_observation']." ".$obs['station'];
$obs['commentaire'];
 
$pdf->write(10, $text."\n");
 
$projet_photo = 'photoflora';
$tab_retour[$projet_photo] = $this->analyserRdf(sprintf(EF_URL_PHOTOFLORA_SERVICE, $obs['nt']));
$url_miniature = '';
foreach ($tab_retour[$projet_photo] as $cle => $illustration) {
if (preg_match(EF_URL_PHOTOFLORA_REGEXP, $illustration['about'], $match)) {
$abreviation = $match[1];
$fichier = $match[2];
$url_miniature = sprintf(EF_URL_PHOTOFLORA_IMG_MIN, $abreviation, $fichier);;
 
// Priorite aux images en png
if (strstr($fichier, '.png')) {
break;
}
}
}
 
if ($url_miniature != '') {
list($debut,$ext)=explode('\.',basename($url_miniature));
$temp = fopen($tempfn, 'w');
$buf=file_get_contents($url_miniature);
fwrite($temp,$buf);
fclose($temp);
$pdf->image($tempfn, 10, ($i*10), 0, 0, $ext);
}
$i++;
}
echo $pdf->output('Rapport');
}
 
private function analyserRdf($chemin) {
$aso_info = array();
$dom = new DOMDocument();
$dom->validateOnParse = true;
if (preg_match('/^http:\/\//', $chemin)) {
$dom->loadXML(file_get_contents($chemin));
} else {
$dom->load($chemin);
}
 
$tab_infos = array();
foreach ($dom->getElementsByTagNameNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'Description') as $rdf_description) {
$aso_info['about'] = $rdf_description->getAttribute('about');
$aso_info['dc:identifier'] = $rdf_description->getAttribute('identifier');
$aso_info['dc:title'] = utf8_decode($rdf_description->getAttribute('title'));
$aso_info['dc:creator'] = utf8_decode($rdf_description->getAttribute('creator'));
$aso_info['dc:contributor'] = utf8_decode($rdf_description->getAttribute('contributor'));
$aso_info['dc:publisher'] = utf8_decode($rdf_description->getAttribute('publisher'));
$aso_info['dc:type'] = utf8_decode($rdf_description->getAttribute('type'));
$aso_info['dc:format'] = utf8_decode($rdf_description->getAttribute('format'));
if (function_exists('date_default_timezone_set')) {
date_default_timezone_set('Europe/Paris');
}
if (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $rdf_description->getAttribute('created'))) {
$aso_info['dcterms:created'] = date('j-m-Y � H:i:s', strtotime($rdf_description->getAttribute('created')));
} else {
$aso_info['dcterms:created'] = $rdf_description->getAttribute('created');
}
$aso_info['dcterms:dateSubmitted'] = utf8_decode($rdf_description->getAttribute('dateSubmitted'));
$aso_info['dcterms:spatial'] = utf8_decode($rdf_description->getAttribute('spatial'));
$aso_info['dcterms:licence'] = utf8_decode($rdf_description->getAttribute('licence'));
$tab_infos[$rdf_description->getAttribute('identifier')] = $aso_info;
}
return $tab_infos;
}
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/InventoryDateList.php
New file
0,0 → 1,76
<?php
// declare(encoding='UTF-8');
/**
* Liste les date de releves par utilisateur.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @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 InventoryDateList extends Cel {
 
private $correspondance_fonction = array(1 => 'year', 2 => 'month', 3 => 'day');
 
/**
* @param int uid[0] : utilisateur obligatoire
* @param int uid[1] : si absent : valeur 'all' (annee)
* @param int uid[2] : si absent : valeur 'all' (mois)
* @param int uid[3] : si absent : valeur 'all' (jour)
*/
public function getElement($uid){
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
$condition_requete = $this->traiterParametresEtConstruireRequete($uid);
 
$requete_liste_dates = 'SELECT DISTINCT date_observation AS id '.
'FROM cel_obs WHERE '.$condition_requete.' '.
'ORDER BY date_observation '.
' -- '.__FILE__.':'.__LINE__;
 
$liste_dates = Cel::db()->requeter($requete_liste_dates);
$liste_dates = $this->formaterListeResultats($liste_dates);
$this->envoyerJson($liste_dates);
return true;
}
 
private function formaterListeResultats($liste_dates) {
if (!$liste_dates) {
$liste_dates = array();
}
 
foreach ($liste_dates as &$date) {
$date_heures = explode(' ',$date['id']);
if (count($date_heures) > 1) {
$date = $date_heures[0];
}
$date = $date;
}
return $liste_dates;
}
 
private function traiterParametresEtConstruireRequete($params) {
$requete_condition = ' ce_utilisateur = '.Cel::db()->proteger($params[0]);
 
$taille_tableau_parametres = count($params);
for ($i = 1; $i < $taille_tableau_parametres; $i++) {
if ($this->estUnParametreDate($params[$i])) {
$fonction_date = $this->correspondance_fonction[$i];
$requete_condition .= ' AND '.$fonction_date.'(date_observation) = '.Cel::db()->proteger($params[$i]);
}
}
return $requete_condition;
}
 
private function estUnParametreDate($valeur) {
return is_numeric($valeur) && $valeur != 'all';
}
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/CatalogueChampsEtendus.php
New file
0,0 → 1,42
<?php
// declare(encoding='UTF-8');
/**
*
* Service fournissant la liste des groupes de champs etendus.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Auto-complétions
* @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 CatalogueChampsEtendus extends Cel {
 
public function getElement($ressources){
$referentiel = array();
// TODO : meilleure vérification si ce service vient à être utilisé par autre chose
// que le cel
$_GET['groupe'] = (isset($_GET['groupe'])) ? $_GET['groupe'] : "" ;
if ($ressources[0] == 'groupes') {
$gestion_champs_etendus = new GestionChampsEtendus($this->config, 'obs');
$referentiel = $gestion_champs_etendus->consulterGroupesChampsEtendusPredefinis($_GET['groupe']);
} else if($ressources[0] == 'champs') {
$gestion_champs_etendus = new GestionChampsEtendus($this->config, 'obs');
$referentiel = $gestion_champs_etendus->consulterCatalogueChampsEtendusPredefinis(false, $_GET['groupe']);
}
$this->envoyerJson($referentiel);
return true;
}
 
public function getRessource() {
$groupes = $gestion_champs_etendus->consulterGroupesChampsEtendusPredefinis();
$this->envoyerJson($groupes);
return true;
}
}
/branches/v3.01-serpe/jrest/services/InventoryContributionList.php
New file
0,0 → 1,66
<?php
// declare(encoding='UTF-8');
/**
* Service renvoyant un fragment de HTML constitué à partir d'une liste très succinte des contributions
* de l'utilisateur.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @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 InventoryContributionList extends Cel {
 
public function getRessource() {
echo '';
}
 
/**
* Retourne la liste des contributions au format HTML.
*
* @param int $uid[0] identitifiant de l'utilisateur
*/
public function getElement($uid){
if (!isset($uid[0])) {
echo '';
}
 
$idUtilisateurP = Cel::db()->proteger($uid[0]);
$requete = 'SELECT * FROM cel_obs '.
"WHERE ce_utilisateur = $idUtilisateurP ".
'ORDER BY date_modification DESC '.
'LIMIT 0,5 '.
' -- '.__FILE__.':'.__LINE__;
$resultat_contributions = Cel::db()->requeter($requete);
 
$resume = '';
if (is_array($resultat_contributions)) {
foreach ($resultat_contributions as $ligne) {
$ligne['nom_sel'] = htmlspecialchars($ligne['nom_sel']);
$ligne['ce_utilisateur'] = htmlspecialchars($ligne['ce_utilisateur']);
$ligne['zone_geo'] = htmlspecialchars($ligne['zone_geo']);
$ligne['id_zone_geo'] = htmlspecialchars($this->convertirCodeZoneGeoVersDepartement($ligne['ce_zone_geo']));
$ligne['station'] = htmlspecialchars($ligne['station']);
$ligne['milieu'] = htmlspecialchars($ligne['milieu']);
$ligne['commentaire'] = htmlspecialchars($ligne['commentaire']);
$ligne['transmission'] = htmlspecialchars($ligne['transmission']);
 
$resume.= '<p>'.$ligne['nom_sel'] ." (".$ligne['nom_sel_nn'].") ".
'Location : '. $ligne['zone_geo']." (".$ligne['id_zone_geo']."),". $ligne['station'] . "," .
$ligne['milieu'] . "," . $ligne['commentaire'] . "," . $ligne['transmission'] .
'</p>';
}
}
 
header('Content-Type: text/html; charset=ISO-8859-1');
print $resume;
exit();
}
}
/branches/v3.01-serpe/jrest/services/InventoryImageListPublic.php
New file
0,0 → 1,65
<?php
// declare(encoding='UTF-8');
/**
* Service recherche d'images publique a partir de divers critères.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 InventoryImageListPublic extends Cel {
 
const start_defaut = 0;
const limit_defaut = 100;
const tri_defaut = 'ci.date_creation';
const dir_defaut = 'DESC';
 
public function getRessource() {
 
}
 
public function getElement($uid) {
// restriction aux observations publiques
$criteres = array('transmission' => '1');
 
if ($uid[0] != '*' && empty($_GET)) {
header("content-type: application/json");
$images_json = json_encode(array());
print $images_json;
exit();
}
 
$this->start = isset($_GET['start']) ? $_GET['start'] : self::start_defaut;
$this->limit = isset($_GET['limit']) ? $_GET['limit'] : self::limit_defaut;
 
$criteres['mots_cles'] = isset($_GET['tag']) ? $_GET['tag'] : null;
$criteres['auteur'] = isset($_GET['auteur']) ? $_GET['auteur'] : null;
$criteres['zone_geo'] = isset($_GET['commune']) ? $_GET['commune'] : null;
$criteres['taxon'] = isset($_GET['taxon']) ? $_GET['taxon'] : null;
$criteres['ce_zone_geo'] = isset($_GET['dept']) ? $_GET['dept'] : null;
$criteres['famille'] = isset($_GET['famille']) ? $_GET['famille'] : null;
$criteres['recherche'] = isset($_GET['recherche']) ? $_GET['recherche'] : null;
$criteres['tri'] = isset($_GET['tri']) ? $_GET['tri'] : self::tri_defaut;
$criteres['dir'] = isset($_GET['dir']) ? $_GET['dir'] : self::dir_defaut;
 
$chercheur_images = new RechercheImage($this->config);
$total = $chercheur_images->compterImages(null, $criteres);
$images = $chercheur_images->rechercherImages(null, $criteres, $this->start, $this->limit);
 
$resultat = array('total' => $total,'images' => $images);
$images_json = json_encode($resultat);
$images_json = str_replace('\u0000','',$images_json);
 
header("content-type: application/json");
print $images_json;
exit();
}
}
/branches/v3.01-serpe/jrest/services/InventoryImageList.php
New file
0,0 → 1,88
<?php
// declare(encoding='UTF-8');
/**
* Service recherche, et de suppression multiple d'images a partir de divers critères.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 InventoryImageList extends Cel {
 
/**
* Recherche les images correspondant aux critères passés en paramètres
* uid[0] : utilisateur obligatoire
* $_GET : critères de filtrage de la forme critère1=valeur1;critère2=valeur2
*/
public function getElement($uid) {
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
$numero_page = 0;
$taille_page = 50;
$criteres = $_GET;
if (isset($criteres['numero_page']) && isset($criteres['limite'])) {
$numero_page = $criteres['numero_page'];
unset($criteres['numero_page']);
$taille_page = $criteres['limite'];
unset($criteres['limite']);
}
$debut = $taille_page * $numero_page;
 
$chercheur_images = new RechercheImage($this->config);
$retour = $chercheur_images->rechercherImagesEtObservationAssociees($uid[0], $criteres, $debut, $taille_page);
$retour = $chercheur_images->formaterPourEnvoiCel($retour);
 
$retour_encode = json_encode($retour);
$retour_encode = $this->nettoyerCaracteresNuls($retour_encode);
 
header('content-type: application/json');
print $retour_encode;
exit();
}
 
private function nettoyerCaracteresNuls($chaine) {
return str_replace('\u0000','',$chaine);
}
 
/**
* Méthode appelée avec une requête de type DELETE.
* Supprime les infos sur l'image et le fichier correspondant à l'ordre passé en parametre
* Supporte la suppression multiple en passant plusieurs numéros séparés par des virgules
*
* @param int uid[0] id utilisateur
* @param string uid[1] : ordre(s) image(s) obligatoire(s) séparés par des virgules
*/
public function deleteElement($uid){
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
if (!isset($uid[1]) || !$this->EstUneSuiteIdentifiantsImage($uid[1])) {
return;
}
$ids_images = rtrim($uid[1], ',');
$ids_images = explode(',',$ids_images);
$gestionnaire_image = new GestionImage($this->config);
$suppression_image = $gestionnaire_image->supprimerImage($ids_images);
$this->envoyer('OK');
exit();
}
 
/**
* Un ensemble d'identifiants est une suite d'identifiants séparés par des virgules
* avec ou sans virgule terminale
*/
private function estUneSuiteIdentifiantsImage($chaine) {
$chaine = rtrim($chaine,',');
$reg_exp = "/^(([0-9])+,)*([0-9])+$/";
return preg_match($reg_exp, $chaine);
}
}
/branches/v3.01-serpe/jrest/services/LicenceUtilisateur.php
New file
0,0 → 1,53
<?php
// declare(encoding='UTF-8');
/**
* Service gérant l'acceptation de la licence utilisateur.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @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 LicenceUtilisateur extends Cel {
 
/**
* Fonction appelée sur un POST
*
* Accepte ou refuse la licence utilisateur, en mettant à jour la base de données pour
* l'utilisateur indiqué
*
* @param array $uid
* @param array $pairs
*/
public function updateElement($uid,$pairs) {
if (!isset($uid[0]) && is_numeric($uid[0])) {
return;
}
 
if (!isset($pairs['licence'])) {
return;
}
 
$requete = 'UPDATE cel_utilisateurs_infos '.
'SET licence_acceptee = '.Cel::db()->proteger($pairs['licence']).
'WHERE id_utilisateur = '.Cel::db()->proteger($uid[0]).' '.
' -- '.__FILE__.':'.__LINE__;
 
$resultat_acceptation_licence = Cel::db()->executer($requete);
 
$resultat = false;
if ($resultat_acceptation_licence) {
$resultat = 'OK';
}
 
echo $resultat;
exit();
}
}
/branches/v3.01-serpe/jrest/services/Inventory.php
New file
0,0 → 1,191
<?php
// declare(encoding='UTF-8');
/**
* Service CRUD sur une observation.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @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 Inventory extends Cel {
 
public function getRessource() {
 
}
 
public function getElement($uid){
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
if (!isset($uid[0])) {
return;
}
 
$parametres_recherche = array(array('ce_utilisateur',$uid[0]),array('ordre',$uid[1]));
 
$chercheur_observations = new RechercheObservation($this->config);
$retour_recherche = $chercheur_observations->rechercherObservations($uid[0], $parametres_recherche, 0, 1)->get();
 
$observation = array();
if (is_array($retour_recherche) && count($retour_recherche) > 0) {
$observation = $retour_recherche[0];
}
$observation = $this->formaterObservationVersTableauSequentiel($observation);
$sortie = json_encode($observation);
$this->envoyerJson($sortie);
return true;
}
 
private function formaterObservationVersTableauSequentiel(&$observation) {
if ($observation['date_observation']!="0000-00-00 00:00:00") {
list($year,$month,$day)= explode('-',$observation['date_observation']);
list($day)= explode(' ',$day);
$observation['date_observation']=$day."/".$month."/".$year;
}
 
$observation = array($observation['nom_sel'], $observation['nom_sel_nn'],
$observation['nom_ret'], $observation['nom_ret_nn'],
$observation['nt'], $observation['famille'], $observation['zone_geo'],
$observation['ce_zone_geo'], $observation['ordre'],
$observation['date_observation'], $observation['lieudit'],
$observation['station'], $observation['milieu'],
$observation['commentaire'], $observation['latitude'],
$observation['longitude']);
return $observation;
}
 
public function updateElement($uid,$pairs) {
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
if (!isset($uid[1])) {
//TODO: envoyer un message d'erreur
return;
}
 
$uid[1] = rtrim($uid[1],',');
 
$champs_etendus = isset($pairs['obs_etendue']) ? json_decode(stripslashes($pairs['obs_etendue']),true) : null;
unset($pairs['obs_etendue']);
 
if (isset($pairs['date_observation']) && !empty($pairs['date_observation'])) {
$time = strtotime(str_replace("/", "-", $pairs['date_observation']));
if(!$time || $time > time()) {
throw new Exception('Date invalide');
}
}
// un nom de bdtfxr est en fait un nom de bdtfx, de même pour les sous-référentiels d'afrique
if ($pairs['nom_referentiel'] == 'bdtfxr') {
$pairs['nom_referentiel'] = 'bdtfx';
} /* elseif (in_array($pairs['nom_referentiel'], array('apdfna', 'apdfta', 'apdfsa'))) {
$pairs['nom_referentiel'] == 'apd';
} */
$gestionnaire_observation = new GestionObservation($this->config);
$modification_observation = $gestionnaire_observation->modifierObservation($uid[0],$uid[1],$pairs);
 
if ($champs_etendus != null) {
$gestion_champs_etendus = new GestionChampsEtendus($this->config, 'obs');
$id_obs = $gestionnaire_observation->renvoyerIdPourOrdre($uid[0],$uid[1]);
foreach($champs_etendus as &$champ_etendu) {
$objet_champ_etendu = new ObsEtendue();
$objet_champ_etendu->id = $id_obs;
if($this->doitGenererCleChampEtendu($champ_etendu)) {
$champ_etendu['cle'] = $gestion_champs_etendus->transformerLabelEnCle($champ_etendu['label']);
}
$objet_champ_etendu->cle = $champ_etendu['cle'];
$objet_champ_etendu->valeur = $champ_etendu['valeur'];
$champ_etendu = $objet_champ_etendu;
}
// ajouterParLots modifie les champs et ajoute ceux qui existent déjà
$champs_supp = $gestion_champs_etendus->ajouterParLots($champs_etendus);
}
return true;
}
 
public function createElement($pairs) {
// Controle detournement utilisateur
$this->controleUtilisateur($pairs['ce_utilisateur']);
 
$champs_etendus = isset($pairs['obs_etendue']) ? json_decode(stripslashes($pairs['obs_etendue']),true) : null;
unset($pairs['obs_etendue']);
 
if (isset($pairs['date_observation']) && !empty($pairs['date_observation'])) {
$time = strtotime(str_replace("/", "-", $pairs['date_observation']));
if(!$time || $time > time()) {
throw new Exception('Date invalide');
}
}
// un nom de bdtfxr est en fait un nom de bdtfx, de même pour les sous-référentiels d'afrique
if ($pairs['nom_referentiel'] == 'bdtfxr') {
$pairs['nom_referentiel'] = 'bdtfx';
} elseif (in_array($pairs['nom_referentiel'], array('apdfna', 'apdfta', 'apdfsa'))) {
$pairs['nom_referentiel'] == 'apd';
}
 
$gestionnaire_observation = new GestionObservation($this->config);
$id_nouvelle_obs = $gestionnaire_observation->ajouterObservation($pairs['ce_utilisateur'], $pairs);
 
if ($champs_etendus != null) {
$gestion_champs_etendus = new GestionChampsEtendus($this->config, 'obs');
foreach($champs_etendus as &$champ_etendu) {
$objet_champ_etendu = new ObsEtendue();
$objet_champ_etendu->id = $id_nouvelle_obs;
if($this->doitGenererCleChampEtendu($champ_etendu)) {
$champ_etendu['cle'] = $gestion_champs_etendus->transformerLabelEnCle($champ_etendu['label']);
}
$objet_champ_etendu->cle = $champ_etendu['cle'];
$objet_champ_etendu->valeur = $champ_etendu['valeur'];
$champ_etendu = $objet_champ_etendu;
}
$champs_supp = $gestion_champs_etendus->ajouterParLots($champs_etendus);
}
return true;
}
 
/**
* Supprime une observation
*
* uid[0] : utilisateur obligatoire
* uid[1] : ordres de l'observation à supprimer
*/
public function deleteElement($uid){
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
if (!isset($uid[1])) {
//TODO: envoyer un message d'erreur
return;
}
 
$uid[1] = rtrim($uid[1],',');
 
$gestionnaire_observation = new GestionObservation($this->config);
$id_obs = $gestionnaire_observation->renvoyerIdPourOrdre($uid[0],$uid[1]);
$suppression_observation = $gestionnaire_observation->supprimerObservation($uid[0],$uid[1]);
 
$gestion_champs_etendus = new GestionChampsEtendus($this->config, 'obs');
$champs_supp = $gestion_champs_etendus->vider($id_obs);
$gestionnaire_images = new GestionImage($this->config);
$gestionnaire_images->modifierTransmissionParObs($id_obs, false);
 
if ($suppression_observation) {
echo "OK";
}
exit();
}
 
private function doitGenererCleChampEtendu($champ_etendu) {
return !isset($champ_etendu['cle']) ||
trim($champ_etendu['cle'] == "" ||
strpos($champ_etendu['cle'],'tempid_') !== false);
}
}
/branches/v3.01-serpe/jrest/services/NomsChampsEtendus.php
New file
0,0 → 1,91
<?php
// declare(encoding='UTF-8');
/**
* Fournit un référentiel relatif à l'utilisateur sur les noms ou les valeurs des champs étendus.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Auto-complétions
* @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 NomsChampsEtendus extends Cel {
 
/**
* Suivant le type de référentiel donné en paramètre, renvoie les liste de ses éléments
*
* uid[0] : "cle" ou "valeur"
* $_GET["cle"] : restreint la recherche sur les valeurs d'une certaine clé
* $_GET["recherche"] : cherche les noms qui commmencent selon la valeur
*/
public function getElement($uid){
if (!$this->paramObligatoiresSontPresents($uid)) {
return;
}
$_GET['recherche'] = str_replace('*', '%', $_GET['recherche']);
$referentiel = array();
 
if ($uid[0] == 'cle') {
$referentiel = $this->rechercherCles($_GET['recherche']);
} else if($uid[0] == 'valeur') {
$referentiel = $this->rechercherValeurs($_GET['cle'], $_GET['recherche']);
}
 
$this->envoyerJson($referentiel);
return true;
}
 
private function rechercherCles($recherche_cle) {
// Recherche dans clé du catalogue et les clés déja saisies par les utilisateurs.
// Si une clé est présente dans les deux tables, on privilégie celle du catalogue
// qui contient un label bien formé
$labelP = Cel::db()->proteger($recherche_cle."%");
$requete = "(SELECT cle, label, 'catalogue' ".
'FROM cel_catalogue_champs_etendus '.
"WHERE label LIKE $labelP ".
'AND groupe = 0 )'.
'UNION '.
"(SELECT DISTINCT cle, cle AS label, 'utilisateur' ".
'FROM cel_obs_etendues '.
"WHERE cle LIKE $labelP ".
'AND cle NOT IN (SELECT cle FROM cel_catalogue_champs_etendus) '.
') '.
' -- '.__FILE__.':'.__LINE__;
$resultat = Cel::db()->requeter($requete);
 
$referentiel = array();
foreach ($resultat as $valeur) {
$referentiel[$valeur['cle']] = $valeur['label'];
}
return $referentiel;
}
 
private function rechercherValeurs($cle, $recherche_valeur) {
$cleP = Cel::db()->proteger($cle);
$valeurP = Cel::db()->proteger($recherche_valeur.'%');
$requete = 'SELECT DISTINCT valeur '.
'FROM cel_obs_etendues '.
"WHERE cle = $cleP ".
"AND valeur LIKE $valeurP ".
' -- '.__FILE__.':'.__LINE__;
$resultats = Cel::db()->requeter($requete);
 
$referentiel = array();
foreach ($resultats as $valeur) {
if (trim($valeur['valeur']) != '') {
$referentiel[] = $valeur['valeur'];
}
}
return $referentiel;
}
 
private function paramObligatoiresSontPresents($uid) {
return (isset($uid[0]) && ($uid[0] == 'cle' || $uid[0] == 'valeur'));
}
}
/branches/v3.01-serpe/jrest/services/InventoryImage.php
New file
0,0 → 1,147
<?php
// declare(encoding='UTF-8');
/**
* Service recherche et ajout d'image a partir de divers critères.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Images
* @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 InventoryImage extends Cel {
 
/**
* Méthode appelée avec une requête de type GET.
* Renvoie les infos sur l'image correspondant à l'id passé en parametre
* @param int uid[0] : utilisateur obligatoire
* @param int uid[1] : identifiant image obligatoire
*/
public function getElement($uid) {
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
 
if (!isset($uid[0]) || !isset($uid[1])) {
return;
}
$parametres = array('ordre' => $uid[1]);
$retour = null;
$chercheurImage = new RechercheImage($this->config);
$image_recherchee = $chercheurImage->rechercherImages($uid[0], $parametres, 0, 1);
if (count($image_recherchee) > 0) {
$retour = $image_recherchee[0];
}
 
$this->envoyerJson($retour);
return true;
}
 
/**
* Méthode appelée avec une requête de type POST avec un identifiant d'image.
* Met a jour l'image correspondant à l'id passé en paramètre avec les valeurs passées dans le post
*
* @param int $uid[0] identifiant utilisateur
* @param int $uid[1] ordre de l'image relatif à l'utilisateur
* @param pairs array tableau contenant les valeurs de metadonnées à modifier
*/
public function updateElement($uid,$pairs) {
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
if (count($pairs) == 0 || !isset($uid[1])) {
return false;
}
 
$gestionnaireImage = new GestionImage($this->config);
$resultat_mise_a_jour = $gestionnaireImage->modifierImage($uid[0], $uid[1], $pairs);
 
$retour = false;
$ok = false;
if ($resultat_mise_a_jour) {
$retour = 'OK';
$ok = true;
}
$this->envoyer($retour);
return $ok;
}
 
/**
* Méthode appelée avec une requête de type PUT.
* Stocke une image, crée ses miniatures et enregistre ses informations
* Renvoie l'identifiant d'image nouvellement crée en cas de succès
*
* @param $pairs array tableau contenant les valeurs de metadonnées à ajouter
*/
public function createElement($pairs) {
if (self::ARRET_SERVICE) {
header('Status: 503 Service Temporarily Unavailable');
echo "L'envoi d'images au cel est temporairement désactivé";
exit;
}
// Controle detournement utilisateur
$this->controleUtilisateur($pairs['ce_utilisateur']);
 
foreach ($_FILES as $file) {
$infos_fichier = $file ;
}
 
$gestionnaireImage = new GestionImage($this->config);
$id_utilisateur = $pairs['ce_utilisateur'];
 
if ($gestionnaireImage->ajouterImage($id_utilisateur, $infos_fichier)) {
// l'upload demande de court-circuiter le fonctionnement normal de JREST
// en quittant directement après l'envoi
$this->envoyerMessageCreationEffectuee();
exit();
} else {
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
echo "Erreur lors du stockage de l'image";
exit();
}
}
 
private function envoyerMessageCreationEffectuee() {
header('HTTP/1.0 200 Created');
echo 'OK';
exit();
}
 
/**
* Méthode appelée avec une requête de type DELETE.
* Supprime les infos sur l'image et le fichier correspondant à l'ordre passé en parametre
* Supporte la suppression multiple en passant plusieurs numéros séparés par des virgules
*
* @param int uid[0] id utilisateur
* @param string uid[1] : ordre(s) image(s) obligatoire(s) séparés par des virgules
*
*/
public function deleteElement($uid){
if (self::ARRET_SERVICE) {
header('Status: 503 Service Temporarily Unavailable');
echo "L'envoi d'images au cel est temporairement désactivé";
exit;
}
// Controle detournement utilisateur
$this->controleUtilisateur($uid[0]);
if (!isset($uid[1]) || !$this->estUneSuiteIdentifiantsImage($uid[1])) {
return;
}
$ids_images = explode(',',$uid[1]);
$gestionnaireImage = new GestionImage($this->config);
$gestionnaireImage->supprimerImage($ids_images);
$this->envoyer('OK');
}
 
/** Un ensemble d'identifiants est une suite d'identifiants séparés par des virgules
* sans virgule terminale
*/
private function estUneSuiteIdentifiantsImage($chaine) {
$reg_exp = "/^(([0-9])+,)*([0-9])+$/";
return preg_match($reg_exp, $chaine);
}
}
/branches/v3.01-serpe/jrest/services/ImportXLS.php
New file
0,0 → 1,1240
<?php
// declare(encoding='UTF-8');
/**
* Service d'import de données d'observation du CEL au format XLS
*
* Sont define()'d commme n° de colonne tous les abbrevs retournés par
* FormateurGroupeColonne::nomEnsembleVersListeColonnes() préfixés par C_ cf: detectionEntete()
*
* Exemple d'un test:
* $ GET "/jrest/ExportXLS/22506?format=csv&range=*&limite=13" \
* | curl -F "upload=@-" -F utilisateur=22506 "/jrest/ImportXLS"
* # 13 observations importées
* + cf MySQL general_log = 1
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Observations
* @version 0.1
* @author Mathias CHOUET <mathias@tela-botanica.org>
* @author Raphaël DROZ <raphael@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>
*/
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(dirname(realpath(__FILE__))) . '/lib');
// TERM
error_reporting(-1);
ini_set('html_errors', 0);
ini_set('xdebug.cli_color', 2);
date_default_timezone_set('Europe/Paris');
require_once 'lib/PHPExcel/Classes/PHPExcel.php';
require_once 'bibliotheque/GestionMotsClesChemin.php';
 
// nombre d'INSERT à cumuler par requête SQL
// (= nombre de lignes XLS à bufferiser)
//define('NB_LIRE_LIGNE_SIMUL', 30);
define('NB_LIRE_LIGNE_SIMUL', 5);
 
// en cas d'import d'un fichier CSV, utilise fgetcsv() plutôt
// que PHPExcel ce qui se traduit par un gain de performances très substanciel
define('QUICK_CSV_IMPORT', TRUE);
 
// Numbers of days between January 1, 1900 and 1970 (including 19 leap years)
// see traiterDateObs()
// define("MIN_DATES_DIFF", 25569);
class MyReadFilter implements PHPExcel_Reader_IReadFilter {
// exclusion de colonnes
public $exclues = array();
 
// lecture par morceaux
public $ligne_debut = 0;
public $ligne_fin = 0;
 
public static $gestion_mots_cles = null;
 
public function __construct() {}
 
public function def_interval($debut, $nb) {
$this->ligne_debut = $debut;
$this->ligne_fin = $debut + $nb;
}
 
public function readCell($colonne, $ligne, $worksheetName = '') {
if(@$this->exclues[$colonne]) return false;
// si des n° de morceaux ont été initialisés, on filtre...
if($this->ligne_debut && ($ligne < $this->ligne_debut || $ligne >= $this->ligne_fin)) return false;
return true;
}
}
 
function __anonyme_1($v) { return !$v['importable']; }
function __anonyme_2(&$v) { $v = $v['nom']; }
function __anonyme_3($cell) { return !is_null($cell); };
function __anonyme_5($item) { return is_null($item) ? '?' : $item; }
function __anonyme_6() { return NULL; }
 
class ImportXLS extends Cel {
static function __anonyme_4(&$item, $key) { $item = self::quoteNonNull(trim($item)); }
 
static $ordre_BDD = Array(
'ce_utilisateur',
'prenom_utilisateur',
'nom_utilisateur',
'courriel_utilisateur',
'ordre',
'nom_sel',
'nom_sel_nn',
'nom_ret',
'nom_ret_nn',
'nt',
'famille',
'nom_referentiel',
'pays',
'zone_geo',
'ce_zone_geo',
'date_observation',
'lieudit',
'station',
'milieu',
'mots_cles_texte',
'commentaire',
'transmission',
'date_creation',
'date_modification',
'date_transmission',
'latitude',
'longitude',
'altitude',
'abondance',
'certitude',
'phenologie',
'code_insee_calcule'
);
 
// cf: initialiser_pdo_ordered_statements()
// eg: "INSERT INTO cel_obs (ce_utilisateur, ..., phenologie, code_insee_calcule) VALUES"
// colonnes statiques d'abord, les autres ensuite, dans l'ordre de $ordre_BDD
static $insert_prefix_ordre;
// eg: "(<id>, <prenom>, <nom>, <email>, now(), now(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
// dont le nombre de placeholder dépend du nombre de colonnes non-statiques
// colonnes statiques d'abord, les autres ensuite, dans l'ordre de $ordre_BDD
static $insert_ligne_pattern_ordre;
 
// seconde (meilleure) possibilité
// cf: initialiser_pdo_statements()
// eg: "INSERT INTO cel_obs (ce_utilisateur, ..., date_creation, ...phenologie, code_insee_calcule) VALUES"
static $insert_prefix;
// eg: "(<id>, <prenom>, <nom>, <email>, ?, ?, ?, now(), now(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
// dont le nombre de placeholder dépend du nombre de colonnes non-statiques
static $insert_ligne_pattern;
 
/*
Ces colonnes:
- sont propres à l'ensemble des enregistrements uploadés
- sont indépendantes du numéro de lignes
- n'ont pas de valeur par défaut dans la structure de la table
- nécessitent une initialisation dans le cadre de l'upload
initialiser_colonnes_statiques() y merge les données d'identification utilisateur
*/
public $colonnes_statiques = array(
'ce_utilisateur' => NULL,
'prenom_utilisateur' => NULL,
'nom_utilisateur' => NULL,
'courriel_utilisateur' => NULL,
 
// fixes (fonction SQL)
// XXX future: mais pourraient varier dans le futur si la mise-à-jour
// d'observation est implémentée
'date_creation' => 'NOW()',
'date_modification' => 'NOW()',
);
 
public static $prefixe_colonnes_etendues = 'ext:';
public static $indexes_colonnes_etendues = Array();
public static $gestion_champs_etendus = null;
 
public $id_utilisateur = NULL;
 
// erreurs d'import
public $bilan = Array();
 
// cache (pour traiterLocalisation() pour l'instant)
static $cache = Array('geo' => array());
 
public function createElement($pairs) {
if (!isset($pairs['utilisateur']) || trim($pairs['utilisateur']) == '') {
exit('0');
}
 
$id_utilisateur = intval($pairs['utilisateur']);
$this->id_utilisateur = $id_utilisateur; // pour traiterImage();
 
if (!isset($_SESSION)) {
session_start();
}
$this->controleUtilisateur($id_utilisateur);
 
$this->utilisateur = $this->getInfosComplementairesUtilisateur($id_utilisateur);
$this->initialiser_colonnes_statiques($id_utilisateur);
list(self::$insert_prefix, self::$insert_ligne_pattern) = $this->initialiser_pdo_statements($this->colonnes_statiques);
 
$infos_fichier = array_pop($_FILES);
 
// renomme le fichier pour lui ajouter son extension initiale, ce qui
// permet (une sorte) d'autodétection du format.
$fichier = $infos_fichier['tmp_name'];
$extension = pathinfo($infos_fichier['name'], PATHINFO_EXTENSION);
if ( (strlen($extension) == 3 || strlen($extension) == 4) && (@rename($fichier, "$fichier.$extension"))) {
$fichier = "$fichier.$extension";
}
 
$objReader = PHPExcel_IOFactory::createReaderForFile($fichier);
// TODO: check if compatible with toArray(<1>,<2>,TRUE,<4>)
$objReader->setReadDataOnly(true);
 
// TODO: is_a obsolete entre 5.0 et 5.3, retirer le @ à terme
$IS_CSV = @is_a($objReader, 'PHPExcel_Reader_CSV') && QUICK_CSV_IMPORT;
// en cas d'usage de fgetcsv, testons que nous pouvons compter les lignes
if ($IS_CSV) {
$nb_lignes = intval(exec("wc -l $fichier"));
}
// et, le cas échéant, fallback sur PHPExcel à nouveau. La raison de ce test ici est
// l'instabilité du serveur (safe_mode, safe_mode_exec_dir, symlink vers binaires pour exec(), ... multiples points-of-failure)
if ($IS_CSV && !$nb_lignes) {
$IS_CSV = FALSE;
}
 
if ($IS_CSV) {
$objReader->setDelimiter(',')
->setEnclosure('"')
->setLineEnding("\n")
->setSheetIndex(0);
}
 
// on ne conserve que l'en-tête
$filtre = new MyReadFilter();
$filtre->def_interval(1, 2);
$objReader->setReadFilter($filtre);
 
$objPHPExcel = $objReader->load($fichier);
$obj_infos = $objReader->listWorksheetInfo($fichier);
 
if ($IS_CSV) {
// $nb_lignes est déjà défini ci-dessus
$csvFileHandler = fopen($fichier, 'r');
// nous utilisons la valeur de retour dans un but informatif de l'utilisateur à la
// fin de l'import, *mais aussi* dans un array_diff_key() ci-dessous car bien que dans le
// fond le "parser" fgetcsv() n'ait pas d'intérêt à connaître les colonnes à ignorer,
// il se trouve que celles-ci peuvent interférer sur des fonctions comme traiterEspece()
// cf test "ref-nom-num.test.php" pour lequel l'élément C_NOM_SEL vaudrait 3 et $ligne serait array(3 => -42)
$filtre->exclues = self::detectionEntete(fgetcsv($csvFileHandler), TRUE);
} else {
// XXX: indépendant du readFilter ?
$nb_lignes = $obj_infos[0]['totalRows'];
$donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, TRUE, TRUE);
$filtre->exclues = self::detectionEntete($donnees[1]);
}
 
$obs_ajouts = 0;
$obs_maj = 0;
$nb_images_ajoutees = 0;
$nb_mots_cle_ajoutes = 0;
$nb_champs_etendus_inseres = 0;
 
$dernier_ordre = Cel::db()->requeter("SELECT MAX(ordre) AS ordre FROM cel_obs WHERE ce_utilisateur = $id_utilisateur");
$dernier_ordre = intval($dernier_ordre[0]['ordre']) + 1;
if (! $dernier_ordre) {
$dernier_ordre = 0;
}
 
// on catch to les trigger_error(E_USER_NOTICE);
set_error_handler(array($this, 'erreurs_stock'), E_USER_NOTICE);
$this->taxon_info_webservice = new RechercheInfosTaxonBeta($this->config, NULL);
 
// lecture par morceaux (chunks), NB_LIRE_LIGNE_SIMUL lignes à fois
// pour aboutir des requêtes SQL d'insert groupés.
for ($ligne = 2; $ligne < $nb_lignes + NB_LIRE_LIGNE_SIMUL; $ligne += NB_LIRE_LIGNE_SIMUL) {
if (!$IS_CSV) {
$filtre->def_interval($ligne, NB_LIRE_LIGNE_SIMUL);
$objReader->setReadFilter($filtre);
 
$objPHPExcel = $objReader->load($fichier)->getActiveSheet();
 
// set col typing
if (C_CE_ZONE_GEO != 'C_CE_ZONE_GEO') {
$objPHPExcel->getStyle(C_CE_ZONE_GEO . '2:' . C_CE_ZONE_GEO . $objPHPExcel->getHighestRow())->getNumberFormat()->setFormatCode('00000');
}
// TODO: set to string type
if (C_ZONE_GEO != 'C_ZONE_GEO') {
$objPHPExcel->getStyle(C_ZONE_GEO . '2:' . C_ZONE_GEO . $objPHPExcel->getHighestRow())->getNumberFormat()->setFormatCode('00000');
}
$donnees = $objPHPExcel->toArray(NULL, FALSE, TRUE, TRUE);
} else {
$i = NB_LIRE_LIGNE_SIMUL;
$donnees = array();
while ($i--) {
$tab = fgetcsv($csvFileHandler);
if (!$tab) {
continue;
}
$donnees[] = array_diff_key($tab, $filtre->exclues);
}
}
 
list($enregistrements, $images, $mots_cle, $champs_etendus) = self::chargerLignes($this, $donnees, $this->colonnes_statiques, $dernier_ordre, $config);
if (! $enregistrements) {
break;
}
 
self::trierColonnes($enregistrements);
// normalement: NB_LIRE_LIGNE_SIMUL, sauf si une enregistrement ne semble pas valide
// ou bien lors du dernier chunk
 
$nb_rec = count($enregistrements);
$sql_pattern = self::$insert_prefix.
str_repeat(self::$insert_ligne_pattern.', ', $nb_rec - 1).
self::$insert_ligne_pattern;
 
Cel::db()->beginTransaction();
$stmt = Cel::db()->prepare($sql_pattern);
$donnees = array();
foreach ($enregistrements as $e) {
$donnees = array_merge($donnees, array_values($e));
}
 
$stmt->execute($donnees);
 
# @TODO lier les mots-clées de l'arbre à l'obs nouvellement insérée, sinon seuls les mots-clés texte
# seront à jour, et ils seront écrasés à la prochaine modification de mots-clés pour cette obs...
# => nécessite d'insérer les obs une par une pour avoir le dernier id inséré
 
$dernier_autoinc = Cel::db()->lastInsertId();
Cel::db()->commit();
 
if (! $dernier_autoinc) {
trigger_error("l'insertion semble avoir échoué", E_USER_NOTICE);
}
 
$obs_ajouts += count($enregistrements);
 
$ordre_ids = self::chargerCorrespondancesIdOrdre($this, $enregistrements);
 
$nb_images_ajoutees += self::stockerImages($enregistrements, $images, $ordre_ids);
$nb_mots_cle_ajoutes += self::stockerMotsCle($enregistrements, $mots_cle, $dernier_autoinc);
$nb_champs_etendus_inseres += self::stockerChampsEtendus($champs_etendus, $ordre_ids, $this->config);
}
 
restore_error_handler();
 
// le cast en string des nombres permet d'unifier le parsing du retour
// car il n'est destiné qu'à être affiché
$retour = array(
'import_obs_ajoutees' => (string)$obs_ajouts,
'import_images_ajoutees' => (string)$nb_images_ajoutees,
'import_mots_cles_ajoutes' => (string)$nb_mots_cle_ajoutes,
'import_colonnes_non_traitees' => implode(', ', $filtre->exclues)
);
// Ajout d'éventuelles erreurs
if ($this->bilan) {
$retour += array('import_erreurs' => implode("\n", $this->bilan) . "\n");
}
// Dans le cas où le client ne sait pas lire le retour d'upload
// on stocke les stats en session pour les appeler plus tard
// car ceci peut poser notamment problème pour les requêtes CORS
$_SESSION['upload_stats'] = $retour;
// On envoie quand même les stats pour les clients qui savent ou peuvent
// les lire directement après l'upload
$this->envoyerJson($retour);
die();
}
public function getElement($uid) {
if($uid[0] == "template") {
 
$tpl_dir = dirname(__FILE__).DIRECTORY_SEPARATOR.'squelettes'.DIRECTORY_SEPARATOR;
$tpl = $tpl_dir.'modele_import.xls';
 
$lecteur = PHPExcel_IOFactory::createReaderForFile($tpl);
$classeur_tpl = $lecteur->load($tpl);
$feuille_tpl = $classeur_tpl->getActiveSheet();
// Détection de la dernière colonne pour connaitre la position d'ajout des champs étendus
// Si un groupe est demandé
$lettre_colonne_max = $feuille_tpl->getHighestColumn();
$nb_colonne_max = PHPExcel_Cell::columnIndexFromString($lettre_colonne_max);
$ligne = 1;
$nb_colonne_en_cours = $nb_colonne_max;
 
// Obtention des descriptions de champs communs et spécifiques
$descriptions = $this->obtenirDescriptions($tpl_dir.'modele_import_description.txt');
if(!empty($_GET['groupe'])) {
$descriptions = $this->obtenirDescriptions($tpl_dir.'modele_import_description_'.$_GET['groupe'].'.txt', $descriptions);
}
// Association de la description des champs commun
for($i = 0; $i < $nb_colonne_max; $i++) {
$lettre_colonne = PHPExcel_Cell::stringFromColumnIndex($i);
$champ_obl = $feuille_tpl->getCell($lettre_colonne.$ligne)->getValue();
if(!empty($descriptions[$champ_obl])) {
$feuille_tpl->getComment($lettre_colonne.$ligne)->getText()->createTextRun($descriptions[$champ_obl]);
$feuille_tpl->getComment($lettre_colonne.$ligne)->setWidth(400);
}
}
$nom_fichier = 'import';
// Ajout des colonnes spécifiques si un groupe de champ est demandé
if(!empty($_GET['groupe'])) {
$requete = "SELECT * FROM cel_catalogue_champs_etendus_liaison WHERE groupe = ".Cel::db()->proteger($_GET['groupe']);
$champs = Cel::db()->requeter($requete);
 
foreach($champs as $champ) {
$lettre_colonne = PHPExcel_Cell::stringFromColumnIndex($nb_colonne_en_cours);
// Les champs étendus sont préfixés par "ext:" pour ne pas être ignoré lors d'un import
// l'import ignore les noms de colonnes qu'il ne connait pas
$feuille_tpl->setCellValue($lettre_colonne.$ligne, 'ext:'.$champ['champ']);
// Ajout de la description dans le commentaire si elle est présente
if(!empty($descriptions[$champ['champ']])) {
$feuille_tpl->getComment($lettre_colonne.$ligne)->getText()->createTextRun($descriptions[$champ['champ']]);
$feuille_tpl->getComment($lettre_colonne.$ligne)->setWidth(400);
}
$nb_colonne_en_cours++;
}
$nom_fichier .= '_'.$_GET['groupe'];
}
// Seul le format xlsx permet l'association de commentaires de colonnes dans PHPExcel
// C'est triste mais bon mais c'est trop pratique pour qu'on s'en passe
header('Content-type: application/vnd.ms-excel');
header('Content-Disposition: attachment; filename="'.$nom_fichier.'.xlsx"');
$generateur = PHPExcel_IOFactory::createWriter($classeur_tpl, 'Excel2007');
$generateur->save('php://output');
exit;
}
}
private function obtenirDescriptions($fichier_description, $descriptions = array()) {
if(file_exists($fichier_description)) {
$descs_str = file_get_contents($fichier_description);
$desc_items = explode("\n", $descs_str);
foreach($desc_items as $item) {
$cle_valeur = explode("=", $item);
$valeur_desc = trim($cle_valeur[1]);
// Les clés des fichiers sont écrasées dans l'ordre de lecture ce qui permet
// d'avoir par exemple une description différente pour le champ station suivant le projet
// les "<br />" sont remplacés par des sauts de lignes
$descriptions[trim($cle_valeur[0])] = str_replace('<br />', "\n", $valeur_desc);
}
}
return $descriptions;
}
public function getRessource() {
return self::getStatsDernierUpload();
}
static function getStatsDernierUpload() {
// renvoi des statistiques du dernier envoi de fichier
$stats = !empty($_SESSION['upload_stats']) ? $_SESSION['upload_stats'] : null;
header("Content-Type: application/json; charset=utf-8");
echo json_encode($stats);
die();
}
 
/* detectionEntete() sert deux rôles:
1) détecter le type de colonne attendu à partir des textes de la ligne d'en-tête afin de define()
2) permet d'identifier les colonnes non-supportées/inutiles afin d'alléger le processus de parsing de PHPExcel
grace au ReadFilter (C'est le rôle de la valeur de retour)
 
La raison de la présence du paramètre $numeric_keys est que pour réussir à identifier les colonnes à exclure nous
devons traiter un tableau représentant la ligne d'en-tête aussi bien:
- sous forme associative pour PHPExcel (les clefs sont les lettres de l'alphabet)
- sous forme de clefs numériques (fgetcsv())
Le détecter après coup est difficile et pourtant cette distinction est importante car le comportement
d'array_merge() (réordonnancement des clefs numérique) n'est pas souhaitable dans le second cas. */
static function detectionEntete($entete, $numeric_keys = FALSE) {
$colonnes_reconnues = Array();
$cols = FormateurGroupeColonne::nomEnsembleVersListeColonnes('standard,avance');
 
foreach ($entete as $k => $v) {
// traite les colonnes en faisant fi de la casse et des accents
$entete_simple = iconv('UTF-8', 'ASCII//TRANSLIT', strtolower(trim($v)));
foreach ($cols as $col) {
$entete_officiel_simple = iconv('UTF-8', 'ASCII//TRANSLIT', strtolower(trim($col['nom'])));
$entete_officiel_abbrev = $col['abbrev'];
if ($entete_simple == $entete_officiel_simple || $entete_simple == $entete_officiel_abbrev) {
// debug echo "define C_" . strtoupper($entete_officiel_abbrev) . ", $k ($v)\n";
define("C_" . strtoupper($entete_officiel_abbrev), $k);
$colonnes_reconnues[$k] = 1;
break;
}
 
if (strpos($v, self::$prefixe_colonnes_etendues) === 0) {
$colonnes_reconnues[$k] = 1;
self::$indexes_colonnes_etendues[$k] = $v;
break;
}
}
}
 
// défini tous les index que nous utilisons à une valeur d'index de colonne Excel qui n'existe pas dans
// le tableau renvoyé par PHPExcel
// Attention cependant d'utiliser des indexes différenciés car traiterLonLat() et traiterEspece()
// les utilisent
foreach ($cols as $col) {
if (!defined('C_'.strtoupper($col['abbrev']))) {
define('C_'.strtoupper($col['abbrev']), 'C_'.strtoupper($col['abbrev']));
}
}
 
// prépare le filtre de PHPExcel qui évitera le traitement de toutes les colonnes superflues
$colonnesID_non_reconnues = array_diff_key($entete, $colonnes_reconnues);
 
// des colonnes de FormateurGroupeColonne::nomEnsembleVersListeColonnes()
// ne retient que celles marquées "importables"
$colonnes_automatiques = array_filter($cols, '__anonyme_1');
 
// ne conserve que le nom long pour matcher avec la ligne XLS d'entête
array_walk($colonnes_automatiques, '__anonyme_2');
 
$colonnesID_a_exclure = array_intersect($entete, $colonnes_automatiques);
 
if ($numeric_keys) {
return $colonnesID_non_reconnues + $colonnesID_a_exclure;
}
return array_merge($colonnesID_non_reconnues, $colonnesID_a_exclure);
}
 
static function chargerCorrespondancesIdOrdre($cel, $lignes) {
$ordresObs = array();
foreach ($lignes as &$ligne) {
$ordresObs[] = $ligne['ordre'];
}
$ordresObsConcat = implode(',', $ordresObs);
$idUtilisateurP = Cel::db()->proteger($cel->id_utilisateur);
$requete = 'SELECT id_observation, ordre '.
'FROM cel_obs '.
"WHERE ordre IN ($ordresObsConcat) ".
"AND ce_utilisateur = $idUtilisateurP ".
' -- '.__FILE__.':'.__LINE__;
$resultats = Cel::db()->requeter($requete);
$ordresIds = array();
foreach ($resultats as &$infos) {
$ordresIds[$infos['ordre']] = $infos['id_observation'];
}
return $ordresIds;
}
 
/*
* charge un groupe de lignes
*/
static function chargerLignes($cel, $lignes, $colonnes_statiques, &$dernier_ordre, $config) {
$enregistrement = NULL;
$enregistrements = array();
$toutes_images = array();
$tous_mots_cle = array();
$tous_champs_etendus = array();
 
foreach ($lignes as $ligne) {
// dans le cas de fgetcsv, on peut avoir des false additionnel (cf do/while l. 279)
if ($ligne === false) {
continue;
}
 
// on a besoin des NULL pour éviter des notice d'index indéfini
if (! array_filter($ligne, '__anonyme_3')) {
continue;
}
 
if ($enregistrement = self::chargerLigne($ligne, $dernier_ordre, $cel, $config)) {
// $enregistrements[] = array_merge($colonnes_statiques, $enregistrement);
if ($enregistrement['latitude'] == NULL && $enregistrement['longitude'] == NULL) {
if (isset($enregistrement['_champs_etendus']['latitudeDebutRue'])) {
$enregistrement['latitude'] = $enregistrement['_champs_etendus']['latitudeDebutRue'];
$enregistrement['longitude'] = $enregistrement['_champs_etendus']['longitudeDebutRue'];
}
}
$enregistrements[] = $enregistrement;
$pos = count($enregistrements) - 1;
$last = &$enregistrements[$pos];
 
if (isset($enregistrement['_images'])) {
// ne dépend pas de cel_obs, et seront insérées *après* les enregistrements
// mais nous ne voulons pas nous priver de faire des INSERT multiples pour autant
$toutes_images[] = array(
'images' => $last['_images'],
'obs_pos' => $pos);
// ce champ n'a pas à faire partie de l'insertion dans cel_obs,
// mais est utile pour la liaison avec les images
unset($last['_images']);
}
 
if (isset($enregistrement['_mots_cle'])) {
// ne dépend pas de cel_obs, et seront insérés *après* les enregistrements
// mais nous ne voulons pas nous priver de faire des INSERT multiples pour autant
$tous_mots_cle[] = array(
'mots_cle' => $last['_mots_cle'],
'obs_pos' => $pos);
unset($last['_mots_cle']);
}
 
if (isset($enregistrement['_champs_etendus'])) {
$tous_champs_etendus[] = array(
'champs_etendus' => $last['_champs_etendus'],
'ordre' => $dernier_ordre);
unset($last['_champs_etendus']);
}
$dernier_ordre++;
}
}
return array($enregistrements, $toutes_images, $tous_mots_cle, $tous_champs_etendus);
}
 
static function trierColonnes(&$enregistrements) {
foreach ($enregistrements as &$enregistrement) {
$enregistrement = self::sortArrayByArray($enregistrement, self::$ordre_BDD);
}
}
 
static function stockerMotsCle($enregistrements, $tous_mots_cle) {
$c = 0;
// debug: var_dump($tous_mots_cle);die;
foreach ($tous_mots_cle as $v) {
$c += count($v['mots_cle']['to_insert']);
}
return $c;
}
 
static function stockerImages($enregistrements, $toutes_images, $ordre_ids) {
$valuesSql = array();
foreach ($toutes_images as $images_pour_obs) {
$obs = $enregistrements[$images_pour_obs['obs_pos']];
$id_obs = $ordre_ids[$obs['ordre']]; // id réel de l'observation correspondant à l'ordre
$transmission = $obs['transmission'];
$date_transmission = 'NOW()'; // par défaut pour les nouveaux imports
if ($obs['date_transmission'] != null) { // peut être NULL selon la valeur par défaut de la colonne, la version du SGBD, etc.
$date_transmission = $obs['date_transmission'];
}
foreach ($images_pour_obs['images'] as $image) {
$id_img = $image['id_image'];
$valuesSql[] = "($id_img, $id_obs, NOW(), $transmission, $date_transmission)";
}
}
 
if ($valuesSql) {
$clauseValues = implode(', ', $valuesSql);
// Utilisation de INSERT pour faire des UPDATE multiples en une seule requête
$requete = 'INSERT INTO cel_images '.
'(id_image, ce_observation, date_liaison, transmission, date_transmission) '.
"VALUES $clauseValues ".
'ON DUPLICATE KEY UPDATE '.
'ce_observation = VALUES(ce_observation), '.
'date_liaison = NOW(), '.
'transmission = VALUES(transmission), '.
'date_transmission = VALUES(date_transmission) '.
' -- '.__FILE__.':'.__LINE__;
Cel::db()->executer($requete);
}
return count($valuesSql);
}
 
/*
Aucune des valeurs présentes dans $enregistrement n'est quotée
cad aucune des valeurs retournée par traiter{Espece|Localisation}()
car ce tableau est passé à un PDO::preparedStatement() qui applique
proprement les règle d'échappement.
*/
static function chargerLigne($ligne, $dernier_ordre, $cel, $config) {
// évite des notices d'index lors des trigger_error()
$ref_ligne = !empty($ligne[C_NOM_SEL]) ? trim($ligne[C_NOM_SEL]) : '';
 
// en premier car le résultat est utile pour
// * traiter espèce (traiterEspece())
// * traiter longitude et latitude (traiterLonLat())
$referentiel = self::identReferentiel(trim(strtolower(@$ligne[C_NOM_REFERENTIEL])), $ligne, $ref_ligne);
 
// $espece est rempli de plusieurs informations
$espece = array(
C_NOM_SEL => NULL,
C_NOM_SEL_NN => NULL,
C_NOM_RET => NULL,
C_NOM_RET_NN => NULL,
C_NT => NULL,
C_FAMILLE => NULL);
self::traiterEspece($ligne, $espece, $referentiel, $cel->taxon_info_webservice);
 
if (!$espece[C_NOM_SEL]) {
$referentiel = Cel::$fallback_referentiel;
}
if ($espece[C_NOM_SEL] && !$espece[C_NOM_SEL_NN]) {
$referentiel = Cel::$fallback_referentiel;
}
 
// $localisation est rempli à partir de plusieurs champs: C_ZONE_GEO et C_CE_ZONE_GEO
$localisation = Array(C_ZONE_GEO => NULL, C_CE_ZONE_GEO => NULL);
self::traiterLocalisation($ligne, $localisation);
//TODO: le jour où c'est efficace, traiter le pays à l'import
 
// $transmission est utilisé pour date_transmission
// XXX: @ contre "Undefined index"
@$transmission = in_array(strtolower(trim($ligne[C_TRANSMISSION])), array(1, 'oui')) ? 1 : 0;
 
 
// Dans ce tableau, seules devraient apparaître les données variable pour chaque ligne.
// Dans ce tableau, l'ordre des clefs n'importe pas (cf: self::sortArrayByArray())
$enregistrement = array(
"ordre" => $dernier_ordre,
 
"nom_sel" => $espece[C_NOM_SEL],
"nom_sel_nn" => $espece[C_NOM_SEL_NN],
"nom_ret" => $espece[C_NOM_RET],
"nom_ret_nn" => $espece[C_NOM_RET_NN],
"nt" => $espece[C_NT],
"famille" => $espece[C_FAMILLE],
 
"nom_referentiel" => $referentiel,
 
"pays" => $ligne[C_PAYS],
"zone_geo" => $localisation[C_ZONE_GEO],
"ce_zone_geo" => $localisation[C_CE_ZONE_GEO],
 
// $ligne: uniquement pour les infos en cas de gestion d'erreurs (date incompréhensible)
"date_observation" => isset($ligne[C_DATE_OBSERVATION]) ? self::traiterDateObs($ligne[C_DATE_OBSERVATION], $ref_ligne) : null,
 
"lieudit" => isset($ligne[C_LIEUDIT]) ? trim($ligne[C_LIEUDIT]) : null,
"station" => isset($ligne[C_STATION]) ? trim($ligne[C_STATION]) : null,
"milieu" => isset($ligne[C_MILIEU]) ? trim($ligne[C_MILIEU]) : null,
 
"mots_cles_texte" => NULL, // TODO: foreign-key
// XXX: @ contre "Undefined index"
"commentaire" => isset($ligne[C_COMMENTAIRE]) ? trim($ligne[C_COMMENTAIRE]) : null,
 
"transmission" => $transmission,
"date_transmission" => $transmission ? date('Y-m-d H:i:s') : null, // pas de fonction SQL dans un PDO statement, <=> now()
 
// $ligne: uniquement pour les infos en cas de gestion d'erreurs (lon/lat incompréhensible)
"latitude" => isset($ligne[C_LATITUDE]) ? self::traiterLonLat(null, $ligne[C_LATITUDE], $referentiel, $ref_ligne) : null,
"longitude" => isset($ligne[C_LONGITUDE]) ? self::traiterLonLat($ligne[C_LONGITUDE], null, $referentiel, $ref_ligne) : null,
"altitude" => isset($ligne[C_ALTITUDE]) ? intval($ligne[C_ALTITUDE]) : null, // TODO: guess alt from lon/lat
 
// @ car potentiellement optionnelles ou toutes vides => pas d'index dans PHPExcel (tableau optimisé)
"abondance" => @$ligne[C_ABONDANCE],
"certitude" => @$ligne[C_CERTITUDE],
"phenologie" => @$ligne[C_PHENOLOGIE],
 
"code_insee_calcule" => substr($localisation[C_CE_ZONE_GEO], -5) // varchar(5)
);
 
// passage de $enregistrement par référence, ainsi ['_images'] n'est défini
// que si des résultats sont trouvés
// "@" car PHPExcel supprime les colonnes null sur toute la feuille (ou tout le chunk)
if (@$ligne[C_IMAGES]) {
self::traiterImage($ligne[C_IMAGES], $cel->id_utilisateur, $enregistrement);
}
 
if (@$ligne[C_MOTS_CLES_TEXTE]) {
self::traiterMotsCle($ligne[C_MOTS_CLES_TEXTE], $cel->id_utilisateur, $enregistrement, $config);
}
 
$champs_etendus = self::traiterChampsEtendus($ligne, self::$indexes_colonnes_etendues);
if (!empty($champs_etendus)) {
$enregistrement['_champs_etendus'] = $champs_etendus;
}
 
return $enregistrement;
}
 
static function traiterChampsEtendus(&$ligne, &$indexes_colonnes_etendues) {
$champs_etendus_indexes = array();
foreach($indexes_colonnes_etendues as $index_num => $label) {
if (isset($ligne[$index_num])) {
$champs_etendus_indexes[str_replace(self::$prefixe_colonnes_etendues, '', $label)] = $ligne[$index_num];
}
}
return $champs_etendus_indexes;
}
 
static function traiterImage($str, $id_utilisateur, &$enregistrement) {
$liste_images = array_filter(explode('/', $str));
array_walk($liste_images, array(__CLASS__, '__anonyme_4'));
 
$nomsOrignalConcat = implode(',', $liste_images);
$requete = 'SELECT id_image, nom_original '.
'FROM cel_images '.
"WHERE ce_utilisateur = $id_utilisateur AND nom_original IN ($nomsOrignalConcat) ".
' -- '.__FILE__.':'.__LINE__;
$resultat = Cel::db()->requeter($requete);
 
if ($resultat) {
$enregistrement['_images'] = $resultat;
}
}
 
static function traiterMotsCle($str, $id_utilisateur, &$enregistrement, $config) {
$liste_mots_cle = $liste_mots_cle_recherche = array_map('trim', array_unique(array_filter(explode(',', $str))));
array_walk($liste_mots_cle_recherche, array(__CLASS__, '__anonyme_4'));
 
#if (self::$gestion_mots_cles == null) {
if (true) {
$gestion_mots_cles = new GestionMotsClesChemin($config, 'obs');
}
 
// Recherche des IDs des mots-cles
$mots_cles_ids = $gestion_mots_cles->obtenirIdsMotClesPourMotsCles($liste_mots_cle, $id_utilisateur);
// Y aura-t-il des nouvaux mots-cles
foreach ($mots_cles_ids as $mot_cle) {
$resultat[$mot_cle['id_mot_cle']] = $mot_cle['mot_cle'];
}
if ($resultat == null) {
// array_diff() ne gère pas les NULL en entrée
$nouveaux_mots_cles = $liste_mots_cle;
} else {
$nouveaux_mots_cles = array_diff($liste_mots_cle, $resultat);
}
// Ajout des mots-cles inexistants dans l'arbre
if (count($nouveaux_mots_cles) > 0) {
foreach ($nouveaux_mots_cles as $nmc) {
$gestion_mots_cles->insererParChemin($nmc, '/', $id_utilisateur);
}
// Mise à jour des ids de mots-cles après ajout
$mots_cles_ids = $gestion_mots_cles->obtenirIdsMotClesPourMotsCles($liste_mots_cle, $id_utilisateur);
}
 
$enregistrement['mots_cles_texte'] = implode(',', $liste_mots_cle);
$enregistrement['_mots_cle'] = array(
'existing' => $resultat,
'to_insert' => $nouveaux_mots_cles
);
}
 
 
/* FONCTIONS de TRANSFORMATION de VALEUR DE CELLULE */
// TODO: PHP 5.3, utiliser date_parse_from_format()
// TODO: parser les heures (cf product-owner)
// TODO: passer par le timestamp pour s'assurer de la validité
static function traiterDateObs($date, $ref_ligne) {
// TODO: see https://github.com/PHPOffice/PHPExcel/issues/208
// TODO: PHPExcel_Shared_Date::ExcelToPHP()
if (is_double($date)) {
if ($date > 0) {
return PHPExcel_Style_NumberFormat::toFormattedString($date, PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2) . " 00:00:00";
}
 
$msg = "ligne «{$ref_ligne}»: Attention: date antérieure à 1970 et format de cellule «DATE» utilisés ensemble";
trigger_error($msg, E_USER_NOTICE);
} else {
// attend l'un des formats de
// http://www.php.net/manual/fr/datetime.formats.date.php
// le plus simple: YYYY/MM/DD (utilisé à l'export), mais DD-MM-YYYY est aussi supporté
$matches = NULL;
// et on essaie d'être sympa et supporter aussi DD/MM/YYYY
if (preg_match(';^([0-3]?\d)/([01]\d)/([12]\d\d\d)$;', $date, $matches)) {
$date = $matches[3] . '/' . $matches[2] . '/' . $matches[1];
}
$timestamp = strtotime($date);
if (! $timestamp || $timestamp > time() + 3600 * 24 * 1) { // une journée d'avance maxi autorisée (décallage horaire ?)
if ($date) {
$msg = "ligne «{$ref_ligne}»: Attention: date erronée ($date)";
trigger_error($msg, E_USER_NOTICE);
}
return NULL;
}
return strftime('%Y-%m-%d 00:00:00', $timestamp);
}
}
 
static function identReferentiel($referentiel, $ligne, $ref_ligne) {
// SELECT DISTINCT nom_referentiel, COUNT(id_observation) AS count FROM cel_obs GROUP BY nom_referentiel ORDER BY count DESC;
if (strpos($referentiel, 'bdtfx') !== FALSE) {
return 'bdtfx'; //:v1.01';
}
if (strpos($referentiel, 'bdtxa') !== FALSE) {
return 'bdtxa'; //:v1.00';
}
if (strpos($referentiel, 'bdnff') !== FALSE) {
return 'bdtfx';
}
if (strpos($referentiel, 'isfan') !== FALSE) {
return 'isfan'; //:v1.00';
}
if (strpos($referentiel, 'apd') !== FALSE) {
return 'apd'; //:v1.00';
}
if (strpos($referentiel, 'autre') !== FALSE) {
return 'autre';
}
 
if ($referentiel && isset($ligne[C_NOM_SEL]) && $ligne[C_NOM_SEL]) {
$msg = "ligne «{$ref_ligne}»: Attention: référentiel «{$referentiel}» inconnu";
trigger_error($msg, E_USER_NOTICE);
return 'autre';
}
return NULL;
}
 
static function traiterLonLat($lon = NULL, $lat = NULL, $referentiel = 'bdtfx', $ref_ligne) {
// en CSV ces valeurs sont des string, avec séparateur en français (","; cf défauts dans ExportXLS)
if ($lon && is_string($lon)) {
$lon = str_replace(',', '.', $lon);
}
if ($lat && is_string($lat)) {
$lat = str_replace(',', '.', $lat);
}
 
// sprintf applique une précision à 5 décimale (comme le ferait MySQL)
// tout en uniformisant le format de séparateur des décimales (le ".")
if ($lon && is_numeric($lon) && $lon >= -180 && $lon <= 180) {
return sprintf('%.5F', $lon);
}
if ($lat && is_numeric($lat) && $lat >= -90 && $lat <= 90) {
return sprintf('%.5F', $lat);
}
 
if ($lon || $lat) {
trigger_error("ligne \"{$ref_ligne}\": " .
"Attention: longitude ou latitude erronée",
E_USER_NOTICE);
}
return NULL;
}
 
/*
TODO: s'affranchir du webservice pour la détermination du nom scientifique en s'appuyant sur cel_references,
pour des questions de performances
*/
static function traiterEspece($ligne, Array &$espece, &$referentiel, $taxon_info_webservice) {
if (empty($ligne[C_NOM_SEL])) {
return;
}
 
// nom_sel reste toujours celui de l'utilisateur
$espece[C_NOM_SEL] = trim($ligne[C_NOM_SEL]);
 
// XXX/attention, nous ne devrions pas accepter un référentiel absent !
if (!$referentiel) {
$referentiel = 'bdtfx';
}
$taxon_info_webservice->setReferentiel($referentiel);
$ascii = iconv('UTF-8', 'ASCII//TRANSLIT', $ligne[C_NOM_SEL]);
 
$determ = $taxon_info_webservice->rechercherInfosSurTexteCodeOuNumTax(trim($ligne[C_NOM_SEL]));
 
// note: rechercherInfosSurTexteCodeOuNumTax peut ne retourner qu'une seule clef "nom_sel"
if (! $determ) {
// on supprime les noms retenus et renvoi tel quel
// on réutilise les define pour les noms d'indexes, tant qu'à faire
// XXX; tout à NULL sauf C_NOM_SEL ci-dessus ?
$espece[C_NOM_SEL_NN] = @$ligne[C_NOM_SEL_NN];
$espece[C_NOM_RET] = @$ligne[C_NOM_RET];
$espece[C_NOM_RET_NN] = @$ligne[C_NOM_RET_NN];
$espece[C_NT] = @$ligne[C_NT];
$espece[C_FAMILLE] = @$ligne[C_FAMILLE];
 
return;
}
 
// succès de la détection, mais résultat partiel
if (!isset($determ->id)) {
$determ = $taxon_info_webservice->effectuerRequeteInfosComplementairesSurNumNom($determ->{"nom_retenu.id"});
}
 
// ne devrait jamais arriver !
if (!$determ) {
die("erreur critique: " . __FILE__ . ':' . __LINE__);
}
 
// un schéma <ref>:(nt|nn):<num> (ie: bdtfx:nt:8503) a été passé
// dans ce cas on met à jour le référentiel avec celui passé dans le champ espèce
if (isset($determ->ref)) {
$referentiel = $determ->ref;
}
 
// succès de la détection
// nom_sel est remplacé, mais seulement si un motif spécial à été utilisé (bdtfx:nn:4567)
if ($taxon_info_webservice->is_notation_spe) {
$espece[C_NOM_SEL] = $determ->nom_sci;
}
 
// écrasement des numéros (nomenclatural, taxonomique) saisis...
$espece[C_NOM_SEL_NN] = $determ->id;
$espece[C_NOM_RET] = RechercheInfosTaxonBeta::supprimerBiblio($determ->nom_retenu_complet);
$espece[C_NOM_RET_NN] = $determ->{"nom_retenu.id"};
$espece[C_NT] = $determ->num_taxonomique;
$espece[C_FAMILLE] = $determ->famille;
return;
}
 
static function detectFromNom($nom) {
$r = Cel::db()->requeter(sprintf("SELECT num_nom, num_tax_sup FROM bdtfx_v1_01 WHERE (nom_sci LIKE '%s') ".
"ORDER BY nom_sci ASC LIMIT 0, 1",
Cel::db()->proteger($nom)));
if ($r) {
return $r;
}
 
Cel::db()->requeter(sprintf("SELECT num_nom, num_tax_sup FROM bdtfx_v1_01 WHERE (nom_sci LIKE '%s' OR nom LIKE '%s') ".
"ORDER BY nom_sci ASC LIMIT 0, 1",
Cel::db()->proteger($nom),
Cel::db()->proteger(str_replace(' ', '% ', $nom))));
return $r;
}
 
static function traiterLocalisation($ligne, Array &$localisation) {
if (empty($ligne[C_ZONE_GEO])) {
$ligne[C_ZONE_GEO] = NULL;
}
if (empty($ligne[C_CE_ZONE_GEO])) {
$ligne[C_CE_ZONE_GEO] = NULL;
}
 
$identifiant_commune = trim($ligne[C_ZONE_GEO]);
if (!$identifiant_commune) {
$departement = trim($ligne[C_CE_ZONE_GEO]);
 
if (strpos($departement, 'INSEE-C:', 0) === 0) {
$localisation[C_CE_ZONE_GEO] = trim($ligne[C_CE_ZONE_GEO]);
if (array_key_exists($localisation[C_CE_ZONE_GEO], self::$cache['geo'])) {
$localisation[C_ZONE_GEO] = self::$cache['geo'][$localisation[C_CE_ZONE_GEO]];
} else {
$nom = Cel::db()->requeter(sprintf("SELECT nom FROM cel_zones_geo WHERE code = %s LIMIT 1",
self::quoteNonNull(substr($localisation[C_CE_ZONE_GEO], strlen("INSEE-C:")))));
if ($nom) {
$localisation[C_ZONE_GEO] = $nom[0]['nom'];
}
self::$cache['geo'][$localisation[C_CE_ZONE_GEO]] = @$nom[0]['nom'];
}
return;
}
 
if (!is_numeric($departement)) {
$localisation[C_CE_ZONE_GEO] = $ligne[C_CE_ZONE_GEO];
return;
}
 
$cache_attempted = FALSE;
if(array_key_exists($departement, self::$cache['geo'])) {
$cache_attempted = TRUE;
if (self::$cache['geo'][$departement][0] && self::$cache['geo'][$departement][1]) {
$localisation[C_ZONE_GEO] = self::$cache['geo'][$departement][0];
$localisation[C_CE_ZONE_GEO] = self::$cache['geo'][$departement][1];
return;
}
}
 
$requete = "SELECT DISTINCT nom, CONCAT('INSEE-C:', code) AS code ".
'FROM cel_zones_geo '.
'WHERE code = %s '.
'LIMIT 1 '.
' -- '.__FILE__.':'.__LINE__;
$resultat_commune = Cel::db()->requeter(sprintf($requete, self::quoteNonNull($departement)));
if (! $cache_attempted && $resultat_commune) {
$localisation[C_ZONE_GEO] = $resultat_commune[0]['nom'];
$localisation[C_CE_ZONE_GEO] = $resultat_commune[0]['code'];
self::$cache['geo'][$departement] = array($resultat_commune[0]['nom'], $resultat_commune[0]['code']);
return;
}
$localisation[C_CE_ZONE_GEO] = $ligne[C_CE_ZONE_GEO];
return;
}
 
$select = "SELECT DISTINCT nom, code FROM cel_zones_geo";
 
if (preg_match('/(.+) \((\d{1,5})\)/', $identifiant_commune, $elements)) {
// commune + departement : montpellier (34)
$nom_commune=$elements[1];
$code_commune=$elements[2];
if (strlen($code_commune) <= 2) {
$requete = sprintf("%s WHERE nom = %s AND code LIKE %s",
$select, self::quoteNonNull($nom_commune),
self::quoteNonNull($code_commune.'%'));
} else {
$requete = sprintf("%s WHERE nom = %s AND code = %d",
$select, self::quoteNonNull($nom_commune),
$code_commune);
}
} elseif (preg_match('/^(\d+|(2[ab]\d+))$/i', $identifiant_commune, $elements)) {
// Code insee seul
$code_insee_commune=$elements[1];
$requete = sprintf("%s WHERE code = %s", $select, self::quoteNonNull($code_insee_commune));
} else {
// Commune seule (le departement sera recupere dans la colonne departement si elle est presente)
// on prend le risque ici de retourner une mauvaise Commune
$nom_commune = str_replace(" ", "%", iconv('UTF-8', 'ASCII//TRANSLIT', $identifiant_commune));
$requete = sprintf("%s WHERE nom LIKE %s", $select, self::quoteNonNull($nom_commune.'%'));
}
 
if (array_key_exists($identifiant_commune, self::$cache['geo'])) {
$resultat_commune = self::$cache['geo'][$identifiant_commune];
} else {
$resultat_commune = Cel::db()->requeter($requete);
self::$cache['geo'][$identifiant_commune] = $resultat_commune;
}
 
// cas de la commune introuvable dans le référentiel
// réinitialisation aux valeurs du fichier XLS
if (! $resultat_commune) {
$localisation[C_ZONE_GEO] = trim($ligne[C_ZONE_GEO]);
$localisation[C_CE_ZONE_GEO] = trim($ligne[C_CE_ZONE_GEO]);
} else {
$localisation[C_ZONE_GEO] = $resultat_commune[0]['nom'];
$localisation[C_CE_ZONE_GEO] = "INSEE-C:" . $resultat_commune[0]['code'];
return;
}
 
$departement =& $localisation[C_CE_ZONE_GEO];
 
if (strpos($departement, "INSEE-C:", 0) === 0) {
$localisation[C_ZONE_GEO] = $localisation[C_ZONE_GEO];
$localisation[C_CE_ZONE_GEO] = $localisation[C_CE_ZONE_GEO];
}
 
if (!is_numeric($departement)) {
$localisation[C_ZONE_GEO] = $localisation[C_ZONE_GEO];
$localisation[C_CE_ZONE_GEO] = $localisation[C_CE_ZONE_GEO];
}
 
if (strlen($departement) == 4) {
$departement = "INSEE-C:0$departement";
}
if (strlen($departement) == 5) {
$departement = "INSEE-C:$departement";
}
$departement = trim($departement);
 
$localisation[C_ZONE_GEO] = $localisation[C_ZONE_GEO];
$localisation[C_CE_ZONE_GEO] = $localisation[C_CE_ZONE_GEO];
}
 
public static function stockerChampsEtendus($champs_etendus, $ordre_ids, $config) {
// singleton du pauvre mais l'export est suffisamment inefficace pour s'en priver
self::$gestion_champs_etendus = self::$gestion_champs_etendus == null ?
new GestionChampsEtendus($config, 'obs') :
self::$gestion_champs_etendus;
 
$champs_etendus_obs = array();
foreach ($champs_etendus as $champ_etendu_a_obs) {
$id_obs = $ordre_ids[$champ_etendu_a_obs['ordre']]; // id réel de l'observation correspondant à l'ordre
foreach ($champ_etendu_a_obs['champs_etendus'] as $label => $champ) {
// XXX: insère t'on des valeurs vides ?
$valeur = $champ;
$cle = $label;
 
if (!empty($cle) && !empty($valeur)) {
$champ_etendu_a_inserer = new ObsEtendue();
$champ_etendu_a_inserer->id = $id_obs;
$champ_etendu_a_inserer->cle = $cle;
$champ_etendu_a_inserer->valeur = $valeur;
 
$champs_etendus_obs[] = $champ_etendu_a_inserer;
}
}
}
 
self::$gestion_champs_etendus->ajouterParLots($champs_etendus_obs);
//TODO: que faire si l'insertion des champs étendus échoue ?
return count($champs_etendus_obs);
}
 
/* HELPERS */
 
// http://stackoverflow.com/questions/348410/sort-an-array-based-on-another-array
// XXX; utilisé aussi (temporairement ?) par FormateurGroupeColonne.
static function sortArrayByArray($array, $orderArray) {
$ordered = array();
foreach($orderArray as $key) {
if (array_key_exists($key, $array)) {
$ordered[$key] = $array[$key];
unset($array[$key]);
}
}
return $ordered + $array;
}
 
// retourne une BBox [N,S,E,O) pour un référentiel donné
static function getReferentielBBox($referentiel) {
if ($referentiel == 'bdtfx') {
return Array(
'NORD' => 51.2, // Dunkerque
'SUD' => 41.3, // Bonifacio
'EST' => 9.7, // Corse
'OUEST' => -5.2); // Ouessan
}
return FALSE;
}
 
// ces valeurs ne sont pas inséré via les placeholders du PDO::preparedStatement
// et doivent donc être échappées correctement.
public function initialiser_colonnes_statiques() {
$this->colonnes_statiques = array_merge($this->colonnes_statiques,
array(
'ce_utilisateur' => self::quoteNonNull($this->id_utilisateur), // peut-être un hash ou un id
'prenom_utilisateur' => self::quoteNonNull($this->utilisateur['prenom']),
'nom_utilisateur' => self::quoteNonNull($this->utilisateur['nom']),
'courriel_utilisateur' => self::quoteNonNull($this->utilisateur['courriel']),
));
}
 
static function initialiser_pdo_ordered_statements($colonnes_statiques) {
return Array(
// insert_ligne_pattern_ordre
sprintf('INSERT INTO cel_obs (%s, %s) VALUES',
implode(', ', array_keys($colonnes_statiques)),
implode(', ', array_diff(self::$ordre_BDD, array_keys($colonnes_statiques)))),
 
// insert_ligne_pattern_ordre
sprintf('(%s, %s ?)',
implode(', ', $colonnes_statiques),
str_repeat('?, ', count(self::$ordre_BDD) - count($colonnes_statiques) - 1))
);
}
 
static function initialiser_pdo_statements($colonnes_statiques) {
return Array(
// insert_prefix
sprintf('INSERT INTO cel_obs (%s) VALUES ',
implode(', ', self::$ordre_BDD)),
 
 
// insert_ligne_pattern, cf: self::$insert_ligne_pattern
'(' .
// 3) créé une chaîne de liste de champ à inséré en DB
implode(', ', array_values(
// 2) garde les valeurs fixes (de $colonnes_statiques),
// mais remplace les NULL par des "?"
array_map('__anonyme_5',
// 1) créé un tableau genre (nom_sel_nn => NULL) depuis self::$ordre_BDD
// et écrase certaines valeurs avec $colonnes_statiques (initilisé avec les données utilisateur)
array_merge(array_map('__anonyme_6', array_flip(self::$ordre_BDD)), $colonnes_statiques
)))) .
')'
);
}
 
// équivalent à Bdd->proteger() (qui wrap PDO::quote),
// sans transformer NULL en ""
static function quoteNonNull($chaine) {
if (is_null($chaine)) {
return 'NULL';
}
if (!is_string($chaine) && !is_integer($chaine)) {
die('erreur: ' . __FILE__ . ':' . __LINE__);
}
return Cel::db()->quote($chaine);
}
 
public function erreurs_stock($errno, $errstr) {
$this->bilan[] = $errstr;
}
}
?>
Property changes:
Added: svnkit:entry:sha1-checksum
+e0804924c0e3cfd0355754a5dbd2050a5012db06
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/CelStatistiqueTxt.php
New file
0,0 → 1,495
<?php
// declare(encoding='UTF-8');
/**
* Service fournissant des statistiques de l'application CEL au format texte (JSON).
* Encodage en entrée : utf8
* Encodage en sortie : utf8
*
* Cas d'utilisation :
* /CelStatistiqueTxt/TypeDeStat : retourne les statistiques demandées
* Paramêtres :
* utilisateur=courriel : retourne les statistiques d'un utilisateur donné.
*
* @internal Mininum PHP version : 5.2
* @category CEL
* @package Services
* @subpackage Statistiques
* @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 CelStatistiqueTxt extends Cel {
 
/**
* Méthode appelée avec une requête de type GET.
*/
public function getElement($ressources) {
$graph = null;
$serveur = '';
 
if (isset($ressources[0])) {
$this->analyserParametresUrl();
$stat_demande = array_shift($ressources);
$methode = 'get'.$stat_demande;
if (method_exists($this, $methode)) {
$this->ressources = $ressources;
$stats = $this->$methode($ressources);
} else {
$this->messages[] = "Ce type de statistiques '$stat_demande' n'est pas disponible.";
}
} else {
$this->messages[] = "La ressource du service CEL StatistiqueTxt doit indiquer le type de statistique. Ex. : .../CelStatistiqueTxt/Nombres";
}
 
if (!is_null($stats)) {
$this->envoyerJson($stats);
}
}
 
private function analyserParametresUrl() {
$this->parametres['utilisateur'] = isset($_GET['utilisateur']) ? Cel::db()->quote($this->verifierSecuriteParametreUrl($_GET['utilisateur'])) : null;
$this->parametres['num_taxon'] = isset($_GET['num_taxon']) ? Cel::db()->quote($this->verifierSecuriteParametreUrl($_GET['num_taxon'])) : null;
$this->parametres['taxon'] = isset($_GET['taxon']) ? Cel::db()->quote($this->verifierSecuriteParametreUrl($_GET['taxon'].'%')) : null;
$this->parametres['tag'] = isset($_GET['tag']) ? $this->verifierSecuriteParametreUrl($_GET['tag']) : null;
$this->parametres['start'] = isset($_GET['start']) ? $this->verifierSecuriteParametreUrl($_GET['start']) : null;
$this->parametres['limit'] = isset($_GET['limit']) ? $this->verifierSecuriteParametreUrl($_GET['limit']) : null;
}
 
private function getListeUtilisateursNbrePhotos() {
$liste = array();
 
$requete = $this->construireRequeteListeUtilisateurNbrePhoto();
if ($requete != null) {
$resultats = Cel::db()->requeter($requete);
if ($resultats != false) {
foreach ($resultats as $resultat) {
$liste[$resultat['courriel_utilisateur']] = $resultat['nbre'];
}
}
}
return $liste;
}
 
private function construireRequeteListeUtilisateurNbrePhoto() {
$select = 'SELECT co.courriel_utilisateur, COUNT(DISTINCT ci.id_image) AS nbre ';
$from = 'FROM cel_export_total AS co '.
' LEFT JOIN cel_images_export AS ci ON (co.id_observation = ci.ce_observation) ';
$where = 'WHERE co.transmission = 1 ';
$groupBy = 'GROUP BY co.courriel_utilisateur ';
$orderBy = 'ORDER BY nbre DESC ';
$limitSql = 'LIMIT 0,150 ';
 
$zero_images = false;
if (count($this->parametres) != 0) {
extract($this->parametres);
 
$filtres = array();
 
if (isset($utilisateur)) {
$filtres[] = "co.courriel_utilisateur = $utilisateur ";
}
if (isset($num_taxon)) {
$filtres[] = "nt = $num_taxon ";
}
if (isset($taxon)) {
$filtres[] = "nom_ret LIKE $taxon ";
}
if (isset($tag)) {
$tagP = Cel::db()->quote("%$tag%");
$filtres[] = "ci.mots_cles_texte LIKE $tagP ";
}
$where .= ((count($filtres) > 0) ? 'AND '.implode(' AND ', $filtres) : '');
 
if (isset($start)) {
$limitSql = str_replace('0,', "$start,", $limitSql);
}
if (isset($limit)) {
$limitSql = str_replace('150', $limit, $limitSql);
}
}
$requete = $select.$from.$where.$groupBy.$orderBy.$limitSql;
return $requete;
}
 
private function getListeTaxonsNbrePhotos() {
$requete = $this->construireRequeteListeTaxonNbrePhoto();
 
$resultats = Cel::db()->requeter($requete);
$liste = array();
if ($resultats != false) {
foreach ($resultats as $resultat) {
$liste[$resultat['nom_ret']] = $resultat['nbre'];
}
}
return $liste;
}
 
private function construireRequeteListeTaxonNbrePhoto() {
$select = 'SELECT nom_ret, COUNT(DISTINCT ci.id_image) AS nbre ';
$from = 'FROM cel_export_total co '.
' LEFT JOIN cel_images_export ci ON (co.id_observation = ci.ce_observation) ';
$where = 'WHERE co.transmission = 1 '.
" AND nom_ret != '' ";
$groupBy = 'GROUP BY nom_ret ';
$orderBy = 'ORDER BY nbre DESC ';
$limitSql = 'LIMIT 0,150 ';
 
 
if (count($this->parametres) != 0) {
extract($this->parametres);
 
$filtres = array();
 
if (isset($utilisateur)) {
$filtres[] = "co.courriel_utilisateur = $utilisateur ";
}
if (isset($num_taxon)) {
$filtres[] = "nt = $num_taxon ";
}
if (isset($taxon)) {
$filtres[] = "nom_ret LIKE $taxon ";
}
$where .= ((count($filtres) > 0) ? 'AND '.implode(' AND ', $filtres) : '');
 
if (isset($start)) {
$limitSql = str_replace('0,', "$start,", $limitSql);
}
if (isset($limit)) {
$limitSql = str_replace('150', $limit, $limitSql);
}
}
 
$requete = $select.$from.$where.$groupBy.$orderBy.$limitSql;
 
return $requete;
}
 
private function getNombres() {
 
$requete = $this->construireRequeteNbreObs();
$info['observations'] = (int) Cel::db()->requeterValeurUnique($requete);
 
$requete = $this->construireRequeteNbreObsPubliques();
$info['observationsPubliques'] = (int) Cel::db()->requeterValeurUnique($requete);
 
$requete = $this->construireRequeteNbreImg();
$info['images'] =(int) Cel::db()->requeterValeurUnique($requete);
 
$requete = $this->construireRequeteNbreImgLiees();
$info['imagesLiees'] =(int) Cel::db()->requeterValeurUnique($requete);
 
$requete = $this->construireRequeteNbreImgLiees(true);
$info['imagesLieesPubliques'] =(int) Cel::db()->requeterValeurUnique($requete);
 
$requete = $this->construireRequeteNbreObsLiees();
$info['observationsLiees'] = (int) Cel::db()->requeterValeurUnique($requete);
 
$info['moyImagesParObs'] = ($info['observationsLiees'] > 0 ? round($info['imagesLiees']/$info['observationsLiees'], 2) : '');
 
$requete = $this->construireRequeteNbreObsParCommune();
$info['communes'] = ($resultats = Cel::db()->requeter($requete)) ? count($resultats) : '' ;
$info['observationsParCommunesMin'] = 1000;
$info['observationsParCommunesMax'] = 0;
$info['observationsParCommunesTotal'] = 0;
foreach ($resultats as $resultat) {
if ($resultat['nbre'] < $info['observationsParCommunesMin']) {
$info['observationsParCommunesMin'] = $resultat['nbre'];
}
if ($resultat['nbre'] > $info['observationsParCommunesMax']) {
$info['observationsParCommunesMax'] = $resultat['nbre'];
}
$info['observationsParCommunesTotal'] += $resultat['nbre'];
}
$info['observationsParCommunesMoyenne'] = ($info['communes'] > 0 ) ? round($info['observationsParCommunesTotal'] / $info['communes'], 2) : 0;
 
return $info;
}
 
private function getNbObsPubliques() {
$requete = $this->construireRequeteNbreObsPubliques();
$info = (int) Cel::db()->requeterValeurUnique($requete);
return $info;
}
 
private function getNbImagesPubliques() {
$requete = $this->construireRequeteNbreImgLiees(true);
$info = (int) Cel::db()->requeterValeurUnique($requete);
return $info;
}
 
private function construireRequeteNbreObs() {
$requete = 'SELECT COUNT(*) AS nbre '.
'FROM cel_export_total ';
 
if (count($this->parametres) != 0) {
$filtres = array();
extract($this->parametres);
 
if (isset($utilisateur)) {
$filtres[] = "courriel_utilisateur = $utilisateur ";
}
if (isset($num_taxon)) {
$filtres[] = "nom_ret_nn = $num_taxon ";
}
if (isset($taxon)) {
$filtres[] = "nom_ret LIKE $taxon ";
}
 
$requete .= ((count($filtres) > 0) ? 'WHERE '.implode(' AND ', $filtres) : '');
}
 
return $requete;
}
 
private function construireRequeteNbreObsPubliques() {
$requete = 'SELECT COUNT(*) AS nbre '.
'FROM cel_export_total '.
"WHERE transmission = 1 ";
 
if (count($this->parametres) != 0) {
$filtres = array();
extract($this->parametres);
 
if (isset($utilisateur)) {
$filtres[] = "courriel_utilisateur = $utilisateur ";
}
if (isset($num_taxon)) {
$filtres[] = "nom_ret_nn = $num_taxon ";
}
if (isset($taxon)) {
$filtres[] = "nom_ret LIKE $taxon ";
}
 
$requete .= ((count($filtres) > 0) ? 'AND '.implode(' AND ', $filtres) : '');
}
 
return $requete;
}
 
private function construireRequeteNbreObsParCommune() {
$requete = 'SELECT COUNT(id_observation) AS nbre '.
'FROM cel_export_total '.
"WHERE zone_geo IS NOT NULL ".
" AND ce_zone_geo IS NOT NULL ";
$groupBy = 'GROUP BY zone_geo, ce_zone_geo';
 
if (count($this->parametres) != 0) {
$filtres = array();
extract($this->parametres);
 
if (isset($utilisateur)) {
$filtres[] = "courriel_utilisateur = $utilisateur ";
}
if (isset($num_taxon)) {
$filtres[] = "nt = $num_taxon ";
}
if (isset($taxon)) {
$filtres[] = "nom_ret LIKE $taxon ";
}
 
$requete .= ((count($filtres) > 0) ? 'AND '.implode(' AND ', $filtres) : '');
}
$requete .= $groupBy;
 
return $requete;
}
 
private function construireRequeteNbreImg() {
$select = 'SELECT COUNT(DISTINCT ci.id_image) AS nbre ';
$from = 'FROM cel_images_export ci ';
 
if (count($this->parametres) != 0) {
$filtres = array();
 
extract($this->parametres);
 
if (isset($utilisateur)) {
$filtres[] = "courriel_utilisateur = $utilisateur ";
}
if (isset($num_taxon)) {
 
$filtres[] = "nt = $num_taxon ";
}
if (isset($taxon)) {
$filtres[] = "nom_ret LIKE $taxon ";
}
if (isset($num_taxon) || isset($taxon)) {
$from .= 'LEFT JOIN cel_export_total co ON (ci.ce_observation = co.id_observation) ';
}
 
$where = ((count($filtres) > 0) ? 'WHERE '.implode(' AND ', $filtres) : '');
}
$requete = $select.$from.$where;
 
return $requete;
}
 
private function construireRequeteNbreImgLiees($publiquesSeulement=false) {
$select = 'SELECT COUNT(DISTINCT ci.id_image) AS nbre ';
$from = 'FROM cel_images_export ci ';
 
if (count($this->parametres) != 0) {
$filtres = array();
 
extract($this->parametres);
 
if (isset($utilisateur)) {
$filtres[] = "ci.courriel_utilisateur = $utilisateur ";
}
if (isset($num_taxon)) {
$filtres[] = "nt = $num_taxon ";
}
if (isset($taxon)) {
$filtres[] = "nom_ret LIKE $taxon ";
}
if ($publiquesSeulement === true) {
$filtres[] = "ci.transmission = 1";
}
 
if (isset($num_taxon) || isset($taxon)) {
$from .= 'LEFT JOIN cel_export_total ON (ci.ce_observation = co.id_observation) ';
}
 
$where = ((count($filtres) > 0) ? 'WHERE '.implode(' AND ', $filtres) : '');
}
 
$requete = $select.$from.$where;
return $requete;
}
 
private function construireRequeteNbreObsLiees() {
$select = 'SELECT COUNT(DISTINCT id_observation) AS nbre ';
$from = 'FROM cel_images_export ci '.
' LEFT JOIN cel_export_total co ON (ci.ce_observation = co.id_observation) ';
 
if (count($this->parametres) != 0) {
$filtres = array();
 
extract($this->parametres);
 
if (isset($utilisateur)) {
$filtres[] = "courriel_utilisateur = $utilisateur ";
}
if (isset($num_taxon)) {
$filtres[] = "nt = $num_taxon ";
}
if (isset($taxon)) {
$filtres[] = "nom_ret LIKE $taxon ";
}
 
$where = ((count($filtres) > 0) ? 'WHERE '.implode(' AND ', $filtres) : '');
}
 
$requete = $select.$from.$where;
 
return $requete;
}
 
 
/**
* Retourne les n principaux contributeurs depuis x jours,
* en termes d'observations ajoutées, d'images ajoutées, ou les deux
* Paramètres : "jours" (int), "nombre" (int), "critere" ("obs" ou "img" ou "")
* @return array
*/
private function getGrandsContributeurs() {
$nombre = 10; // les $nombre plus importants contributeurs
$jours = 7; // depuis $jours jours
$critere = null; // "obs", "img" ou null (les deux)
 
if (isset($this->parametres['nombre'])) {
$nombre = $this->parametres['nombre'];
}
if (isset($this->parametres['jours'])) {
$jours = $this->parametres['jours'];
}
if (isset($this->parametres['critere'])) {
$critere = $this->parametres['critere'];
}
 
$requete = $this->construireRequeteGrandsContributeurs($nombre, $jours, $critere);
$resultats = Cel::db()->requeter($requete);
 
$courriels = array();
foreach ($resultats as $res) {
$courriels[] = $res['courriel_utilisateur'];
}
$identites = $this->recupererUtilisateursIdentite($courriels);
foreach ($resultats as &$res) {
$res['intitule_utilisateur'] = $identites[$res['courriel_utilisateur']]['intitule'];
unset($res['courriel_utilisateur']);
unset($res['nom_utilisateur']);
unset($res['prenom_utilisateur']);
}
 
$retour = array(
'entete' => array(
'nombre' => intval($nombre),
'jours' => intval($jours),
'critere' => $critere
),
'resultats' => array()
);
$liste = array();
if ($resultats != false) {
foreach ($resultats as $resultat) {
// essayons de faire du JSON propre
if (isset($resultat['nombreImg'])) {
$resultat['nombreImg'] = intval($resultat['nombreImg']);
}
if (isset($resultat['nombreObs'])) {
$resultat['nombreObs'] = intval($resultat['nombreObs']);
}
if (isset($resultat['somme'])) {
$resultat['somme'] = intval($resultat['somme']);
}
$liste[] = $resultat; // pas de clefs afin de renvoyer une "liste" JSON, qui sera interprétée en conservant l'ordre
}
$retour['resultats'] = $liste;
}
return $retour;
}
 
private function construireRequeteGrandsContributeurs($nombre = 10, $jours = 7, $critere = null) {
$requete = '';
switch ($critere) {
case 'obs':
$requete = "SELECT ce_utilisateur , prenom_utilisateur , nom_utilisateur , courriel_utilisateur , ".
" COUNT(*) AS nombreObs ".
"FROM cel_export_total ".
"WHERE transmission = 1 ".
"AND TO_DAYS(NOW()) - TO_DAYS(date_transmission) <= $jours ".
"GROUP BY ce_utilisateur ".
"ORDER BY nombreObs DESC ".
"LIMIT $nombre ";
break;
case 'img':
$requete = "SELECT co.ce_utilisateur , co.prenom_utilisateur , co.nom_utilisateur , ".
" co.courriel_utilisateur , COUNT(DISTINCT ci.id_image) AS nombreImg ".
"FROM cel_images_export ci ".
" RIGHT JOIN cel_export_total co ON ci.ce_observation = co.id_observation ".
"WHERE co.transmission = 1 ".
"AND TO_DAYS(NOW()) - TO_DAYS(co.date_transmission) <= $jours ".
"GROUP BY co.ce_utilisateur ".
"ORDER BY nombreImg DESC ".
"LIMIT $nombre ";
break;
default:
$requete = "SELECT co.ce_utilisateur, co.prenom_utilisateur, co.nom_utilisateur, co.courriel_utilisateur, ".
"COUNT(DISTINCT ci.id_image) AS nombreImg, COUNT(DISTINCT co.id_observation) AS nombreObs, ".
"COUNT(DISTINCT ci.id_image) + COUNT(DISTINCT co.id_observation) AS somme ".
"FROM cel_images_export ci ".
" RIGHT JOIN cel_export_total co ON ci.ce_observation = co.id_observation ".
"WHERE co.transmission = 1 ".
"AND TO_DAYS(NOW()) - TO_DAYS(co.date_transmission) <= $jours ".
"GROUP BY co.ce_utilisateur ".
"ORDER BY somme DESC ".
"LIMIT $nombre ";
}
return $requete;
}
}
Property changes:
Added: svnkit:entry:sha1-checksum
+32dc69106cc48846a20bc24c7567e5fdf4af646b
\ No newline at end of property
/branches/v3.01-serpe/jrest/services/.
New file
Property changes:
Added: svn:mergeinfo
Merged /branches/v2.0-elagueuse/jrest/services:r2113-2114
Merged /branches/v2.4-fourche/jrest/services:r2295,2310-2311,2313,2316
Merged /branches/topic-dbsingleton/jrest/services:r1720-1764
Merged /branches/v1.8-debroussailleuse/jrest/services:r1981,1987,1992
Merged /branches/v2.23-rouleau/jrest/services:r2777
Merged /branches/v2.6-greffoir/services:r2396-2397
Merged /branches/v2.10-motoculteur/jrest/services:r2655-2661
Merged /branches/v2.24-sarcloir/jrest/services:r2825,2827,2829
Merged /branches/v2.2-faucille/jrest/services:r2185-2186,2188,2197-2198
Merged /branches/v2.6-greffoir/jrest:r2396-2397
Merged /branches/v2.8-houe/jrest/services:r2477-2485,2489,2495,2502-2503
Merged /branches/v2.6-greffoir/jrest/services:r2355-2384,2396-2397,2399
Merged /branches/v1.7-croissant/jrest/services:r1855,1879-1880,1885-1886,1917,1923,1983
Merged /branches/v2.25-scarificateur/jrest/services:r3001
Added: svn:ignore
+MigrationImages.php
+MigrationMotsCles.php
+MigrationObs.php
+Test.php