Rev 846 | Rev 1044 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php// declare(encoding='UTF-8');/*** Classe implémentant l'API d'eFlore Images pour le projet CEL.** @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=EfloreApi01Images** @package eFlore/services* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>* @author Aurélien 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>* @version 1.0* @copyright 1999-2011 Tela Botanica (accueil@tela-botanica.org)*/// TODO : Config et Outils sont des classes statiques qui doivent poser des pb pour les tests...class Images extends Commun {protected $parametres = array();protected $ressources = array();private $Bdd;const CODE_REFTAX_DEFAUT = 'bdtfx';const TPL_URL_IMG = 'http://www.tela-botanica.org/appli:cel-img:%s.jpg';const TAILLE_IMG_DEFAUT = 'M';const MIME_JPEG = 'image/jpeg';const MIME_JSON = 'application/json';private $config = array();private $cheminImagesBase = '';private $formats_supportes = array(self::MIME_JPEG, self::MIME_JSON);private $tris_supportes = array('date');private $retour_champs = array('determination.nom_sci' => 'nom_sel', 'determination.nom_sci.code' => 'nom_sel_nn','station.lieudit' => 'lieudit', 'station', 'milieu');private $code_ref_tax_demande = null;private $ref_tax_demande = array();private $infosImages = array();private $nbreImages = 0;private $Utilisateurs = null;private $UrlNavigation = null;public function __construct(Bdd $bdd = null, Array $config = null, Utilisateurs $utilisateurs = null, Url $url = null) {$this->config = is_null($config) ? Config::get('Images') : $config;$this->Bdd = is_null($bdd) ? new Bdd() : $bdd;$this->Utilisateurs = is_null($utilisateurs) ? new Utilisateurs() : $utilisateurs;$this->UrlNavigation = is_null($url) ? new Url($this->config['urlService']) : $url;$this->cheminImagesBase = $this->config['chemin'];}public function consulter($ressources, $parametres) {//$tpsDebut = microtime(true);$this->parametres = $parametres;$this->ressources = $ressources;$this->definirValeurParDefautDesParametres();$this->verifierParametres();$resultat = new ResultatService();if ($this->parametres['retour'] == self::MIME_JPEG) {if (@$this->parametres['retour.tri'] == 'date') { // recherche la plus vieille image du CEL$id_image_a_renvoyer = $this->obtenirIdPremiereImage();} else {$id_image_a_renvoyer = $this->obtenirIdImageAuHasard();}$resultat->corps = $this->recupererImageBinaire($id_image_a_renvoyer);} else if ($this->parametres['retour'] == self::MIME_JSON) {if (isset($this->ressources[0])) {$this->chargerInfosImage();$this->extraireIdentitesAuteurs();$resultat->corps = $this->formaterInfosImage($this->infosImages[0]);} else {$this->chargerListeImages();$this->chargerNbreImagesTotal();$resultat->corps = $this->formaterListeImages();}}$resultat->mime = $this->parametres['retour'];return $resultat;}//+---------------------------FONCTION D'ANALYSE DES PARAMETRES---------------------------------------------------------+private function definirValeurParDefautDesParametres() {if (isset($this->parametres['retour']) == false) {$this->parametres['retour'] = self::MIME_JSON;}if (isset($this->parametres['retour.format']) == false) {$this->parametres['retour.format'] = 'M';}if (isset($this->parametres['navigation.depart']) == false) {$this->parametres['navigation.depart'] = 0;}if (isset($this->parametres['navigation.limite']) == false) {$this->parametres['navigation.limite'] = 100;}if (isset($this->parametres['referentiel']) == false) {$this->parametres['referentiel'] = self::CODE_REFTAX_DEFAUT;}}private function verifierParametres() {$erreurs = array();if (!isset($this->ressources[0])) {if (isset($this->parametres['masque.nn']) == false) {$erreurs[] = "Le paramètre masque.nn est obligatoire.";} else {$this->analyserMasqueNn();if ($this->verifierMasqueNnAutorisePourRetourJPEG() == false) {$erreurs[] = "Le paramètre masque.nn peut contenir une seule valeur numérique pour l'instant pour le format de retour image/jpeg.";} else if ($this->verifierValeurParametreMasqueNn() == false) {$erreurs[] = "Le paramètre masque.nn est mal formé.";}}}if (isset($this->parametres['retour']) == false) {$erreurs[] = "Le paramètre type de retour 'retour' est obligatoire.";}if ($this->verifierValeurParametreRetour() == false) {$erreurs[] = "Le type de retour '{$this->parametres['retour']}' n'est pas supporté";}if (isset($this->parametres['retour.format']) == false) {$erreurs[] = "Le paramètre de format de retour 'retour.format' est obligatoire.";}if ($this->verifierValeurParametreFormat() == false) {$erreurs[] = "Le type de format '{$this->parametres['retour.format']}' n'est pas supporté";}if (isset($this->parametres['retour.tri'])){if ($this->verifierValeurParametreTri() == false) {$erreurs[] = "Le type de tri '{$this->parametres['retour.tri']}' n'est pas supporté";}}if (isset($this->parametres['retour.champs'])){if ($this->verifierValeurParametreRetourChamps() == false) {$erreurs[] = "Le champs '{$this->parametres['retour.champs']}' n'existe pas";}}if ($this->verifierValeurParametreNavigationDepart() == false) {$erreurs[] = "Le paramètre 'navigation.depart' doit possèder un valeur numérique.";}if ($this->verifierValeurParametreNavigationLimite() == false) {$erreurs[] = "Le paramètre 'navigation.limite' doit possèder un valeur numérique supérieure à 0.";}if (count($erreurs) > 0) {$message = implode('<br />', $erreurs);$code = RestServeur::HTTP_CODE_MAUVAISE_REQUETE;throw new Exception($message, $code);}}private function verifierMasqueNnAutorisePourRetourJPEG() {$ok = true;$masque = $this->parametres['masque.nn'];$retour = $this->parametres['retour'];if ($retour == self::MIME_JPEG) {$ok = is_numeric($masque) ? true : false;}return $ok;}private function verifierValeurParametreMasqueNn() {$nn = $this->parametres['masque.nn'];$projetPattern = '(?:(?:[A-Z0-9]+:)?(?:[0-9]+,)*[0-9]+)';$patternComplet = "/^$projetPattern(?:;$projetPattern)*$/i";$ok = preg_match($patternComplet, $nn) ? true : false;return $ok;}private function verifierValeurParametreRetour() {return in_array($this->parametres['retour'], $this->formats_supportes);}private function verifierValeurParametreFormat() {$formats = Outils::recupererTableauConfig('Images.formats');$ok = array_key_exists($this->parametres['retour.format'], $formats);return $ok;}private function verifierValeurParametreTri() {return in_array($this->parametres['retour.tri'], $this->tris_supportes);}private function verifierValeurParametreRetourChamps() {$ok = false;$liste_champs = preg_split(',', $this->parametres['retour.champs']);foreach ($liste_champs as $champs) {$ok[$champs] = array_key_exists($champs, $this->retour_champs);}return $ok;}private function verifierValeurParametreNavigationDepart() {$depart = $this->parametres['navigation.depart'];$ok = is_numeric($depart) ? true : false;return $ok;}private function verifierValeurParametreNavigationLimite() {$limite = $this->parametres['navigation.limite'];$ok = (is_numeric($limite) && $limite != 0) ? true : false;return $ok;}private function analyserMasqueNn() {$nn = $this->parametres['masque.nn'];if (preg_match('/^[0-9]+$/', $nn)) {$this->ref_tax_demande[$this->parametres['referentiel']][] = $nn;} else {// ceci contient potentiellement des formes ref_tax1:nn1,nn2;ref_tax2:nn3,nn4$projetsListeEtNumNoms = explode(';', $nn);if (count($projetsListeEtNumNoms) > 0) {foreach ($projetsListeEtNumNoms as $projetEtNumNoms) {$projetEtNumNoms = (strpos($projetEtNumNoms, ':')) ? $projetEtNumNoms : $this->parametres['referentiel'].':'.$projetEtNumNoms;list($projet, $numNoms) = explode(':', $projetEtNumNoms);$this->ref_tax_demande[$projet] = explode(',', $numNoms);}}}}//+---------------------------------------- REQUETES ---------------------------------------------------------------+private function obtenirIdImageAuHasard() {$refTax = $this->parametres['referentiel'];$numNom = $this->Bdd->proteger($this->ref_tax_demande[$refTax][0]);$requete = 'SELECT coi.id_image AS id_image '.'FROM cel_obs_images AS coi '.' LEFT JOIN cel_obs AS co '.'ON (coi.id_observation = co.id_observation) '.'WHERE co.transmission = 1 '." AND co.nom_ret_nn IN ($numNom)";" AND co.nom_referentiel = ".$this->Bdd->proteger($refTax) . ' -- ' . __FILE__ . ':' . __LINE__;$resultat = $this->Bdd->recupererTous($requete);if (!is_array($resultat) || count($resultat) <= 0) {$message = "Aucune image ne correspond au numéro numenclatural $refTax:$numNom";$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE;throw new Exception($message, $code);}$id_image_hasard = $resultat[array_rand($resultat)]['id_image'];return $id_image_hasard;}private function obtenirIdPremiereImage() {$refTax = $this->parametres['referentiel'];$numNom = $this->Bdd->proteger($this->ref_tax_demande[$refTax][0]);$requete = 'SELECT ci.id_image AS id_image '.'FROM cel_images AS ci'.' LEFT JOIN cel_obs_images AS coi '.' ON (coi.id_image = ci.id_image) '.' LEFT JOIN cel_obs AS co '.' ON (coi.id_observation = co.id_observation) '.'WHERE co.transmission = 1 '." AND co.nom_ret_nn IN ($numNom) ".' AND ci.date_prise_de_vue != "0000-00-00" ORDER BY ci.date_prise_de_vue ASC '.' AND co.nom_referentiel LIKE '.$this->proteger($refTax.'%').' '.'LIMIT 1' . ' -- ' . __FILE__ . ':' . __LINE__;$resultat = $this->Bdd->recupererTous($requete);if (!is_array($resultat) || count($resultat) <= 0) {$message = "Aucune image ne correspond au numéro numenclatural $refTax:$numNom";$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE;throw new Exception($message, $code);}$id_image_hasard = $resultat[0]['id_image'];return $id_image_hasard;}private function chargerInfosImage() {$requete = 'SELECT SQL_CALC_FOUND_ROWS '.' ci.id_image AS id_img, co.date_observation AS date, '.' co.id_observation AS id_obs, '.' ci.courriel_utilisateur AS utilisateur_courriel, '.' nom_sel, nom_sel_nn, '.' zone_geo, ce_zone_geo, lieudit, station, milieu '.'FROM cel_images AS ci'.' LEFT JOIN cel_obs_images AS coi '.' ON (coi.id_image = ci.id_image) '.' LEFT JOIN cel_obs AS co '.' ON (coi.id_observation = co.id_observation) '.'WHERE ci.id_image = '.$this->ressources[0].' AND co.id_observation IS NOT NULL' . ' -- ' . __FILE__ . ':' . __LINE__;$this->infosImages = $this->Bdd->recupererTous($requete);}private function chargerListeImages() {$refTax = $this->parametres['referentiel'];$numNomListe = implode(',', $this->ref_tax_demande[$refTax]);$depart = $this->parametres['navigation.depart'];$limite = $this->parametres['navigation.limite'];//TODO: modifier la requete lors du passage à la nouvelle base de données pour faire quelque chose// du numéro nomenclatural + modifier les champs appelés pour le nouveau format$requete = 'SELECT SQL_CALC_FOUND_ROWS '.' co.id_observation AS id_obs, co.courriel_utilisateur AS utilisateur_courriel, co.zone_geo, co.ce_zone_geo, '.' co.nom_sel, co.nom_sel_nn, '.' ci.id_image AS id_img, co.date_observation AS date '.(isset($this->parametres['retour.champs']) ? ', '.$this->parametres['retour.champs'] : '').'FROM cel_images AS ci'.' LEFT JOIN cel_obs_images AS coi '.' ON (coi.id_image = ci.id_image) '.' LEFT JOIN cel_obs AS co '.' ON (coi.id_observation = co.id_observation) '.$this->formerRequeteConditions($numNomListe).' '.'GROUP BY id_img '.$this->formerRequeteTri()."LIMIT $depart,$limite " . ' -- ' . __FILE__ . ':' . __LINE__;$this->infosImages = $this->Bdd->recupererTous($requete);}private function formerRequeteConditions($numNomListe) {$refTax = $this->parametres['referentiel'];$where[] = " co.transmission = 1 AND co.nom_ret_nn IN ($numNomListe) ";$where[] = " co.nom_referentiel LIKE ".$this->Bdd->proteger($refTax."%").' ';return ' WHERE '.implode(' AND ', $where);}private function formerRequeteTri() {$order = '';if (isset($this->parametres['retour.tri']) && $this->parametres['retour.tri'] == 'date') {$order = ' ORDER BY co.date_observation ASC ';}return $order;}private function chargerNbreImagesTotal() {$requete = 'SELECT FOUND_ROWS() AS nbre ';$resultats = $this->Bdd->recuperer($requete);$this->nbreImages = (int) $resultats['nbre'];}//+---------------------------------------CHEMIN ET CONVERSION--------------------------------------------------------+private function recupererImageBinaire($id_image) {$image = '';$chemin = $this->obtenirCheminImage($id_image);$image = file_get_contents($chemin);if ($image === false) {$message = "L'image demandée est introuvable sur le serveur : $chemin";$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE;throw new Exception($message, $code);}return $image;}private function obtenirCheminImage($idImage) {$nom = $this->convertirIdImageVersNomFichier($idImage);$dossier = $this->convertirIdImageVersChemin($idImage);return $dossier.'/'.$nom;}private function convertirIdImageVersNomFichier($idImage) {$codeImage = $this->construireCodeImage($idImage);$nom_fichier = $codeImage.'.jpg';return $nom_fichier;}private function convertirIdImageVersChemin($idImage) {$codeImage = $this->construireCodeImage($idImage);list($dossierNiveau1, $dossierNiveau2, $idFichier, $format) = explode('_', $codeImage);$chemin_sur_serveur = $this->cheminImagesBase.'/'.$dossierNiveau1.'/'.$dossierNiveau2.'/'.$format;return $chemin_sur_serveur;}private function construireCodeImage($idImage) {$codeImage = sprintf('%09s', $idImage);$codeImage = wordwrap($codeImage, 3, '_', true);$format = $this->parametres['retour.format'];$codeImage .= '_'.$format;return $codeImage;}//+------------------------------------FORMATAGE LISTE----------------------------------------------------------------+private function formaterListeImages() {$entete = $this->construireEntete();$resultats = $this->construireResultats();$resultat = array('entete' => $entete, 'resultats' => $resultats);return $resultat;}private function construireEntete() {$entete = array('masque' => '', 'depart' => 0, 'limite' => 100, 'total' => 0);$entete['masque'] = $this->recupererMasque();$entete['depart'] = (int) $this->parametres['navigation.depart'];$entete['limite'] = (int) $this->parametres['navigation.limite'];$entete['total'] = $this->nbreImages;if ($hrefPrecedent = $this->recupererHrefPrecedent()) {$entete['href.precedent'] = $hrefPrecedent;}if ($hrefSuivant = $this->recupererHrefSuivant()) {$entete['href.suivant'] = $hrefSuivant;}return $entete;}private function recupererMasque() {$masqueEntete = '';if ($masqueNn = $this->parametres['masque.nn']) {$masqueEntete = "nn=$masqueNn";}return $masqueEntete;}private function recupererHrefPrecedent() {$departActuel = $this->parametres['navigation.depart'];$limite = $this->parametres['navigation.limite'];$departPrecedent = $departActuel - $limite;$url = null;if ($departPrecedent >= 0) {$url = $this->obtenirUrlNavigation($departPrecedent, $limite);}return $url;}private function recupererHrefSuivant() {$departActuel = $this->parametres['navigation.depart'];$limite = $this->parametres['navigation.limite'];$departSuivant = $departActuel + $limite;$url = null;if ($departSuivant < $this->nbreImages) {$url = $this->obtenirUrlNavigation($departSuivant, $limite);}return $url;}private function obtenirUrlNavigation($depart, $limite) {$parametres = array('navigation.depart' => $depart,'navigation.limite' => $limite);if (isset($this->parametres['masque.nn'])) {$parametres['masque.nn'] = $this->parametres['masque.nn'];}$this->UrlNavigation->setRequete($parametres);$url = $this->UrlNavigation->getURL();return $url;}private function construireResultats() {$resultats = array();$this->extraireIdentitesAuteurs();foreach ($this->infosImages as $img) {$info = $this->formaterInfosImage($img);$id = $img['id_img'];$info['href'] = $this->config['urlService'].'/'.$id;if (!isset($resultats[$id])) {$resultats[$id] = $info;} else {throw new Exception("Double : $id");}}return $resultats;}private function formaterInfosImage($img) {$info = array();$info['date'] = $img['date'];$info['mime'] = self::MIME_JPEG;$info['auteur.libelle'] = $this->Utilisateurs->getIntitule($img['utilisateur_courriel']);$info['auteur.id'] = $this->Utilisateurs->getId($img['utilisateur_courriel']);$info['binaire.href'] = $this->formaterUrlImage($img);$info['observation.id'] = $img['id_obs'];if (isset($img['nom_sel'])) {$info['determination.libelle'] = $this->formaterDetermination($img);$info['determination.nom_sci'] = $img['nom_sel'];$info['determination.nom_sci.code'] = $this->formaterNomSciCode($img);}$info = array_merge($info, $this->formaterStation($img));return $info;}private function extraireIdentitesAuteurs() {$courriels = array();foreach ($this->infosImages as $img) {$courriels[] = $img['utilisateur_courriel'];}// pour Acer monspessulanum L. Sapindaceae, cela divise par 9 le nombre// de courriels (213 => 23)$courriels = array_values(array_unique($courriels, SORT_STRING));$this->Utilisateurs->setCourriels($courriels);// XXX: webservices: /service:annuaire:utilisateur/identite-par-courriel/ [/bibliotheque/Utilisateurs.php]$this->Utilisateurs->chargerIdentites();}private function formaterUrlImage($infos) {$format = $this->parametres['retour.format'];$id = sprintf('%09s', $infos['id_img']).$format;$url = sprintf(self::TPL_URL_IMG, $id);return $url;}private function formaterDetermination($infos) {$auteur = $this->Utilisateurs->getIntitule($infos['utilisateur_courriel']);return $infos['nom_sel']."[Dét. : $auteur]";}private function formaterNomSciCode($infos) {return $this->parametres['referentiel'].'.'.$infos['nom_sel_nn'];}private function formaterStation($infos) {$station = array();if (isset($infos['zone_geo']) && $commune = $this->formaterCommune($infos)) {$station['station.commune'] = $commune;}if (isset($infos['lieudit']) && $this->avoirContenu($infos['lieudit'])) {$station['station.lieudit'] = $infos['lieudit'];}if (isset($infos['station']) && $this->avoirContenu($infos['station'])) {$station['station.station'] = $infos['station'];}if (isset($infos['milieu']) && $this->avoirContenu($infos['milieu'])) {$station['station.milieu'] = $infos['milieu'];}if (count($station) >= 1) {$station['station.libelle'] = implode(' > ', $station);}return $station;}private function formaterCommune($infos) {$commune = array();if ($this->avoirContenu($infos['zone_geo'])) {$commune[] = $infos['zone_geo'];}if (isset($infos['ce_zone_geo']) && $this->avoirContenu($infos['ce_zone_geo']) && $infos['ce_zone_geo'] != 'INSEE-C:') {$commune[] = '('.substr(str_replace('INSEE-C:','',$infos['ce_zone_geo']), 0, 2).')';}return implode(' ', $commune);}private function avoirContenu($info) {return !($info == null || $info == '' || $info == '000null');}}?>