Rev 2538 | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?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.4error_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 widgetsprivate $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','num_taxon' => 'nt','date_debut' => 'date_debut','date_fin' => 'date_fin','taxon' => 'taxon','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',);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 FormateurGroupeColonnestatic $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);$criteres['transmission'] = 1;// 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'];}$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']);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éfiniif(!$criteres) die('erreur: pas de paramètre reçu');if(!in_array($this->format, array('pdf','csv','xls'))) die('erreur: format invalide');$criteres['transmission'] = 1;// 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['ce_utilisateur'];}$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($criteres['obsids']) $criteres['sql_brut'] = sprintf('id_observation IN (%s)',implode(',', $criteres['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 FormateurGroupeColonnequ'il initialise et utilise en interne sans qu'un passage par paramètre dans le contexte de CelWidgetExportne soit nécessaire.* Pour les champs étendus, c'est CelWidgetExport::$cache qui est utilisé, aussi bien pour les en-têtes quepour 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;}}$parametres_traites['obsids'] = @self::traiterObsIds($parametres['obsids']);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 FormateurGroupeColonneif(isset($colonnes['etendu'])) {$intitule_champs = array_merge($intitule_champs, array_values(self::$cache['etendu']['header']));}// headerfputcsv($outstream, $intitule_champs, ',', '"');// lignesforeach($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 FormateurGroupeColonneif(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 User($this->config);$utilisateur = $gestion_utilisateur->obtenirIdentiteConnectee();return ! empty($utilisateur['id_utilisateur']) && $id_utilisateur == $utilisateur['id_utilisateur'];}static function traiterObsIds($range_param) {if (!isset($range_param)) return NULL;// trim() car: `POST http://url<<<"range=*"`if (trim($range_param) == '*') return NULL;return self::rangeToList(trim($range_param));}/** @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(',', trim($in, ','));$outSets = array();foreach($inSets as $inSet) {list($start,$end) = explode('-', $inSet . '-' . $inSet);// ignore les ranges trop importantsif($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;}}?>