Subversion Repositories eFlore/Applications.cel

Rev

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

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