Rev 1690 | Rev 1694 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php
/**
* Service fournissant des informations concernant le CEL au format RSS1, RSS2 ou ATOM.
* Encodage en entrée : utf8
* Encodage en sortie : utf8
* Format du service :
* /CelWidgetExport/format
* /CelWidgetExport/csv
*
* Les paramêtres :
* - "start" indique le numéro du premier item à afficher
* - "limit" nombre d'items à afficher
*
* @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 $Id$
* @copyright 2012
*/
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.4
error_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 widgets
private $parametres_autorises = array(
'id_utilisateur' => 'ce_utilisateur',
'utilisateur' => 'courriel_utilisateur',
'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 function getRessource() {
return $this->getElement(array());
}
/**
* Méthode appelée avec une requête de type GET.
*/
public function getElement($params = array()) {
if(count($params) > 0) {
switch(strtolower($params[0])) {
case 'calcul':
$this->getCalcul();
break;
case 'export':
$this->getExport();
break;
default:
$this->getExport();
}
} else {
$this->getExport();
}
}
private function getCalcul() {
$criteres = $this->traiterParametresAutorises($_GET);
$criteres['transmission'] = 1;
if($this->doitEtPeutExporterObsPrivees($criteres)) {
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 = isset($criteres['colonnes']) ? $criteres['colonnes'] : 'standard,avance';
unset($criteres['limite']);
unset($criteres['debut']);
unset($criteres['format']);
unset($criteres['colonnes']);
$nb_observations = $chercheur_observations->compterObservations(null, $criteres);
$limite_decoupage = $this->calculerNbLignesMaxParFichier();
$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 >= $limite_decoupage);
$this->envoyerJson($url_telechargements);
}
private function calculerNbLignesMaxParFichier() {
$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);
$criteres['transmission'] = 1;
if($this->doitEtPeutExporterObsPrivees($criteres)) {
unset($criteres['transmission']);
}
$chercheur_observations = new RechercheObservation($this->config);
$debut = isset($criteres['debut']) ? intval($criteres['debut']) : 0;
$limite = isset($criteres['limite']) ? intval($criteres['limite']) : 0;
$colonnes = isset($criteres['colonnes']) ? $criteres['colonnes'] : 'standard,avance';
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') {
$gestion_champs_etendus = new GestionChampsEtendus($this->config, 'obs');
$champs_supp_par_obs = $gestion_champs_etendus->consulterParLots($ids);
$colonnes_champs_supp_par_obs = $gestion_champs_etendus->consulterClesParLots($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, $colonnes_champs_supp_par_obs, $champs_supp_par_obs);
$this->envoyerCsv($csv);
break;
case 'xls':
$xls = $this->convertirEnXls($observations, $colonnes, $colonnes_champs_supp_par_obs, $champs_supp_par_obs);
$this->envoyerXls($xls);
break;
case 'pdf':
$pdf = $this->convertirEnPdf($observations);
$this->envoyerPdf($pdf);
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(trim($valeur) != '' && 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, &$colonnes_supplementaires, &$champs_supplementaires = array()) {
$chemin_temp = "php://temp";
$outstream = fopen($chemin_temp, 'r+');
$groupe_colonnes = FormateurGroupeColonne::nomEnsembleVersListeColonnes($colonnes);
$intitule_champs = array_merge(FormateurGroupeColonne::getIntitulesColonnes($groupe_colonnes),
array_values($colonnes_supplementaires));
// header
fputcsv($outstream, $intitule_champs, ',', '"');
// lignes
foreach($data as &$ligne) {
$id_obs = $ligne['id_observation'];
$ligne = self::filtrerDonneesSensibles($ligne);
$ligne = FormateurGroupeColonne::getLigneObservation($ligne, $groupe_colonnes, $this);
$ligne_etendue_aplatie = self::aplatirChampsEtendus($champs_supplementaires[$id_obs]);
self::traiterLigneEtendue($ligne, $colonnes_supplementaires, $ligne_etendue_aplatie);
fputcsv($outstream, $ligne, ',', '"');
}
rewind($outstream);
$csv = stream_get_contents($outstream);
fclose($outstream);
return $csv;
}
private function convertirEnXls(&$data, &$colonnes, &$colonnes_supplementaires, &$champs_supplementaires = array()) {
$this->extendSpreadsheetProductor = new SpreadsheetProductor();
$this->extendSpreadsheetProductor->initSpreadsheet();
$workbook = new Spreadsheet_Excel_Writer();
$worksheet = $workbook->addWorksheet('Liste');
$workbook->setTempDir($this->config['cel']['chemin_stockage_temp']);
$workbook->setVersion(8);
$worksheet->setInputEncoding('utf-8');
$workbook->send($this->nom_fichier_export.'.xls');
$nb_lignes = 1;
$groupe_colonnes = FormateurGroupeColonne::nomEnsembleVersListeColonnes($colonnes);
$intitule_champs = array_merge(FormateurGroupeColonne::getIntitulesColonnes($groupe_colonnes),
array_values($colonnes_supplementaires));
// header
$indice = 0;
foreach ($intitule_champs as &$intitule) {
$worksheet->write(0,$indice++,$intitule);
}
foreach($data as &$ligne) {
$id_obs = $ligne['id_observation'];
$ligne = self::filtrerDonneesSensibles($ligne);
$ligne = FormateurGroupeColonne::getLigneObservation($ligne, $groupe_colonnes, $this);
$ligne_etendue_aplatie = self::aplatirChampsEtendus($champs_supplementaires[$id_obs]);
$ligne_supp = self::traiterLigneEtendue($ligne, $colonnes_supplementaires, $ligne_etendue_aplatie);
$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('trop de données');
//require_once('GenerateurPDF.php');
$pdf = new GenerateurPDF();
$pdf->export($observations);
return $pdf;
}
private function envoyerPdf(&$pdf) {
$pdf->pdf->Output('etiquettes.pdf', 'I');
exit;;
}
static function traiterLigneEtendue(&$ligne, &$colonnes_etendues, $ligne_etendue_aplatie) {
if(! $colonnes_etendues) return;
if(! $ligne_etendue_aplatie) return;
$nb_colonnes_supp = count($colonnes_etendues);
$ligne_supp = array_fill(0, $nb_colonnes_supp, '');
$ligne_etendue_fmt = array();
foreach($colonnes_etendues as $colonne) {
if(!isset($ligne_etendue_aplatie[$colonne])) {
$ligne_etendue_fmt[$colonne] = '';
} else {
$ligne_etendue_fmt[$colonne] = $ligne_etendue_aplatie[$colonne];
}
}
$ligne += $ligne_etendue_fmt;
}
static function aplatirChampsEtendus(&$ligne_champs_etendus) {
$champs_etendus_fmt = array();
foreach($ligne_champs_etendus as $champ) {
$champs_etendus_fmt[$champ->cle] = $champ->valeur;
}
return $champs_etendus_fmt;
}
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 $utilisateur['connecte'] &&
$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 importants
if($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;
}
}
?>