Subversion Repositories eFlore/Applications.cel

Rev

Rev 3603 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1374 aurelien 1
<?php
2462 jpm 2
// declare(encoding='UTF-8');
1374 aurelien 3
/**
2462 jpm 4
 * Service fournissant des exports des données publiques du CEL pour le widget.
5
 *
6
 * Format du service :
7
 * /CelWidgetExport/format
8
 * /CelWidgetExport/csv
9
 *
10
 * Les paramêtres :
11
 *  - "start" indique le numéro du premier item à afficher
12
 *  - "limit" nombre d'items à afficher
13
 *
14
 * @internal   Mininum PHP version : 5.2
15
 * @category   CEL
16
 * @package    Services
17
 * @subpackage Widget
18
 * @version    0.1
19
 * @author     Mathias CHOUET <mathias@tela-botanica.org>
20
 * @author     Jean-Pascal MILCENT <jpm@tela-botanica.org>
21
 * @author     Aurelien PERONNET <aurelien@tela-botanica.org>
22
 * @license    GPL v3 <http://www.gnu.org/licenses/gpl.txt>
23
 * @license    CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
24
 * @copyright  1999-2014 Tela Botanica <accueil@tela-botanica.org>
25
 */
1610 raphael 26
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(dirname(realpath(__FILE__))) . '/lib');
27
// la sortie est binaire (xls), mais OLE n'est pas compatible E_ALL en PHP-5.4
1700 raphael 28
error_reporting(error_reporting() & ~E_STRICT);
2459 jpm 29
require_once 'lib/OLE.php';
30
require_once 'lib/Spreadsheet/Excel/Writer.php';
1610 raphael 31
 
1374 aurelien 32
class CelWidgetExport extends Cel {
3131 delphine 33
 
1408 aurelien 34
	private $nom_fichier_export = 'cel_export';
1671 aurelien 35
	// certains paramètres apparaissent plusieurs fois car ils ont des alias
36
	// dans certains widgets
1376 aurelien 37
	private $parametres_autorises = array(
3131 delphine 38
			'id_utilisateur' => 'ce_utilisateur',
39
			'utilisateur' => 'courriel_utilisateur',
40
			'courriel_utilisateur' => 'courriel_utilisateur',
41
			'pays' => 'pays',
42
			'commune' => 'zone_geo',
43
			'zone_geo' => 'zone_geo',
44
			'dept' => 'departement',
45
			'departement' => 'departement',
46
			'lieudit' => 'lieudit',
47
			'station' => 'station',
48
			'projet' => 'mots_cles',
49
			'programme' => 'programme',
3437 delphine 50
	        'num_taxon' => 'nt',
51
	        'certitude' => 'certitude',
3131 delphine 52
			'date_debut' => 'date_debut',
53
			'date_fin' => 'date_fin',
54
			'taxon' => 'taxon',
55
			'identiplante' => 'validation_identiplante',
56
			'validation_identiplante' => 'validation_identiplante',
57
			'annee' => 'annee',
58
			'mois' => 'mois',
59
			'jour' => 'jour',
60
			'recherche' => 'recherche',
61
			'id_mots_cles' => 'id_mots_cles',
62
			'mots_cles' => 'mots_cles',
63
			'debut' => 'debut',
64
			'limite' => 'limite',
65
			'format' => 'format',
66
			'colonnes' => 'colonnes',
67
			'transmission' => 'transmission',
68
			'obsids' => 'obsids',
3134 delphine 69
			'standard' => 'standard',
1376 aurelien 70
	);
3131 delphine 71
 
2459 jpm 72
	private $limite_decoupage_defaut = 9000;
3131 delphine 73
 
1402 aurelien 74
	private $format = 'csv';
3131 delphine 75
 
1659 aurelien 76
	public $id_utilisateur = null;
3131 delphine 77
 
2403 aurelien 78
	public $export_prive = false;
3131 delphine 79
 
1715 raphael 80
	// un cache, initialisé par certaines fonctions de préchargement, à la manière
81
	// de ce qui est fait par FormateurGroupeColonne
82
	static $cache = Array();
3131 delphine 83
 
1579 aurelien 84
	public function getRessource() {
85
		return $this->getElement(array());
86
	}
3131 delphine 87
 
1374 aurelien 88
	/**
89
	 * Méthode appelée avec une requête de type GET.
90
	 */
1709 raphael 91
	public function getElement($params = array()) {
1711 raphael 92
		switch(@strtolower($params[0])) {
3131 delphine 93
			case 'calcul':
94
				$this->getCalcul();
95
				break;
96
 
97
			case 'export':
98
				$this->getExport();
99
				break;
100
			default:
101
				$this->getExport();
1625 aurelien 102
		}
103
	}
3131 delphine 104
 
1625 aurelien 105
	private function getCalcul() {
1611 raphael 106
		$criteres = $this->traiterParametresAutorises($_GET);
3134 delphine 107
		if (!isset($criteres['standard'])) {
108
				$criteres['transmission'] = 1;
109
		} else {
110
			unset($criteres['transmission']);
111
		}
2403 aurelien 112
		// Définit si l'on exporte les obs privées ainsi que les champs étendus privés
113
		$this->export_prive = $this->doitEtPeutExporterObsPrivees($criteres);
114
		if($this->export_prive) {
1654 aurelien 115
			unset($criteres['transmission']);
1659 aurelien 116
			$this->id_utilisateur = $criteres['id_utilisateur'];
1654 aurelien 117
		}
3471 delphine 118
		//if (isset($criteres['standard']) && $criteres['standard'] == 1) {
3134 delphine 119
			$chercheur_observations = new RechercheObservationExport($this->config);
3471 delphine 120
		/*} else {
3134 delphine 121
			$chercheur_observations = new RechercheObservation($this->config);
3471 delphine 122
		}*/
1379 aurelien 123
		$numero_page = isset($criteres['debut']) ? $criteres['debut'] : 0;
124
		$limite = isset($criteres['limite']) ? $criteres['limite'] : 0;
3134 delphine 125
		$colonnes = @FormateurGroupeColonne::colGroupsValidation($criteres['colonnes'], $criteres['programme']);
3131 delphine 126
 
1374 aurelien 127
		unset($criteres['limite']);
128
		unset($criteres['debut']);
1625 aurelien 129
		unset($criteres['format']);
1654 aurelien 130
		unset($criteres['colonnes']);
3131 delphine 131
 
1625 aurelien 132
		$nb_observations = $chercheur_observations->compterObservations(null, $criteres);
2250 aurelien 133
		$limite_decoupage = $this->calculerNbLignesMaxParFichier(explode(',', $colonnes));
3131 delphine 134
 
1625 aurelien 135
		$url_telechargements = array();
136
		$intervalle = 0;
3131 delphine 137
 
1625 aurelien 138
		$params_url = $criteres;
139
		unset($params_url['transmission']);
140
		do {
141
			$base_url = $this->config['settings']['baseURLAbsolu'].'CelWidgetExport/export';
142
			$params_url['debut'] = $intervalle;
143
			$params_url['limite'] = $limite_decoupage;
144
			$url_telechargement_fichier = $base_url;
1654 aurelien 145
			$url_telechargements[] = $base_url.'?'.http_build_query($params_url).'&format='.$this->format.'&colonnes='.$colonnes;
1625 aurelien 146
			$intervalle += $limite_decoupage;
147
			$nb_observations -= $limite_decoupage;
2190 mathias 148
		} while($nb_observations > 0);
3131 delphine 149
 
1625 aurelien 150
		$this->envoyerJson($url_telechargements);
151
	}
3131 delphine 152
 
2250 aurelien 153
	private function calculerNbLignesMaxParFichier($colonnes) {
2459 jpm 154
		$limite = $this->limite_decoupage_defaut;
3131 delphine 155
 
1402 aurelien 156
		switch($this->format) {
157
			case 'csv':
1625 aurelien 158
				$limite = 20000;
159
				break;
160
			case 'xls':
161
				$limite = 8000;
162
				break;
1660 raphael 163
			case 'pdf':
164
				$limite = 300;
165
				break;
1625 aurelien 166
		}
3131 delphine 167
 
2253 aurelien 168
		return $limite;
1625 aurelien 169
	}
3131 delphine 170
 
1625 aurelien 171
	private function getExport() {
172
		$criteres = $this->traiterParametresAutorises($_GET);
1711 raphael 173
		// ne pas faire de super-requête en cas d'absence de paramètres
174
		// par exemple "format", au minimum, devrait être défini
1715 raphael 175
		if(!$criteres) die('erreur: pas de paramètre reçu');
176
		if(!in_array($this->format, array('pdf','csv','xls'))) die('erreur: format invalide');
3131 delphine 177
 
3134 delphine 178
		if (!isset($criteres['standard'])) {
3472 delphine 179
		    $criteres['transmission'] = 1;
3134 delphine 180
		} else {
3472 delphine 181
		    unset($criteres['transmission']);
3134 delphine 182
		}
2403 aurelien 183
		// Définit si l'on exporte les obs privées ainsi que les champs étendus privés
184
		$this->export_prive = $this->doitEtPeutExporterObsPrivees($criteres);
185
		if($this->export_prive) {
3472 delphine 186
		    unset($criteres['transmission']);
187
		    $this->id_utilisateur = $criteres['id_utilisateur'];
1654 aurelien 188
		}
3472 delphine 189
		//if (isset($criteres['standard']) && $criteres['standard'] == 1) {
190
		$chercheur_observations = new RechercheObservationExport($this->config);
191
		/*} else {
192
		 $chercheur_observations = new RechercheObservation($this->config);
193
		 }*/
3142 delphine 194
 
1679 raphael 195
		$debut = isset($criteres['debut']) ? intval($criteres['debut']) : 0;
196
		$limite = isset($criteres['limite']) ? intval($criteres['limite']) : 0;
1714 raphael 197
		$groupes = @FormateurGroupeColonne::colGroupsValidation($criteres['colonnes']);
1835 raphael 198
		$groupes .= ',auteur';
3131 delphine 199
 
1714 raphael 200
		if(!$groupes) die('erreur: Ne peut identifier les groupes de champs demandés.');
3131 delphine 201
 
202
 
3437 delphine 203
		if(isset($criteres['obsids'])) {
204
		    $obsids = (is_array($criteres['obsids'])) ? implode(',', $criteres['obsids']) : $criteres['obsids'];
205
		    $criteres['sql_brut'] = sprintf('id_observation IN (%s)',
206
		        $obsids);
207
		}
3131 delphine 208
 
1625 aurelien 209
		unset($criteres['limite']);
210
		unset($criteres['debut']);
211
		unset($criteres['format']);
1654 aurelien 212
		unset($criteres['colonnes']);
1679 raphael 213
		unset($criteres['obsids']);
3131 delphine 214
 
1679 raphael 215
		$observations = $chercheur_observations->rechercherObservations(null, $criteres, $debut, $limite, TRUE)->get();
1659 aurelien 216
		$ids = array();
217
		foreach($observations as &$obs) {
218
			$ids[] = $obs['id_observation'];
219
		}
3131 delphine 220
 
1703 raphael 221
		if($this->format == 'pdf') {
222
			$pdf = $this->convertirEnPdf($observations);
223
			$pdf->pdf->Output('etiquettes.pdf', 'I');
224
			exit;
1662 aurelien 225
		}
3131 delphine 226
 
1703 raphael 227
		// cas XLS et CSV: on peut avoir besoin des champs étendus, des noms communs et des champs baseflor:
3131 delphine 228
 
1715 raphael 229
		// Obtention des colonnes correspondantes aux groupes de champs
1714 raphael 230
		$colonnes = FormateurGroupeColonne::nomEnsembleVersListeColonnes($groupes);
3131 delphine 231
 
1715 raphael 232
		/*
3131 delphine 233
		 Champs étendus et noms communs, si demandés.
234
		 * Pour "nom commun", "preload" retourne NULL, car c'est le cache statique de FormateurGroupeColonne
235
		 qu'il initialise et utilise en interne sans qu'un passage par paramètre dans le contexte de CelWidgetExport
236
		 ne soit nécessaire.
237
		 * Pour les champs étendus, c'est CelWidgetExport::$cache qui est utilisé, aussi bien pour les en-têtes que
238
		 pour les données préchargées, cf self::traiterLigneEtendue()
239
		 */
1715 raphael 240
		self::$cache = FormateurGroupeColonne::preload($colonnes, $this, $ids);
3131 delphine 241
 
242
		// TODO: tous les champs étendus et les paramètres supplémentaires devraient être passés en un seul
243
		// tableau (et chaque formateur csv, xls etc... pourrait également être dans une classe à part)
1625 aurelien 244
		switch($this->format) {
3131 delphine 245
			case 'csv':
246
				$csv = $this->convertirEnCsv($observations, $colonnes);
247
				$this->envoyerCsv($csv);
248
				break;
249
			case 'xls':
250
				$xls = $this->convertirEnXls($observations, $colonnes);
251
				$this->envoyerXls($xls);
252
				break;
253
			default:
1402 aurelien 254
		}
1374 aurelien 255
	}
3131 delphine 256
 
1611 raphael 257
	protected function traiterParametresAutorises(Array $parametres) {
1376 aurelien 258
		$parametres_traites = array();
1402 aurelien 259
		$this->format = (isset($parametres['format']) && $parametres['format'] != '') ? $parametres['format'] : $this->format;
1376 aurelien 260
		foreach($parametres as $cle => $valeur) {
1711 raphael 261
			if(is_string($valeur) && !trim($valeur)) continue;
262
			if(isset($this->parametres_autorises[$cle])) {
1376 aurelien 263
				$parametres_traites[$this->parametres_autorises[$cle]] = $valeur;
264
			}
265
		}
266
		return $parametres_traites;
267
	}
3131 delphine 268
 
1374 aurelien 269
	private function envoyerCsv($csv) {
270
		header('Content-Type: text/csv; charset=UTF-8');
1408 aurelien 271
		header('Content-Disposition: attachment;filename='.$this->nom_fichier_export.'.csv');
1374 aurelien 272
		echo $csv;
1376 aurelien 273
		exit;
1374 aurelien 274
	}
3131 delphine 275
 
1402 aurelien 276
	private function envoyerXls($workbook) {
277
		$workbook->close();
278
		exit;
279
	}
3131 delphine 280
 
1715 raphael 281
	private function convertirEnCsv(&$data, $colonnes) {
1374 aurelien 282
		$chemin_temp = "php://temp";
283
		$outstream = fopen($chemin_temp, 'r+');
3131 delphine 284
 
1711 raphael 285
		$intitule_champs = array_merge(FormateurGroupeColonne::getIntitulesColonnes($colonnes));
1703 raphael 286
		// en premier car utilisé génériquement dans getLigneObservation()
1711 raphael 287
		if(isset($colonnes['baseflor'])) {
1703 raphael 288
			$intitule_champs = array_merge($intitule_champs, FormateurGroupeColonne::$baseflor_col);
289
		}
290
		// en second car manuellement appellé plus bas, TODO: utiliser l'API du FormateurGroupeColonne
1715 raphael 291
		if(isset($colonnes['etendu'])) {
292
			$intitule_champs = array_merge($intitule_champs, array_values(self::$cache['etendu']['header']));
293
		}
3131 delphine 294
 
1690 raphael 295
		// header
2459 jpm 296
		fputcsv($outstream, $intitule_champs, ',', '"');
1690 raphael 297
		// lignes
1617 aurelien 298
		foreach($data as &$ligne) {
1692 raphael 299
			$ligne = self::filtrerDonneesSensibles($ligne);
1711 raphael 300
			$ligne = FormateurGroupeColonne::getLigneObservation($ligne, $colonnes, $this);
1374 aurelien 301
			fputcsv($outstream, $ligne, ',', '"');
302
		}
303
		rewind($outstream);
304
		$csv = stream_get_contents($outstream);
305
		fclose($outstream);
306
		return $csv;
307
	}
3131 delphine 308
 
1715 raphael 309
	private function convertirEnXls(&$data, $colonnes) {
1402 aurelien 310
		$this->extendSpreadsheetProductor = new SpreadsheetProductor();
311
		$this->extendSpreadsheetProductor->initSpreadsheet();
3131 delphine 312
 
1402 aurelien 313
		$workbook = new Spreadsheet_Excel_Writer();
1804 raphael 314
		// avant la définition du titre de la worksheet !
315
		$workbook->setVersion(8);
3131 delphine 316
 
1625 aurelien 317
		$worksheet = $workbook->addWorksheet('Liste');
318
		$workbook->setTempDir($this->config['cel']['chemin_stockage_temp']);
1612 raphael 319
		$worksheet->setInputEncoding('utf-8');
1408 aurelien 320
		$workbook->send($this->nom_fichier_export.'.xls');
3131 delphine 321
 
1402 aurelien 322
		$nb_lignes = 1;
3131 delphine 323
 
1711 raphael 324
		$intitule_champs = array_merge(FormateurGroupeColonne::getIntitulesColonnes($colonnes));
1703 raphael 325
		// en premier car utilisé génériquement dans getLigneObservation()
1711 raphael 326
		if(isset($colonnes['baseflor'])) {
1703 raphael 327
			$intitule_champs = array_merge($intitule_champs, FormateurGroupeColonne::$baseflor_col);
328
		}
329
		// en second car manuellement appellé plus bas, TODO: utiliser l'API du FormateurGroupeColonne
1715 raphael 330
		if(isset($colonnes['etendu'])) {
331
			$intitule_champs = array_merge($intitule_champs, array_values(self::$cache['etendu']['header']));
332
		}
3131 delphine 333
 
1690 raphael 334
		// header
335
		$indice = 0;
2459 jpm 336
		foreach ($intitule_champs as &$intitule) {
1692 raphael 337
			$worksheet->write(0,$indice++,$intitule);
1690 raphael 338
		}
3131 delphine 339
 
1617 aurelien 340
		foreach($data as &$ligne) {
1692 raphael 341
			$ligne = self::filtrerDonneesSensibles($ligne);
1711 raphael 342
			$ligne = FormateurGroupeColonne::getLigneObservation($ligne, $colonnes, $this);
1402 aurelien 343
			$indice = 0;
1617 aurelien 344
			foreach($ligne as &$champ) {
1692 raphael 345
				$worksheet->write($nb_lignes,$indice++,$champ);
1402 aurelien 346
			}
347
			$nb_lignes++;
348
		}
349
		return $workbook;
350
	}
3131 delphine 351
 
1662 aurelien 352
	private function convertirEnPdf(&$observations) {
1715 raphael 353
		if(count($observations) > 300) die('erreur: trop de données');
1662 aurelien 354
		//require_once('GenerateurPDF.php');
355
		$pdf = new GenerateurPDF();
356
		$pdf->export($observations);
357
		return $pdf;
358
	}
3131 delphine 359
 
1692 raphael 360
	static function filtrerDonneesSensibles($ligne) {
1429 aurelien 361
		if(stripos($ligne['mots_cles_texte'], 'sensible') !== false) {
362
			$ligne['latitude'] = '';
363
			$ligne['longitude'] = '';
3942 delphine 364
			$ligne['geometry'] = '';
1429 aurelien 365
		}
3942 delphine 366
		if ($ligne['localisation_floutage'] == "10x10km" || $ligne['localisation_floutage'] == "localité") {
367
		    $ligne['geometry'] = '';
368
		}
1429 aurelien 369
		return $ligne;
370
	}
3131 delphine 371
 
1654 aurelien 372
	private function doitEtPeutExporterObsPrivees($criteres) {
3603 delphine 373
		return isset($criteres['ce_utilisateur']) &&
374
		$this->peutExporterObsPrivees($criteres['ce_utilisateur']);
1654 aurelien 375
	}
3131 delphine 376
 
1654 aurelien 377
	private function peutExporterObsPrivees($id_utilisateur) {
2806 aurelien 378
		$gestion_utilisateur = new GestionUtilisateur($this->config);
1654 aurelien 379
		$utilisateur = $gestion_utilisateur->obtenirIdentiteConnectee();
1703 raphael 380
		return ! empty($utilisateur['id_utilisateur']) && $id_utilisateur == $utilisateur['id_utilisateur'];
1654 aurelien 381
	}
3131 delphine 382
 
3134 delphine 383
 
1374 aurelien 384
}
3138 killian 385
?>