Rev 143 | Rev 331 | 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 {private $parametres = array();private $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 $ref_tax_demande = array();private $infosImages = array();private $nbreImages = 0;private $Utilisateurs = null;private $intitulesAuteurs = array();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();$this->analyserMasqueNn();$resultat = new ResultatService();if ($this->parametres['retour'] == self::MIME_JPEG) {$id_image_a_renvoyer = $this->obtenirIdImageAuHasard();$resultat->corps = $this->recupererImageBinaire($id_image_a_renvoyer);} else if ($this->parametres['retour'] == self::MIME_JSON) {$this->chargerListeImages();$this->chargerNbreImagesTotal();$resultat->corps = $infos = $this->formaterListeImages();//$tpsFin = microtime(true);//$resultat->corps['entete']['execution.tps'] = $tpsFin - $tpsDebut;}$resultat->mime = $this->parametres['retour'];return $resultat;}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;}}private function verifierParametres() {$erreurs = array();if (isset($this->parametres['masque.nn']) == false) {$erreurs[] = "Le paramètre masque.nn est obligatoire.";} else {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 ($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 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[self::CODE_REFTAX_DEFAUT][] = $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 : self::CODE_REFTAX_DEFAUT.':'.$projetEtNumNoms;list($projet, $numNoms) = explode(':', $projetEtNumNoms);$this->ref_tax_demande[$projet] = explode(',', $numNoms);}}}}private function obtenirIdImageAuHasard() {$refTax = self::CODE_REFTAX_DEFAUT;$numNom = $this->Bdd->proteger($this->ref_tax_demande[$refTax][0]);//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 coi.coi_ce_image AS id_image '.'FROM cel_obs_images AS coi '.' LEFT JOIN cel_inventory AS ci '.'ON (coi.coi_ce_observation = ci.ordre AND coi.coi_ce_utilisateur = ci.identifiant) '.'WHERE ci.transmission = 1 '." AND ci.num_nom_ret IN ($numNom) ";$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 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;}private function chargerListeImages() {$refTax = self::CODE_REFTAX_DEFAUT;$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 '.' ci.ci_id_image AS id_img, co.id AS id_obs, '.' identifiant AS utilisateur_courriel, '.' nom_sel, num_nom_sel, '.' location, id_location, lieudit, station, milieu, '.' ci.ci_meta_date AS date '.'FROM cel_images AS ci'.' LEFT JOIN cel_obs_images AS coi '.' ON (coi.coi_ce_image = ci.ci_id_image) '.' LEFT JOIN cel_inventory AS co '.' ON (coi.coi_ce_observation = co.ordre AND coi.coi_ce_utilisateur = co.identifiant) '.'WHERE co.transmission = 1 '." AND co.num_nom_ret IN ($numNomListe) ".'GROUP BY id_img '."LIMIT $depart,$limite ";$this->infosImages = $this->Bdd->recupererTous($requete);}private function chargerNbreImagesTotal() {$requete = 'SELECT FOUND_ROWS() AS nbre ';$resultats = $this->Bdd->recuperer($requete);$this->nbreImages = (int) $resultats['nbre'];}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->extraireIntitulesAuteurs();foreach ($this->infosImages as $img) {$info = array();$info['date'] = $img['date'];$info['mime'] = self::MIME_JPEG;$info['auteur'] = $this->formaterAuteur($img);$info['binaire.href'] = $this->formaterUrlImage($img);$info['determination'] = $this->formaterDetermination($img);$info['determination.nom_sci'] = $img['nom_sel'];$info['determination.nom_sci.code'] = $this->formaterNomSciCode($img);$info['station'] = $this->formaterStation($img);$id = $img['id_img'];if (!isset($resultats[$id])) {$resultats[$id] = $info;} else {throw new Exception("Double : $id");}}return $resultats;}private function extraireIntitulesAuteurs() {$courriels = array();foreach ($this->infosImages as $img) {$courriels[] = $img['utilisateur_courriel'];}$utilisateurs = new Utilisateurs($courriels);$this->intitulesAuteurs = $utilisateurs->getIntitules();}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) {return $infos['nom_sel'].'[Dét. : '.$this->intitulesAuteurs[$infos['utilisateur_courriel']].']';}private function formaterNomSciCode($infos) {return self::CODE_REFTAX_DEFAUT.'.'.$infos['num_nom_sel'];}private function formaterStation($infos) {$station = array();if ($commune = $this->formaterCommune($infos)) {$station[] = $commune;}if ($this->avoirContenu($infos['lieudit'])) {$station[] = $infos['lieudit'];}if ($this->avoirContenu($infos['station'])) {$station[] = $infos['station'];}if ($this->avoirContenu($infos['milieu'])) {$station[] = $infos['milieu'];}return implode(' > ', $station);}private function formaterCommune($infos) {$commune = array();if ($this->avoirContenu($infos['location'])) {$commune[] = $infos['location'];}if ($this->avoirContenu($infos['id_location'])) {$commune[] = '('.$infos['id_location'].')';}return implode(' ', $commune);}private function formaterAuteur($infos) {$auteur = $this->intitulesAuteurs[$infos['utilisateur_courriel']];return $auteur;}private function avoirContenu($info) {$vide = true;if ($info == null || $info == '' || $info == '000null') {$vide = false;}return $vide;}}?>