Subversion Repositories eFlore/Applications.cel

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1374 aurelien 1
<?php
2
/**
3
* Service fournissant des informations concernant le CEL au format RSS1, RSS2 ou ATOM.
4
* Encodage en entrée : utf8
5
* Encodage en sortie : utf8
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
* @author Aurélien Peronnet <aurelien@tela-botanica.org>
15
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
16
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
17
* @version $Id$
18
* @copyright 2012
19
*/
1610 raphael 20
 
21
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(dirname(realpath(__FILE__))) . '/lib');
22
// la sortie est binaire (xls), mais OLE n'est pas compatible E_ALL en PHP-5.4
1690 raphael 23
error_reporting(error_reporting() ^ E_STRICT);
1610 raphael 24
require_once("lib/OLE.php");
25
require_once("lib/Spreadsheet/Excel/Writer.php");
26
 
1374 aurelien 27
class CelWidgetExport extends Cel {
28
 
1408 aurelien 29
	private $nom_fichier_export = 'cel_export';
1671 aurelien 30
	// certains paramètres apparaissent plusieurs fois car ils ont des alias
31
	// dans certains widgets
1376 aurelien 32
	private $parametres_autorises = array(
1654 aurelien 33
		'id_utilisateur' => 'ce_utilisateur',
1376 aurelien 34
		'utilisateur' => 'courriel_utilisateur',
35
		'commune' => 'zone_geo',
1671 aurelien 36
		'zone_geo' => 'zone_geo',
1376 aurelien 37
		'dept' => 'departement',
1654 aurelien 38
		'departement' => 'departement',
39
		'lieudit' => 'lieudit',
40
		'station' => 'station',
1376 aurelien 41
		'projet' => 'mots_cles',
1379 aurelien 42
		'num_taxon' => 'nt',
1378 aurelien 43
		'date_debut' => 'date_debut',
1387 aurelien 44
		'date_fin' => 'date_fin',
1625 aurelien 45
		'taxon' => 'taxon',
1654 aurelien 46
		'annee' => 'annee',
47
		'mois' => 'mois',
48
		'jour' => 'jour',
49
		'recherche' => 'recherche',
50
		'id_mots_cles' => 'id_mots_cles',
1662 aurelien 51
		'mots_cles' => 'mots_cles',
1625 aurelien 52
		'debut' => 'debut',
53
		'limite' => 'limite',
1654 aurelien 54
		'format' => 'format',
55
		'colonnes' => 'colonnes',
1679 raphael 56
		'transmission' => 'transmission',
57
		'obsids' => 'obsids',
1376 aurelien 58
	);
1402 aurelien 59
 
1625 aurelien 60
	private $limite_decoupage_defaut = 9000;
61
 
1402 aurelien 62
	private $format = 'csv';
1579 aurelien 63
 
1659 aurelien 64
	public $id_utilisateur = null;
65
 
1579 aurelien 66
	public function getRessource() {
67
		return $this->getElement(array());
68
	}
1374 aurelien 69
 
70
	/**
71
	 * Méthode appelée avec une requête de type GET.
72
	 */
1625 aurelien 73
	public function getElement($params = array()) {
74
		if(count($params) > 0) {
75
			switch(strtolower($params[0])) {
76
				case 'calcul':
77
					$this->getCalcul();
78
				break;
79
 
80
				case 'export':
81
					$this->getExport();
82
				break;
83
 
84
				default:
85
					$this->getExport();
86
			}
87
		} else {
88
			$this->getExport();
89
		}
90
	}
91
 
92
	private function getCalcul() {
1611 raphael 93
		$criteres = $this->traiterParametresAutorises($_GET);
1654 aurelien 94
 
1374 aurelien 95
		$criteres['transmission'] = 1;
1654 aurelien 96
		if($this->doitEtPeutExporterObsPrivees($criteres)) {
97
			unset($criteres['transmission']);
1659 aurelien 98
			$this->id_utilisateur = $criteres['id_utilisateur'];
1654 aurelien 99
		}
1374 aurelien 100
		$chercheur_observations = new RechercheObservation($this->config);
101
 
1379 aurelien 102
		$numero_page = isset($criteres['debut']) ? $criteres['debut'] : 0;
103
		$limite = isset($criteres['limite']) ? $criteres['limite'] : 0;
1654 aurelien 104
		$colonnes = isset($criteres['colonnes']) ? $criteres['colonnes'] : 'standard,avance';
1374 aurelien 105
 
106
		unset($criteres['limite']);
107
		unset($criteres['debut']);
1625 aurelien 108
		unset($criteres['format']);
1654 aurelien 109
		unset($criteres['colonnes']);
1625 aurelien 110
 
111
		$nb_observations = $chercheur_observations->compterObservations(null, $criteres);
112
		$limite_decoupage = $this->calculerNbLignesMaxParFichier();
113
 
114
		$url_telechargements = array();
115
		$intervalle = 0;
116
 
117
		$params_url = $criteres;
118
		unset($params_url['transmission']);
119
		do {
120
			$base_url = $this->config['settings']['baseURLAbsolu'].'CelWidgetExport/export';
121
			$params_url['debut'] = $intervalle;
122
			$params_url['limite'] = $limite_decoupage;
123
			$url_telechargement_fichier = $base_url;
1654 aurelien 124
			$url_telechargements[] = $base_url.'?'.http_build_query($params_url).'&format='.$this->format.'&colonnes='.$colonnes;
1625 aurelien 125
			$intervalle += $limite_decoupage;
126
			$nb_observations -= $limite_decoupage;
127
		} while($nb_observations >= $limite_decoupage);
128
 
129
		$this->envoyerJson($url_telechargements);
130
	}
1374 aurelien 131
 
1625 aurelien 132
	private function calculerNbLignesMaxParFichier() {
133
		$limite = $this->limite_decoupage_defaut;
1402 aurelien 134
		switch($this->format) {
135
			case 'csv':
1625 aurelien 136
				$limite = 20000;
137
				break;
138
			case 'xls':
139
				$limite = 8000;
140
				break;
1660 raphael 141
			case 'pdf':
142
				$limite = 300;
143
				break;
1625 aurelien 144
		}
145
		return $limite;
146
	}
147
 
148
	private function getExport() {
149
		$criteres = $this->traiterParametresAutorises($_GET);
150
		$criteres['transmission'] = 1;
1654 aurelien 151
		if($this->doitEtPeutExporterObsPrivees($criteres)) {
152
			unset($criteres['transmission']);
153
		}
1625 aurelien 154
		$chercheur_observations = new RechercheObservation($this->config);
155
 
1679 raphael 156
		$debut = isset($criteres['debut']) ? intval($criteres['debut']) : 0;
157
		$limite = isset($criteres['limite']) ? intval($criteres['limite']) : 0;
1654 aurelien 158
		$colonnes = isset($criteres['colonnes']) ? $criteres['colonnes'] : 'standard,avance';
1679 raphael 159
 
160
		if($criteres['obsids']) $criteres['sql_brut'] = sprintf('id_observation IN (%s)',
161
																implode(',', $criteres['obsids']));
1625 aurelien 162
 
163
		unset($criteres['limite']);
164
		unset($criteres['debut']);
165
		unset($criteres['format']);
1654 aurelien 166
		unset($criteres['colonnes']);
1679 raphael 167
		unset($criteres['obsids']);
168
 
169
		$observations = $chercheur_observations->rechercherObservations(null, $criteres, $debut, $limite, TRUE)->get();
1659 aurelien 170
		$ids = array();
171
		foreach($observations as &$obs) {
172
			$ids[] = $obs['id_observation'];
173
		}
174
 
1662 aurelien 175
		if($this->format != 'pdf') {
176
			$gestion_champs_etendus = new GestionChampsEtendus($this->config, 'obs');
177
    		$champs_supp_par_obs = $gestion_champs_etendus->consulterParLots($ids);
178
    		$colonnes_champs_supp_par_obs = $gestion_champs_etendus->consulterClesParLots($ids);
179
		}
180
 
1659 aurelien 181
    	// TODO: tous les champs étendus et les paramètres supplémentaires devraient être passés en un seul
182
    	// tableau (et chaque formateur csv, xls etc... pourrait également être dans une classe à part)
1625 aurelien 183
		switch($this->format) {
1660 raphael 184
		case 'csv':
185
			$csv = $this->convertirEnCsv($observations, $colonnes, $colonnes_champs_supp_par_obs, $champs_supp_par_obs);
186
			$this->envoyerCsv($csv);
187
			break;
188
		case 'xls':
189
			$xls = $this->convertirEnXls($observations, $colonnes, $colonnes_champs_supp_par_obs, $champs_supp_par_obs);
190
			$this->envoyerXls($xls);
191
			break;
192
		case 'pdf':
1662 aurelien 193
			$pdf = $this->convertirEnPdf($observations);
194
			$this->envoyerPdf($pdf);
1660 raphael 195
			break;
196
		default:
1402 aurelien 197
		}
1374 aurelien 198
	}
199
 
1611 raphael 200
	protected function traiterParametresAutorises(Array $parametres) {
1376 aurelien 201
		$parametres_traites = array();
1402 aurelien 202
		$this->format = (isset($parametres['format']) && $parametres['format'] != '') ? $parametres['format'] : $this->format;
1376 aurelien 203
		foreach($parametres as $cle => $valeur) {
204
			if(trim($valeur) != '' && isset($this->parametres_autorises[$cle])) {
205
				$parametres_traites[$this->parametres_autorises[$cle]] = $valeur;
206
			}
207
		}
1679 raphael 208
		$parametres_traites['obsids'] = @self::traiterObsIds($parametres['obsids']);
1376 aurelien 209
		return $parametres_traites;
210
	}
211
 
1374 aurelien 212
	private function envoyerCsv($csv) {
213
		header('Content-Type: text/csv; charset=UTF-8');
1408 aurelien 214
		header('Content-Disposition: attachment;filename='.$this->nom_fichier_export.'.csv');
1374 aurelien 215
		echo $csv;
1376 aurelien 216
		exit;
1374 aurelien 217
	}
218
 
1402 aurelien 219
	private function envoyerXls($workbook) {
220
		$workbook->close();
221
		exit;
222
	}
223
 
1692 raphael 224
	private function convertirEnCsv(&$data, &$colonnes, &$colonnes_supplementaires, &$champs_supplementaires = array()) {
1374 aurelien 225
		$chemin_temp = "php://temp";
226
		$outstream = fopen($chemin_temp, 'r+');
1690 raphael 227
 
1654 aurelien 228
		$groupe_colonnes = FormateurGroupeColonne::nomEnsembleVersListeColonnes($colonnes);
1690 raphael 229
 
1692 raphael 230
		$intitule_champs = array_merge(FormateurGroupeColonne::getIntitulesColonnes($groupe_colonnes),
231
									   array_values($colonnes_supplementaires));
1690 raphael 232
 
233
		// header
234
		fputcsv($outstream, $intitule_champs, ',', '"');
235
		// lignes
1617 aurelien 236
		foreach($data as &$ligne) {
1659 aurelien 237
			$id_obs = $ligne['id_observation'];
1692 raphael 238
			$ligne = self::filtrerDonneesSensibles($ligne);
1659 aurelien 239
			$ligne = FormateurGroupeColonne::getLigneObservation($ligne, $groupe_colonnes, $this);
1690 raphael 240
			$ligne_etendue_aplatie = self::aplatirChampsEtendus($champs_supplementaires[$id_obs]);
241
			self::traiterLigneEtendue($ligne, $colonnes_supplementaires, $ligne_etendue_aplatie);
1374 aurelien 242
			fputcsv($outstream, $ligne, ',', '"');
243
		}
244
		rewind($outstream);
245
		$csv = stream_get_contents($outstream);
246
		fclose($outstream);
247
		return $csv;
248
	}
249
 
1662 aurelien 250
	private function convertirEnXls(&$data, &$colonnes,  &$colonnes_supplementaires, &$champs_supplementaires = array()) {
1402 aurelien 251
		$this->extendSpreadsheetProductor = new SpreadsheetProductor();
252
		$this->extendSpreadsheetProductor->initSpreadsheet();
253
 
254
		$workbook = new Spreadsheet_Excel_Writer();
1625 aurelien 255
		$worksheet = $workbook->addWorksheet('Liste');
256
		$workbook->setTempDir($this->config['cel']['chemin_stockage_temp']);
1612 raphael 257
		$workbook->setVersion(8);
1402 aurelien 258
 
1612 raphael 259
		$worksheet->setInputEncoding('utf-8');
1408 aurelien 260
		$workbook->send($this->nom_fichier_export.'.xls');
1402 aurelien 261
 
262
		$nb_lignes = 1;
1654 aurelien 263
		$groupe_colonnes = FormateurGroupeColonne::nomEnsembleVersListeColonnes($colonnes);
1692 raphael 264
		$intitule_champs = array_merge(FormateurGroupeColonne::getIntitulesColonnes($groupe_colonnes),
265
									   array_values($colonnes_supplementaires));
1690 raphael 266
 
267
		// header
268
		$indice = 0;
269
		foreach ($intitule_champs as &$intitule) {
1692 raphael 270
			$worksheet->write(0,$indice++,$intitule);
1690 raphael 271
		}
272
 
1617 aurelien 273
		foreach($data as &$ligne) {
1659 aurelien 274
			$id_obs = $ligne['id_observation'];
1692 raphael 275
			$ligne = self::filtrerDonneesSensibles($ligne);
1659 aurelien 276
			$ligne = FormateurGroupeColonne::getLigneObservation($ligne, $groupe_colonnes, $this);
1690 raphael 277
 
278
			$ligne_etendue_aplatie = self::aplatirChampsEtendus($champs_supplementaires[$id_obs]);
279
			$ligne_supp = self::traiterLigneEtendue($ligne, $colonnes_supplementaires, $ligne_etendue_aplatie);
1402 aurelien 280
			$indice = 0;
1617 aurelien 281
			foreach($ligne as &$champ) {
1692 raphael 282
				$worksheet->write($nb_lignes,$indice++,$champ);
1402 aurelien 283
			}
284
			$nb_lignes++;
285
		}
286
		return $workbook;
287
	}
288
 
1662 aurelien 289
	private function convertirEnPdf(&$observations) {
290
		if(count($observations) > 300) die('trop de données');
291
		//require_once('GenerateurPDF.php');
292
		$pdf = new GenerateurPDF();
293
		$pdf->export($observations);
294
		return $pdf;
295
	}
296
 
297
	private function envoyerPdf(&$pdf) {
298
		$pdf->pdf->Output('etiquettes.pdf', 'I');
299
		exit;;
300
	}
301
 
1690 raphael 302
	static function traiterLigneEtendue(&$ligne, &$colonnes_etendues, $ligne_etendue_aplatie) {
303
		if(! $colonnes_etendues) return;
304
		if(! $ligne_etendue_aplatie) return;
305
		$nb_colonnes_supp = count($colonnes_etendues);
306
 
307
		$ligne_supp = array_fill(0, $nb_colonnes_supp, '');
1659 aurelien 308
		$ligne_etendue_fmt = array();
1690 raphael 309
 
1659 aurelien 310
		foreach($colonnes_etendues as $colonne) {
311
			if(!isset($ligne_etendue_aplatie[$colonne])) {
312
				$ligne_etendue_fmt[$colonne] = '';
313
			} else {
314
				$ligne_etendue_fmt[$colonne] = $ligne_etendue_aplatie[$colonne];
315
			}
316
		}
1690 raphael 317
 
318
		$ligne += $ligne_etendue_fmt;
1659 aurelien 319
	}
320
 
1690 raphael 321
	static function aplatirChampsEtendus(&$ligne_champs_etendus) {
1659 aurelien 322
		$champs_etendus_fmt = array();
323
		foreach($ligne_champs_etendus as $champ) {
324
			$champs_etendus_fmt[$champ->cle] = $champ->valeur;
325
		}
326
		return $champs_etendus_fmt;
327
	}
328
 
1692 raphael 329
	static function filtrerDonneesSensibles($ligne) {
1429 aurelien 330
		if(stripos($ligne['mots_cles_texte'], 'sensible') !== false) {
331
			$ligne['latitude'] = '';
332
			$ligne['longitude'] = '';
333
		}
334
		return $ligne;
335
	}
336
 
1654 aurelien 337
	private function doitEtPeutExporterObsPrivees($criteres) {
338
		return isset($criteres['ce_utilisateur']) &&
339
					$this->peutExporterObsPrivees($criteres['ce_utilisateur']);
340
	}
341
 
342
	private function peutExporterObsPrivees($id_utilisateur) {
343
		$gestion_utilisateur = new User($this->config);
344
		$utilisateur = $gestion_utilisateur->obtenirIdentiteConnectee();
345
		return $utilisateur['connecte'] &&
346
				$utilisateur['id_utilisateur'] != '' &&
347
				$id_utilisateur == $utilisateur['id_utilisateur'];
348
	}
1679 raphael 349
 
350
	static function traiterObsIds($range_param) {
351
		if (!isset($range_param)) return NULL;
352
		// trim() car: `POST http://url<<<"range=*"`
353
		if (trim($range_param) == '*') return NULL;
354
		return self::rangeToList(trim($range_param));
355
	}
356
 
357
	/*
358
	 * @param $fieldSets: un range, eg: 1-5,8,32,58-101
359
	 * @return un tableau trié, eg: 1,2,3,4,5,8,32,58,...,101
360
	 * http://stackoverflow.com/questions/7698664/converting-a-range-or-partial-array-in-the-form-3-6-or-3-6-12-into-an-arra
361
	 */
362
	static function rangeToList($in = '') {
363
		$inSets = explode(',', trim($in, ','));
364
		$outSets = array();
365
 
366
		foreach($inSets as $inSet) {
367
			list($start,$end) = explode('-', $inSet . '-' . $inSet);
368
			// ignore les ranges trop importants
369
			if($start > 10000000 || $end > 10000000 || abs($start-$end) > 10000) continue;
370
			$outSets = array_merge($outSets,range($start,$end));
371
		}
372
		$outSets = array_unique($outSets);
373
		$outSets = array_filter($outSets, 'is_numeric');
374
		sort($outSets);
375
		return $outSets;
376
	}
1374 aurelien 377
}
378
?>