Subversion Repositories eFlore/Applications.cel

Compare Revisions

Ignore whitespace Rev 1641 → Rev 1642

/trunk/jrest/services/ExportXLS.php
73,6 → 73,11
else {
$obs_ids = self::rangeToList(trim($_POST['range']));
}
 
$params['format'] = 'CSV';
if($_POST['format'] == 'xls') $params['format'] = 'Excel5';
if($_POST['format'] == 'xlsx') $params['format'] = 'Excel2007';
 
$this->export($obs_ids, NULL, $params);
exit;
}
144,6 → 149,15
)
);
}
if(! $colonne['importable']) {
$feuille->getStyleByColumnAndRow($colid, 1)->getFill()->applyFromArray(
array(
'type' => PHPExcel_Style_Fill::FILL_SOLID,
'color' => array('rgb' => PHPExcel_Style_Color::COLOR_YELLOW)
)
);
}
 
$colid++;
}
 
189,9 → 203,10
header("Content-Type: application/vnd.ms-excel");
header("Content-Disposition: attachment; filename=\"liste.xls\"; charset=utf-8");
header("Cache-Control: max-age=0");
// Le format Excel2007 utilise un fichier temporaire
$generateur = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
// $generateur = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
 
// csv|xls|xlsx => CSV|Excel5|Excel2007
// Note: le format Excel2007 utilise un fichier temporaire
$generateur = PHPExcel_IOFactory::createWriter($objPHPExcel, $params['format']);
$generateur->save('php://output');
exit;
}
237,11 → 252,11
if(isset($groupe_de_champs['standard'])) {
$colonnes += Array(
'nom_sel' => self::GenColInfo('nom_sel', 'Espèce'),
'nom_sel_nn' => self::GenColInfo('nom_sel_nn', 'Numéro nomenclatural'),
'nom_ret' => self::GenColInfo('nom_ret', 'Nom retenu'),
'nom_ret_nn' => self::GenColInfo('nom_ret_nn', 'Numéro nomenclatural nom retenu'),
'nt' => self::GenColInfo('nt', 'Numéro taxonomique'),
'famille' => self::GenColInfo('famille', 'Famille'),
'nom_sel_nn' => self::GenColInfo('nom_sel_nn', 'Numéro nomenclatural', 0, NULL, NULL, FALSE),
'nom_ret' => self::GenColInfo('nom_ret', 'Nom retenu', 0, NULL, NULL, FALSE),
'nom_ret_nn' => self::GenColInfo('nom_ret_nn', 'Numéro nomenclatural nom retenu', 0, NULL, NULL, FALSE),
'nt' => self::GenColInfo('nt', 'Numéro taxonomique', 0, NULL, NULL, FALSE),
'famille' => self::GenColInfo('famille', 'Famille', 0, NULL, NULL, FALSE),
'nom_referentiel' => self::GenColInfo('nom_referentiel', 'Referentiel taxonomique'),
'zone_geo' => self::GenColInfo('zone_geo', 'Commune'),
'ce_zone_geo' => self::GenColInfo('ce_zone_geo', 'Identifiant Commune', 0, 'convertirCodeZoneGeoVersDepartement'),
252,7 → 267,7
'commentaire' => self::GenColInfo('commentaire', 'Notes'),
'latitude' => self::GenColInfo('latitude', 'Latitude', 1),
'longitude' => self::GenColInfo('longitude', 'Longitude', 1),
'geodatum' => self::GenColInfo('geodatum', 'Référentiel Géographique', 1),
'geodatum' => self::GenColInfo('geodatum', 'Référentiel Géographique', 1, NULL, NULL, FALSE),
 
// TODO: importable = FALSE car pas de merge de données importées
'ordre' => self::GenColInfo('ordre', 'Ordre', 1, NULL, NULL, FALSE),
260,23 → 275,23
 
'mots_cles_texte' => self::GenColInfo('mots_cles_texte', 'Mots Clés', 1),
'commentaire' => self::GenColInfo('commentaire', 'Commentaires', 1),
'date_creation' => self::GenColInfo('date_creation', 'Date Création', 1),
'date_modification' => self::GenColInfo('date_modification', 'Date Modification', 1),
'date_creation' => self::GenColInfo('date_creation', 'Date Création', 1, NULL, NULL, FALSE),
'date_modification' => self::GenColInfo('date_modification', 'Date Modification', 1, NULL, NULL, FALSE),
 
// rappel transmission = 1, signifie simplement "public"
// des données importées peuvent être d'emblée "publiques"
// "importable" = TRUE
'transmission' => self::GenColInfo('transmission', 'Transmis', 1),
'date_transmission' => self::GenColInfo('date_transmission', 'Date Transmission', 1),
'abondance' => self::GenColInfo('abondance', 'Abondance', 1, NULL, NULL, FALSE),
'certitude' => self::GenColInfo('certitude', 'Certitude', 1, NULL, NULL, FALSE),
'phenologie' => self::GenColInfo('phenologie', 'Phénologie', 1, NULL, NULL, FALSE),
'date_transmission' => self::GenColInfo('date_transmission', 'Date Transmission', 1, NULL, NULL, FALSE),
'abondance' => self::GenColInfo('abondance', 'Abondance', 1),
'certitude' => self::GenColInfo('certitude', 'Certitude', 1),
'phenologie' => self::GenColInfo('phenologie', 'Phénologie', 1),
 
'nom_commun' => self::GenColInfo('nom_commun', 'Nom Commun', 1, NULL, 'getNomCommun', FALSE),
//'nom-commun' => self::GenColInfo('nom-commun', 'Nom Commun', 1, NULL, 'getNomCommun_v2'),
//'nom-commun' => self::GenColInfo('nom-commun', 'Nom Commun', 1, NULL, 'getNomCommun_v3'),
 
'images' => self::GenColInfo('image', 'Image(s)', 1, NULL, 'getImages', TRUE),
'images' => self::GenColInfo('images', 'Image(s)', 1, NULL, 'getImages', TRUE),
);
}
 
/trunk/jrest/services/ImportXLS.php
87,7 → 87,7
 
/*
Ces colonnes:
- sont propre à tous les enregistrements uploadés
- sont propres à l'ensemble des enregistrements uploadés
- sont indépendantes du numéro de lignes
- n'ont pas de valeur par défaut dans la structure de la table
- nécessitent une initialisation dans le cadre de l'upload
98,12 → 98,17
"nom_utilisateur" => NULL,
"courriel_utilisateur" => NULL,
 
// XXX: fixes (mais pourraient varier dans le futur si la mise-à-jour
// fixes (fonction SQL)
// XXX future: mais pourraient varier dans le futur si la mise-à-jour
// d'observation est implémentée
"date_creation" => NULL, // ne peut initialiser d'une date ici
"date_modification" => NULL, // idem, cf initialiser_colonnes_statiques()
"date_creation" => "now()",
"date_modification" => "now()",
);
 
public $id_utilisateur = NULL;
// erreurs d'import
public $bilan = Array();
 
function ExportXLS($config) {
parent::__construct($config);
}
113,6 → 118,7
echo '0'; exit;
}
$id_utilisateur = intval($pairs['utilisateur']);
$this->id_utilisateur = $id_utilisateur; // pour traiterImage();
 
if(!isset($_SESSION)) session_start();
$this->controleUtilisateur($id_utilisateur);
132,16 → 138,32
 
//var_dump($donnees);
 
$objReader = PHPExcel_IOFactory::createReader("Excel5");
// renomme le fichier pour lui ajouter son extension initiale, ce qui
// permet (une sorte) d'autodétection du format.
$fichier = $infos_fichier['tmp_name'];
$extension = pathinfo($infos_fichier['name'], PATHINFO_EXTENSION);
if( (strlen($extension) == 3 || strlen($extension) == 4) &&
(rename($fichier, $fichier . '.' . $extension))) {
$fichier = $fichier . '.' . $extension;
}
 
$objReader = PHPExcel_IOFactory::createReaderForFile($fichier);
$objReader->setReadDataOnly(true);
 
if(is_a($objReader, 'PHPExcel_Reader_CSV')) {
$objReader->setDelimiter(',')
->setEnclosure('"')
->setLineEnding("\n")
->setSheetIndex(0);
}
 
// on ne conserve que l'en-tête
$filtre = new MyReadFilter();
$filtre->def_interval(1, 2);
$objReader->setReadFilter($filtre);
 
$objPHPExcel = $objReader->load($infos_fichier['tmp_name']);
$obj_infos = $objReader->listWorksheetInfo($infos_fichier['tmp_name']);
$objPHPExcel = $objReader->load($fichier);
$obj_infos = $objReader->listWorksheetInfo($fichier);
// XXX: indépendant du readFilter ?
$nb_lignes = $obj_infos[0]['totalRows'];
 
154,6 → 176,9
$dernier_ordre = intval($dernier_ordre[0]['ordre']) + 1;
if(! $dernier_ordre) $dernier_ordre = 0;
 
// on catch to les trigger_error(E_USER_NOTICE);
set_error_handler(array($this, 'erreurs_stock'), E_USER_NOTICE);
 
// lecture par morceaux (chunks), NB_LIRE_LIGNE_SIMUL lignes à fois
// pour aboutir des requêtes SQL d'insert groupés.
for($ligne = 2; $ligne < $nb_lignes + NB_LIRE_LIGNE_SIMUL; $ligne += NB_LIRE_LIGNE_SIMUL) {
163,7 → 188,7
/* recharge avec $filtre actif (filtre sur lignes colonnes):
- exclue les colonnes inutiles/inutilisables)
- ne selectionne que les lignes dans le range [$ligne - $ligne + NB_LIRE_LIGNE_SIMUL] */
$objPHPExcel = $objReader->load($infos_fichier['tmp_name']);
$objPHPExcel = $objReader->load($fichier);
$donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, FALSE, TRUE);
 
// ici on appel la fonction qui fera effectivement l'insertion multiple
171,9 → 196,21
 
// TODO: passer $this, ne sert que pour appeler des méthodes public qui pourraient être statiques
// notamment dans RechercheInfosTaxonBeta.php
self::chargerLignes($donnees, $this->colonnes_statiques, $dernier_ordre, $this, $obs_ajouts, $obs_maj);
list($enregistrements, $images) =
self::chargerLignes($this, $donnees, $this->colonnes_statiques, $dernier_ordre);
if(! $enregistrements) break;
 
$dernier_autoinc = self::stockerEnregistrements($this, $enregistrements);
$obs_ajouts += count($enregistrements);
// $obs_maj += count($enregistrements_a_MAJ);
self::stockerImages($this, $enregistrements, $images, $dernier_autoinc);
}
die('end');
 
restore_error_handler();
 
if($this->bilan) echo implode("\n", $this->bilan) . "\n";
// fin: renvoi summary
die("$obs_ajouts observations ajoutées");
}
 
static function detectionEntete($entete) {
185,7 → 222,7
$entete_officiel_simple = iconv('UTF-8', 'ASCII//TRANSLIT', strtolower(trim($col['nom'])));
$entete_officiel_abbrev = $col['abbrev'];
if($entete_simple == $entete_officiel_simple || $entete_simple == $entete_officiel_abbrev) {
// debug echo "define C_" . strtoupper($entete_officiel_abbrev) . ", $k\n";
//debug echo "define C_" . strtoupper($entete_officiel_abbrev) . ", $k ($v)\n";
define("C_" . strtoupper($entete_officiel_abbrev), $k);
$colonnes_reconnues[$k] = 1;
break;
219,27 → 256,30
/*
* charge un groupe de lignes
*/
static function chargerLignes($lignes, $colonnes_statiques, &$dernier_ordre, $cel, &$inserted, &$updated) {
static function chargerLignes($cel, $lignes, $colonnes_statiques, &$dernier_ordre) {
$enregistrement = NULL;
$enregistrements = Array();
$images = Array();
$toutes_images = Array();
 
foreach($lignes as $ligne) {
$ligne = array_filter($ligne, function($cell) { return !is_null($cell); });
if(!$ligne) continue;
//$ligne = array_filter($ligne, function($cell) { return !is_null($cell); });
//if(!$ligne) continue;
// on a besoin des NULL pour éviter des notice d'index indéfini
if(! array_filter($ligne, function($cell) { return !is_null($cell); })) continue;
 
if( ($enregistrement = self::chargerLigne($ligne, $colonnes_statiques, $dernier_ordre, $cel)) ) {
$enregistrements[] = $enregistrement;
if( ($enregistrement = self::chargerLigne($ligne, $dernier_ordre, $cel)) ) {
$enregistrements[] = array_merge($colonnes_statiques, $enregistrement);
 
if(isset($enregistrement['_images'])) {
$pos = count($enregistrements) - 1;
$last = &$enregistrements[$pos];
// ne dépend pas de cel_obs, et seront insérées *après* les enregistrements
// mais nous ne voulons pas nous priver de faire des INSERT multiples pour autant
$images[] = Array("text" => $enregistrements[$pos]['_images'],
"obs_pos" => $pos);
$toutes_images[] = Array("images" => $last['_images'],
"obs_pos" => $pos);
// ce champ n'a pas a faire partie de l'insertion dans cel_obs,
// mais est utile pour cel_obs_images
unset($enregistrements[$pos]['_images']);
unset($last['_images']);
}
 
$dernier_ordre++;
246,81 → 286,146
}
}
 
if(!$enregistrements) die('AIE // XXX');
// XXX future: return Array($enregistrements_a_inserer, $enregistrements_a_MAJ, $toutes_images);
return Array($enregistrements, $toutes_images);
}
 
 
static function stockerEnregistrements($cel, $enregistrements) {
$req = '';
 
foreach($enregistrements as $enregistrement) {
$enregistrement = self::sortArrayByArray($enregistrement, self::$ordre_BDD);
array_walk($enregistrement,
function(&$item, $k, $obj) { $item = is_null($item) ? "NULL" : $item; },
$cel);
$req .= implode(', ', $enregistrement) . "\n";
}
echo "$req\n";
// TODO: insert
 
foreach($enregistrements as $enregistrement)
$req .= implode(', ', self::sortArrayByArray($enregistrement, self::$ordre_BDD));
print_r($req);
 
// $cel->executer($req);
// transactionnel + auto-inc
$lastid = $cel->bdd->lastInsertId();
foreach($images as $image) {
$obs = $enregistrements[$image["obs_pos"]];
return $cel->bdd->lastInsertId();
}
 
 
static function stockerImages($cel, $enregistrements, $toutes_images, $lastid) {
if(! $lastid) $lastid = rand();
 
$images_insert =
'INSERT INTO cel_obs_images (id_image, id_observation) VALUES'
.' %s '
.'ON DUPLICATE KEY UPDATE id_image = id_image';
$images_obs_assoc = Array();
 
foreach($toutes_images as $images_pour_obs) {
$obs = $enregistrements[$images_pour_obs["obs_pos"]];
$id_obs = $lastid // dernier autoinc inséré
- count($enregistrements) - 1 // correspondrait au premier autoinc
+ $image["obs_pos"]; // ordre d'insertion = ordre dans le tableau $enregistrements
// TODO: INSERT
+ $images_pour_obs["obs_pos"]; // ordre d'insertion = ordre dans le tableau $enregistrements
foreach($images_pour_obs['images'] as $image) {
$images_obs_assoc[] = sprintf('(%d,%d)',
$image['id_image'], // intval() useless
$id_obs); // intval() useless
}
}
 
if($images_obs_assoc) {
$requete = sprintf($images_insert, implode(', ', $images_obs_assoc));
echo "$requete\n";
}
}
 
 
static function chargerLigne($ligne, $colonnes_statiques, $dernier_ordre, $cel) {
static function chargerLigne($ligne, $dernier_ordre, $cel) {
// en premier car le résultat est utile pour
// traiter longitude et latitude (traiterLonLat())
$referentiel = self::identReferentiel($ligne[C_NOM_REFERENTIEL]);
 
// $espece est rempli de plusieurs informations
$espece = Array();
$espece = Array(C_NOM_SEL => NULL, C_NOM_SEL_NN => NULL, C_NOM_RET => NULL,
C_NOM_RET_NN => NULL, C_NT => NULL, C_FAMILLE => NULL);
self::traiterEspece($ligne, $espece, $cel);
 
return array_merge($colonnes_statiques,
// Dans ce tableau, seules devraient apparaître les données variable pour chaque ligne.
// Dans ce tableau, l'ordre des clefs n'importe pas (cf: self::sortArrayByArray())
Array(
"ordre" => $dernier_ordre,
// $localisation est rempli à partir de plusieurs champs: C_ZONE_GEO et C_CE_ZONE_GEO
$localisation = Array(C_ZONE_GEO => NULL, C_CE_ZONE_GEO => NULL);
self::traiterLocalisation($ligne, $localisation, $cel);
 
"nom_sel" => $espece[C_NOM_SEL],
"nom_sel_nn" => $espece[C_NOM_SEL_NN],
"nom_ret" => $espece[C_NOM_RET],
"nom_ret_nn" => $espece[C_NOM_RET_NN],
"nt" => $espece[C_NT],
"famille" => $espece[C_FAMILLE],
// Dans ce tableau, seules devraient apparaître les données variable pour chaque ligne.
// Dans ce tableau, l'ordre des clefs n'importe pas (cf: self::sortArrayByArray())
$enregistrement = Array(
"ordre" => $dernier_ordre,
 
"nom_referentiel" => $referentiel,
// $this->quoteNonNull() est déjà appliquée dans traiterEspece()
"nom_sel" => $espece[C_NOM_SEL],
"nom_sel_nn" => $espece[C_NOM_SEL_NN],
"nom_ret" => $espece[C_NOM_RET],
"nom_ret_nn" => $espece[C_NOM_RET_NN],
"nt" => $espece[C_NT],
"famille" => $espece[C_FAMILLE],
 
"zone_geo" => TODO,
"ce_zone_geo" => self::traiterDepartement(trim($ligne[C_CE_ZONE_GEO])),
"nom_referentiel" => $cel->quoteNonNull($referentiel),
 
"date_observation" => self::traiterDateObs($ligne[C_DATE_OBSERVATION]),
"lieudit" => trim($ligne[C_LIEUDIT]),
"station" => trim($ligne[C_STATION]),
"milieu" => trim($ligne[C_MILIEU]),
"commentaire" => trim($ligne[C_COMMENTAIRE]), // TODO: foreign-key
// $this->quoteNonNull() est déjà appliquée dans traiterLocalisation()
"zone_geo" => $localisation[C_ZONE_GEO],
"ce_zone_geo" => $localisation[C_CE_ZONE_GEO],
 
"transmission" => in_array(strtolower(trim($ligne[C_TRANSMISSION])), array(1, 'oui')) ? 1 : 0,
// $ligne: uniquement pour les infos en cas de gestion d'erreurs (date incompréhensible)
"date_observation" => $cel->quoteNonNull(self::traiterDateObs($ligne[C_DATE_OBSERVATION], $ligne)),
 
"latitude" => self::traiterLonLat(NULL, $ligne[C_LATITUDE], $referentiel),
"longitude" => self::traiterLonLat($ligne[C_LONGITUDE], NULL, $referentiel),
));
"lieudit" => $cel->quoteNonNull(trim($ligne[C_LIEUDIT])),
"station" => $cel->quoteNonNull(trim($ligne[C_STATION])),
"milieu" => $cel->quoteNonNull(trim($ligne[C_MILIEU])),
"commentaire" => $cel->quoteNonNull(trim($ligne[C_COMMENTAIRE])), // TODO: foreign-key
 
 
"transmission" => in_array(strtolower(trim($ligne[C_TRANSMISSION])), array(1, 'oui')) ? 1 : 0,
 
// $ligne: uniquement pour les infos en cas de gestion d'erreurs (lon/lat incompréhensible)
"latitude" => self::traiterLonLat(NULL, $ligne[C_LATITUDE], $referentiel, $ligne),
"longitude" => self::traiterLonLat($ligne[C_LONGITUDE], NULL, $referentiel, $ligne),
);
 
// passage de $enregistrement par référence, ainsi ['_images'] n'est défini
// que si des résultats sont trouvés
// "@" car PHPExcel supprime les colonnes null sur toute la feuille (ou tout le chunk)
if(@$ligne[C_IMAGES]) self::traiterImage($ligne[C_IMAGES], $cel, $enregistrement);
 
return $enregistrement;
}
 
static function traiterImage($str, $cel, &$enregistrement) {
$liste_images = array_filter(explode("/", $str));
array_walk($liste_images,
function($item, $key, $obj) { $item = $obj->quoteNonNull(trim($item)); },
$cel);
$requete = sprintf(
"SELECT id_image, nom_original FROM cel_images WHERE ce_utilisateur = %d AND nom_original IN (\"%s\")",
$cel->id_utilisateur,
implode('","', $liste_images));
 
$resultat = $cel->requeter($requete);
 
if($resultat) $enregistrement['_images'] = $resultat;
}
 
 
/* FONCTIONS de TRANSFORMATION de VALEUR DE CELLULE */
 
// TODO: PHP 5.3, utiliser date_parse_from_format()
// TODO: parser les heures (cf product-owner)
// TODO: passer par le timestamp pour s'assurer de la validité
static function traiterDateObs($date) {
static function traiterDateObs($date, $ligne) {
// TODO: see https://github.com/PHPOffice/PHPExcel/issues/208
if(is_double($date)) {
if($date > 0)
return PHPExcel_Style_NumberFormat::toFormattedString($date, PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2) . " 00:00:00";
throw new Exception("erreur: date antérieure à 1970 et format de cellule \"DATE\" utilisés ensemble");
trigger_error("ligne \"{$ligne[C_NOM_SEL]}\": " .
"Attention: date antérieure à 1970 et format de cellule \"DATE\" utilisés ensemble",
E_USER_NOTICE);
// throw new Exception("erreur: date antérieure à 1970 et format de cellule \"DATE\" utilisés ensemble");
 
// attention, UNIX timestamp, car Excel les décompte depuis 1900
// cf http://fczaja.blogspot.fr/2011/06/convert-excel-date-into-timestamp.html
332,7 → 437,10
}
else {
$timestamp = strtotime($date);
if(!$timestamp) return NULL; // TODO: throw error
if(! $timestamp) {
if($date) trigger_error("ligne \"{$ligne[C_NOM_SEL]}\": Attention: date erronée ($date)", E_USER_NOTICE);
return NULL;
}
return strftime("%Y-%m-%d 00:00:00", strtotime($date));
}
}
343,20 → 451,39
if(strpos(strtolower($referentiel), 'bdtxa') !== FALSE) return 'bdtxa:v1.00';
if(strpos(strtolower($referentiel), 'bdnff') !== FALSE) return 'bdnff:4.02';
if(strpos(strtolower($referentiel), 'isfan') !== FALSE) return 'isfan:v1.00';
 
if($referentiel) {
trigger_error("ligne \"{$ligne[C_NOM_SEL]}\": Attention: référentiel inconnu", E_USER_NOTICE);
}
return NULL;
/* TODO: cf story,
En cas de NULL faire une seconde passe de détection à partir du nom saisie */
En cas de NULL faire une seconde passe de détection à partir du nom saisi
+ accepter les n° de version */
}
 
/* NON!
Un taxon d'un référentiel donné peut être théoriquement observé n'importe où sur le globe.
Il n'y a pas lieu d'effectuer des restriction ici.
Cependant des erreurs fréquentes (0,0 ou lon/lat inversées) peuvent être détectés ici.
TODO */
static function traiterLonLat($lon = NULL, $lat = NULL, $referentiel = 'bdtfx:v1.01') {
// verifier format decimal +
// + limite france si bdtfx ou bdtxa
static function traiterLonLat($lon = NULL, $lat = NULL, $referentiel = 'bdtfx:v1.01', $ligne) {
// en CSV ces valeurs sont des string, avec séparateur en français (","; cf défauts dans ExportXLS)
if($lon && is_string($lon)) $lon = str_replace(',', '.', $lon);
if($lat && is_string($lat)) $lat = str_replace(',', '.', $lat);
 
// sprintf applique une précision à 5 décimale (comme le ferait MySQL)
// tout en uniformisant le format de séparateur des décimales (le ".")
if($lon && is_numeric($lon) && $lon >= -180 && $lon <= 180) return sprintf('%.5F', $lon);
if($lat && is_numeric($lat) && $lat >= -90 && $lat <= 90) return sprintf('%.5F', $lat);
 
if($lon || $lat) {
trigger_error("ligne \"{$ligne[C_NOM_SEL]}\": " .
"Attention: longitude ou latitude erronée",
E_USER_NOTICE);
}
return NULL;
 
/* limite france métropole si bdtfx ? ou bdtxa ? ...
NON!
Un taxon d'un référentiel donné peut être théoriquement observé n'importe où sur le globe.
Il n'y a pas lieu d'effectuer des restriction ici.
Cependant des erreurs fréquentes (0,0 ou lon/lat inversées) peuvent être détectés ici.
TODO */
$bbox = self::getReferentielBBox($referentiel);
if(!$bbox) return NULL;
 
372,18 → 499,22
 
 
static function traiterEspece($ligne, Array &$espece, $cel) {
if(!$ligne[C_NOM_SEL]) return;
 
$taxon_info_webservice = new RechercheInfosTaxonBeta($cel->config);
 
$ascii = iconv('UTF-8', 'ASCII//TRANSLIT', $ligne[C_NOM_SEL]);
// FALSE = recherche étendue (LIKE x%)
$resultat_recherche_espece = $taxon_info_webservice->rechercherInfosSurTexteCodeOuNumTax($ligne[C_NOM_SEL]);
 
// on supprime les noms retenus et renvoi tel quel
// on réutilise les define pour les noms d'indexes, tant qu'à faire
if (empty($resultat_recherche_espece['en_id_nom'])) {
$espece[C_NOM_SEL] = $ligne[C_NOM_SEL];
$espece[C_NOM_SEL_NN] = $ligne[C_NOM_SEL_NN];
$espece[C_NOM_SEL] = $cel->quoteNonNull(trim($ligne[C_NOM_SEL]));
 
// le reste reste à NULL
// TODO: si empty(C_NOM_SEL) et !empty(C_NOM_SEL_NN) : recherche info à partir de C_NOM_SEL_NN
$espece[C_NOM_SEL_NN] = $ligne[C_NOM_SEL_NN];
$espece[C_NOM_RET] = $ligne[C_NOM_RET];
$espece[C_NOM_RET_NN] = $ligne[C_NOM_RET_NN];
$espece[C_NT] = $ligne[C_NT];
393,27 → 524,78
}
 
// succès de la détection, récupération des infos
$espece[C_NOM_SEL] = $resultat_recherche_espece['nom_sel'];
$espece[C_NOM_SEL_NN] = $resultat_recherche_espece['en_id_nom'];
$espece[C_NOM_SEL] = $cel->quoteNonNull($resultat_recherche_espece['nom_sel']);
$espece[C_NOM_SEL_NN] = $cel->quoteNonNull($resultat_recherche_espece['en_id_nom']);
 
$complement = $taxon_info_webservice->rechercherInformationsComplementairesSurNumNom($resultat_recherche_espece['en_id_nom']);
$espece[C_NOM_RET] = $complement['Nom_Retenu'];
$espece[C_NOM_RET_NN] = $complement['Num_Nom_Retenu'];
$espece[C_NT] = $complement['Num_Taxon'];
$espece[C_FAMILLE] = $complement['Famille'];
$espece[C_NOM_RET] = $cel->quoteNonNull($complement['Nom_Retenu']);
$espece[C_NOM_RET_NN] = $cel->quoteNonNull($complement['Num_Nom_Retenu']);
$espece[C_NT] = $cel->quoteNonNull($complement['Num_Taxon']);
$espece[C_FAMILLE] = $cel->quoteNonNull($complement['Famille']);
}
 
 
static function traiterDepartement($departement) {
if(strpos($departement, "INSEE-C:", 0) === 0) return $departement;
if(!is_numeric($departement)) return NULL; // TODO ?
if(strlen($departement) == 4) return "INSEE-C:0" . $departement;
if(strlen($departement) == 5) return "INSEE-C:" . $departement;
static function traiterLocalisation($ligne, Array &$localisation, $cel) {
$identifiant_commune = trim($ligne[C_ZONE_GEO]);
if(!$identifiant_commune) {
$departement = trim($ligne[C_CE_ZONE_GEO]);
goto testdepartement;
}
 
 
$select = "SELECT DISTINCT nom, code FROM cel_zones_geo";
if (preg_match('/(.*) \((\d+)\)/', $identifiant_commune, $elements)) {
// commune + departement : montpellier (34)
$nom_commune=$elements[1];
$code_commune=$elements[2];
$requete = sprintf("%s WHERE nom = %s AND code LIKE %s",
$select, $cel->quoteNonNull($nom_commune), $cel->quoteNonNull($code_commune.'%'));
}
elseif (preg_match('/^(\d+|(2[ab]\d+))$/i', $identifiant_commune, $elements)) {
// Code insee seul
$code_insee_commune=$elements[1];
$requete = sprintf("%s WHERE code = %s", $select, $cel->quoteNonNull($code_insee_commune));
}
else {
// Commune seule (le departement sera recupere dans la colonne departement si elle est presente)
// on prend le risque ici de retourner une mauvaise Commune
$nom_commune = str_replace(" ", "%", iconv('UTF-8', 'ASCII//TRANSLIT', $identifiant_commune));
$requete = sprintf("%s WHERE nom LIKE %s", $select, $cel->quoteNonNull($nom_commune.'%'));
}
$resultat_commune = $cel->requeter($requete);
// TODO: levenstein sort ?
 
// cas de la commune introuvable dans le référentiel
// réinitialisation aux valeurs du fichier XLS
if(! $resultat_commune) {
$localisation[C_ZONE_GEO] = trim($ligne[C_ZONE_GEO]);
$localisation[C_CE_ZONE_GEO] = trim($ligne[C_CE_ZONE_GEO]);
} else {
$localisation[C_ZONE_GEO] = $resultat_commune[0]['nom'];
$localisation[C_CE_ZONE_GEO] = $resultat_commune[0]['code'];
}
 
$departement = &$localisation[C_CE_ZONE_GEO];
 
testdepartement:
if(strpos($departement, "INSEE-C:", 0) === 0) goto protectloc;
 
if(!is_numeric($departement)) goto protectloc; // TODO ?
if(strlen($departement) == 4) $departement = "INSEE-C:0" . $departement;
if(strlen($departement) == 5) $departement = "INSEE-C:" . $departement;
// if(strlen($departement) <= 9) return "INSEE-C:0" . $departement; // ? ... TODO
return trim($departement); // TODO
 
$departement = trim($departement); // TODO
 
protectloc:
$localisation[C_ZONE_GEO] = $cel->quoteNonNull($localisation[C_ZONE_GEO]);
$localisation[C_CE_ZONE_GEO] = $cel->quoteNonNull($localisation[C_CE_ZONE_GEO]);
}
 
 
 
/* HELPERS */
 
// http://stackoverflow.com/questions/348410/sort-an-array-based-on-another-array
439,17 → 621,26
}
 
 
public function initialiser_colonnes_statiques($id_utisateur) {
public function initialiser_colonnes_statiques() {
$this->colonnes_statiques = array_merge($this->colonnes_statiques,
Array(
"ce_utilisateur" => $id_utisateur,
"prenom_utilisateur" => $this->utilisateur['prenom'],
"nom_utilisateur" => $this->utilisateur['nom'],
"courriel_utilisateur" => $this->utilisateur['courriel'],
 
"date_creation" => date("Y-m-d H:i:s"),
"date_modification" => date("Y-m-d H:i:s"),
"ce_utilisateur" => $this->id_utilisateur,
"prenom_utilisateur" => $this->quoteNonNull($this->utilisateur['prenom']),
"nom_utilisateur" => $this->quoteNonNull($this->utilisateur['nom']),
"courriel_utilisateur" => $this->quoteNonNull($this->utilisateur['courriel']),
));
 
}
 
// équivalent à CEL->Bdd->proteger() (qui wrap PDO::quote),
// sans transformer NULL en ""
private function quoteNonNull($chaine) {
if(is_null($chaine)) return "NULL";
if(!is_string($chaine)) die("erreur __FILE__, __LINE__");
return $this->bdd->quote($chaine);
}
 
public function erreurs_stock($errno, $errstr) {
$this->bilan[] = $errstr;
}
}