Subversion Repositories eFlore/Applications.cel

Rev

Rev 1814 | Rev 1852 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1814 Rev 1818
1
<?php
1
<?php
2
/**
2
/**
3
* @category  PHP
3
* @category  PHP
4
* @package   jrest
4
* @package   jrest
5
* @author    Raphaël Droz <raphael@tela-botania.org>
5
* @author    Raphaël Droz <raphael@tela-botania.org>
6
* @copyright 2013 Tela-Botanica
6
* @copyright 2013 Tela-Botanica
7
* @license   http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
7
* @license   http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
8
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
8
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
9
*/
9
*/
10
 
10
 
11
/**
11
/**
12
 * Service d'import de données d'observation du CEL au format XLS
12
 * Service d'import de données d'observation du CEL au format XLS
13
 *
13
 *
14
 * Sont define()'d commme n° de colonne tous les abbrevs retournés par
14
 * Sont define()'d commme n° de colonne tous les abbrevs retournés par
15
 * FormateurGroupeColonne::nomEnsembleVersListeColonnes() préfixés par C_  cf: detectionEntete()
15
 * FormateurGroupeColonne::nomEnsembleVersListeColonnes() préfixés par C_  cf: detectionEntete()
16
 *
16
 *
17
 * Exemple d'un test:
17
 * Exemple d'un test:
18
 * $ GET "/jrest/ExportXLS/22506?format=csv&range=*&limite=13" \
18
 * $ GET "/jrest/ExportXLS/22506?format=csv&range=*&limite=13" \
19
 *   | curl -F "upload=@-" -F utilisateur=22506 "/jrest/ImportXLS"
19
 *   | curl -F "upload=@-" -F utilisateur=22506 "/jrest/ImportXLS"
20
 * # 13 observations importées
20
 * # 13 observations importées
21
 * + cf MySQL general_log = 1
21
 * + cf MySQL general_log = 1
22
 *  
22
 *  
23
 **/
23
 **/
24
 
24
 
25
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(dirname(realpath(__FILE__))) . '/lib');
25
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(dirname(realpath(__FILE__))) . '/lib');
26
// TERM
26
// TERM
27
error_reporting(-1);
27
error_reporting(-1);
28
ini_set('html_errors', 0);
28
ini_set('html_errors', 0);
29
ini_set('xdebug.cli_color', 2);
29
ini_set('xdebug.cli_color', 2);
30
require_once('lib/PHPExcel/Classes/PHPExcel.php');
30
require_once('lib/PHPExcel/Classes/PHPExcel.php');
31
require_once('FormateurGroupeColonne.php');
31
require_once('FormateurGroupeColonne.php');
32
 
32
 
33
 
33
 
34
date_default_timezone_set("Europe/Paris");
34
date_default_timezone_set("Europe/Paris");
35
 
35
 
36
// nombre d'INSERT à cumuler par requête SQL
36
// nombre d'INSERT à cumuler par requête SQL
37
// (= nombre de lignes XLS à bufferiser)
37
// (= nombre de lignes XLS à bufferiser)
38
//define('NB_LIRE_LIGNE_SIMUL', 30);
38
//define('NB_LIRE_LIGNE_SIMUL', 30);
39
define('NB_LIRE_LIGNE_SIMUL', 5);
39
define('NB_LIRE_LIGNE_SIMUL', 5);
40
 
40
 
41
// Numbers of days between January 1, 1900 and 1970 (including 19 leap years)
41
// Numbers of days between January 1, 1900 and 1970 (including 19 leap years)
42
// see traiterDateObs()
42
// see traiterDateObs()
43
// define("MIN_DATES_DIFF", 25569);
43
// define("MIN_DATES_DIFF", 25569);
44
 
44
 
45
 
45
 
46
class MyReadFilter implements PHPExcel_Reader_IReadFilter {
46
class MyReadFilter implements PHPExcel_Reader_IReadFilter {
47
	// exclusion de colonnes
47
	// exclusion de colonnes
48
	public $exclues = array();
48
	public $exclues = array();
49
 
49
 
50
	// lecture par morceaux
50
	// lecture par morceaux
51
    public $ligne_debut = 0; 
51
    public $ligne_debut = 0; 
52
    public $ligne_fin = 0;
52
    public $ligne_fin = 0;
53
 
53
 
54
	public function __construct() {}
54
	public function __construct() {}
55
	public function def_interval($debut, $nb) {
55
	public function def_interval($debut, $nb) {
56
		$this->ligne_debut = $debut;
56
		$this->ligne_debut = $debut;
57
		$this->ligne_fin = $debut + $nb;
57
		$this->ligne_fin = $debut + $nb;
58
	}
58
	}
59
    public function readCell($colonne, $ligne, $worksheetName = '') {
59
    public function readCell($colonne, $ligne, $worksheetName = '') {
60
		if(@$this->exclues[$colonne]) return false;
60
		if(@$this->exclues[$colonne]) return false;
61
		// si des n° de morceaux ont été initialisés, on filtre...
61
		// si des n° de morceaux ont été initialisés, on filtre...
62
		if($this->ligne_debut && ($ligne < $this->ligne_debut || $ligne >= $this->ligne_fin)) return false;
62
		if($this->ligne_debut && ($ligne < $this->ligne_debut || $ligne >= $this->ligne_fin)) return false;
63
		return true;
63
		return true;
64
    } 
64
    } 
65
} 
65
} 
66
 
66
 
67
// XXX: PHP 5.3
67
// XXX: PHP 5.3
68
function __anonyme_1($v) {	return !$v['importable']; }
68
function __anonyme_1($v) {	return !$v['importable']; }
69
function __anonyme_2(&$v) {	$v = $v['nom']; }
69
function __anonyme_2(&$v) {	$v = $v['nom']; }
70
function __anonyme_3($cell) { return !is_null($cell); };
70
function __anonyme_3($cell) { return !is_null($cell); };
71
function __anonyme_5($item) { return is_null($item) ? '?' : $item; }
71
function __anonyme_5($item) { return is_null($item) ? '?' : $item; }
72
function __anonyme_6() { return NULL; }
72
function __anonyme_6() { return NULL; }
73
 
73
 
74
class ImportXLS extends Cel  {
74
class ImportXLS extends Cel  {
75
	static function __anonyme_4(&$item, $key) { $item = self::quoteNonNull(trim($item)); }
75
	static function __anonyme_4(&$item, $key) { $item = self::quoteNonNull(trim($item)); }
76
 
76
 
77
	static $ordre_BDD = Array(
77
	static $ordre_BDD = Array(
78
		"ce_utilisateur",
78
		"ce_utilisateur",
79
		"prenom_utilisateur",
79
		"prenom_utilisateur",
80
		"nom_utilisateur",
80
		"nom_utilisateur",
81
		"courriel_utilisateur",
81
		"courriel_utilisateur",
82
		"ordre",
82
		"ordre",
83
		"nom_sel",
83
		"nom_sel",
84
		"nom_sel_nn",
84
		"nom_sel_nn",
85
		"nom_ret",
85
		"nom_ret",
86
		"nom_ret_nn",
86
		"nom_ret_nn",
87
		"nt",
87
		"nt",
88
		"famille",
88
		"famille",
89
		"nom_referentiel",
89
		"nom_referentiel",
90
		"zone_geo",
90
		"zone_geo",
91
		"ce_zone_geo",
91
		"ce_zone_geo",
92
		"date_observation",
92
		"date_observation",
93
		"lieudit",
93
		"lieudit",
94
		"station",
94
		"station",
95
		"milieu",
95
		"milieu",
96
		"mots_cles_texte",
96
		"mots_cles_texte",
97
		"commentaire",
97
		"commentaire",
98
		"transmission",
98
		"transmission",
99
		"date_creation",
99
		"date_creation",
100
		"date_modification",
100
		"date_modification",
101
		"date_transmission",
101
		"date_transmission",
102
		"latitude",
102
		"latitude",
103
		"longitude",
103
		"longitude",
104
		"altitude",
104
		"altitude",
105
		"abondance",
105
		"abondance",
106
		"certitude",
106
		"certitude",
107
		"phenologie",
107
		"phenologie",
108
		"code_insee_calcule"
108
		"code_insee_calcule"
109
	);
109
	);
110
 
110
 
111
	// cf: initialiser_pdo_ordered_statements()
111
	// cf: initialiser_pdo_ordered_statements()
112
	// eg: "INSERT INTO cel_obs (ce_utilisateur, ..., phenologie, code_insee_calcule) VALUES"
112
	// eg: "INSERT INTO cel_obs (ce_utilisateur, ..., phenologie, code_insee_calcule) VALUES"
113
	// colonnes statiques d'abord, les autres ensuite, dans l'ordre de $ordre_BDD
113
	// colonnes statiques d'abord, les autres ensuite, dans l'ordre de $ordre_BDD
114
	static $insert_prefix_ordre;
114
	static $insert_prefix_ordre;
115
	// eg: "(<id>, <prenom>, <nom>, <email>, now(), now(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
115
	// eg: "(<id>, <prenom>, <nom>, <email>, now(), now(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
116
	// dont le nombre de placeholder dépend du nombre de colonnes non-statiques
116
	// dont le nombre de placeholder dépend du nombre de colonnes non-statiques
117
	// colonnes statiques d'abord, les autres ensuite, dans l'ordre de $ordre_BDD
117
	// colonnes statiques d'abord, les autres ensuite, dans l'ordre de $ordre_BDD
118
	static $insert_ligne_pattern_ordre;
118
	static $insert_ligne_pattern_ordre;
119
 
119
 
120
	// seconde (meilleure) possibilité
120
	// seconde (meilleure) possibilité
121
	// cf: initialiser_pdo_statements()
121
	// cf: initialiser_pdo_statements()
122
	// eg: "INSERT INTO cel_obs (ce_utilisateur, ..., date_creation, ...phenologie, code_insee_calcule) VALUES"
122
	// eg: "INSERT INTO cel_obs (ce_utilisateur, ..., date_creation, ...phenologie, code_insee_calcule) VALUES"
123
	static $insert_prefix;
123
	static $insert_prefix;
124
	// eg: "(<id>, <prenom>, <nom>, <email>, ?, ?, ?, now(), now(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
124
	// eg: "(<id>, <prenom>, <nom>, <email>, ?, ?, ?, now(), now(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
125
	// dont le nombre de placeholder dépend du nombre de colonnes non-statiques
125
	// dont le nombre de placeholder dépend du nombre de colonnes non-statiques
126
	static $insert_ligne_pattern;
126
	static $insert_ligne_pattern;
127
 
127
 
128
	/*
128
	/*
129
	  Ces colonnes:
129
	  Ces colonnes:
130
	  - sont propres à l'ensemble des enregistrements uploadés
130
	  - sont propres à l'ensemble des enregistrements uploadés
131
	  - sont indépendantes du numéro de lignes
131
	  - sont indépendantes du numéro de lignes
132
	  - n'ont pas de valeur par défaut dans la structure de la table
132
	  - n'ont pas de valeur par défaut dans la structure de la table
133
	  - nécessitent une initialisation dans le cadre de l'upload
133
	  - nécessitent une initialisation dans le cadre de l'upload
134
 
134
 
135
	  initialiser_colonnes_statiques() y merge les données d'identification utilisateur
135
	  initialiser_colonnes_statiques() y merge les données d'identification utilisateur
136
	*/
136
	*/
137
	public $colonnes_statiques = Array(
137
	public $colonnes_statiques = Array(
138
		"ce_utilisateur" => NULL,
138
		"ce_utilisateur" => NULL,
139
		"prenom_utilisateur" => NULL,
139
		"prenom_utilisateur" => NULL,
140
		"nom_utilisateur" => NULL,
140
		"nom_utilisateur" => NULL,
141
		"courriel_utilisateur" => NULL,
141
		"courriel_utilisateur" => NULL,
142
 
142
 
143
		// fixes (fonction SQL)
143
		// fixes (fonction SQL)
144
		// XXX future: mais pourraient varier dans le futur si la mise-à-jour
144
		// XXX future: mais pourraient varier dans le futur si la mise-à-jour
145
		// d'observation est implémentée
145
		// d'observation est implémentée
146
		"date_creation" => "now()",
146
		"date_creation" => "now()",
147
		"date_modification" => "now()",
147
		"date_modification" => "now()",
148
	);
148
	);
149
 
149
 
150
	public $id_utilisateur = NULL;
150
	public $id_utilisateur = NULL;
151
 
151
 
152
	// erreurs d'import
152
	// erreurs d'import
153
	public $bilan = Array();
153
	public $bilan = Array();
154
 
154
 
155
 
155
 
156
	function ImportXLS($config) {
156
	function ImportXLS($config) {
157
		parent::__construct($config);
157
		parent::__construct($config);
158
	}
158
	}
159
 
159
 
160
	function createElement($pairs) {
160
	function createElement($pairs) {
161
		if(!isset($pairs['utilisateur']) || trim($pairs['utilisateur']) == '') {
161
		if(!isset($pairs['utilisateur']) || trim($pairs['utilisateur']) == '') {
162
			exit('0');
162
			exit('0');
163
		}
163
		}
164
 
164
 
165
		$id_utilisateur = intval($pairs['utilisateur']);
165
		$id_utilisateur = intval($pairs['utilisateur']);
166
		$this->id_utilisateur = $id_utilisateur; // pour traiterImage();
166
		$this->id_utilisateur = $id_utilisateur; // pour traiterImage();
167
 
167
 
168
		if(!isset($_SESSION)) session_start();
168
		if(!isset($_SESSION)) session_start();
169
        $this->controleUtilisateur($id_utilisateur);
169
        $this->controleUtilisateur($id_utilisateur);
170
 
170
 
171
        $this->utilisateur = $this->getInfosComplementairesUtilisateur($id_utilisateur);
171
        $this->utilisateur = $this->getInfosComplementairesUtilisateur($id_utilisateur);
172
 
172
 
173
		$this->initialiser_colonnes_statiques($id_utilisateur);
173
		$this->initialiser_colonnes_statiques($id_utilisateur);
174
 
174
 
175
		// initialisation du statement PDO/MySQL
175
		// initialisation du statement PDO/MySQL
176
		// première version, pattern de requête pas génial
176
		// première version, pattern de requête pas génial
177
		/* list(self;;$insert_prefix_ordre, self::$insert_ligne_pattern_ordre) =
177
		/* list(self;;$insert_prefix_ordre, self::$insert_ligne_pattern_ordre) =
178
		   $this->initialiser_pdo_ordered_statements($this->colonnes_statiques); */
178
		   $this->initialiser_pdo_ordered_statements($this->colonnes_statiques); */
179
		list(self::$insert_prefix, self::$insert_ligne_pattern) =
179
		list(self::$insert_prefix, self::$insert_ligne_pattern) =
180
			$this->initialiser_pdo_statements($this->colonnes_statiques);
180
			$this->initialiser_pdo_statements($this->colonnes_statiques);
181
 
181
 
182
		$infos_fichier = array_pop($_FILES);
182
		$infos_fichier = array_pop($_FILES);
183
		
183
		
184
		/*$objPHPExcel = PHPExcel_IOFactory::load($infos_fichier['tmp_name']);
184
		/*$objPHPExcel = PHPExcel_IOFactory::load($infos_fichier['tmp_name']);
185
		  $donnees = $objPHPExcel->getActiveSheet()->toArray(NULL,FALSE,FALSE,TRUE);*/
185
		  $donnees = $objPHPExcel->getActiveSheet()->toArray(NULL,FALSE,FALSE,TRUE);*/
186
 
186
 
187
		/*$objReader = PHPExcel_IOFactory::createReader("Excel5");
187
		/*$objReader = PHPExcel_IOFactory::createReader("Excel5");
188
		$objReader->setReadDataOnly(true);
188
		$objReader->setReadDataOnly(true);
189
		$objPHPExcel = $objReader->load($infos_fichier['tmp_name']);*/
189
		$objPHPExcel = $objReader->load($infos_fichier['tmp_name']);*/
190
 
190
 
191
		//var_dump($donnees);
191
		//var_dump($donnees);
192
 
192
 
193
		// renomme le fichier pour lui ajouter son extension initiale, ce qui
193
		// renomme le fichier pour lui ajouter son extension initiale, ce qui
194
		// permet (une sorte) d'autodétection du format.
194
		// permet (une sorte) d'autodétection du format.
195
		$fichier = $infos_fichier['tmp_name'];
195
		$fichier = $infos_fichier['tmp_name'];
196
		$extension = pathinfo($infos_fichier['name'], PATHINFO_EXTENSION);
196
		$extension = pathinfo($infos_fichier['name'], PATHINFO_EXTENSION);
197
		if( (strlen($extension) == 3 || strlen($extension) == 4) &&
197
		if( (strlen($extension) == 3 || strlen($extension) == 4) &&
198
			(@rename($fichier, $fichier . '.' . $extension))) { // XXX: @ safe-mode
198
			(@rename($fichier, $fichier . '.' . $extension))) { // XXX: @ safe-mode
199
			$fichier = $fichier . '.' . $extension;
199
			$fichier = $fichier . '.' . $extension;
200
		}
200
		}
201
 
201
 
202
		$objReader = PHPExcel_IOFactory::createReaderForFile($fichier);
202
		$objReader = PHPExcel_IOFactory::createReaderForFile($fichier);
-
 
203
		// TODO: check if compatible with toArray(<1>,<2>,TRUE,<4>)
203
		$objReader->setReadDataOnly(true);
204
		$objReader->setReadDataOnly(true);
204
 
205
 
205
		// TODO: is_a obsolete entre 5.0 et 5.3, retirer le @ à terme
206
		// TODO: is_a obsolete entre 5.0 et 5.3, retirer le @ à terme
206
		if(@is_a($objReader, 'PHPExcel_Reader_CSV')) {
207
		if(@is_a($objReader, 'PHPExcel_Reader_CSV')) {
207
			$objReader->setDelimiter(',')
208
			$objReader->setDelimiter(',')
208
				->setEnclosure('"')
209
				->setEnclosure('"')
209
				->setLineEnding("\n")
210
				->setLineEnding("\n")
210
				->setSheetIndex(0);
211
				->setSheetIndex(0);
211
		}
212
		}
212
 
213
 
213
		// on ne conserve que l'en-tête
214
		// on ne conserve que l'en-tête
214
		$filtre = new MyReadFilter();
215
		$filtre = new MyReadFilter();
215
		$filtre->def_interval(1, 2);
216
		$filtre->def_interval(1, 2);
216
		$objReader->setReadFilter($filtre);
217
		$objReader->setReadFilter($filtre);
217
 
218
 
218
		$objPHPExcel = $objReader->load($fichier);
219
		$objPHPExcel = $objReader->load($fichier);
219
		$obj_infos = $objReader->listWorksheetInfo($fichier);
220
		$obj_infos = $objReader->listWorksheetInfo($fichier);
220
		// XXX: indépendant du readFilter ?
221
		// XXX: indépendant du readFilter ?
221
		$nb_lignes = $obj_infos[0]['totalRows'];
222
		$nb_lignes = $obj_infos[0]['totalRows'];
222
 
223
 
223
		$donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, FALSE, TRUE);
224
		$donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, TRUE, TRUE);
224
		$filtre->exclues = self::detectionEntete($donnees[1]);
225
		$filtre->exclues = self::detectionEntete($donnees[1]);
225
 
226
 
226
		$obs_ajouts = 0;
227
		$obs_ajouts = 0;
227
		$obs_maj = 0;
228
		$obs_maj = 0;
228
		$nb_images_ajoutees = 0;
229
		$nb_images_ajoutees = 0;
229
		$nb_mots_cle_ajoutes = 0;
230
		$nb_mots_cle_ajoutes = 0;
230
 
231
 
231
		$dernier_ordre = Cel::db()->requeter("SELECT MAX(ordre) AS ordre FROM cel_obs WHERE ce_utilisateur = $id_utilisateur");
232
		$dernier_ordre = Cel::db()->requeter("SELECT MAX(ordre) AS ordre FROM cel_obs WHERE ce_utilisateur = $id_utilisateur");
232
		$dernier_ordre = intval($dernier_ordre[0]['ordre']) + 1;
233
		$dernier_ordre = intval($dernier_ordre[0]['ordre']) + 1;
233
		if(! $dernier_ordre) $dernier_ordre = 0;
234
		if(! $dernier_ordre) $dernier_ordre = 0;
234
 
235
 
235
		// on catch to les trigger_error(E_USER_NOTICE);
236
		// on catch to les trigger_error(E_USER_NOTICE);
236
		set_error_handler(array($this, 'erreurs_stock'), E_USER_NOTICE);
237
		set_error_handler(array($this, 'erreurs_stock'), E_USER_NOTICE);
237
 
238
 
238
		// lecture par morceaux (chunks), NB_LIRE_LIGNE_SIMUL lignes à fois
239
		// lecture par morceaux (chunks), NB_LIRE_LIGNE_SIMUL lignes à fois
239
		// pour aboutir des requêtes SQL d'insert groupés.
240
		// pour aboutir des requêtes SQL d'insert groupés.
240
		for($ligne = 2; $ligne < $nb_lignes + NB_LIRE_LIGNE_SIMUL; $ligne += NB_LIRE_LIGNE_SIMUL) {
241
		for($ligne = 2; $ligne < $nb_lignes + NB_LIRE_LIGNE_SIMUL; $ligne += NB_LIRE_LIGNE_SIMUL) {
241
			$filtre->def_interval($ligne, NB_LIRE_LIGNE_SIMUL);
242
			$filtre->def_interval($ligne, NB_LIRE_LIGNE_SIMUL);
242
			$objReader->setReadFilter($filtre);
243
			$objReader->setReadFilter($filtre);
243
 
244
 
244
			/* recharge avec $filtre actif (filtre sur lignes colonnes):
245
			/* recharge avec $filtre actif (filtre sur lignes colonnes):
245
			   - exclue les colonnes inutiles/inutilisables)
246
			   - exclue les colonnes inutiles/inutilisables)
246
			   - ne selectionne que les lignes dans le range [$ligne - $ligne + NB_LIRE_LIGNE_SIMUL] */
247
			   - ne selectionne que les lignes dans le range [$ligne - $ligne + NB_LIRE_LIGNE_SIMUL] */
247
			$objPHPExcel = $objReader->load($fichier);
248
			$objPHPExcel = $objReader->load($fichier)->getActiveSheet();
-
 
249
 
-
 
250
			// set col typing
-
 
251
			if(C_CE_ZONE_GEO != 'C_CE_ZONE_GEO')
-
 
252
				$objPHPExcel->getStyle(C_CE_ZONE_GEO . '2:' . C_CE_ZONE_GEO . $objPHPExcel->getHighestRow())->getNumberFormat()->setFormatCode('00000');
-
 
253
 
-
 
254
			// TODO: set to string type
-
 
255
			if(C_ZONE_GEO != 'C_ZONE_GEO')
-
 
256
				$objPHPExcel->getStyle(C_ZONE_GEO . '2:' . C_ZONE_GEO . $objPHPExcel->getHighestRow())->getNumberFormat()->setFormatCode('00000');
-
 
257
 
248
			$donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, FALSE, TRUE);
258
			$donnees = $objPHPExcel->toArray(NULL, FALSE, TRUE, TRUE);
249
 
259
 
250
			// ici on appel la fonction qui fera effectivement l'insertion multiple
260
			// ici on appel la fonction qui fera effectivement l'insertion multiple
251
			// à partir des (au plus) NB_LIRE_LIGNE_SIMUL lignes
261
			// à partir des (au plus) NB_LIRE_LIGNE_SIMUL lignes
252
 
262
 
253
			// TODO: passer $this, ne sert que pour appeler des méthodes publiques qui pourraient être statiques
263
			// TODO: passer $this, ne sert que pour appeler des méthodes publiques qui pourraient être statiques
254
			// notamment dans RechercheInfosTaxonBeta.php
264
			// notamment dans RechercheInfosTaxonBeta.php
255
			list($enregistrements, $images, $mots_cle) =
265
			list($enregistrements, $images, $mots_cle) =
256
				self::chargerLignes($this, $donnees, $this->colonnes_statiques, $dernier_ordre);
266
				self::chargerLignes($this, $donnees, $this->colonnes_statiques, $dernier_ordre);
257
			if(! $enregistrements) break;
267
			if(! $enregistrements) break;
258
 
268
 
259
			self::trierColonnes($enregistrements);
269
			self::trierColonnes($enregistrements);
260
			// normalement: NB_LIRE_LIGNE_SIMUL, sauf si une enregistrement ne semble pas valide
270
			// normalement: NB_LIRE_LIGNE_SIMUL, sauf si une enregistrement ne semble pas valide
261
			// ou bien lors du dernier chunk
271
			// ou bien lors du dernier chunk
262
 
272
 
263
			$nb_rec = count($enregistrements);
273
			$nb_rec = count($enregistrements);
264
			$sql_pattern = self::$insert_prefix .
274
			$sql_pattern = self::$insert_prefix .
265
				str_repeat(self::$insert_ligne_pattern_ordre . ', ', $nb_rec - 1) .
275
				str_repeat(self::$insert_ligne_pattern_ordre . ', ', $nb_rec - 1) .
266
				self::$insert_ligne_pattern_ordre;
276
				self::$insert_ligne_pattern_ordre;
267
 
277
 
268
			$sql_pattern = self::$insert_prefix .
278
			$sql_pattern = self::$insert_prefix .
269
				str_repeat(self::$insert_ligne_pattern . ', ', $nb_rec - 1) .
279
				str_repeat(self::$insert_ligne_pattern . ', ', $nb_rec - 1) .
270
				self::$insert_ligne_pattern;
280
				self::$insert_ligne_pattern;
271
 
281
 
272
			Cel::db()->beginTransaction();
282
			Cel::db()->beginTransaction();
273
			$stmt = Cel::db()->prepare($sql_pattern);
283
			$stmt = Cel::db()->prepare($sql_pattern);
274
			$donnees = array();
284
			$donnees = array();
275
			foreach($enregistrements as $e) $donnees = array_merge($donnees, array_values($e));
285
			foreach($enregistrements as $e) $donnees = array_merge($donnees, array_values($e));
276
 
286
 
277
			/* debug ici: echo $sql_pattern . "\n"; var_dump($enregistrements, $donnees); die;*/
287
			/* debug ici: echo $sql_pattern . "\n"; var_dump($enregistrements, $donnees); die;*/
278
 
288
 
279
			$stmt->execute($donnees);
289
			$stmt->execute($donnees);
280
 
290
 
281
			// $stmt->debugDumpParams(); // https://bugs.php.net/bug.php?id=52384
291
			// $stmt->debugDumpParams(); // https://bugs.php.net/bug.php?id=52384
282
			$dernier_autoinc = Cel::db()->lastInsertId();
292
			$dernier_autoinc = Cel::db()->lastInsertId();
283
			Cel::db()->commit();
293
			Cel::db()->commit();
284
 
294
 
285
			if(! $dernier_autoinc) trigger_error("l'insertion semble avoir échoué", E_USER_NOTICE);
295
			if(! $dernier_autoinc) trigger_error("l'insertion semble avoir échoué", E_USER_NOTICE);
286
 
296
 
287
			$obs_ajouts += count($enregistrements);
297
			$obs_ajouts += count($enregistrements);
288
			// $obs_ajouts += count($enregistrements['insert']);
298
			// $obs_ajouts += count($enregistrements['insert']);
289
			// $obs_maj += count($enregistrements['update']);
299
			// $obs_maj += count($enregistrements['update']);
290
			$nb_images_ajoutees += self::stockerImages($enregistrements, $images, $dernier_autoinc);
300
			$nb_images_ajoutees += self::stockerImages($enregistrements, $images, $dernier_autoinc);
291
			$nb_mots_cle_ajoutes += self::stockerMotsCle($enregistrements, $mots_cle, $dernier_autoinc);
301
			$nb_mots_cle_ajoutes += self::stockerMotsCle($enregistrements, $mots_cle, $dernier_autoinc);
292
		}
302
		}
293
 
303
 
294
		restore_error_handler();
304
		restore_error_handler();
295
 
305
 
296
		if($this->bilan) echo implode("\n", $this->bilan) . "\n";
306
		if($this->bilan) echo implode("\n", $this->bilan) . "\n";
297
 		printf('%1$d observation%2$s ajoutée%2$s' . "\n" .
307
 		printf('%1$d observation%2$s ajoutée%2$s' . "\n" .
298
			   '%3$d image%4$s attachée%4$s' . "\n" .
308
			   '%3$d image%4$s attachée%4$s' . "\n" .
299
			   // '%5$d mot%6$c-clef ajouté%6$c [TODO]' . "\n" . // TODO
309
			   // '%5$d mot%6$c-clef ajouté%6$c [TODO]' . "\n" . // TODO
300
			   (count($filtre->exclues) > 0 ? 'colonne%7$s non-traitée%7$s: %8$s' . "\n" : ''),
310
			   (count($filtre->exclues) > 0 ? 'colonne%7$s non-traitée%7$s: %8$s' . "\n" : ''),
301
 
311
 
302
			   $obs_ajouts,
312
			   $obs_ajouts,
303
			   $obs_ajouts > 1 ? 's' : '',
313
			   $obs_ajouts > 1 ? 's' : '',
304
			   $nb_images_ajoutees,
314
			   $nb_images_ajoutees,
305
			   $nb_images_ajoutees > 1 ? 's' : '',
315
			   $nb_images_ajoutees > 1 ? 's' : '',
306
			   $nb_mots_cle_ajoutes,
316
			   $nb_mots_cle_ajoutes,
307
			   $nb_mots_cle_ajoutes > 1 ? 's' : '',
317
			   $nb_mots_cle_ajoutes > 1 ? 's' : '',
308
			   count($filtre->exclues) > 1 ? 's' : '',
318
			   count($filtre->exclues) > 1 ? 's' : '',
309
			   implode(', ', $filtre->exclues));
319
			   implode(', ', $filtre->exclues));
310
		die();
320
		die();
311
	}
321
	}
312
 
322
 
313
	static function detectionEntete($entete) {
323
	static function detectionEntete($entete) {
314
		$colonnes_reconnues = Array();
324
		$colonnes_reconnues = Array();
315
		$cols = FormateurGroupeColonne::nomEnsembleVersListeColonnes('standard,avance');
325
		$cols = FormateurGroupeColonne::nomEnsembleVersListeColonnes('standard,avance');
316
		foreach($entete as $k => $v) {
326
		foreach($entete as $k => $v) {
317
			// traite les colonnes en faisant fi de la casse et des accents
327
			// traite les colonnes en faisant fi de la casse et des accents
318
			$entete_simple = iconv('UTF-8', 'ASCII//TRANSLIT', strtolower(trim($v)));
328
			$entete_simple = iconv('UTF-8', 'ASCII//TRANSLIT', strtolower(trim($v)));
319
			foreach($cols as $col) {
329
			foreach($cols as $col) {
320
				$entete_officiel_simple = iconv('UTF-8', 'ASCII//TRANSLIT', strtolower(trim($col['nom'])));
330
				$entete_officiel_simple = iconv('UTF-8', 'ASCII//TRANSLIT', strtolower(trim($col['nom'])));
321
				$entete_officiel_abbrev = $col['abbrev'];
331
				$entete_officiel_abbrev = $col['abbrev'];
322
				if($entete_simple == $entete_officiel_simple || $entete_simple == $entete_officiel_abbrev) {
332
				if($entete_simple == $entete_officiel_simple || $entete_simple == $entete_officiel_abbrev) {
323
					// debug echo "define C_" . strtoupper($entete_officiel_abbrev) . ", $k ($v)\n";
333
					// debug echo "define C_" . strtoupper($entete_officiel_abbrev) . ", $k ($v)\n";
324
					define("C_" . strtoupper($entete_officiel_abbrev), $k);
334
					define("C_" . strtoupper($entete_officiel_abbrev), $k);
325
					$colonnes_reconnues[$k] = 1;
335
					$colonnes_reconnues[$k] = 1;
326
					break;
336
					break;
327
				}
337
				}
328
			}
338
			}
329
		}
339
		}
330
		// défini tous les index que nous utilisons à une valeur d'index de colonne Excel qui n'existe pas dans
340
		// défini tous les index que nous utilisons à une valeur d'index de colonne Excel qui n'existe pas dans
331
		// le tableau renvoyé par PHPExcel
341
		// le tableau renvoyé par PHPExcel
332
		// Attention cependant d'utiliser des indexes différenciés car traiterLonLat() et traiterEspece()
342
		// Attention cependant d'utiliser des indexes différenciés car traiterLonLat() et traiterEspece()
333
		// les utilisent
343
		// les utilisent
334
		foreach($cols as $col) {
344
		foreach($cols as $col) {
335
			if(!defined("C_" . strtoupper($col['abbrev'])))
345
			if(!defined("C_" . strtoupper($col['abbrev'])))
336
				define("C_" . strtoupper($col['abbrev']), "C_" . strtoupper($col['abbrev']));
346
				define("C_" . strtoupper($col['abbrev']), "C_" . strtoupper($col['abbrev']));
337
		}
347
		}
338
 
348
 
339
		// prépare le filtre de PHPExcel qui évitera le traitement de toutes les colonnes superflues
349
		// prépare le filtre de PHPExcel qui évitera le traitement de toutes les colonnes superflues
340
 
350
 
341
		// eg: diff ( Array( H => Commune, I => rien ) , Array( H => 1, K => 1 )
351
		// eg: diff ( Array( H => Commune, I => rien ) , Array( H => 1, K => 1 )
342
		// ==> Array( I => rien )
352
		// ==> Array( I => rien )
343
		$colonnesID_non_reconnues = array_diff_key($entete, $colonnes_reconnues);
353
		$colonnesID_non_reconnues = array_diff_key($entete, $colonnes_reconnues);
344
 
354
 
345
		// des colonnes de FormateurGroupeColonne::nomEnsembleVersListeColonnes()
355
		// des colonnes de FormateurGroupeColonne::nomEnsembleVersListeColonnes()
346
		// ne retient que celles marquées "importables"
356
		// ne retient que celles marquées "importables"
347
		$colonnes_automatiques = array_filter($cols, '__anonyme_1');
357
		$colonnes_automatiques = array_filter($cols, '__anonyme_1');
348
 
358
 
349
		// ne conserve que le nom long pour matcher avec la ligne XLS d'entête
359
		// ne conserve que le nom long pour matcher avec la ligne XLS d'entête
350
		array_walk($colonnes_automatiques, '__anonyme_2');
360
		array_walk($colonnes_automatiques, '__anonyme_2');
351
 
361
 
352
		// intersect ( Array ( N => Milieu, S => Ordre ), Array ( ordre => Ordre, phenologie => Phénologie ) )
362
		// intersect ( Array ( N => Milieu, S => Ordre ), Array ( ordre => Ordre, phenologie => Phénologie ) )
353
		// ==> Array ( S => Ordre, AA => Phénologie )
363
		// ==> Array ( S => Ordre, AA => Phénologie )
354
		$colonnesID_a_exclure = array_intersect($entete, $colonnes_automatiques);
364
		$colonnesID_a_exclure = array_intersect($entete, $colonnes_automatiques);
355
 
365
 
356
		// TODO: pourquoi ne pas comparer avec les abbrevs aussi ?
366
		// TODO: pourquoi ne pas comparer avec les abbrevs aussi ?
357
		// merge ( Array( I => rien ) , Array ( S => Ordre, AA => Phénologie ) )
367
		// merge ( Array( I => rien ) , Array ( S => Ordre, AA => Phénologie ) )
358
		// ==> Array ( I => rien, AA => Phénologie )
368
		// ==> Array ( I => rien, AA => Phénologie )
359
		return array_merge($colonnesID_non_reconnues, $colonnesID_a_exclure);
369
		return array_merge($colonnesID_non_reconnues, $colonnesID_a_exclure);
360
	}
370
	}
361
 
371
 
362
	/*
372
	/*
363
	 * charge un groupe de lignes
373
	 * charge un groupe de lignes
364
	 */
374
	 */
365
	static function chargerLignes($cel, $lignes, $colonnes_statiques, &$dernier_ordre) {
375
	static function chargerLignes($cel, $lignes, $colonnes_statiques, &$dernier_ordre) {
366
		$enregistrement = NULL;
376
		$enregistrement = NULL;
367
		$enregistrements = Array();
377
		$enregistrements = Array();
368
		$toutes_images = Array();
378
		$toutes_images = Array();
369
		$tous_mots_cle = Array();
379
		$tous_mots_cle = Array();
370
 
380
 
371
		foreach($lignes as $ligne) {
381
		foreach($lignes as $ligne) {
372
			//$ligne = array_filter($ligne, function($cell) { return !is_null($cell); });
382
			//$ligne = array_filter($ligne, function($cell) { return !is_null($cell); });
373
			//if(!$ligne) continue;
383
			//if(!$ligne) continue;
374
			// on a besoin des NULL pour éviter des notice d'index indéfini
384
			// on a besoin des NULL pour éviter des notice d'index indéfini
375
			if(! array_filter($ligne, '__anonyme_3')) continue;
385
			if(! array_filter($ligne, '__anonyme_3')) continue;
376
 
386
 
377
			if( ($enregistrement = self::chargerLigne($ligne, $dernier_ordre, $cel)) ) {
387
			if( ($enregistrement = self::chargerLigne($ligne, $dernier_ordre, $cel)) ) {
378
				// $enregistrements[] = array_merge($colonnes_statiques, $enregistrement);
388
				// $enregistrements[] = array_merge($colonnes_statiques, $enregistrement);
379
				$enregistrements[] = $enregistrement;
389
				$enregistrements[] = $enregistrement;
380
				$pos = count($enregistrements) - 1;
390
				$pos = count($enregistrements) - 1;
381
				$last = &$enregistrements[$pos];
391
				$last = &$enregistrements[$pos];
382
 
392
 
383
				if(isset($enregistrement['_images'])) {
393
				if(isset($enregistrement['_images'])) {
384
					// ne dépend pas de cel_obs, et seront insérées *après* les enregistrements
394
					// ne dépend pas de cel_obs, et seront insérées *après* les enregistrements
385
					// mais nous ne voulons pas nous priver de faire des INSERT multiples pour autant
395
					// mais nous ne voulons pas nous priver de faire des INSERT multiples pour autant
386
					$toutes_images[] = Array("images" => $last['_images'],
396
					$toutes_images[] = Array("images" => $last['_images'],
387
											 "obs_pos" => $pos);
397
											 "obs_pos" => $pos);
388
					// ce champ n'a pas à faire partie de l'insertion dans cel_obs,
398
					// ce champ n'a pas à faire partie de l'insertion dans cel_obs,
389
					// mais est utile pour cel_obs_images
399
					// mais est utile pour cel_obs_images
390
					unset($last['_images']);
400
					unset($last['_images']);
391
				}
401
				}
392
 
402
 
393
				if(isset($enregistrement['_mots_cle'])) {
403
				if(isset($enregistrement['_mots_cle'])) {
394
					// ne dépend pas de cel_obs, et seront insérés *après* les enregistrements
404
					// ne dépend pas de cel_obs, et seront insérés *après* les enregistrements
395
					// mais nous ne voulons pas nous priver de faire des INSERT multiples pour autant
405
					// mais nous ne voulons pas nous priver de faire des INSERT multiples pour autant
396
					$tous_mots_cle[] = Array("mots_cle" => $last['_mots_cle'],
406
					$tous_mots_cle[] = Array("mots_cle" => $last['_mots_cle'],
397
											 "obs_pos" => $pos);
407
											 "obs_pos" => $pos);
398
					// la version inlinée des mots est enregistrées dans cel_obs
408
					// la version inlinée des mots est enregistrées dans cel_obs
399
					// mais cel_mots_cles_obs fait foi.
409
					// mais cel_mots_cles_obs fait foi.
400
					// XXX: postponer l'ajout de ces informations dans cel_obs *après* l'insertion effective
410
					// XXX: postponer l'ajout de ces informations dans cel_obs *après* l'insertion effective
401
					// des records dans cel_mots_cles_obs ?
411
					// des records dans cel_mots_cles_obs ?
402
					unset($last['_mots_cle']);
412
					unset($last['_mots_cle']);
403
				}
413
				}
404
 
414
 
405
				$dernier_ordre++;
415
				$dernier_ordre++;
406
			}
416
			}
407
		}
417
		}
408
 
418
 
409
		// XXX future: return Array($enregistrements_a_inserer, $enregistrements_a_MAJ, $toutes_images);
419
		// XXX future: return Array($enregistrements_a_inserer, $enregistrements_a_MAJ, $toutes_images);
410
		return Array($enregistrements, $toutes_images, $tous_mots_cle);
420
		return Array($enregistrements, $toutes_images, $tous_mots_cle);
411
	}
421
	}
412
 
422
 
413
 
423
 
414
	static function trierColonnes(&$enregistrements) {
424
	static function trierColonnes(&$enregistrements) {
415
		foreach($enregistrements as &$enregistrement) {
425
		foreach($enregistrements as &$enregistrement) {
416
			$enregistrement = self::sortArrayByArray($enregistrement, self::$ordre_BDD);
426
			$enregistrement = self::sortArrayByArray($enregistrement, self::$ordre_BDD);
417
			//array_walk($enregistrement, function(&$item, $k) { $item = is_null($item) ? "NULL" : $item; });
427
			//array_walk($enregistrement, function(&$item, $k) { $item = is_null($item) ? "NULL" : $item; });
418
			//$req .= implode(', ', $enregistrement) . "\n";
428
			//$req .= implode(', ', $enregistrement) . "\n";
419
		}
429
		}
420
	}
430
	}
421
 
431
 
422
 
432
 
423
	static function stockerMotsCle($enregistrements, $tous_mots_cle, $lastid) {
433
	static function stockerMotsCle($enregistrements, $tous_mots_cle, $lastid) {
424
		$c = 0;
434
		$c = 0;
425
		// debug: var_dump($tous_mots_cle);die;
435
		// debug: var_dump($tous_mots_cle);die;
426
		foreach($tous_mots_cle as $v) $c += count($v['mots_cle']['to_insert']);
436
		foreach($tous_mots_cle as $v) $c += count($v['mots_cle']['to_insert']);
427
		return $c;
437
		return $c;
428
	}
438
	}
429
 
439
 
430
	static function stockerImages($enregistrements, $toutes_images, $lastid) {
440
	static function stockerImages($enregistrements, $toutes_images, $lastid) {
431
		$images_insert = 'INSERT INTO cel_obs_images (id_image, id_observation) VALUES %s ON DUPLICATE KEY UPDATE id_image = id_image';
441
		$images_insert = 'INSERT INTO cel_obs_images (id_image, id_observation) VALUES %s ON DUPLICATE KEY UPDATE id_image = id_image';
432
		$images_obs_assoc = Array();
442
		$images_obs_assoc = Array();
433
 
443
 
434
		foreach($toutes_images as $images_pour_obs) {
444
		foreach($toutes_images as $images_pour_obs) {
435
			$obs = $enregistrements[$images_pour_obs["obs_pos"]];
445
			$obs = $enregistrements[$images_pour_obs["obs_pos"]];
436
			$id_obs = $lastid // dernier autoinc inséré
446
			$id_obs = $lastid // dernier autoinc inséré
437
				- count($enregistrements) + 1 // correspondrait au premier autoinc
447
				- count($enregistrements) + 1 // correspondrait au premier autoinc
438
				+ $images_pour_obs["obs_pos"]; // ordre d'insertion = ordre dans le tableau $enregistrements (commence à 0)
448
				+ $images_pour_obs["obs_pos"]; // ordre d'insertion = ordre dans le tableau $enregistrements (commence à 0)
439
			foreach($images_pour_obs['images'] as $image) {
449
			foreach($images_pour_obs['images'] as $image) {
440
				$images_obs_assoc[] = sprintf('(%d,%d)',
450
				$images_obs_assoc[] = sprintf('(%d,%d)',
441
											  $image['id_image'], // intval() useless
451
											  $image['id_image'], // intval() useless
442
											  $id_obs); // intval() useless
452
											  $id_obs); // intval() useless
443
			}
453
			}
444
		}
454
		}
445
 
455
 
446
		if($images_obs_assoc) {
456
		if($images_obs_assoc) {
447
			$requete = sprintf($images_insert, implode(', ', $images_obs_assoc));
457
			$requete = sprintf($images_insert, implode(', ', $images_obs_assoc));
448
			// debug echo "$requete\n";
458
			// debug echo "$requete\n";
449
			Cel::db()->requeter($requete);
459
			Cel::db()->requeter($requete);
450
		}
460
		}
451
 
461
 
452
		return count($images_obs_assoc);
462
		return count($images_obs_assoc);
453
	}
463
	}
454
 
464
 
455
	/*
465
	/*
456
	  Aucune des valeurs présentes dans $enregistrement n'est quotée
466
	  Aucune des valeurs présentes dans $enregistrement n'est quotée
457
	  cad aucune des valeurs retournée par traiter{Espece|Localisation}()
467
	  cad aucune des valeurs retournée par traiter{Espece|Localisation}()
458
	  car ce tableau est passé à un PDO::preparedStatement() qui applique
468
	  car ce tableau est passé à un PDO::preparedStatement() qui applique
459
	  proprement les règle d'échappement.
469
	  proprement les règle d'échappement.
460
	 */
470
	 */
461
	static function chargerLigne($ligne, $dernier_ordre, $cel) {
471
	static function chargerLigne($ligne, $dernier_ordre, $cel) {
462
		// évite des notices d'index lors des trigger_error()
472
		// évite des notices d'index lors des trigger_error()
463
		$ref_ligne = !empty($ligne[C_NOM_SEL]) ? trim($ligne[C_NOM_SEL]) : '';
473
		$ref_ligne = !empty($ligne[C_NOM_SEL]) ? trim($ligne[C_NOM_SEL]) : '';
464
 
474
 
465
		// en premier car le résultat est utile pour
475
		// en premier car le résultat est utile pour
466
		// * traiter espèce (traiterEspece())
476
		// * traiter espèce (traiterEspece())
467
		// * traiter longitude et latitude (traiterLonLat())
477
		// * traiter longitude et latitude (traiterLonLat())
468
		$referentiel = self::identReferentiel(trim(strtolower(@$ligne[C_NOM_REFERENTIEL])), $ligne, $ref_ligne);
478
		$referentiel = self::identReferentiel(trim(strtolower(@$ligne[C_NOM_REFERENTIEL])), $ligne, $ref_ligne);
469
 
479
 
470
		// $espece est rempli de plusieurs informations
480
		// $espece est rempli de plusieurs informations
471
		$espece = Array(C_NOM_SEL => NULL, C_NOM_SEL_NN => NULL, C_NOM_RET => NULL,
481
		$espece = Array(C_NOM_SEL => NULL, C_NOM_SEL_NN => NULL, C_NOM_RET => NULL,
472
						C_NOM_RET_NN => NULL, C_NT => NULL, C_FAMILLE => NULL);
482
						C_NOM_RET_NN => NULL, C_NT => NULL, C_FAMILLE => NULL);
473
		self::traiterEspece($ligne, $espece, $referentiel, $cel);
483
		self::traiterEspece($ligne, $espece, $referentiel, $cel);
474
 
484
 
475
		// $localisation est rempli à partir de plusieurs champs: C_ZONE_GEO et C_CE_ZONE_GEO
485
		// $localisation est rempli à partir de plusieurs champs: C_ZONE_GEO et C_CE_ZONE_GEO
476
		$localisation = Array(C_ZONE_GEO => NULL, C_CE_ZONE_GEO => NULL);
486
		$localisation = Array(C_ZONE_GEO => NULL, C_CE_ZONE_GEO => NULL);
477
		self::traiterLocalisation($ligne, $localisation);
487
		self::traiterLocalisation($ligne, $localisation);
478
 
488
 
479
		// $transmission est utilisé pour date_transmission
489
		// $transmission est utilisé pour date_transmission
480
		// XXX: @ contre "Undefined index"
490
		// XXX: @ contre "Undefined index"
481
		@$transmission = in_array(strtolower(trim($ligne[C_TRANSMISSION])), array(1, 'oui')) ? 1 : 0;
491
		@$transmission = in_array(strtolower(trim($ligne[C_TRANSMISSION])), array(1, 'oui')) ? 1 : 0;
482
 
492
 
483
 
493
 
484
		// Dans ce tableau, seules devraient apparaître les données variable pour chaque ligne.
494
		// Dans ce tableau, seules devraient apparaître les données variable pour chaque ligne.
485
		// Dans ce tableau, l'ordre des clefs n'importe pas (cf: self::sortArrayByArray())
495
		// Dans ce tableau, l'ordre des clefs n'importe pas (cf: self::sortArrayByArray())
486
		$enregistrement = Array(
496
		$enregistrement = Array(
487
			"ordre" => $dernier_ordre,
497
			"ordre" => $dernier_ordre,
488
 
498
 
489
			"nom_sel" => $espece[C_NOM_SEL],
499
			"nom_sel" => $espece[C_NOM_SEL],
490
			"nom_sel_nn" => $espece[C_NOM_SEL_NN],
500
			"nom_sel_nn" => $espece[C_NOM_SEL_NN],
491
			"nom_ret" => $espece[C_NOM_RET],
501
			"nom_ret" => $espece[C_NOM_RET],
492
			"nom_ret_nn" => $espece[C_NOM_RET_NN],
502
			"nom_ret_nn" => $espece[C_NOM_RET_NN],
493
			"nt" => $espece[C_NT],
503
			"nt" => $espece[C_NT],
494
			"famille" => $espece[C_FAMILLE],
504
			"famille" => $espece[C_FAMILLE],
495
 
505
 
496
			"nom_referentiel" => $referentiel,
506
			"nom_referentiel" => $referentiel,
497
 
507
 
498
			"zone_geo" => $localisation[C_ZONE_GEO],
508
			"zone_geo" => $localisation[C_ZONE_GEO],
499
			"ce_zone_geo" => $localisation[C_CE_ZONE_GEO],
509
			"ce_zone_geo" => $localisation[C_CE_ZONE_GEO],
500
 
510
 
501
			// $ligne: uniquement pour les infos en cas de gestion d'erreurs (date incompréhensible)
511
			// $ligne: uniquement pour les infos en cas de gestion d'erreurs (date incompréhensible)
502
			"date_observation" => isset($ligne[C_DATE_OBSERVATION]) ? self::traiterDateObs($ligne[C_DATE_OBSERVATION], $ref_ligne) : NULL,
512
			"date_observation" => isset($ligne[C_DATE_OBSERVATION]) ? self::traiterDateObs($ligne[C_DATE_OBSERVATION], $ref_ligne) : NULL,
503
 
513
 
504
			"lieudit" => isset($ligne[C_LIEUDIT]) ? trim($ligne[C_LIEUDIT]) : NULL,
514
			"lieudit" => isset($ligne[C_LIEUDIT]) ? trim($ligne[C_LIEUDIT]) : NULL,
505
			"station" => isset($ligne[C_STATION]) ? trim($ligne[C_STATION]) : NULL,
515
			"station" => isset($ligne[C_STATION]) ? trim($ligne[C_STATION]) : NULL,
506
			"milieu" => isset($ligne[C_MILIEU]) ? trim($ligne[C_MILIEU]) : NULL,
516
			"milieu" => isset($ligne[C_MILIEU]) ? trim($ligne[C_MILIEU]) : NULL,
507
 
517
 
508
			"mots_cles_texte" => NULL, // TODO: foreign-key
518
			"mots_cles_texte" => NULL, // TODO: foreign-key
509
			// XXX: @ contre "Undefined index"
519
			// XXX: @ contre "Undefined index"
510
			"commentaire" => isset($ligne[C_COMMENTAIRE]) ? trim($ligne[C_COMMENTAIRE]) : NULL,
520
			"commentaire" => isset($ligne[C_COMMENTAIRE]) ? trim($ligne[C_COMMENTAIRE]) : NULL,
511
 
521
 
512
			"transmission" => $transmission,
522
			"transmission" => $transmission,
513
			"date_transmission" => $transmission ? date("Y-m-d H:i:s") : NULL, // pas de fonction SQL dans un PDO statement, <=> now()
523
			"date_transmission" => $transmission ? date("Y-m-d H:i:s") : NULL, // pas de fonction SQL dans un PDO statement, <=> now()
514
 
524
 
515
			// $ligne: uniquement pour les infos en cas de gestion d'erreurs (lon/lat incompréhensible)
525
			// $ligne: uniquement pour les infos en cas de gestion d'erreurs (lon/lat incompréhensible)
516
			"latitude" => isset($ligne[C_LATITUDE]) ? self::traiterLonLat(NULL, $ligne[C_LATITUDE], $referentiel, $ref_ligne) : NULL,
526
			"latitude" => isset($ligne[C_LATITUDE]) ? self::traiterLonLat(NULL, $ligne[C_LATITUDE], $referentiel, $ref_ligne) : NULL,
517
			"longitude" => isset($ligne[C_LONGITUDE]) ? self::traiterLonLat($ligne[C_LONGITUDE], NULL, $referentiel, $ref_ligne) : NULL,
527
			"longitude" => isset($ligne[C_LONGITUDE]) ? self::traiterLonLat($ligne[C_LONGITUDE], NULL, $referentiel, $ref_ligne) : NULL,
518
			"altitude" => isset($ligne[C_ALTITUDE]) ? intval($ligne[C_ALTITUDE]) : NULL, // TODO: guess alt from lon/lat
528
			"altitude" => isset($ligne[C_ALTITUDE]) ? intval($ligne[C_ALTITUDE]) : NULL, // TODO: guess alt from lon/lat
519
 
529
 
520
			// @ car potentiellement optionnelles ou toutes vides => pas d'index dans PHPExcel (tableau optimisé)
530
			// @ car potentiellement optionnelles ou toutes vides => pas d'index dans PHPExcel (tableau optimisé)
521
			"abondance" => @$ligne[C_ABONDANCE],
531
			"abondance" => @$ligne[C_ABONDANCE],
522
			"certitude" => @$ligne[C_CERTITUDE],
532
			"certitude" => @$ligne[C_CERTITUDE],
523
			"phenologie" => @$ligne[C_PHENOLOGIE],
533
			"phenologie" => @$ligne[C_PHENOLOGIE],
524
 
534
 
525
			"code_insee_calcule" => substr($localisation[C_CE_ZONE_GEO], -5) // varchar(5)
535
			"code_insee_calcule" => substr($localisation[C_CE_ZONE_GEO], -5) // varchar(5)
526
		);
536
		);
527
 
537
 
528
		// passage de $enregistrement par référence, ainsi ['_images'] n'est défini
538
		// passage de $enregistrement par référence, ainsi ['_images'] n'est défini
529
		// que si des résultats sont trouvés
539
		// que si des résultats sont trouvés
530
		// "@" car PHPExcel supprime les colonnes null sur toute la feuille (ou tout le chunk)
540
		// "@" car PHPExcel supprime les colonnes null sur toute la feuille (ou tout le chunk)
531
		if(@$ligne[C_IMAGES]) self::traiterImage($ligne[C_IMAGES], $cel->id_utilisateur, $enregistrement);
541
		if(@$ligne[C_IMAGES]) self::traiterImage($ligne[C_IMAGES], $cel->id_utilisateur, $enregistrement);
532
 
542
 
533
		if(@$ligne[C_MOTS_CLES_TEXTE]) self::traiterMotsCle($ligne[C_MOTS_CLES_TEXTE], $cel->id_utilisateur, $enregistrement);
543
		if(@$ligne[C_MOTS_CLES_TEXTE]) self::traiterMotsCle($ligne[C_MOTS_CLES_TEXTE], $cel->id_utilisateur, $enregistrement);
534
 
544
 
535
		return $enregistrement;
545
		return $enregistrement;
536
	}
546
	}
537
 
547
 
538
	static function traiterImage($str, $id_utilisateur, &$enregistrement) {
548
	static function traiterImage($str, $id_utilisateur, &$enregistrement) {
539
		$liste_images = array_filter(explode("/", $str));
549
		$liste_images = array_filter(explode("/", $str));
540
 
550
 
541
		//array_walk($liste_images, '__anonyme_4');
551
		//array_walk($liste_images, '__anonyme_4');
542
		array_walk($liste_images, array(__CLASS__, '__anonyme_4'));
552
		array_walk($liste_images, array(__CLASS__, '__anonyme_4'));
543
		$requete = sprintf(
553
		$requete = sprintf(
544
			"SELECT id_image, nom_original FROM cel_images WHERE ce_utilisateur = %d AND nom_original IN (%s)",
554
			"SELECT id_image, nom_original FROM cel_images WHERE ce_utilisateur = %d AND nom_original IN (%s)",
545
			$id_utilisateur,
555
			$id_utilisateur,
546
			implode(',', $liste_images));
556
			implode(',', $liste_images));
547
 
557
 
548
		$resultat = Cel::db()->requeter($requete);
558
		$resultat = Cel::db()->requeter($requete);
549
 
559
 
550
		if($resultat) $enregistrement['_images'] = $resultat;
560
		if($resultat) $enregistrement['_images'] = $resultat;
551
	}
561
	}
552
 
562
 
553
	static function traiterMotsCle($str, $id_utilisateur, &$enregistrement) {
563
	static function traiterMotsCle($str, $id_utilisateur, &$enregistrement) {
554
		$liste_mots_cle = $liste_mots_cle_recherche = array_map("trim", array_unique(array_filter(explode(",", $str))));
564
		$liste_mots_cle = $liste_mots_cle_recherche = array_map("trim", array_unique(array_filter(explode(",", $str))));
555
		array_walk($liste_mots_cle_recherche, array(__CLASS__, '__anonyme_4'));
565
		array_walk($liste_mots_cle_recherche, array(__CLASS__, '__anonyme_4'));
556
 
566
 
557
		// TODO!!!! remplace > (pour les tests uniquement) par un = et supprimer le group by mot_cle
567
		// TODO!!!! remplace > (pour les tests uniquement) par un = et supprimer le group by mot_cle
558
		$requete = sprintf("SELECT id_mot_cle_obs, mot_cle FROM cel_mots_cles_obs WHERE id_utilisateur > %d ".
568
		$requete = sprintf("SELECT id_mot_cle_obs, mot_cle FROM cel_mots_cles_obs WHERE id_utilisateur > %d ".
559
						   "AND mot_cle IN (%s) ".
569
						   "AND mot_cle IN (%s) ".
560
						   "GROUP BY mot_cle",
570
						   "GROUP BY mot_cle",
561
						   $id_utilisateur,
571
						   $id_utilisateur,
562
						   implode(',', $liste_mots_cle_recherche));
572
						   implode(',', $liste_mots_cle_recherche));
563
 
573
 
564
		$resultat_sql = Cel::db()->requeter($requete);
574
		$resultat_sql = Cel::db()->requeter($requete);
565
		if(!$resultat_sql) return;
575
		if(!$resultat_sql) return;
566
 
576
 
567
		$resultat = array();
577
		$resultat = array();
568
		foreach($resultat_sql as $v) $resultat[$v['id_mot_cle_obs']] = $v['mot_cle'];
578
		foreach($resultat_sql as $v) $resultat[$v['id_mot_cle_obs']] = $v['mot_cle'];
569
 
579
 
570
		$enregistrement['mots_cles_texte'] = implode(',', $liste_mots_cle);
580
		$enregistrement['mots_cles_texte'] = implode(',', $liste_mots_cle);
571
		$enregistrement['_mots_cle'] = array("existing" => $resultat,
581
		$enregistrement['_mots_cle'] = array("existing" => $resultat,
572
											 "to_insert" => array_diff($liste_mots_cle, $resultat));
582
											 "to_insert" => array_diff($liste_mots_cle, $resultat));
573
	}
583
	}
574
 
584
 
575
 
585
 
576
	/* FONCTIONS de TRANSFORMATION de VALEUR DE CELLULE */
586
	/* FONCTIONS de TRANSFORMATION de VALEUR DE CELLULE */
577
 
587
 
578
	// TODO: PHP 5.3, utiliser date_parse_from_format()
588
	// TODO: PHP 5.3, utiliser date_parse_from_format()
579
	// TODO: parser les heures (cf product-owner)
589
	// TODO: parser les heures (cf product-owner)
580
	// TODO: passer par le timestamp pour s'assurer de la validité
590
	// TODO: passer par le timestamp pour s'assurer de la validité
581
	static function traiterDateObs($date, $ref_ligne) {
591
	static function traiterDateObs($date, $ref_ligne) {
582
		// TODO: see https://github.com/PHPOffice/PHPExcel/issues/208
592
		// TODO: see https://github.com/PHPOffice/PHPExcel/issues/208
-
 
593
		// TODO: PHPExcel_Shared_Date::ExcelToPHP()
583
		if(is_double($date)) {
594
		if(is_double($date)) {
584
			if($date > 0)
595
			if($date > 0)
585
				return PHPExcel_Style_NumberFormat::toFormattedString($date, PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2) . " 00:00:00";
596
				return PHPExcel_Style_NumberFormat::toFormattedString($date, PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2) . " 00:00:00";
586
			trigger_error("ligne \"{$ref_ligne}\": " .
597
			trigger_error("ligne \"{$ref_ligne}\": " .
587
						  "Attention: date antérieure à 1970 et format de cellule \"DATE\" utilisés ensemble",
598
						  "Attention: date antérieure à 1970 et format de cellule \"DATE\" utilisés ensemble",
588
						  E_USER_NOTICE);
599
						  E_USER_NOTICE);
589
 
600
 
590
			// throw new Exception("erreur: date antérieure à 1970 et format de cellule \"DATE\" utilisés ensemble");
601
			// throw new Exception("erreur: date antérieure à 1970 et format de cellule \"DATE\" utilisés ensemble");
591
 
602
 
592
			// attention, UNIX timestamp, car Excel les décompte depuis 1900
603
			// attention, UNIX timestamp, car Excel les décompte depuis 1900
593
			// cf http://fczaja.blogspot.fr/2011/06/convert-excel-date-into-timestamp.html
604
			// cf http://fczaja.blogspot.fr/2011/06/convert-excel-date-into-timestamp.html
594
			// $timestamp = ($date - MIN_DATES_DIFF) * 60 * 60 * 24 - time(); // NON
605
			// $timestamp = ($date - MIN_DATES_DIFF) * 60 * 60 * 24 - time(); // NON
595
 
606
 
596
			// $timestamp = PHPExcel_Calculation::getInstance()->calculateFormula("=" . $date . "-DATE(1970,1,1)*60*60*24"); // NON
607
			// $timestamp = PHPExcel_Calculation::getInstance()->calculateFormula("=" . $date . "-DATE(1970,1,1)*60*60*24"); // NON
597
 
608
 
598
			// echo strftime("%Y/%m/%d 00:00:00", $timestamp); // NON
609
			// echo strftime("%Y/%m/%d 00:00:00", $timestamp); // NON
599
		}
610
		}
600
		else {
611
		else {
601
			// attend l'un des formats de
612
			// attend l'un des formats de
602
			// http://www.php.net/manual/fr/datetime.formats.date.php
613
			// http://www.php.net/manual/fr/datetime.formats.date.php
603
			// le plus simple: YYYY/MM/DD (utilisé à l'export), mais DD-MM-YYYY est aussi supporté
614
			// le plus simple: YYYY/MM/DD (utilisé à l'export), mais DD-MM-YYYY est aussi supporté
604
			$matches = NULL;
615
			$matches = NULL;
605
			// et on essaie d'être sympa et supporter aussi DD/MM/YYYY
616
			// et on essaie d'être sympa et supporter aussi DD/MM/YYYY
606
			if(preg_match(';^([0-3]?\d)/([01]\d)/([12]\d\d\d)$;', $date, $matches)) {
617
			if(preg_match(';^([0-3]?\d)/([01]\d)/([12]\d\d\d)$;', $date, $matches)) {
607
				$date = $matches[3] . '/' . $matches[2] . '/' . $matches[1];
618
				$date = $matches[3] . '/' . $matches[2] . '/' . $matches[1];
608
			}
619
			}
609
			$timestamp = strtotime($date);
620
			$timestamp = strtotime($date);
610
			if(! $timestamp || $timestamp > time() + 3600 * 24 * 1) { // une journée d'avance maxi autorisée (décallage horaire ?)
621
			if(! $timestamp || $timestamp > time() + 3600 * 24 * 1) { // une journée d'avance maxi autorisée (décallage horaire ?)
611
				if($date) trigger_error("ligne \"{$ref_ligne}\": Attention: date erronée ($date)", E_USER_NOTICE);
622
				if($date) trigger_error("ligne \"{$ref_ligne}\": Attention: date erronée ($date)", E_USER_NOTICE);
612
				return NULL;
623
				return NULL;
613
			}
624
			}
614
			return strftime("%Y-%m-%d 00:00:00", $timestamp);
625
			return strftime("%Y-%m-%d 00:00:00", $timestamp);
615
		}
626
		}
616
	}
627
	}
617
 
628
 
618
	static function identReferentiel($referentiel, $ligne, $ref_ligne) {
629
	static function identReferentiel($referentiel, $ligne, $ref_ligne) {
619
		// SELECT DISTINCT nom_referentiel, COUNT(id_observation) AS count FROM cel_obs GROUP BY nom_referentiel ORDER BY count DESC;
630
		// SELECT DISTINCT nom_referentiel, COUNT(id_observation) AS count FROM cel_obs GROUP BY nom_referentiel ORDER BY count DESC;
620
		if(strpos($referentiel, 'bdtfx') !== FALSE) return 'bdtfx'; //:v1.01';
631
		if(strpos($referentiel, 'bdtfx') !== FALSE) return 'bdtfx'; //:v1.01';
621
		if(strpos($referentiel, 'bdtxa') !== FALSE) return 'bdtxa'; //:v1.00';
632
		if(strpos($referentiel, 'bdtxa') !== FALSE) return 'bdtxa'; //:v1.00';
622
		//if(strpos($referentiel, 'bdnff') !== FALSE) return 'bdnff'; //:4.02';
633
		//if(strpos($referentiel, 'bdnff') !== FALSE) return 'bdnff'; //:4.02';
623
		if(strpos($referentiel, 'bdnff') !== FALSE) return 'bdtfx';
634
		if(strpos($referentiel, 'bdnff') !== FALSE) return 'bdtfx';
624
		if(strpos($referentiel, 'isfan') !== FALSE) return 'isfan'; //:v1.00';
635
		if(strpos($referentiel, 'isfan') !== FALSE) return 'isfan'; //:v1.00';
625
		if(strpos($referentiel, 'autre') !== FALSE) return 'autre';
636
		if(strpos($referentiel, 'autre') !== FALSE) return 'autre';
626
 
637
 
627
		if($referentiel && isset($ligne[C_NOM_SEL]) && $ligne[C_NOM_SEL]) {
638
		if($referentiel && isset($ligne[C_NOM_SEL]) && $ligne[C_NOM_SEL]) {
628
			trigger_error("ligne \"{$ref_ligne}\": Attention: référentiel inconnu", E_USER_NOTICE);
639
			trigger_error("ligne \"{$ref_ligne}\": Attention: référentiel inconnu", E_USER_NOTICE);
629
			return 'autre';
640
			return 'autre';
630
		}
641
		}
631
 
642
 
632
		// pas de référentiel ou pas de NOM_SEL: NULL
643
		// pas de référentiel ou pas de NOM_SEL: NULL
633
		return NULL;
644
		return NULL;
634
		/* TODO: cf story,
645
		/* TODO: cf story,
635
		   En cas de NULL faire une seconde passe de détection à partir du nom saisi
646
		   En cas de NULL faire une seconde passe de détection à partir du nom saisi
636
		   + accepter les n° de version */
647
		   + accepter les n° de version */
637
	}
648
	}
638
 
649
 
639
	static function traiterLonLat($lon = NULL, $lat = NULL, $referentiel = 'bdtfx', $ref_ligne) {
650
	static function traiterLonLat($lon = NULL, $lat = NULL, $referentiel = 'bdtfx', $ref_ligne) {
640
		// en CSV ces valeurs sont des string, avec séparateur en français (","; cf défauts dans ExportXLS)
651
		// en CSV ces valeurs sont des string, avec séparateur en français (","; cf défauts dans ExportXLS)
641
		if($lon && is_string($lon)) $lon = str_replace(',', '.', $lon);
652
		if($lon && is_string($lon)) $lon = str_replace(',', '.', $lon);
642
		if($lat && is_string($lat)) $lat = str_replace(',', '.', $lat);
653
		if($lat && is_string($lat)) $lat = str_replace(',', '.', $lat);
643
 
654
 
644
		// sprintf applique une précision à 5 décimale (comme le ferait MySQL)
655
		// sprintf applique une précision à 5 décimale (comme le ferait MySQL)
645
		// tout en uniformisant le format de séparateur des décimales (le ".")
656
		// tout en uniformisant le format de séparateur des décimales (le ".")
646
		if($lon && is_numeric($lon) && $lon >= -180 && $lon <= 180) return sprintf('%.5F', $lon);
657
		if($lon && is_numeric($lon) && $lon >= -180 && $lon <= 180) return sprintf('%.5F', $lon);
647
		if($lat && is_numeric($lat) && $lat >= -90 && $lat <= 90) return sprintf('%.5F', $lat);
658
		if($lat && is_numeric($lat) && $lat >= -90 && $lat <= 90) return sprintf('%.5F', $lat);
648
 
659
 
649
		if($lon || $lat) {
660
		if($lon || $lat) {
650
			trigger_error("ligne \"{$ref_ligne}\": " .
661
			trigger_error("ligne \"{$ref_ligne}\": " .
651
						  "Attention: longitude ou latitude erronée",
662
						  "Attention: longitude ou latitude erronée",
652
						  E_USER_NOTICE);
663
						  E_USER_NOTICE);
653
		}
664
		}
654
		return NULL;
665
		return NULL;
655
 
666
 
656
		/* limite france métropole si bdtfx ? ou bdtxa ? ...
667
		/* limite france métropole si bdtfx ? ou bdtxa ? ...
657
		   NON!
668
		   NON!
658
		   Un taxon d'un référentiel donné peut être théoriquement observé n'importe où sur le globe.
669
		   Un taxon d'un référentiel donné peut être théoriquement observé n'importe où sur le globe.
659
		   Il n'y a pas lieu d'effectuer des restriction ici.
670
		   Il n'y a pas lieu d'effectuer des restriction ici.
660
		   Cependant des erreurs fréquentes (0,0 ou lon/lat inversées) peuvent être détectés ici.
671
		   Cependant des erreurs fréquentes (0,0 ou lon/lat inversées) peuvent être détectés ici.
661
		   TODO */
672
		   TODO */
662
		$bbox = self::getReferentielBBox($referentiel);
673
		$bbox = self::getReferentielBBox($referentiel);
663
		if(!$bbox) return NULL;
674
		if(!$bbox) return NULL;
664
 
675
 
665
		if($lon) {
676
		if($lon) {
666
			if($lon < $bbox['EST'] && $lon > $bbox['OUEST']) return is_numeric($lon) ? $lon : NULL;
677
			if($lon < $bbox['EST'] && $lon > $bbox['OUEST']) return is_numeric($lon) ? $lon : NULL;
667
			else return NULL;
678
			else return NULL;
668
		}
679
		}
669
		if($lat) {
680
		if($lat) {
670
			if($lat < $bbox['NORD'] && $lat > $bbox['SUD']) return is_numeric($lat) ? $lat : NULL;
681
			if($lat < $bbox['NORD'] && $lat > $bbox['SUD']) return is_numeric($lat) ? $lat : NULL;
671
			return NULL;
682
			return NULL;
672
		}
683
		}
673
	}
684
	}
674
 
685
 
675
	/*
686
	/*
676
	  TODO: s'affranchir du webservice pour la détermination du nom scientifique en s'appuyant sur cel_references,
687
	  TODO: s'affranchir du webservice pour la détermination du nom scientifique en s'appuyant sur cel_references,
677
	  pour des questions de performances
688
	  pour des questions de performances
678
	*/
689
	*/
679
	static function traiterEspece($ligne, Array &$espece, &$referentiel, $cel) {
690
	static function traiterEspece($ligne, Array &$espece, &$referentiel, $cel) {
680
		if(empty($ligne[C_NOM_SEL])) return;
691
		if(empty($ligne[C_NOM_SEL])) return;
681
 
692
 
682
		// nom_sel reste toujours celui de l'utilisateur
693
		// nom_sel reste toujours celui de l'utilisateur
683
		$espece[C_NOM_SEL] = trim($ligne[C_NOM_SEL]);
694
		$espece[C_NOM_SEL] = trim($ligne[C_NOM_SEL]);
684
 
695
 
685
		// XXX/attention, nous ne devrions pas accepter un référentiel absent !
696
		// XXX/attention, nous ne devrions pas accepter un référentiel absent !
686
		if(!$referentiel) $referentiel = 'bdtfx';
697
		if(!$referentiel) $referentiel = 'bdtfx';
687
		$taxon_info_webservice = new RechercheInfosTaxonBeta($cel->config, $referentiel);
698
		$taxon_info_webservice = new RechercheInfosTaxonBeta($cel->config, $referentiel);
688
		$ascii = iconv('UTF-8', 'ASCII//TRANSLIT', $ligne[C_NOM_SEL]);
699
		$ascii = iconv('UTF-8', 'ASCII//TRANSLIT', $ligne[C_NOM_SEL]);
689
 
700
 
690
		// TODO: si empty(C_NOM_SEL) et !empty(C_NOM_SEL_NN) : recherche info à partir de C_NOM_SEL_NN
701
		// TODO: si empty(C_NOM_SEL) et !empty(C_NOM_SEL_NN) : recherche info à partir de C_NOM_SEL_NN
691
		// echo "rechercherInformationsComplementairesSurNom()\n";
702
		// echo "rechercherInformationsComplementairesSurNom()\n";
692
		/*
703
		/*
693
		  SELECT num_nom, nom_sci, num_nom_retenu ,auteur, annee, biblio_origine, nom_sci,auteur  FROM bdtfx_v1_01  WHERE (nom_sci LIKE 'Heliotropium europaeum')  ORDER BY nom_sci ASC   LIMIT 0, 1
704
		  SELECT num_nom, nom_sci, num_nom_retenu ,auteur, annee, biblio_origine, nom_sci,auteur  FROM bdtfx_v1_01  WHERE (nom_sci LIKE 'Heliotropium europaeum')  ORDER BY nom_sci ASC   LIMIT 0, 1
694
		  #
705
		  #
695
		  SELECT num_nom, nom_sci, num_nom_retenu ,auteur, annee, biblio_origine, nom_sci,auteur  FROM bdtfx_v1_01  WHERE (nom_sci LIKE 'eliotropium euro')  ORDER BY nom_sci ASC   LIMIT 0, 1
706
		  SELECT num_nom, nom_sci, num_nom_retenu ,auteur, annee, biblio_origine, nom_sci,auteur  FROM bdtfx_v1_01  WHERE (nom_sci LIKE 'eliotropium euro')  ORDER BY nom_sci ASC   LIMIT 0, 1
696
		  SELECT num_nom, nom_sci, num_nom_retenu ,auteur, annee, biblio_origine, nom_sci,auteur  FROM bdtfx_v1_01  WHERE (nom_sci LIKE 'eliotropium')  ORDER BY nom_sci ASC   LIMIT 0, 1
707
		  SELECT num_nom, nom_sci, num_nom_retenu ,auteur, annee, biblio_origine, nom_sci,auteur  FROM bdtfx_v1_01  WHERE (nom_sci LIKE 'eliotropium')  ORDER BY nom_sci ASC   LIMIT 0, 1
697
		  SELECT num_nom, nom_sci, num_nom_retenu ,auteur, annee, biblio_origine, nom_sci,auteur  FROM bdtfx_v1_01  WHERE (nom_sci LIKE 'eliotropium% euro%')  ORDER BY nom_sci ASC   LIMIT 0, 1
708
		  SELECT num_nom, nom_sci, num_nom_retenu ,auteur, annee, biblio_origine, nom_sci,auteur  FROM bdtfx_v1_01  WHERE (nom_sci LIKE 'eliotropium% euro%')  ORDER BY nom_sci ASC   LIMIT 0, 1
698
		  #
709
		  #
699
 
710
 
700
		  SELECT nom_sci, num_nom_retenu, nom_sci_html, auteur, annee, biblio_origine FROM bdtfx_v1_01 WHERE num_nom = 31468
711
		  SELECT nom_sci, num_nom_retenu, nom_sci_html, auteur, annee, biblio_origine FROM bdtfx_v1_01 WHERE num_nom = 31468
701
		*/
712
		*/
702
		// $determ = $taxon_info_webservice->rechercherInformationsComplementairesSurNom($ligne[C_NOM_SEL]);
713
		// $determ = $taxon_info_webservice->rechercherInformationsComplementairesSurNom($ligne[C_NOM_SEL]);
703
		// permet une reconnaissance de bdtfx:nn:XXXX
714
		// permet une reconnaissance de bdtfx:nn:XXXX
704
		$determ = $taxon_info_webservice->rechercherInfosSurTexteCodeOuNumTax(trim($ligne[C_NOM_SEL]));
715
		$determ = $taxon_info_webservice->rechercherInfosSurTexteCodeOuNumTax(trim($ligne[C_NOM_SEL]));
705
 
716
 
706
		// note: rechercherInfosSurTexteCodeOuNumTax peut ne retourner qu'une seule clef "nom_sel"
717
		// note: rechercherInfosSurTexteCodeOuNumTax peut ne retourner qu'une seule clef "nom_sel"
707
		if (! $determ) {
718
		if (! $determ) {
708
			// on supprime les noms retenus et renvoi tel quel
719
			// on supprime les noms retenus et renvoi tel quel
709
			// on réutilise les define pour les noms d'indexes, tant qu'à faire
720
			// on réutilise les define pour les noms d'indexes, tant qu'à faire
710
			// XXX; tout à NULL sauf C_NOM_SEL ci-dessus ?
721
			// XXX; tout à NULL sauf C_NOM_SEL ci-dessus ?
711
			$espece[C_NOM_SEL_NN] = @$ligne[C_NOM_SEL_NN];
722
			$espece[C_NOM_SEL_NN] = @$ligne[C_NOM_SEL_NN];
712
			$espece[C_NOM_RET] = @$ligne[C_NOM_RET];
723
			$espece[C_NOM_RET] = @$ligne[C_NOM_RET];
713
			$espece[C_NOM_RET_NN] = @$ligne[C_NOM_RET_NN];
724
			$espece[C_NOM_RET_NN] = @$ligne[C_NOM_RET_NN];
714
			$espece[C_NT] = @$ligne[C_NT];
725
			$espece[C_NT] = @$ligne[C_NT];
715
			$espece[C_FAMILLE] = @$ligne[C_FAMILLE];
726
			$espece[C_FAMILLE] = @$ligne[C_FAMILLE];
716
 
727
 
717
			return;
728
			return;
718
		}
729
		}
719
 
730
 
720
		// succès de la détection, mais résultat partiel
731
		// succès de la détection, mais résultat partiel
721
		if(!isset($determ->id)) 
732
		if(!isset($determ->id)) 
722
			$determ = $taxon_info_webservice->effectuerRequeteInfosComplementairesSurNumNom($determ->{"nom_retenu.id"});
733
			$determ = $taxon_info_webservice->effectuerRequeteInfosComplementairesSurNumNom($determ->{"nom_retenu.id"});
723
 
734
 
724
		// ne devrait jamais arriver !
735
		// ne devrait jamais arriver !
725
		if(!$determ) die("erreur critique: " . __FILE__ . ':' . __LINE__);
736
		if(!$determ) die("erreur critique: " . __FILE__ . ':' . __LINE__);
726
 
737
 
727
		// un schéma <ref>:(nt|nn):<num> (ie: bdtfx:nt:8503) a été passé
738
		// un schéma <ref>:(nt|nn):<num> (ie: bdtfx:nt:8503) a été passé
728
		// dans ce cas on met à jour le référentiel avec celui passé dans le champ espèce
739
		// dans ce cas on met à jour le référentiel avec celui passé dans le champ espèce
729
		if(isset($determ->ref)) {
740
		if(isset($determ->ref)) {
730
			$referentiel = $determ->ref;
741
			$referentiel = $determ->ref;
731
		}
742
		}
732
 
743
 
733
		// succès de la détection
744
		// succès de la détection
734
		// nom_sel est remplacé, mais seulement si un motif spécial à été utilisé (bdtfx:nn:4567)
745
		// nom_sel est remplacé, mais seulement si un motif spécial à été utilisé (bdtfx:nn:4567)
735
		if($taxon_info_webservice->is_notation_spe) {
746
		if($taxon_info_webservice->is_notation_spe) {
736
			$espece[C_NOM_SEL] = $determ->nom_sci;
747
			$espece[C_NOM_SEL] = $determ->nom_sci;
737
		}
748
		}
738
 
749
 
739
		// écrasement des numéros (nomenclatural, taxonomique) saisis...
750
		// écrasement des numéros (nomenclatural, taxonomique) saisis...
740
		$espece[C_NOM_SEL_NN] = $determ->id;
751
		$espece[C_NOM_SEL_NN] = $determ->id;
741
		$espece[C_NOM_RET] = RechercheInfosTaxonBeta::supprimerBiblio($determ->nom_retenu_complet);
752
		$espece[C_NOM_RET] = RechercheInfosTaxonBeta::supprimerBiblio($determ->nom_retenu_complet);
742
		$espece[C_NOM_RET_NN] = $determ->{"nom_retenu.id"};
753
		$espece[C_NOM_RET_NN] = $determ->{"nom_retenu.id"};
743
		$espece[C_NT] = $determ->num_taxonomique;
754
		$espece[C_NT] = $determ->num_taxonomique;
744
		$espece[C_FAMILLE] = $determ->famille;
755
		$espece[C_FAMILLE] = $determ->famille;
745
		return;
756
		return;
746
		// et des info complémentaires
757
		// et des info complémentaires
747
 
758
 
748
		/*
759
		/*
749
		  // GET /service:eflore:0.1/bdtfx/noms/31468?retour.champs=nom_sci,auteur,id,nom_retenu_complet,nom_retenu.id,num_taxonomique,famille
760
		  // GET /service:eflore:0.1/bdtfx/noms/31468?retour.champs=nom_sci,auteur,id,nom_retenu_complet,nom_retenu.id,num_taxonomique,famille
750
		  /home/raphael/eflore/projets/services/modules/0.1/bdtfx/Noms.php:280
761
		  /home/raphael/eflore/projets/services/modules/0.1/bdtfx/Noms.php:280
751
		  SELECT  *, nom_sci   FROM bdtfx_v1_01  WHERE num_nom = '31468' 
762
		  SELECT  *, nom_sci   FROM bdtfx_v1_01  WHERE num_nom = '31468' 
752
		  SELECT nom_sci, num_nom_retenu, nom_sci_html, auteur, annee, biblio_origine FROM bdtfx_v1_01 WHERE num_nom = 31468
763
		  SELECT nom_sci, num_nom_retenu, nom_sci_html, auteur, annee, biblio_origine FROM bdtfx_v1_01 WHERE num_nom = 31468
753
		  SELECT nom_sci, num_nom_retenu, nom_sci_html, auteur, annee, biblio_origine FROM bdtfx_v1_01 WHERE num_nom = 86535
764
		  SELECT nom_sci, num_nom_retenu, nom_sci_html, auteur, annee, biblio_origine FROM bdtfx_v1_01 WHERE num_nom = 86535
754
		*/
765
		*/
755
 
766
 
756
 
767
 
757
		//var_dump($complement, $espece);die;
768
		//var_dump($complement, $espece);die;
758
	}
769
	}
759
 
770
 
760
	static function detectFromNom($nom) {
771
	static function detectFromNom($nom) {
761
		$r = Cel::db()->requeter(sprintf("SELECT num_nom, num_tax_sup FROM bdtfx_v1_01 WHERE (nom_sci LIKE '%s') ".
772
		$r = Cel::db()->requeter(sprintf("SELECT num_nom, num_tax_sup FROM bdtfx_v1_01 WHERE (nom_sci LIKE '%s') ".
762
									"ORDER BY nom_sci ASC LIMIT 0, 1",
773
									"ORDER BY nom_sci ASC LIMIT 0, 1",
763
									Cel::db()->proteger($nom)));
774
									Cel::db()->proteger($nom)));
764
		if($r) return $r;
775
		if($r) return $r;
765
 
776
 
766
		Cel::db()->requeter(sprintf("SELECT num_nom, num_tax_sup FROM bdtfx_v1_01 WHERE (nom_sci LIKE '%s' OR nom LIKE '%s') ".
777
		Cel::db()->requeter(sprintf("SELECT num_nom, num_tax_sup FROM bdtfx_v1_01 WHERE (nom_sci LIKE '%s' OR nom LIKE '%s') ".
767
							   "ORDER BY nom_sci ASC LIMIT 0, 1",
778
							   "ORDER BY nom_sci ASC LIMIT 0, 1",
768
							   Cel::db()->proteger($nom),
779
							   Cel::db()->proteger($nom),
769
							   Cel::db()->proteger(str_replace(' ', '% ', $nom))));
780
							   Cel::db()->proteger(str_replace(' ', '% ', $nom))));
770
		return $r;
781
		return $r;
771
	}
782
	}
772
 
783
 
773
 
784
 
774
	/*
785
	/*
775
	 * TODO: analyse rigoureuse:
786
	 * TODO: analyse rigoureuse:
776
	 * == Identifiant Commune
787
	 * == Identifiant Commune
777
	 * - INSEE-C:\d{5}
788
	 * - INSEE-C:\d{5}
778
	 * - \d{5}
789
	 * - \d{5}
779
	 * - \d{2}
790
	 * - \d{2}
780
	 * == Commune
791
	 * == Commune
781
	 * - \w+ (\d{2})
792
	 * - \w+ (\d{2})
782
	 * - \w+ (\d{5})
793
	 * - \w+ (\d{5})
783
	 * - \w+
794
	 * - \w+
784
	 *
795
	 *
785
	*/
796
	*/
786
	static function traiterLocalisation($ligne, Array &$localisation) {
797
	static function traiterLocalisation($ligne, Array &$localisation) {
787
		if(empty($ligne[C_ZONE_GEO])) $ligne[C_ZONE_GEO] = NULL;
798
		if(empty($ligne[C_ZONE_GEO])) $ligne[C_ZONE_GEO] = NULL;
788
		if(empty($ligne[C_CE_ZONE_GEO])) $ligne[C_CE_ZONE_GEO] = NULL;
799
		if(empty($ligne[C_CE_ZONE_GEO])) $ligne[C_CE_ZONE_GEO] = NULL;
789
 
800
 
790
	    $identifiant_commune = trim($ligne[C_ZONE_GEO]);
801
	    $identifiant_commune = trim($ligne[C_ZONE_GEO]);
791
		if(!$identifiant_commune) {
802
		if(!$identifiant_commune) {
792
			$departement = trim($ligne[C_CE_ZONE_GEO]);
803
			$departement = trim($ligne[C_CE_ZONE_GEO]);
793
			if(strpos($departement, "INSEE-C:", 0) === 0) {
804
			if(strpos($departement, "INSEE-C:", 0) === 0) {
794
				$localisation[C_CE_ZONE_GEO] = trim($ligne[C_CE_ZONE_GEO]);
805
				$localisation[C_CE_ZONE_GEO] = trim($ligne[C_CE_ZONE_GEO]);
795
				$nom = Cel::db()->requeter(sprintf("SELECT nom FROM cel_zones_geo WHERE code = %s LIMIT 1",
806
				$nom = Cel::db()->requeter(sprintf("SELECT nom FROM cel_zones_geo WHERE code = %s LIMIT 1",
796
																		self::quoteNonNull(substr($localisation[C_CE_ZONE_GEO], strlen("INSEE-C:")))));
807
																		self::quoteNonNull(substr($localisation[C_CE_ZONE_GEO], strlen("INSEE-C:")))));
797
				if($nom) $localisation[C_ZONE_GEO] = $nom[0]['nom'];
808
				if($nom) $localisation[C_ZONE_GEO] = $nom[0]['nom'];
798
				return;
809
				return;
799
			}
810
			}
800
 
-
 
801
 
811
 
802
			if(!is_numeric($departement)) {
812
			if(!is_numeric($departement)) {
803
				$localisation[C_CE_ZONE_GEO] = $ligne[C_CE_ZONE_GEO];
813
				$localisation[C_CE_ZONE_GEO] = $ligne[C_CE_ZONE_GEO];
804
				return;
814
				return;
805
			}
815
			}
-
 
816
 
-
 
817
			if( ($resultat_commune = Cel::db()->requeter(sprintf("SELECT DISTINCT nom, CONCAT('INSEE-C:', code) AS code FROM cel_zones_geo WHERE code = %s LIMIT 1",
-
 
818
																 self::quoteNonNull($departement)))) ) {
-
 
819
				$localisation[C_ZONE_GEO] = $resultat_commune[0]['nom'];
-
 
820
				$localisation[C_CE_ZONE_GEO] = $resultat_commune[0]['code'];
-
 
821
				return;
-
 
822
			}
806
 
823
;
807
			if(strlen($departement) == 4) $departement = "INSEE-C:0" . $departement;
824
			// if(strlen($departement) == 4) $departement = "INSEE-C:0" . $departement;
808
			if(strlen($departement) == 5) $departement = "INSEE-C:" . $departement;
825
			// if(strlen($departement) == 5) $departement = "INSEE-C:" . $departement;
809
			// if(strlen($departement) <= 9) return "INSEE-C:0" . $departement; // ? ... TODO
826
			// if(strlen($departement) <= 9) return "INSEE-C:0" . $departement; // ? ... TODO
810
 
827
 
811
			$departement = trim($departement); // TODO
828
			$departement = trim($departement); // TODO
812
 
829
 
813
			$localisation[C_CE_ZONE_GEO] = $ligne[C_CE_ZONE_GEO];
830
			$localisation[C_CE_ZONE_GEO] = $ligne[C_CE_ZONE_GEO];
814
			return;
831
			return;
815
		}
832
		}
816
 
833
 
817
 
834
 
818
		$select = "SELECT DISTINCT nom, code  FROM cel_zones_geo";
835
		$select = "SELECT DISTINCT nom, code FROM cel_zones_geo";
819
	
836
	
820
		if (preg_match('/(.+) \((\d{1,5})\)/', $identifiant_commune, $elements)) {
837
		if (preg_match('/(.+) \((\d{1,5})\)/', $identifiant_commune, $elements)) {
821
			// commune + departement : montpellier (34)
838
			// commune + departement : montpellier (34)
822
			$nom_commune=$elements[1];
839
			$nom_commune=$elements[1];
823
			$code_commune=$elements[2];
840
			$code_commune=$elements[2];
824
			if(strlen($code_commune) <= 2) {
841
			if(strlen($code_commune) <= 2) {
825
				$requete = sprintf("%s WHERE nom = %s AND code LIKE %s",
842
				$requete = sprintf("%s WHERE nom = %s AND code LIKE %s",
826
								   $select, self::quoteNonNull($nom_commune),
843
								   $select, self::quoteNonNull($nom_commune),
827
								   self::quoteNonNull($code_commune.'%'));
844
								   self::quoteNonNull($code_commune.'%'));
828
			}
845
			}
829
			else {
846
			else {
830
				$requete = sprintf("%s WHERE nom = %s AND code = %d",
847
				$requete = sprintf("%s WHERE nom = %s AND code = %d",
831
								   $select, self::quoteNonNull($nom_commune),
848
								   $select, self::quoteNonNull($nom_commune),
832
								   $code_commune);
849
								   $code_commune);
833
			}
850
			}
834
 
-
 
835
		}
851
		}
836
		elseif (preg_match('/^(\d+|(2[ab]\d+))$/i', $identifiant_commune, $elements)) {
852
		elseif (preg_match('/^(\d+|(2[ab]\d+))$/i', $identifiant_commune, $elements)) {
837
			// Code insee seul  
853
			// Code insee seul  
838
			$code_insee_commune=$elements[1];
854
			$code_insee_commune=$elements[1];
839
	 	    $requete = sprintf("%s WHERE code = %s", $select, self::quoteNonNull($code_insee_commune));
855
	 	    $requete = sprintf("%s WHERE code = %s", $select, self::quoteNonNull($code_insee_commune));
840
		}
856
		}
841
		else {
857
		else {
842
			// Commune seule (le departement sera recupere dans la colonne departement si elle est presente)
858
			// Commune seule (le departement sera recupere dans la colonne departement si elle est presente)
843
			// on prend le risque ici de retourner une mauvaise Commune
859
			// on prend le risque ici de retourner une mauvaise Commune
844
			$nom_commune = str_replace(" ", "%", iconv('UTF-8', 'ASCII//TRANSLIT', $identifiant_commune));
860
			$nom_commune = str_replace(" ", "%", iconv('UTF-8', 'ASCII//TRANSLIT', $identifiant_commune));
845
	 	    $requete = sprintf("%s WHERE nom LIKE %s", $select, self::quoteNonNull($nom_commune.'%'));
861
	 	    $requete = sprintf("%s WHERE nom LIKE %s", $select, self::quoteNonNull($nom_commune.'%'));
846
		}
862
		}
847
	
863
	
848
		$resultat_commune = Cel::db()->requeter($requete);
864
		$resultat_commune = Cel::db()->requeter($requete);
849
		// TODO: levenstein sort ?
865
		// TODO: levenstein sort ?
850
		// TODO: count résultat !
866
		// TODO: count résultat !
851
 
867
 
852
		// cas de la commune introuvable dans le référentiel
868
		// cas de la commune introuvable dans le référentiel
853
		// réinitialisation aux valeurs du fichier XLS
869
		// réinitialisation aux valeurs du fichier XLS
854
		if(! $resultat_commune) {
870
		if(! $resultat_commune) {
855
			$localisation[C_ZONE_GEO] = trim($ligne[C_ZONE_GEO]);
871
			$localisation[C_ZONE_GEO] = trim($ligne[C_ZONE_GEO]);
856
			$localisation[C_CE_ZONE_GEO] = trim($ligne[C_CE_ZONE_GEO]);
872
			$localisation[C_CE_ZONE_GEO] = trim($ligne[C_CE_ZONE_GEO]);
857
		} else {
873
		} else {
858
			$localisation[C_ZONE_GEO] = $resultat_commune[0]['nom'];
874
			$localisation[C_ZONE_GEO] = $resultat_commune[0]['nom'];
859
			$localisation[C_CE_ZONE_GEO] = "INSEE-C:" . $resultat_commune[0]['code'];
875
			$localisation[C_CE_ZONE_GEO] = "INSEE-C:" . $resultat_commune[0]['code'];
860
			return;
876
			return;
861
		}
877
		}
862
 
878
 
863
		$departement = &$localisation[C_CE_ZONE_GEO];
879
		$departement = &$localisation[C_CE_ZONE_GEO];
864
 
880
 
865
		if(strpos($departement, "INSEE-C:", 0) === 0) {
881
		if(strpos($departement, "INSEE-C:", 0) === 0) {
866
			$localisation[C_ZONE_GEO] = $localisation[C_ZONE_GEO];
882
			$localisation[C_ZONE_GEO] = $localisation[C_ZONE_GEO];
867
			$localisation[C_CE_ZONE_GEO] = $localisation[C_CE_ZONE_GEO];
883
			$localisation[C_CE_ZONE_GEO] = $localisation[C_CE_ZONE_GEO];
868
		}
884
		}
869
 
885
 
870
 
886
 
871
		if(!is_numeric($departement)) {
887
		if(!is_numeric($departement)) {
872
			$localisation[C_ZONE_GEO] = $localisation[C_ZONE_GEO];
888
			$localisation[C_ZONE_GEO] = $localisation[C_ZONE_GEO];
873
			$localisation[C_CE_ZONE_GEO] = $localisation[C_CE_ZONE_GEO];
889
			$localisation[C_CE_ZONE_GEO] = $localisation[C_CE_ZONE_GEO];
874
		}
890
		}
875
 
891
 
876
		if(strlen($departement) == 4) $departement = "INSEE-C:0" . $departement;
892
		if(strlen($departement) == 4) $departement = "INSEE-C:0" . $departement;
877
		if(strlen($departement) == 5) $departement = "INSEE-C:" . $departement;
893
		if(strlen($departement) == 5) $departement = "INSEE-C:" . $departement;
878
		// if(strlen($departement) <= 9) return "INSEE-C:0" . $departement; // ? ... TODO
894
		// if(strlen($departement) <= 9) return "INSEE-C:0" . $departement; // ? ... TODO
879
 
895
 
880
		$departement = trim($departement); // TODO
896
		$departement = trim($departement); // TODO
881
 
897
 
882
		$localisation[C_ZONE_GEO] = $localisation[C_ZONE_GEO];
898
		$localisation[C_ZONE_GEO] = $localisation[C_ZONE_GEO];
883
		$localisation[C_CE_ZONE_GEO] = $localisation[C_CE_ZONE_GEO];
899
		$localisation[C_CE_ZONE_GEO] = $localisation[C_CE_ZONE_GEO];
884
	}
900
	}
885
 
901
 
886
	/*
902
	/*
887
	static function traiterLocalisation($ligne, Array &$localisation) {
903
	static function traiterLocalisation($ligne, Array &$localisation) {
888
	    $identifiant_commune = trim($ligne[C_ZONE_GEO]);
904
	    $identifiant_commune = trim($ligne[C_ZONE_GEO]);
889
		if(!$identifiant_commune) {
905
		if(!$identifiant_commune) {
890
			$departement = trim($ligne[C_CE_ZONE_GEO]);
906
			$departement = trim($ligne[C_CE_ZONE_GEO]);
891
			goto testdepartement;
907
			goto testdepartement;
892
		}
908
		}
893
 
909
 
894
 
910
 
895
		$select = "SELECT DISTINCT nom, code  FROM cel_zones_geo";
911
		$select = "SELECT DISTINCT nom, code  FROM cel_zones_geo";
896
	
912
	
897
		if (preg_match('/(.*) \((\d+)\)/', $identifiant_commune, $elements)) {
913
		if (preg_match('/(.*) \((\d+)\)/', $identifiant_commune, $elements)) {
898
			// commune + departement : montpellier (34)
914
			// commune + departement : montpellier (34)
899
			$nom_commune=$elements[1];
915
			$nom_commune=$elements[1];
900
			$code_commune=$elements[2];
916
			$code_commune=$elements[2];
901
	 	    $requete = sprintf("%s WHERE nom = %s AND code LIKE %s",
917
	 	    $requete = sprintf("%s WHERE nom = %s AND code LIKE %s",
902
							   $select, self::quoteNonNull($nom_commune), self::quoteNonNull($code_commune.'%'));
918
							   $select, self::quoteNonNull($nom_commune), self::quoteNonNull($code_commune.'%'));
903
		}
919
		}
904
		elseif (preg_match('/^(\d+|(2[ab]\d+))$/i', $identifiant_commune, $elements)) {
920
		elseif (preg_match('/^(\d+|(2[ab]\d+))$/i', $identifiant_commune, $elements)) {
905
			// Code insee seul  
921
			// Code insee seul  
906
			$code_insee_commune=$elements[1];
922
			$code_insee_commune=$elements[1];
907
	 	    $requete = sprintf("%s WHERE code = %s", $select, self::quoteNonNull($code_insee_commune));
923
	 	    $requete = sprintf("%s WHERE code = %s", $select, self::quoteNonNull($code_insee_commune));
908
		}
924
		}
909
		else {
925
		else {
910
			// Commune seule (le departement sera recupere dans la colonne departement si elle est presente)
926
			// Commune seule (le departement sera recupere dans la colonne departement si elle est presente)
911
			// on prend le risque ici de retourner une mauvaise Commune
927
			// on prend le risque ici de retourner une mauvaise Commune
912
			$nom_commune = str_replace(" ", "%", iconv('UTF-8', 'ASCII//TRANSLIT', $identifiant_commune));
928
			$nom_commune = str_replace(" ", "%", iconv('UTF-8', 'ASCII//TRANSLIT', $identifiant_commune));
913
	 	    $requete = sprintf("%s WHERE nom LIKE %s", $select, self::quoteNonNull($nom_commune.'%'));
929
	 	    $requete = sprintf("%s WHERE nom LIKE %s", $select, self::quoteNonNull($nom_commune.'%'));
914
		}
930
		}
915
	
931
	
916
		$resultat_commune = Cel::db()->requeter($requete);
932
		$resultat_commune = Cel::db()->requeter($requete);
917
		// TODO: levenstein sort ?
933
		// TODO: levenstein sort ?
918
 
934
 
919
		// cas de la commune introuvable dans le référentiel
935
		// cas de la commune introuvable dans le référentiel
920
		// réinitialisation aux valeurs du fichier XLS
936
		// réinitialisation aux valeurs du fichier XLS
921
		if(! $resultat_commune) {
937
		if(! $resultat_commune) {
922
			$localisation[C_ZONE_GEO] = trim($ligne[C_ZONE_GEO]);
938
			$localisation[C_ZONE_GEO] = trim($ligne[C_ZONE_GEO]);
923
			$localisation[C_CE_ZONE_GEO] = trim($ligne[C_CE_ZONE_GEO]);
939
			$localisation[C_CE_ZONE_GEO] = trim($ligne[C_CE_ZONE_GEO]);
924
		} else {
940
		} else {
925
			$localisation[C_ZONE_GEO] = $resultat_commune[0]['nom'];
941
			$localisation[C_ZONE_GEO] = $resultat_commune[0]['nom'];
926
			$localisation[C_CE_ZONE_GEO] = $resultat_commune[0]['code'];
942
			$localisation[C_CE_ZONE_GEO] = $resultat_commune[0]['code'];
927
		}
943
		}
928
 
944
 
929
		$departement = &$localisation[C_CE_ZONE_GEO];
945
		$departement = &$localisation[C_CE_ZONE_GEO];
930
 
946
 
931
	testdepartement:
947
	testdepartement:
932
		if(strpos($departement, "INSEE-C:", 0) === 0) goto protectloc;
948
		if(strpos($departement, "INSEE-C:", 0) === 0) goto protectloc;
933
 
949
 
934
		if(!is_numeric($departement)) goto protectloc; // TODO ?
950
		if(!is_numeric($departement)) goto protectloc; // TODO ?
935
		if(strlen($departement) == 4) $departement = "INSEE-C:0" . $departement;
951
		if(strlen($departement) == 4) $departement = "INSEE-C:0" . $departement;
936
		if(strlen($departement) == 5) $departement = "INSEE-C:" . $departement;
952
		if(strlen($departement) == 5) $departement = "INSEE-C:" . $departement;
937
		// if(strlen($departement) <= 9) return "INSEE-C:0" . $departement; // ? ... TODO
953
		// if(strlen($departement) <= 9) return "INSEE-C:0" . $departement; // ? ... TODO
938
 
954
 
939
		$departement = trim($departement); // TODO
955
		$departement = trim($departement); // TODO
940
 
956
 
941
	protectloc:
957
	protectloc:
942
		$localisation[C_ZONE_GEO] = $localisation[C_ZONE_GEO];
958
		$localisation[C_ZONE_GEO] = $localisation[C_ZONE_GEO];
943
		$localisation[C_CE_ZONE_GEO] = $localisation[C_CE_ZONE_GEO];
959
		$localisation[C_CE_ZONE_GEO] = $localisation[C_CE_ZONE_GEO];
944
	}
960
	}
945
*/
961
*/
946
 
962
 
947
 
963
 
948
	/* HELPERS */
964
	/* HELPERS */
949
 
965
 
950
	// http://stackoverflow.com/questions/348410/sort-an-array-based-on-another-array
966
	// http://stackoverflow.com/questions/348410/sort-an-array-based-on-another-array
951
	// XXX; utilisé aussi (temporairement ?) par FormateurGroupeColonne.
967
	// XXX; utilisé aussi (temporairement ?) par FormateurGroupeColonne.
952
	static function sortArrayByArray($array, $orderArray) {
968
	static function sortArrayByArray($array, $orderArray) {
953
		$ordered = array();
969
		$ordered = array();
954
		foreach($orderArray as $key) {
970
		foreach($orderArray as $key) {
955
			if(array_key_exists($key, $array)) {
971
			if(array_key_exists($key, $array)) {
956
				$ordered[$key] = $array[$key];
972
				$ordered[$key] = $array[$key];
957
				unset($array[$key]);
973
				unset($array[$key]);
958
			}
974
			}
959
		}
975
		}
960
		return $ordered + $array;
976
		return $ordered + $array;
961
	}
977
	}
962
 
978
 
963
	// retourne une BBox [N,S,E,O) pour un référentiel donné
979
	// retourne une BBox [N,S,E,O) pour un référentiel donné
964
	static function getReferentielBBox($referentiel) {
980
	static function getReferentielBBox($referentiel) {
965
		if($referentiel == 'bdtfx') return Array(
981
		if($referentiel == 'bdtfx') return Array(
966
			'NORD' => 51.2, // Dunkerque
982
			'NORD' => 51.2, // Dunkerque
967
			'SUD' => 41.3, // Bonifacio
983
			'SUD' => 41.3, // Bonifacio
968
			'EST' => 9.7, // Corse
984
			'EST' => 9.7, // Corse
969
			'OUEST' => -5.2); // Ouessan
985
			'OUEST' => -5.2); // Ouessan
970
		return FALSE;
986
		return FALSE;
971
	}
987
	}
972
 
988
 
973
	// ces valeurs ne sont pas inséré via les placeholders du PDO::preparedStatement
989
	// ces valeurs ne sont pas inséré via les placeholders du PDO::preparedStatement
974
	// et doivent donc être échappées correctement.
990
	// et doivent donc être échappées correctement.
975
	public function initialiser_colonnes_statiques() {
991
	public function initialiser_colonnes_statiques() {
976
		$this->colonnes_statiques = array_merge($this->colonnes_statiques,
992
		$this->colonnes_statiques = array_merge($this->colonnes_statiques,
977
												Array(
993
												Array(
978
													"ce_utilisateur" => self::quoteNonNull($this->id_utilisateur), // peut-être un hash ou un id
994
													"ce_utilisateur" => self::quoteNonNull($this->id_utilisateur), // peut-être un hash ou un id
979
													"prenom_utilisateur" => self::quoteNonNull($this->utilisateur['prenom']),
995
													"prenom_utilisateur" => self::quoteNonNull($this->utilisateur['prenom']),
980
													"nom_utilisateur" => self::quoteNonNull($this->utilisateur['nom']),
996
													"nom_utilisateur" => self::quoteNonNull($this->utilisateur['nom']),
981
													"courriel_utilisateur" => self::quoteNonNull($this->utilisateur['courriel']),
997
													"courriel_utilisateur" => self::quoteNonNull($this->utilisateur['courriel']),
982
												));
998
												));
983
 
999
 
984
	}
1000
	}
985
 
1001
 
986
	static function initialiser_pdo_ordered_statements($colonnes_statiques) {
1002
	static function initialiser_pdo_ordered_statements($colonnes_statiques) {
987
		return Array(
1003
		return Array(
988
			// insert_ligne_pattern_ordre
1004
			// insert_ligne_pattern_ordre
989
			sprintf('INSERT INTO cel_obs (%s, %s) VALUES',
1005
			sprintf('INSERT INTO cel_obs (%s, %s) VALUES',
990
					implode(', ', array_keys($colonnes_statiques)),
1006
					implode(', ', array_keys($colonnes_statiques)),
991
					implode(', ', array_diff(self::$ordre_BDD, array_keys($colonnes_statiques)))),
1007
					implode(', ', array_diff(self::$ordre_BDD, array_keys($colonnes_statiques)))),
992
 
1008
 
993
			// insert_ligne_pattern_ordre
1009
			// insert_ligne_pattern_ordre
994
			sprintf('(%s, %s ?)',
1010
			sprintf('(%s, %s ?)',
995
					implode(', ', $colonnes_statiques),
1011
					implode(', ', $colonnes_statiques),
996
					str_repeat('?, ', count(self::$ordre_BDD) - count($colonnes_statiques) - 1))
1012
					str_repeat('?, ', count(self::$ordre_BDD) - count($colonnes_statiques) - 1))
997
		);
1013
		);
998
	}
1014
	}
999
 
1015
 
1000
	static function initialiser_pdo_statements($colonnes_statiques) {
1016
	static function initialiser_pdo_statements($colonnes_statiques) {
1001
		return Array( 
1017
		return Array( 
1002
			// insert_prefix
1018
			// insert_prefix
1003
			sprintf('INSERT INTO cel_obs (%s) VALUES ',
1019
			sprintf('INSERT INTO cel_obs (%s) VALUES ',
1004
					implode(', ', self::$ordre_BDD)),
1020
					implode(', ', self::$ordre_BDD)),
1005
 
1021
 
1006
 
1022
 
1007
			// insert_ligne_pattern, cf: self::$insert_ligne_pattern
1023
			// insert_ligne_pattern, cf: self::$insert_ligne_pattern
1008
			'(' .
1024
			'(' .
1009
			// 3) créé une chaîne de liste de champ à inséré en DB
1025
			// 3) créé une chaîne de liste de champ à inséré en DB
1010
			implode(', ', array_values(
1026
			implode(', ', array_values(
1011
				// 2) garde les valeurs fixes (de $colonnes_statiques),
1027
				// 2) garde les valeurs fixes (de $colonnes_statiques),
1012
				// mais remplace les NULL par des "?"
1028
				// mais remplace les NULL par des "?"
1013
				array_map('__anonyme_5',
1029
				array_map('__anonyme_5',
1014
						  // 1) créé un tableau genre (nom_sel_nn => NULL) depuis self::$ordre_BDD
1030
						  // 1) créé un tableau genre (nom_sel_nn => NULL) depuis self::$ordre_BDD
1015
						  // et écrase certaines valeurs avec $colonnes_statiques (initilisé avec les données utilisateur)
1031
						  // et écrase certaines valeurs avec $colonnes_statiques (initilisé avec les données utilisateur)
1016
						  array_merge(array_map('__anonyme_6', array_flip(self::$ordre_BDD)), $colonnes_statiques
1032
						  array_merge(array_map('__anonyme_6', array_flip(self::$ordre_BDD)), $colonnes_statiques
1017
				)))) .
1033
				)))) .
1018
			')'
1034
			')'
1019
		);
1035
		);
1020
	}
1036
	}
1021
 
1037
 
1022
	// équivalent à Bdd2->proteger() (qui wrap PDO::quote),
1038
	// équivalent à Bdd2->proteger() (qui wrap PDO::quote),
1023
	// sans transformer NULL en ""
1039
	// sans transformer NULL en ""
1024
	static function quoteNonNull($chaine) {
1040
	static function quoteNonNull($chaine) {
1025
		if(is_null($chaine)) return "NULL";
1041
		if(is_null($chaine)) return "NULL";
1026
		if(!is_string($chaine) && !is_integer($chaine)) {
1042
		if(!is_string($chaine) && !is_integer($chaine)) {
1027
			die("erreur: " . __FILE__ . ':' . __LINE__);
1043
			die("erreur: " . __FILE__ . ':' . __LINE__);
1028
		}
1044
		}
1029
		return Cel::db()->quote($chaine);
1045
		return Cel::db()->quote($chaine);
1030
	}
1046
	}
1031
 
1047
 
1032
	public function erreurs_stock($errno, $errstr) {
1048
	public function erreurs_stock($errno, $errstr) {
1033
		$this->bilan[] = $errstr;
1049
		$this->bilan[] = $errstr;
1034
	}
1050
	}
1035
}
1051
}