Subversion Repositories eFlore/Applications.cel

Rev

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

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