Subversion Repositories eFlore/Applications.cel

Rev

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

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