Subversion Repositories eFlore/Applications.cel

Rev

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

Rev 1677 Rev 1678
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, $obj) { $item = $obj->quoteNonNull(trim($item)); }
75
	static function __anonyme_4(&$item, $key, $obj) { $item = $obj->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
		"abondance",
104
		"abondance",
105
		"certitude",
105
		"certitude",
106
		"phenologie",
106
		"phenologie",
107
		"code_insee_calcule"
107
		"code_insee_calcule"
108
	);
108
	);
109
 
109
 
110
	// cf: initialiser_pdo_ordered_statements()
110
	// cf: initialiser_pdo_ordered_statements()
111
	// eg: "INSERT INTO cel_obs (ce_utilisateur, ..., phenologie, code_insee_calcule) VALUES"
111
	// eg: "INSERT INTO cel_obs (ce_utilisateur, ..., phenologie, code_insee_calcule) VALUES"
112
	// colonnes statiques d'abord, les autres ensuite, dans l'ordre de $ordre_BDD
112
	// colonnes statiques d'abord, les autres ensuite, dans l'ordre de $ordre_BDD
113
	static $insert_prefix_ordre;
113
	static $insert_prefix_ordre;
114
	// eg: "(<id>, <prenom>, <nom>, <email>, now(), now(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
114
	// eg: "(<id>, <prenom>, <nom>, <email>, now(), now(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
115
	// dont le nombre de placeholder dépend du nombre de colonnes non-statiques
115
	// dont le nombre de placeholder dépend du nombre de colonnes non-statiques
116
	// colonnes statiques d'abord, les autres ensuite, dans l'ordre de $ordre_BDD
116
	// colonnes statiques d'abord, les autres ensuite, dans l'ordre de $ordre_BDD
117
	static $insert_ligne_pattern_ordre;
117
	static $insert_ligne_pattern_ordre;
118
 
118
 
119
	// seconde (meilleure) possibilité
119
	// seconde (meilleure) possibilité
120
	// cf: initialiser_pdo_statements()
120
	// cf: initialiser_pdo_statements()
121
	// eg: "INSERT INTO cel_obs (ce_utilisateur, ..., date_creation, ...phenologie, code_insee_calcule) VALUES"
121
	// eg: "INSERT INTO cel_obs (ce_utilisateur, ..., date_creation, ...phenologie, code_insee_calcule) VALUES"
122
	static $insert_prefix;
122
	static $insert_prefix;
123
	// eg: "(<id>, <prenom>, <nom>, <email>, ?, ?, ?, now(), now(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
123
	// eg: "(<id>, <prenom>, <nom>, <email>, ?, ?, ?, now(), now(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
124
	// dont le nombre de placeholder dépend du nombre de colonnes non-statiques
124
	// dont le nombre de placeholder dépend du nombre de colonnes non-statiques
125
	static $insert_ligne_pattern;
125
	static $insert_ligne_pattern;
126
 
126
 
127
	/*
127
	/*
128
	  Ces colonnes:
128
	  Ces colonnes:
129
	  - sont propres à l'ensemble des enregistrements uploadés
129
	  - sont propres à l'ensemble des enregistrements uploadés
130
	  - sont indépendantes du numéro de lignes
130
	  - sont indépendantes du numéro de lignes
131
	  - n'ont pas de valeur par défaut dans la structure de la table
131
	  - n'ont pas de valeur par défaut dans la structure de la table
132
	  - nécessitent une initialisation dans le cadre de l'upload
132
	  - nécessitent une initialisation dans le cadre de l'upload
133
 
133
 
134
	  initialiser_colonnes_statiques() y merge les données d'identification utilisateur
134
	  initialiser_colonnes_statiques() y merge les données d'identification utilisateur
135
	*/
135
	*/
136
	public $colonnes_statiques = Array(
136
	public $colonnes_statiques = Array(
137
		"ce_utilisateur" => NULL,
137
		"ce_utilisateur" => NULL,
138
		"prenom_utilisateur" => NULL,
138
		"prenom_utilisateur" => NULL,
139
		"nom_utilisateur" => NULL,
139
		"nom_utilisateur" => NULL,
140
		"courriel_utilisateur" => NULL,
140
		"courriel_utilisateur" => NULL,
141
 
141
 
142
		// fixes (fonction SQL)
142
		// fixes (fonction SQL)
143
		// XXX future: mais pourraient varier dans le futur si la mise-à-jour
143
		// XXX future: mais pourraient varier dans le futur si la mise-à-jour
144
		// d'observation est implémentée
144
		// d'observation est implémentée
145
		"date_creation" => "now()",
145
		"date_creation" => "now()",
146
		"date_modification" => "now()",
146
		"date_modification" => "now()",
147
	);
147
	);
148
 
148
 
149
	public $id_utilisateur = NULL;
149
	public $id_utilisateur = NULL;
150
 
150
 
151
	// erreurs d'import
151
	// erreurs d'import
152
	public $bilan = Array();
152
	public $bilan = Array();
153
 
153
 
154
 
154
 
155
	function ExportXLS($config) {
155
	function ExportXLS($config) {
156
		parent::__construct($config);
156
		parent::__construct($config);
157
	}
157
	}
158
 
158
 
159
	function createElement($pairs) {
159
	function createElement($pairs) {
160
		if(!isset($pairs['utilisateur']) || trim($pairs['utilisateur']) == '') {
160
		if(!isset($pairs['utilisateur']) || trim($pairs['utilisateur']) == '') {
161
			echo '0'; exit;
161
			echo '0'; exit;
162
		}
162
		}
163
 
163
 
164
		$id_utilisateur = intval($pairs['utilisateur']);
164
		$id_utilisateur = intval($pairs['utilisateur']);
165
		$this->id_utilisateur = $id_utilisateur; // pour traiterImage();
165
		$this->id_utilisateur = $id_utilisateur; // pour traiterImage();
166
 
166
 
167
		if(!isset($_SESSION)) session_start();
167
		if(!isset($_SESSION)) session_start();
168
        $this->controleUtilisateur($id_utilisateur);
168
        $this->controleUtilisateur($id_utilisateur);
169
 
169
 
170
        $this->utilisateur = $this->getInfosComplementairesUtilisateur($id_utilisateur);
170
        $this->utilisateur = $this->getInfosComplementairesUtilisateur($id_utilisateur);
171
 
171
 
172
		$this->initialiser_colonnes_statiques($id_utilisateur);
172
		$this->initialiser_colonnes_statiques($id_utilisateur);
173
 
173
 
174
		// initialisation du statement PDO/MySQL
174
		// initialisation du statement PDO/MySQL
175
		// première version, pattern de requête pas génial
175
		// première version, pattern de requête pas génial
176
		/* list(self;;$insert_prefix_ordre, self::$insert_ligne_pattern_ordre) =
176
		/* list(self;;$insert_prefix_ordre, self::$insert_ligne_pattern_ordre) =
177
		   $this->initialiser_pdo_ordered_statements($this->colonnes_statiques); */
177
		   $this->initialiser_pdo_ordered_statements($this->colonnes_statiques); */
178
		list(self::$insert_prefix, self::$insert_ligne_pattern) =
178
		list(self::$insert_prefix, self::$insert_ligne_pattern) =
179
			$this->initialiser_pdo_statements($this->colonnes_statiques);
179
			$this->initialiser_pdo_statements($this->colonnes_statiques);
180
 
180
 
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))) {
198
			(rename($fichier, $fichier . '.' . $extension))) {
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
		if(is_a($objReader, 'PHPExcel_Reader_CSV')) {
205
		if(is_a($objReader, 'PHPExcel_Reader_CSV')) {
206
			$objReader->setDelimiter(',')
206
			$objReader->setDelimiter(',')
207
				->setEnclosure('"')
207
				->setEnclosure('"')
208
				->setLineEnding("\n")
208
				->setLineEnding("\n")
209
				->setSheetIndex(0);
209
				->setSheetIndex(0);
210
		}
210
		}
211
 
211
 
212
		// on ne conserve que l'en-tête
212
		// on ne conserve que l'en-tête
213
		$filtre = new MyReadFilter();
213
		$filtre = new MyReadFilter();
214
		$filtre->def_interval(1, 2);
214
		$filtre->def_interval(1, 2);
215
		$objReader->setReadFilter($filtre);
215
		$objReader->setReadFilter($filtre);
216
 
216
 
217
		$objPHPExcel = $objReader->load($fichier);
217
		$objPHPExcel = $objReader->load($fichier);
218
		$obj_infos = $objReader->listWorksheetInfo($fichier);
218
		$obj_infos = $objReader->listWorksheetInfo($fichier);
219
		// XXX: indépendant du readFilter ?
219
		// XXX: indépendant du readFilter ?
220
		$nb_lignes = $obj_infos[0]['totalRows'];
220
		$nb_lignes = $obj_infos[0]['totalRows'];
221
 
221
 
222
		$donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, FALSE, TRUE);
222
		$donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, FALSE, TRUE);
223
		$filtre->exclues = self::detectionEntete($donnees[1]);
223
		$filtre->exclues = self::detectionEntete($donnees[1]);
224
 
224
 
225
		$obs_ajouts = 0;
225
		$obs_ajouts = 0;
226
		$obs_maj = 0;
226
		$obs_maj = 0;
227
		$nb_images_ajoutees = 0;
227
		$nb_images_ajoutees = 0;
228
		$nb_mots_cle_ajoutes = 0;
228
		$nb_mots_cle_ajoutes = 0;
229
 
229
 
230
		$dernier_ordre = $this->requeter("SELECT MAX(ordre) AS ordre FROM cel_obs WHERE ce_utilisateur = $id_utilisateur");
230
		$dernier_ordre = $this->requeter("SELECT MAX(ordre) AS ordre FROM cel_obs WHERE ce_utilisateur = $id_utilisateur");
231
		$dernier_ordre = intval($dernier_ordre[0]['ordre']) + 1;
231
		$dernier_ordre = intval($dernier_ordre[0]['ordre']) + 1;
232
		if(! $dernier_ordre) $dernier_ordre = 0;
232
		if(! $dernier_ordre) $dernier_ordre = 0;
233
 
233
 
234
		// on catch to les trigger_error(E_USER_NOTICE);
234
		// on catch to les trigger_error(E_USER_NOTICE);
235
		set_error_handler(array($this, 'erreurs_stock'), E_USER_NOTICE);
235
		set_error_handler(array($this, 'erreurs_stock'), E_USER_NOTICE);
236
 
236
 
237
		// lecture par morceaux (chunks), NB_LIRE_LIGNE_SIMUL lignes à fois
237
		// lecture par morceaux (chunks), NB_LIRE_LIGNE_SIMUL lignes à fois
238
		// pour aboutir des requêtes SQL d'insert groupés.
238
		// pour aboutir des requêtes SQL d'insert groupés.
239
		for($ligne = 2; $ligne < $nb_lignes + NB_LIRE_LIGNE_SIMUL; $ligne += NB_LIRE_LIGNE_SIMUL) {
239
		for($ligne = 2; $ligne < $nb_lignes + NB_LIRE_LIGNE_SIMUL; $ligne += NB_LIRE_LIGNE_SIMUL) {
240
			$filtre->def_interval($ligne, NB_LIRE_LIGNE_SIMUL);
240
			$filtre->def_interval($ligne, NB_LIRE_LIGNE_SIMUL);
241
			$objReader->setReadFilter($filtre);
241
			$objReader->setReadFilter($filtre);
242
 
242
 
243
			/* recharge avec $filtre actif (filtre sur lignes colonnes):
243
			/* recharge avec $filtre actif (filtre sur lignes colonnes):
244
			   - exclue les colonnes inutiles/inutilisables)
244
			   - exclue les colonnes inutiles/inutilisables)
245
			   - ne selectionne que les lignes dans le range [$ligne - $ligne + NB_LIRE_LIGNE_SIMUL] */
245
			   - ne selectionne que les lignes dans le range [$ligne - $ligne + NB_LIRE_LIGNE_SIMUL] */
246
			$objPHPExcel = $objReader->load($fichier);
246
			$objPHPExcel = $objReader->load($fichier);
247
			$donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, FALSE, TRUE);
247
			$donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, FALSE, TRUE);
248
 
248
 
249
			// ici on appel la fonction qui fera effectivement l'insertion multiple
249
			// ici on appel la fonction qui fera effectivement l'insertion multiple
250
			// à partir des (au plus) NB_LIRE_LIGNE_SIMUL lignes
250
			// à partir des (au plus) NB_LIRE_LIGNE_SIMUL lignes
251
 
251
 
252
			// TODO: passer $this, ne sert que pour appeler des méthodes publiques qui pourraient être statiques
252
			// TODO: passer $this, ne sert que pour appeler des méthodes publiques qui pourraient être statiques
253
			// notamment dans RechercheInfosTaxonBeta.php
253
			// notamment dans RechercheInfosTaxonBeta.php
254
			list($enregistrements, $images, $mots_cle) =
254
			list($enregistrements, $images, $mots_cle) =
255
				self::chargerLignes($this, $donnees, $this->colonnes_statiques, $dernier_ordre);
255
				self::chargerLignes($this, $donnees, $this->colonnes_statiques, $dernier_ordre);
256
			if(! $enregistrements) break;
256
			if(! $enregistrements) break;
257
 
257
 
258
			self::trierColonnes($enregistrements);
258
			self::trierColonnes($enregistrements);
259
			// normalement: NB_LIRE_LIGNE_SIMUL, sauf si une enregistrement ne semble pas valide
259
			// normalement: NB_LIRE_LIGNE_SIMUL, sauf si une enregistrement ne semble pas valide
260
			// ou bien lors du dernier chunk
260
			// ou bien lors du dernier chunk
261
 
261
 
262
			$nb_rec = count($enregistrements);
262
			$nb_rec = count($enregistrements);
263
			$sql_pattern = self::$insert_prefix .
263
			$sql_pattern = self::$insert_prefix .
264
				str_repeat(self::$insert_ligne_pattern_ordre . ', ', $nb_rec - 1) .
264
				str_repeat(self::$insert_ligne_pattern_ordre . ', ', $nb_rec - 1) .
265
				self::$insert_ligne_pattern_ordre;
265
				self::$insert_ligne_pattern_ordre;
266
 
266
 
267
			$sql_pattern = self::$insert_prefix .
267
			$sql_pattern = self::$insert_prefix .
268
				str_repeat(self::$insert_ligne_pattern . ', ', $nb_rec - 1) .
268
				str_repeat(self::$insert_ligne_pattern . ', ', $nb_rec - 1) .
269
				self::$insert_ligne_pattern;
269
				self::$insert_ligne_pattern;
270
 
270
 
271
			$this->bdd->beginTransaction();
271
			$this->bdd->beginTransaction();
272
			$stmt = $this->bdd->prepare($sql_pattern);
272
			$stmt = $this->bdd->prepare($sql_pattern);
273
			$donnees = array();
273
			$donnees = array();
274
			foreach($enregistrements as $e) $donnees = array_merge($donnees, array_values($e));
274
			foreach($enregistrements as $e) $donnees = array_merge($donnees, array_values($e));
275
 
275
 
276
			/* debug ici: */ echo $sql_pattern . "\n"; var_dump($enregistrements, $donnees); die;
276
			/* debug ici: echo $sql_pattern . "\n"; var_dump($enregistrements, $donnees); die;*/
277
 
277
 
278
			$stmt->execute($donnees);
278
			$stmt->execute($donnees);
279
 
279
 
280
			// $stmt->debugDumpParams(); // https://bugs.php.net/bug.php?id=52384
280
			// $stmt->debugDumpParams(); // https://bugs.php.net/bug.php?id=52384
281
			$dernier_autoinc = $this->bdd->lastInsertId();
281
			$dernier_autoinc = $this->bdd->lastInsertId();
282
			$this->bdd->commit();
282
			$this->bdd->commit();
283
 
283
 
284
			if(! $dernier_autoinc) trigger_error("l'insertion semble avoir échoué", E_USER_NOTICE);
284
			if(! $dernier_autoinc) trigger_error("l'insertion semble avoir échoué", E_USER_NOTICE);
285
 
285
 
286
			$obs_ajouts += count($enregistrements);
286
			$obs_ajouts += count($enregistrements);
287
			// $obs_ajouts += count($enregistrements['insert']);
287
			// $obs_ajouts += count($enregistrements['insert']);
288
			// $obs_maj += count($enregistrements['update']);
288
			// $obs_maj += count($enregistrements['update']);
289
			$nb_images_ajoutees += self::stockerImages($this, $enregistrements, $images, $dernier_autoinc);
289
			$nb_images_ajoutees += self::stockerImages($this, $enregistrements, $images, $dernier_autoinc);
290
			$nb_mots_cle_ajoutes += self::stockerMotsCle($this, $enregistrements, $mots_cle, $dernier_autoinc);
290
			$nb_mots_cle_ajoutes += self::stockerMotsCle($this, $enregistrements, $mots_cle, $dernier_autoinc);
291
		}
291
		}
292
 
292
 
293
		restore_error_handler();
293
		restore_error_handler();
294
 
294
 
295
		if($this->bilan) echo implode("\n", $this->bilan) . "\n";
295
		if($this->bilan) echo implode("\n", $this->bilan) . "\n";
296
 		$summary = sprintf("%d observation(s) ajoutée(s)\n%d image(s) attachée(s)",
296
 		$summary = sprintf("%d observation(s) ajoutée(s)\n%d image(s) attachée(s)\n%d mot(s)-clé ajouté(s) [TODO]\n",
297
						   $obs_ajouts,
297
						   $obs_ajouts,
298
						   $nb_images_ajoutees);
298
						   $nb_images_ajoutees,
-
 
299
						   $nb_mots_cle_ajoutes);
299
 
300
 
300
		die("$summary");
301
		die("$summary");
301
	}
302
	}
302
 
303
 
303
	static function detectionEntete($entete) {
304
	static function detectionEntete($entete) {
304
		$colonnes_reconnues = Array();
305
		$colonnes_reconnues = Array();
305
		$cols = FormateurGroupeColonne::nomEnsembleVersListeColonnes('standard'); // ,avance
306
		$cols = FormateurGroupeColonne::nomEnsembleVersListeColonnes('standard,avance');
306
		foreach($entete as $k => $v) {
307
		foreach($entete as $k => $v) {
307
			$entete_simple = iconv('UTF-8', 'ASCII//TRANSLIT', strtolower(trim($v)));
308
			$entete_simple = iconv('UTF-8', 'ASCII//TRANSLIT', strtolower(trim($v)));
308
			foreach($cols as $col) {
309
			foreach($cols as $col) {
309
				$entete_officiel_simple = iconv('UTF-8', 'ASCII//TRANSLIT', strtolower(trim($col['nom'])));
310
				$entete_officiel_simple = iconv('UTF-8', 'ASCII//TRANSLIT', strtolower(trim($col['nom'])));
310
				$entete_officiel_abbrev = $col['abbrev'];
311
				$entete_officiel_abbrev = $col['abbrev'];
311
				if($entete_simple == $entete_officiel_simple || $entete_simple == $entete_officiel_abbrev) {
312
				if($entete_simple == $entete_officiel_simple || $entete_simple == $entete_officiel_abbrev) {
312
					// debug echo "define C_" . strtoupper($entete_officiel_abbrev) . ", $k ($v)\n";
313
					// debug echo "define C_" . strtoupper($entete_officiel_abbrev) . ", $k ($v)\n";
313
					define("C_" . strtoupper($entete_officiel_abbrev), $k);
314
					define("C_" . strtoupper($entete_officiel_abbrev), $k);
314
					$colonnes_reconnues[$k] = 1;
315
					$colonnes_reconnues[$k] = 1;
315
					break;
316
					break;
316
				}
317
				}
317
			}
318
			}
318
		}
319
		}
319
 
320
 
320
		// prépare le filtre de PHPExcel qui évitera le traitement de toutes les colonnes superflues
321
		// prépare le filtre de PHPExcel qui évitera le traitement de toutes les colonnes superflues
321
 
322
 
322
		// eg: diff ( Array( H => Commune, I => rien ) , Array( H => 1, K => 1 )
323
		// eg: diff ( Array( H => Commune, I => rien ) , Array( H => 1, K => 1 )
323
		// ==> Array( I => rien )
324
		// ==> Array( I => rien )
324
		$colonnesID_non_reconnues = array_diff_key($entete, $colonnes_reconnues);
325
		$colonnesID_non_reconnues = array_diff_key($entete, $colonnes_reconnues);
325
 
326
 
326
		// des colonnes de FormateurGroupeColonne::nomEnsembleVersListeColonnes()
327
		// des colonnes de FormateurGroupeColonne::nomEnsembleVersListeColonnes()
327
		// ne retient que celles marquées "importables"
328
		// ne retient que celles marquées "importables"
328
		$colonnes_automatiques = array_filter($cols, '__anonyme_1');
329
		$colonnes_automatiques = array_filter($cols, '__anonyme_1');
329
 
330
 
330
		// ne conserve que le nom long pour matcher avec la ligne XLS d'entête
331
		// ne conserve que le nom long pour matcher avec la ligne XLS d'entête
331
		array_walk($colonnes_automatiques, '__anonyme_2');
332
		array_walk($colonnes_automatiques, '__anonyme_2');
332
 
333
 
333
		// intersect ( Array ( N => Milieu, S => Ordre ), Array ( ordre => Ordre, phenologie => Phénologie ) )
334
		// intersect ( Array ( N => Milieu, S => Ordre ), Array ( ordre => Ordre, phenologie => Phénologie ) )
334
		// ==> Array ( S => Ordre, AA => Phénologie )
335
		// ==> Array ( S => Ordre, AA => Phénologie )
335
		$colonnesID_a_exclure = array_intersect($entete, $colonnes_automatiques);
336
		$colonnesID_a_exclure = array_intersect($entete, $colonnes_automatiques);
336
 
337
 
337
		// TODO: pourquoi ne pas comparer avec les abbrevs aussi ?
338
		// TODO: pourquoi ne pas comparer avec les abbrevs aussi ?
338
		// merge ( Array( I => rien ) , Array ( S => Ordre, AA => Phénologie ) )
339
		// merge ( Array( I => rien ) , Array ( S => Ordre, AA => Phénologie ) )
339
		// ==> Array ( I => rien, AA => Phénologie )
340
		// ==> Array ( I => rien, AA => Phénologie )
340
		return array_merge($colonnesID_non_reconnues, $colonnesID_a_exclure);
341
		return array_merge($colonnesID_non_reconnues, $colonnesID_a_exclure);
341
	}
342
	}
342
 
343
 
343
	/*
344
	/*
344
	 * charge un groupe de lignes
345
	 * charge un groupe de lignes
345
	 */
346
	 */
346
	static function chargerLignes($cel, $lignes, $colonnes_statiques, &$dernier_ordre) {
347
	static function chargerLignes($cel, $lignes, $colonnes_statiques, &$dernier_ordre) {
347
		$enregistrement = NULL;
348
		$enregistrement = NULL;
348
		$enregistrements = Array();
349
		$enregistrements = Array();
349
		$toutes_images = Array();
350
		$toutes_images = Array();
-
 
351
		$tous_mots_cle = Array();
350
 
352
 
351
		foreach($lignes as $ligne) {
353
		foreach($lignes as $ligne) {
352
			//$ligne = array_filter($ligne, function($cell) { return !is_null($cell); });
354
			//$ligne = array_filter($ligne, function($cell) { return !is_null($cell); });
353
			//if(!$ligne) continue;
355
			//if(!$ligne) continue;
354
			// on a besoin des NULL pour éviter des notice d'index indéfini
356
			// on a besoin des NULL pour éviter des notice d'index indéfini
355
			if(! array_filter($ligne, '__anonyme_3')) continue;
357
			if(! array_filter($ligne, '__anonyme_3')) continue;
356
 
358
 
357
			if( ($enregistrement = self::chargerLigne($ligne, $dernier_ordre, $cel)) ) {
359
			if( ($enregistrement = self::chargerLigne($ligne, $dernier_ordre, $cel)) ) {
358
				// $enregistrements[] = array_merge($colonnes_statiques, $enregistrement);
360
				// $enregistrements[] = array_merge($colonnes_statiques, $enregistrement);
359
				$enregistrements[] = $enregistrement;
361
				$enregistrements[] = $enregistrement;
360
				$pos = count($enregistrements) - 1;
362
				$pos = count($enregistrements) - 1;
361
				$last = &$enregistrements[$pos];
363
				$last = &$enregistrements[$pos];
362
 
364
 
363
				if(isset($enregistrement['_images'])) {
365
				if(isset($enregistrement['_images'])) {
364
					// ne dépend pas de cel_obs, et seront insérées *après* les enregistrements
366
					// ne dépend pas de cel_obs, et seront insérées *après* les enregistrements
365
					// mais nous ne voulons pas nous priver de faire des INSERT multiples pour autant
367
					// mais nous ne voulons pas nous priver de faire des INSERT multiples pour autant
366
					$toutes_images[] = Array("images" => $last['_images'],
368
					$toutes_images[] = Array("images" => $last['_images'],
367
											 "obs_pos" => $pos);
369
											 "obs_pos" => $pos);
368
					// ce champ n'a pas à faire partie de l'insertion dans cel_obs,
370
					// ce champ n'a pas à faire partie de l'insertion dans cel_obs,
369
					// mais est utile pour cel_obs_images
371
					// mais est utile pour cel_obs_images
370
					unset($last['_images']);
372
					unset($last['_images']);
371
				}
373
				}
372
 
374
 
373
				if(isset($enregistrement['_mots_cle'])) {
375
				if(isset($enregistrement['_mots_cle'])) {
374
					// ne dépend pas de cel_obs, et seront insérés *après* les enregistrements
376
					// ne dépend pas de cel_obs, et seront insérés *après* les enregistrements
375
					// mais nous ne voulons pas nous priver de faire des INSERT multiples pour autant
377
					// mais nous ne voulons pas nous priver de faire des INSERT multiples pour autant
376
					$tous_mots_cle[] = Array("mots_cle" => $last['_mots_cle'],
378
					$tous_mots_cle[] = Array("mots_cle" => $last['_mots_cle'],
377
											 "obs_pos" => $pos);
379
											 "obs_pos" => $pos);
378
					// la version inlinée des mots est enregistrées dans cel_obs
380
					// la version inlinée des mots est enregistrées dans cel_obs
379
					// mais cel_mots_cles_obs fait foi.
381
					// mais cel_mots_cles_obs fait foi.
380
					// XXX: postponer l'ajout de ces informations dans cel_obs *après* l'insertion effective
382
					// XXX: postponer l'ajout de ces informations dans cel_obs *après* l'insertion effective
381
					// des records dans cel_mots_cles_obs ?
383
					// des records dans cel_mots_cles_obs ?
382
					$last[C_MOTS_CLES_TEXTE] = $last['_mots_cle']['inline_cel_obs'];
-
 
383
					unset($last['_mots_cle']);
384
					unset($last['_mots_cle']);
384
				}
385
				}
385
 
386
 
386
				$dernier_ordre++;
387
				$dernier_ordre++;
387
			}
388
			}
388
		}
389
		}
389
 
390
 
390
		// XXX future: return Array($enregistrements_a_inserer, $enregistrements_a_MAJ, $toutes_images);
391
		// XXX future: return Array($enregistrements_a_inserer, $enregistrements_a_MAJ, $toutes_images);
391
		return Array($enregistrements, $toutes_images, $tous_mots_cle);
392
		return Array($enregistrements, $toutes_images, $tous_mots_cle);
392
	}
393
	}
393
 
394
 
394
 
395
 
395
	static function trierColonnes(&$enregistrements) {
396
	static function trierColonnes(&$enregistrements) {
396
		foreach($enregistrements as &$enregistrement) {
397
		foreach($enregistrements as &$enregistrement) {
397
			$enregistrement = self::sortArrayByArray($enregistrement, self::$ordre_BDD);
398
			$enregistrement = self::sortArrayByArray($enregistrement, self::$ordre_BDD);
398
			//array_walk($enregistrement, function(&$item, $k) { $item = is_null($item) ? "NULL" : $item; });
399
			//array_walk($enregistrement, function(&$item, $k) { $item = is_null($item) ? "NULL" : $item; });
399
			//$req .= implode(', ', $enregistrement) . "\n";
400
			//$req .= implode(', ', $enregistrement) . "\n";
400
		}
401
		}
401
	}
402
	}
402
 
403
 
403
 
404
 
404
	static function stockerMotsCle($cel, $enregistrements, $tous_mots_cle, $lastid) {
405
	static function stockerMotsCle($cel, $enregistrements, $tous_mots_cle, $lastid) {
-
 
406
		$c = 0;
405
		return count($tous_mots_cle);
407
		// debug: var_dump($tous_mots_cle);die;
-
 
408
		foreach($tous_mots_cle as $v) $c += count($v['mots_cle']['to_insert']);
-
 
409
		return $c;
406
	}
410
	}
407
 
411
 
408
	static function stockerImages($cel, $enregistrements, $toutes_images, $lastid) {
412
	static function stockerImages($cel, $enregistrements, $toutes_images, $lastid) {
409
		$images_insert = 'INSERT INTO cel_obs_images (id_image, id_observation) VALUES %s ON DUPLICATE KEY UPDATE id_image = id_image';
413
		$images_insert = 'INSERT INTO cel_obs_images (id_image, id_observation) VALUES %s ON DUPLICATE KEY UPDATE id_image = id_image';
410
		$images_obs_assoc = Array();
414
		$images_obs_assoc = Array();
411
 
415
 
412
		foreach($toutes_images as $images_pour_obs) {
416
		foreach($toutes_images as $images_pour_obs) {
413
			$obs = $enregistrements[$images_pour_obs["obs_pos"]];
417
			$obs = $enregistrements[$images_pour_obs["obs_pos"]];
414
			$id_obs = $lastid // dernier autoinc inséré
418
			$id_obs = $lastid // dernier autoinc inséré
415
				- count($enregistrements) + 1 // correspondrait au premier autoinc
419
				- count($enregistrements) + 1 // correspondrait au premier autoinc
416
				+ $images_pour_obs["obs_pos"]; // ordre d'insertion = ordre dans le tableau $enregistrements (commence à 0)
420
				+ $images_pour_obs["obs_pos"]; // ordre d'insertion = ordre dans le tableau $enregistrements (commence à 0)
417
			foreach($images_pour_obs['images'] as $image) {
421
			foreach($images_pour_obs['images'] as $image) {
418
				$images_obs_assoc[] = sprintf('(%d,%d)',
422
				$images_obs_assoc[] = sprintf('(%d,%d)',
419
											  $image['id_image'], // intval() useless
423
											  $image['id_image'], // intval() useless
420
											  $id_obs); // intval() useless
424
											  $id_obs); // intval() useless
421
			}
425
			}
422
		}
426
		}
423
 
427
 
424
		if($images_obs_assoc) {
428
		if($images_obs_assoc) {
425
			$requete = sprintf($images_insert, implode(', ', $images_obs_assoc));
429
			$requete = sprintf($images_insert, implode(', ', $images_obs_assoc));
426
			// debug echo "$requete\n";
430
			// debug echo "$requete\n";
427
			$cel->requeter($requete);
431
			$cel->requeter($requete);
428
		}
432
		}
429
 
433
 
430
		return count($images_obs_assoc);
434
		return count($images_obs_assoc);
431
	}
435
	}
432
 
436
 
433
	/*
437
	/*
434
	  Aucune des valeurs présentes dans $enregistrement n'est quotée
438
	  Aucune des valeurs présentes dans $enregistrement n'est quotée
435
	  cad aucune des valeurs retournée par traiter{Espece|Localisation}()
439
	  cad aucune des valeurs retournée par traiter{Espece|Localisation}()
436
	  car ce tableau est passé à un PDO::preparedStatement() qui applique
440
	  car ce tableau est passé à un PDO::preparedStatement() qui applique
437
	  proprement les règle d'échappement.
441
	  proprement les règle d'échappement.
438
	 */
442
	 */
439
	static function chargerLigne($ligne, $dernier_ordre, $cel) {
443
	static function chargerLigne($ligne, $dernier_ordre, $cel) {
440
		// en premier car le résultat est utile pour
444
		// en premier car le résultat est utile pour
441
		// traiter longitude et latitude (traiterLonLat())
445
		// traiter longitude et latitude (traiterLonLat())
442
		$referentiel = self::identReferentiel($ligne[C_NOM_REFERENTIEL]);
446
		$referentiel = self::identReferentiel($ligne[C_NOM_REFERENTIEL]);
443
 
447
 
444
		// $espece est rempli de plusieurs informations
448
		// $espece est rempli de plusieurs informations
445
		$espece = Array(C_NOM_SEL => NULL, C_NOM_SEL_NN => NULL, C_NOM_RET => NULL,
449
		$espece = Array(C_NOM_SEL => NULL, C_NOM_SEL_NN => NULL, C_NOM_RET => NULL,
446
						C_NOM_RET_NN => NULL, C_NT => NULL, C_FAMILLE => NULL);
450
						C_NOM_RET_NN => NULL, C_NT => NULL, C_FAMILLE => NULL);
447
		self::traiterEspece($ligne, $espece, $cel);
451
		self::traiterEspece($ligne, $espece, $cel);
448
 
452
 
449
		// $localisation est rempli à partir de plusieurs champs: C_ZONE_GEO et C_CE_ZONE_GEO
453
		// $localisation est rempli à partir de plusieurs champs: C_ZONE_GEO et C_CE_ZONE_GEO
450
		$localisation = Array(C_ZONE_GEO => NULL, C_CE_ZONE_GEO => NULL);
454
		$localisation = Array(C_ZONE_GEO => NULL, C_CE_ZONE_GEO => NULL);
451
		self::traiterLocalisation($ligne, $localisation, $cel);
455
		self::traiterLocalisation($ligne, $localisation, $cel);
452
 
456
 
453
		// $transmission est utilisé pour date_transmission
457
		// $transmission est utilisé pour date_transmission
454
		// XXX: @ contre "Undefined index"
458
		// XXX: @ contre "Undefined index"
455
		@$transmission = in_array(strtolower(trim($ligne[C_TRANSMISSION])), array(1, 'oui')) ? 1 : 0;
459
		@$transmission = in_array(strtolower(trim($ligne[C_TRANSMISSION])), array(1, 'oui')) ? 1 : 0;
456
 
460
 
457
 
461
 
458
		// Dans ce tableau, seules devraient apparaître les données variable pour chaque ligne.
462
		// Dans ce tableau, seules devraient apparaître les données variable pour chaque ligne.
459
		// Dans ce tableau, l'ordre des clefs n'importe pas (cf: self::sortArrayByArray())
463
		// Dans ce tableau, l'ordre des clefs n'importe pas (cf: self::sortArrayByArray())
460
		$enregistrement = Array(
464
		$enregistrement = Array(
461
			"ordre" => $dernier_ordre,
465
			"ordre" => $dernier_ordre,
462
 
466
 
463
			"nom_sel" => $espece[C_NOM_SEL],
467
			"nom_sel" => $espece[C_NOM_SEL],
464
			"nom_sel_nn" => $espece[C_NOM_SEL_NN],
468
			"nom_sel_nn" => $espece[C_NOM_SEL_NN],
465
			"nom_ret" => $espece[C_NOM_RET],
469
			"nom_ret" => $espece[C_NOM_RET],
466
			"nom_ret_nn" => $espece[C_NOM_RET_NN],
470
			"nom_ret_nn" => $espece[C_NOM_RET_NN],
467
			"nt" => $espece[C_NT],
471
			"nt" => $espece[C_NT],
468
			"famille" => $espece[C_FAMILLE],
472
			"famille" => $espece[C_FAMILLE],
469
 
473
 
470
			"nom_referentiel" => $referentiel,
474
			"nom_referentiel" => $referentiel,
471
 
475
 
472
			"zone_geo" => $localisation[C_ZONE_GEO],
476
			"zone_geo" => $localisation[C_ZONE_GEO],
473
			"ce_zone_geo" => $localisation[C_CE_ZONE_GEO],
477
			"ce_zone_geo" => $localisation[C_CE_ZONE_GEO],
474
 
478
 
475
			// $ligne: uniquement pour les infos en cas de gestion d'erreurs (date incompréhensible)
479
			// $ligne: uniquement pour les infos en cas de gestion d'erreurs (date incompréhensible)
476
			"date_observation" => self::traiterDateObs($ligne[C_DATE_OBSERVATION], $ligne),
480
			"date_observation" => self::traiterDateObs($ligne[C_DATE_OBSERVATION], $ligne),
477
 
481
 
478
			"lieudit" => trim($ligne[C_LIEUDIT]),
482
			"lieudit" => trim($ligne[C_LIEUDIT]),
479
			"station" => trim($ligne[C_STATION]),
483
			"station" => trim($ligne[C_STATION]),
480
			"milieu" => trim($ligne[C_MILIEU]),
484
			"milieu" => trim($ligne[C_MILIEU]),
481
 
485
 
482
			"mots_cles_texte" => NULL, // TODO: foreign-key
486
			"mots_cles_texte" => NULL, // TODO: foreign-key
483
			// XXX: @ contre "Undefined index"
487
			// XXX: @ contre "Undefined index"
484
			"commentaire" => @trim($ligne[C_COMMENTAIRE]),
488
			"commentaire" => @trim($ligne[C_COMMENTAIRE]),
485
 
489
 
486
			"transmission" => $transmission,
490
			"transmission" => $transmission,
487
			"date_transmission" => $transmission ? date("Y-m-d H:i:s") : NULL, // pas de fonction SQL dans un PDO statement, <=> now()
491
			"date_transmission" => $transmission ? date("Y-m-d H:i:s") : NULL, // pas de fonction SQL dans un PDO statement, <=> now()
488
 
492
 
489
			// $ligne: uniquement pour les infos en cas de gestion d'erreurs (lon/lat incompréhensible)
493
			// $ligne: uniquement pour les infos en cas de gestion d'erreurs (lon/lat incompréhensible)
490
			"latitude" => self::traiterLonLat(NULL, $ligne[C_LATITUDE], $referentiel, $ligne),
494
			"latitude" => self::traiterLonLat(NULL, $ligne[C_LATITUDE], $referentiel, $ligne),
491
			"longitude" => self::traiterLonLat($ligne[C_LONGITUDE], NULL, $referentiel, $ligne),
495
			"longitude" => self::traiterLonLat($ligne[C_LONGITUDE], NULL, $referentiel, $ligne),
492
 
496
 
493
			// @ car potentiellement optionnelles ou toutes vides => pas d'index dans PHPExcel (tableau optimisé)
497
			// @ car potentiellement optionnelles ou toutes vides => pas d'index dans PHPExcel (tableau optimisé)
494
			"abondance" => @$ligne[C_ABONDANCE],
498
			"abondance" => @$ligne[C_ABONDANCE],
495
			"certitude" => @$ligne[C_CERTITUDE],
499
			"certitude" => @$ligne[C_CERTITUDE],
496
			"phenologie" => @$ligne[C_PHENOLOGIE],
500
			"phenologie" => @$ligne[C_PHENOLOGIE],
497
 
501
 
498
			"code_insee_calcule" => substr($localisation[C_CE_ZONE_GEO], -5) // varchar(5)
502
			"code_insee_calcule" => substr($localisation[C_CE_ZONE_GEO], -5) // varchar(5)
499
		);
503
		);
500
 
504
 
501
		// passage de $enregistrement par référence, ainsi ['_images'] n'est défini
505
		// passage de $enregistrement par référence, ainsi ['_images'] n'est défini
502
		// que si des résultats sont trouvés
506
		// que si des résultats sont trouvés
503
		// "@" car PHPExcel supprime les colonnes null sur toute la feuille (ou tout le chunk)
507
		// "@" car PHPExcel supprime les colonnes null sur toute la feuille (ou tout le chunk)
504
		if(@$ligne[C_IMAGES]) self::traiterImage($ligne[C_IMAGES], $cel, $enregistrement);
508
		if(@$ligne[C_IMAGES]) self::traiterImage($ligne[C_IMAGES], $cel, $enregistrement);
505
 
509
 
506
		if(@$ligne[C_MOTS_CLES_TEXTE]) self::traiterMotsCle($ligne[C_MOTS_CLES_TEXTE], $cel, $enregistrement);
510
		if(@$ligne[C_MOTS_CLES_TEXTE]) self::traiterMotsCle($ligne[C_MOTS_CLES_TEXTE], $cel, $enregistrement);
507
 
511
 
508
		return $enregistrement;
512
		return $enregistrement;
509
	}
513
	}
510
 
514
 
511
	static function traiterImage($str, $cel, &$enregistrement) {
515
	static function traiterImage($str, $cel, &$enregistrement) {
512
		$liste_images = array_filter(explode("/", $str));
516
		$liste_images = array_filter(explode("/", $str));
513
 
517
 
514
		//array_walk($liste_images, '__anonyme_4', $cel);
518
		//array_walk($liste_images, '__anonyme_4', $cel);
515
		array_walk($liste_images, array(__CLASS__, '__anonyme_4'), $cel);
519
		array_walk($liste_images, array(__CLASS__, '__anonyme_4'), $cel);
516
		$requete = sprintf(
520
		$requete = sprintf(
517
			"SELECT id_image, nom_original FROM cel_images WHERE ce_utilisateur = %d AND nom_original IN (\"%s\")",
521
			"SELECT id_image, nom_original FROM cel_images WHERE ce_utilisateur = %d AND nom_original IN (\"%s\")",
518
			$cel->id_utilisateur,
522
			$cel->id_utilisateur,
519
			implode('","', $liste_images));
523
			implode('","', $liste_images));
520
 
524
 
521
		$resultat = $cel->requeter($requete);
525
		$resultat = $cel->requeter($requete);
522
 
526
 
523
		if($resultat) $enregistrement['_images'] = $resultat;
527
		if($resultat) $enregistrement['_images'] = $resultat;
524
	}
528
	}
525
 
529
 
526
	static function traiterMotsCle($str, $cel, &$enregistrement) {
530
	static function traiterMotsCle($str, $cel, &$enregistrement) {
527
		$liste_mots_cle = array_filter(explode(",", $str));
531
		$liste_mots_cle = $liste_mots_cle_recherche = array_map("trim", array_unique(array_filter(explode(",", $str))));
528
		array_walk($liste_mots_cle, array(__CLASS__, '__anonyme_4'), $cel);
532
		array_walk($liste_mots_cle_recherche, array(__CLASS__, '__anonyme_4'), $cel);
-
 
533
 
529
		// TODO!!!! remplace > (pour les tests uniquement) par un = et supprimer le group by mot_cle
534
		// TODO!!!! remplace > (pour les tests uniquement) par un = et supprimer le group by mot_cle
530
		$requete = sprintf("SELECT id_mot_cle_obs, mot_cle FROM cel_mots_cles_obs WHERE id_utilisateur > %d ".
535
		$requete = sprintf("SELECT id_mot_cle_obs, mot_cle FROM cel_mots_cles_obs WHERE id_utilisateur > %d ".
531
						   "AND mot_cle IN (\"%s\") ".
536
						   "AND mot_cle IN (%s) ".
532
						   "GROUP BY mot_cle",
537
						   "GROUP BY mot_cle",
533
						   $cel->id_utilisateur,
538
						   $cel->id_utilisateur,
534
						   implode('","', $liste_mots_cle));
539
						   implode(',', $liste_mots_cle_recherche));
535
 
540
 
536
		$resultat_sql = $cel->requeter($requete);
541
		$resultat_sql = $cel->requeter($requete);
537
		if(!$resultat_sql) return;
542
		if(!$resultat_sql) return;
538
 
543
 
539
		$resultat = array();
544
		$resultat = array();
540
		foreach($resultat_sql as $v) $resultat[$v['id_mot_cle_obs']] = $v['mot_cle'];
545
		foreach($resultat_sql as $v) $resultat[$v['id_mot_cle_obs']] = $v['mot_cle'];
541
 
546
 
542
		$enregistrement['_mots_cle'] = array("inline_cel_obs" => implode(',', $liste_mots_cle),
547
		$enregistrement['mots_cles_texte'] = implode(',', $liste_mots_cle);
543
											 "existing" => $resultat,
548
		$enregistrement['_mots_cle'] = array("existing" => $resultat,
544
											 "to_insert" => $liste_mots_cle);
549
											 "to_insert" => array_diff($liste_mots_cle, $resultat));
545
	}
550
	}
546
 
551
 
547
 
552
 
548
	/* FONCTIONS de TRANSFORMATION de VALEUR DE CELLULE */
553
	/* FONCTIONS de TRANSFORMATION de VALEUR DE CELLULE */
549
 
554
 
550
	// TODO: PHP 5.3, utiliser date_parse_from_format()
555
	// TODO: PHP 5.3, utiliser date_parse_from_format()
551
	// TODO: parser les heures (cf product-owner)
556
	// TODO: parser les heures (cf product-owner)
552
	// TODO: passer par le timestamp pour s'assurer de la validité
557
	// TODO: passer par le timestamp pour s'assurer de la validité
553
	static function traiterDateObs($date, $ligne) {
558
	static function traiterDateObs($date, $ligne) {
554
		// TODO: see https://github.com/PHPOffice/PHPExcel/issues/208
559
		// TODO: see https://github.com/PHPOffice/PHPExcel/issues/208
555
		if(is_double($date)) {
560
		if(is_double($date)) {
556
			if($date > 0)
561
			if($date > 0)
557
				return PHPExcel_Style_NumberFormat::toFormattedString($date, PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2) . " 00:00:00";
562
				return PHPExcel_Style_NumberFormat::toFormattedString($date, PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2) . " 00:00:00";
558
			trigger_error("ligne \"{$ligne[C_NOM_SEL]}\": " .
563
			trigger_error("ligne \"{$ligne[C_NOM_SEL]}\": " .
559
						  "Attention: date antérieure à 1970 et format de cellule \"DATE\" utilisés ensemble",
564
						  "Attention: date antérieure à 1970 et format de cellule \"DATE\" utilisés ensemble",
560
						  E_USER_NOTICE);
565
						  E_USER_NOTICE);
561
			
566
			
562
			// throw new Exception("erreur: date antérieure à 1970 et format de cellule \"DATE\" utilisés ensemble");
567
			// throw new Exception("erreur: date antérieure à 1970 et format de cellule \"DATE\" utilisés ensemble");
563
 
568
 
564
			// attention, UNIX timestamp, car Excel les décompte depuis 1900
569
			// attention, UNIX timestamp, car Excel les décompte depuis 1900
565
			// cf http://fczaja.blogspot.fr/2011/06/convert-excel-date-into-timestamp.html
570
			// cf http://fczaja.blogspot.fr/2011/06/convert-excel-date-into-timestamp.html
566
			// $timestamp = ($date - MIN_DATES_DIFF) * 60 * 60 * 24 - time(); // NON
571
			// $timestamp = ($date - MIN_DATES_DIFF) * 60 * 60 * 24 - time(); // NON
567
 
572
 
568
			// $timestamp = PHPExcel_Calculation::getInstance()->calculateFormula("=" . $date . "-DATE(1970,1,1)*60*60*24"); // NON
573
			// $timestamp = PHPExcel_Calculation::getInstance()->calculateFormula("=" . $date . "-DATE(1970,1,1)*60*60*24"); // NON
569
 
574
 
570
			// echo strftime("%Y/%m/%d 00:00:00", $timestamp); // NON
575
			// echo strftime("%Y/%m/%d 00:00:00", $timestamp); // NON
571
		}
576
		}
572
		else {
577
		else {
573
			$timestamp = strtotime($date);
578
			$timestamp = strtotime($date);
574
			if(! $timestamp) {
579
			if(! $timestamp) {
575
				if($date) trigger_error("ligne \"{$ligne[C_NOM_SEL]}\": Attention: date erronée ($date)", E_USER_NOTICE);
580
				if($date) trigger_error("ligne \"{$ligne[C_NOM_SEL]}\": Attention: date erronée ($date)", E_USER_NOTICE);
576
				return NULL;
581
				return NULL;
577
			}
582
			}
578
			return strftime("%Y-%m-%d 00:00:00", strtotime($date));
583
			return strftime("%Y-%m-%d 00:00:00", strtotime($date));
579
		}
584
		}
580
	}
585
	}
581
 
586
 
582
	static function identReferentiel($referentiel) {
587
	static function identReferentiel($referentiel) {
583
		// SELECT DISTINCT nom_referentiel, COUNT(id_observation) AS count FROM cel_obs GROUP BY nom_referentiel ORDER BY count DESC;
588
		// SELECT DISTINCT nom_referentiel, COUNT(id_observation) AS count FROM cel_obs GROUP BY nom_referentiel ORDER BY count DESC;
584
		if(strpos(strtolower($referentiel), 'bdtfx') !== FALSE) return 'bdtfx:v1.01';
589
		if(strpos(strtolower($referentiel), 'bdtfx') !== FALSE) return 'bdtfx:v1.01';
585
		if(strpos(strtolower($referentiel), 'bdtxa') !== FALSE) return 'bdtxa:v1.00';
590
		if(strpos(strtolower($referentiel), 'bdtxa') !== FALSE) return 'bdtxa:v1.00';
586
		if(strpos(strtolower($referentiel), 'bdnff') !== FALSE) return 'bdnff:4.02';
591
		if(strpos(strtolower($referentiel), 'bdnff') !== FALSE) return 'bdnff:4.02';
587
		if(strpos(strtolower($referentiel), 'isfan') !== FALSE) return 'isfan:v1.00';
592
		if(strpos(strtolower($referentiel), 'isfan') !== FALSE) return 'isfan:v1.00';
588
 
593
 
589
		if($referentiel) {
594
		if($referentiel) {
590
			trigger_error("ligne \"{$ligne[C_NOM_SEL]}\": Attention: référentiel inconnu", E_USER_NOTICE);
595
			trigger_error("ligne \"{$ligne[C_NOM_SEL]}\": Attention: référentiel inconnu", E_USER_NOTICE);
591
		}
596
		}
592
		return NULL;
597
		return NULL;
593
		/* TODO: cf story,
598
		/* TODO: cf story,
594
		   En cas de NULL faire une seconde passe de détection à partir du nom saisi
599
		   En cas de NULL faire une seconde passe de détection à partir du nom saisi
595
		   + accepter les n° de version */
600
		   + accepter les n° de version */
596
	}
601
	}
597
 
602
 
598
	static function traiterLonLat($lon = NULL, $lat = NULL, $referentiel = 'bdtfx:v1.01', $ligne) {
603
	static function traiterLonLat($lon = NULL, $lat = NULL, $referentiel = 'bdtfx:v1.01', $ligne) {
599
		// en CSV ces valeurs sont des string, avec séparateur en français (","; cf défauts dans ExportXLS)
604
		// en CSV ces valeurs sont des string, avec séparateur en français (","; cf défauts dans ExportXLS)
600
		if($lon && is_string($lon)) $lon = str_replace(',', '.', $lon);
605
		if($lon && is_string($lon)) $lon = str_replace(',', '.', $lon);
601
		if($lat && is_string($lat)) $lat = str_replace(',', '.', $lat);
606
		if($lat && is_string($lat)) $lat = str_replace(',', '.', $lat);
602
 
607
 
603
		// sprintf applique une précision à 5 décimale (comme le ferait MySQL)
608
		// sprintf applique une précision à 5 décimale (comme le ferait MySQL)
604
		// tout en uniformisant le format de séparateur des décimales (le ".")
609
		// tout en uniformisant le format de séparateur des décimales (le ".")
605
		if($lon && is_numeric($lon) && $lon >= -180 && $lon <= 180) return sprintf('%.5F', $lon);
610
		if($lon && is_numeric($lon) && $lon >= -180 && $lon <= 180) return sprintf('%.5F', $lon);
606
		if($lat && is_numeric($lat) && $lat >= -90 && $lat <= 90) return sprintf('%.5F', $lat);
611
		if($lat && is_numeric($lat) && $lat >= -90 && $lat <= 90) return sprintf('%.5F', $lat);
607
 
612
 
608
		if($lon || $lat) {
613
		if($lon || $lat) {
609
			trigger_error("ligne \"{$ligne[C_NOM_SEL]}\": " .
614
			trigger_error("ligne \"{$ligne[C_NOM_SEL]}\": " .
610
						  "Attention: longitude ou latitude erronée",
615
						  "Attention: longitude ou latitude erronée",
611
						  E_USER_NOTICE);
616
						  E_USER_NOTICE);
612
		}
617
		}
613
		return NULL;
618
		return NULL;
614
 
619
 
615
		/* limite france métropole si bdtfx ? ou bdtxa ? ...
620
		/* limite france métropole si bdtfx ? ou bdtxa ? ...
616
		   NON!
621
		   NON!
617
		   Un taxon d'un référentiel donné peut être théoriquement observé n'importe où sur le globe.
622
		   Un taxon d'un référentiel donné peut être théoriquement observé n'importe où sur le globe.
618
		   Il n'y a pas lieu d'effectuer des restriction ici.
623
		   Il n'y a pas lieu d'effectuer des restriction ici.
619
		   Cependant des erreurs fréquentes (0,0 ou lon/lat inversées) peuvent être détectés ici.
624
		   Cependant des erreurs fréquentes (0,0 ou lon/lat inversées) peuvent être détectés ici.
620
		   TODO */
625
		   TODO */
621
		$bbox = self::getReferentielBBox($referentiel);
626
		$bbox = self::getReferentielBBox($referentiel);
622
		if(!$bbox) return NULL;
627
		if(!$bbox) return NULL;
623
 
628
 
624
		if($lon) {
629
		if($lon) {
625
			if($lon < $bbox['EST'] && $lon > $bbox['OUEST']) return is_numeric($lon) ? $lon : NULL;
630
			if($lon < $bbox['EST'] && $lon > $bbox['OUEST']) return is_numeric($lon) ? $lon : NULL;
626
			else return NULL;
631
			else return NULL;
627
		}
632
		}
628
		if($lat) {
633
		if($lat) {
629
			if($lat < $bbox['NORD'] && $lat > $bbox['SUD']) return is_numeric($lat) ? $lat : NULL;
634
			if($lat < $bbox['NORD'] && $lat > $bbox['SUD']) return is_numeric($lat) ? $lat : NULL;
630
			return NULL;
635
			return NULL;
631
		}
636
		}
632
	}
637
	}
633
 
638
 
634
 
639
 
635
	static function traiterEspece($ligne, Array &$espece, $cel) {
640
	static function traiterEspece($ligne, Array &$espece, $cel) {
636
		if(!$ligne[C_NOM_SEL]) return;
641
		if(!$ligne[C_NOM_SEL]) return;
637
 
642
 
638
		// nom_sel reste toujours celui de l'utilisateur
643
		// nom_sel reste toujours celui de l'utilisateur
639
		$espece[C_NOM_SEL] = trim($ligne[C_NOM_SEL]);
644
		$espece[C_NOM_SEL] = trim($ligne[C_NOM_SEL]);
640
 
645
 
641
		$taxon_info_webservice = new RechercheInfosTaxonBeta($cel->config);
646
		$taxon_info_webservice = new RechercheInfosTaxonBeta($cel->config);
642
 
647
 
643
		$ascii = iconv('UTF-8', 'ASCII//TRANSLIT', $ligne[C_NOM_SEL]);
648
		$ascii = iconv('UTF-8', 'ASCII//TRANSLIT', $ligne[C_NOM_SEL]);
644
 
649
 
645
		// TODO: si empty(C_NOM_SEL) et !empty(C_NOM_SEL_NN) : recherche info à partir de C_NOM_SEL_NN
650
		// TODO: si empty(C_NOM_SEL) et !empty(C_NOM_SEL_NN) : recherche info à partir de C_NOM_SEL_NN
646
		$resultat_recherche_espece = $taxon_info_webservice->rechercherInfosSurTexteCodeOuNumTax($ligne[C_NOM_SEL]);
651
		$resultat_recherche_espece = $taxon_info_webservice->rechercherInfosSurTexteCodeOuNumTax($ligne[C_NOM_SEL]);
647
 
652
 
648
		// on supprime les noms retenus et renvoi tel quel
653
		// on supprime les noms retenus et renvoi tel quel
649
		// on réutilise les define pour les noms d'indexes, tant qu'à faire
654
		// on réutilise les define pour les noms d'indexes, tant qu'à faire
650
		if (empty($resultat_recherche_espece['en_id_nom'])) {
655
		if (empty($resultat_recherche_espece['en_id_nom'])) {
651
			// XXX; tout à NULL sauf C_NOM_SEL ci-dessus ?
656
			// XXX; tout à NULL sauf C_NOM_SEL ci-dessus ?
652
			$espece[C_NOM_SEL_NN] = $ligne[C_NOM_SEL_NN];
657
			$espece[C_NOM_SEL_NN] = $ligne[C_NOM_SEL_NN];
653
			$espece[C_NOM_RET] = $ligne[C_NOM_RET];
658
			$espece[C_NOM_RET] = $ligne[C_NOM_RET];
654
			$espece[C_NOM_RET_NN] = $ligne[C_NOM_RET_NN];
659
			$espece[C_NOM_RET_NN] = $ligne[C_NOM_RET_NN];
655
			$espece[C_NT] = $ligne[C_NT];
660
			$espece[C_NT] = $ligne[C_NT];
656
			$espece[C_FAMILLE] = $ligne[C_FAMILLE];
661
			$espece[C_FAMILLE] = $ligne[C_FAMILLE];
657
 
662
 
658
			return;
663
			return;
659
		}
664
		}
660
 
665
 
661
		// succès de la détection = écrasement du numéro nomenclatural saisi...
666
		// succès de la détection = écrasement du numéro nomenclatural saisi...
662
		$espece[C_NOM_SEL_NN] = $resultat_recherche_espece['en_id_nom'];
667
		$espece[C_NOM_SEL_NN] = $resultat_recherche_espece['en_id_nom'];
663
		// et des info complémentaires
668
		// et des info complémentaires
664
		$complement = $taxon_info_webservice->rechercherInformationsComplementairesSurNumNom($resultat_recherche_espece['en_id_nom']);
669
		$complement = $taxon_info_webservice->rechercherInformationsComplementairesSurNumNom($resultat_recherche_espece['en_id_nom']);
665
		$espece[C_NOM_RET] = $complement['Nom_Retenu'];
670
		$espece[C_NOM_RET] = $complement['Nom_Retenu'];
666
		$espece[C_NOM_RET_NN] = $complement['Num_Nom_Retenu'];
671
		$espece[C_NOM_RET_NN] = $complement['Num_Nom_Retenu'];
667
		$espece[C_NT] = $complement['Num_Taxon'];
672
		$espece[C_NT] = $complement['Num_Taxon'];
668
		$espece[C_FAMILLE] = $complement['Famille'];
673
		$espece[C_FAMILLE] = $complement['Famille'];
669
	}
674
	}
670
 
675
 
671
 
676
 
672
	static function traiterLocalisation($ligne, Array &$localisation, $cel) {
677
	static function traiterLocalisation($ligne, Array &$localisation, $cel) {
673
	    $identifiant_commune = trim($ligne[C_ZONE_GEO]);
678
	    $identifiant_commune = trim($ligne[C_ZONE_GEO]);
674
		if(!$identifiant_commune) {
679
		if(!$identifiant_commune) {
675
			$departement = trim($ligne[C_CE_ZONE_GEO]);
680
			$departement = trim($ligne[C_CE_ZONE_GEO]);
676
			goto testdepartement;
681
			goto testdepartement;
677
		}
682
		}
678
 
683
 
679
 
684
 
680
		$select = "SELECT DISTINCT nom, code  FROM cel_zones_geo";
685
		$select = "SELECT DISTINCT nom, code  FROM cel_zones_geo";
681
	
686
	
682
		if (preg_match('/(.*) \((\d+)\)/', $identifiant_commune, $elements)) {
687
		if (preg_match('/(.*) \((\d+)\)/', $identifiant_commune, $elements)) {
683
			// commune + departement : montpellier (34)
688
			// commune + departement : montpellier (34)
684
			$nom_commune=$elements[1];
689
			$nom_commune=$elements[1];
685
			$code_commune=$elements[2];
690
			$code_commune=$elements[2];
686
	 	    $requete = sprintf("%s WHERE nom = %s AND code LIKE %s",
691
	 	    $requete = sprintf("%s WHERE nom = %s AND code LIKE %s",
687
							   $select, $cel->quoteNonNull($nom_commune), $cel->quoteNonNull($code_commune.'%'));
692
							   $select, $cel->quoteNonNull($nom_commune), $cel->quoteNonNull($code_commune.'%'));
688
		}
693
		}
689
		elseif (preg_match('/^(\d+|(2[ab]\d+))$/i', $identifiant_commune, $elements)) {
694
		elseif (preg_match('/^(\d+|(2[ab]\d+))$/i', $identifiant_commune, $elements)) {
690
			// Code insee seul  
695
			// Code insee seul  
691
			$code_insee_commune=$elements[1];
696
			$code_insee_commune=$elements[1];
692
	 	    $requete = sprintf("%s WHERE code = %s", $select, $cel->quoteNonNull($code_insee_commune));
697
	 	    $requete = sprintf("%s WHERE code = %s", $select, $cel->quoteNonNull($code_insee_commune));
693
		}
698
		}
694
		else {
699
		else {
695
			// Commune seule (le departement sera recupere dans la colonne departement si elle est presente)
700
			// Commune seule (le departement sera recupere dans la colonne departement si elle est presente)
696
			// on prend le risque ici de retourner une mauvaise Commune
701
			// on prend le risque ici de retourner une mauvaise Commune
697
			$nom_commune = str_replace(" ", "%", iconv('UTF-8', 'ASCII//TRANSLIT', $identifiant_commune));
702
			$nom_commune = str_replace(" ", "%", iconv('UTF-8', 'ASCII//TRANSLIT', $identifiant_commune));
698
	 	    $requete = sprintf("%s WHERE nom LIKE %s", $select, $cel->quoteNonNull($nom_commune.'%'));
703
	 	    $requete = sprintf("%s WHERE nom LIKE %s", $select, $cel->quoteNonNull($nom_commune.'%'));
699
		}
704
		}
700
	
705
	
701
		$resultat_commune = $cel->requeter($requete);
706
		$resultat_commune = $cel->requeter($requete);
702
		// TODO: levenstein sort ?
707
		// TODO: levenstein sort ?
703
 
708
 
704
		// cas de la commune introuvable dans le référentiel
709
		// cas de la commune introuvable dans le référentiel
705
		// réinitialisation aux valeurs du fichier XLS
710
		// réinitialisation aux valeurs du fichier XLS
706
		if(! $resultat_commune) {
711
		if(! $resultat_commune) {
707
			$localisation[C_ZONE_GEO] = trim($ligne[C_ZONE_GEO]);
712
			$localisation[C_ZONE_GEO] = trim($ligne[C_ZONE_GEO]);
708
			$localisation[C_CE_ZONE_GEO] = trim($ligne[C_CE_ZONE_GEO]);
713
			$localisation[C_CE_ZONE_GEO] = trim($ligne[C_CE_ZONE_GEO]);
709
		} else {
714
		} else {
710
			$localisation[C_ZONE_GEO] = $resultat_commune[0]['nom'];
715
			$localisation[C_ZONE_GEO] = $resultat_commune[0]['nom'];
711
			$localisation[C_CE_ZONE_GEO] = $resultat_commune[0]['code'];
716
			$localisation[C_CE_ZONE_GEO] = $resultat_commune[0]['code'];
712
		}
717
		}
713
 
718
 
714
		$departement = &$localisation[C_CE_ZONE_GEO];
719
		$departement = &$localisation[C_CE_ZONE_GEO];
715
 
720
 
716
	testdepartement:
721
	testdepartement:
717
		if(strpos($departement, "INSEE-C:", 0) === 0) goto protectloc;
722
		if(strpos($departement, "INSEE-C:", 0) === 0) goto protectloc;
718
 
723
 
719
		if(!is_numeric($departement)) goto protectloc; // TODO ?
724
		if(!is_numeric($departement)) goto protectloc; // TODO ?
720
		if(strlen($departement) == 4) $departement = "INSEE-C:0" . $departement;
725
		if(strlen($departement) == 4) $departement = "INSEE-C:0" . $departement;
721
		if(strlen($departement) == 5) $departement = "INSEE-C:" . $departement;
726
		if(strlen($departement) == 5) $departement = "INSEE-C:" . $departement;
722
		// if(strlen($departement) <= 9) return "INSEE-C:0" . $departement; // ? ... TODO
727
		// if(strlen($departement) <= 9) return "INSEE-C:0" . $departement; // ? ... TODO
723
 
728
 
724
		$departement = trim($departement); // TODO
729
		$departement = trim($departement); // TODO
725
 
730
 
726
	protectloc:
731
	protectloc:
727
		$localisation[C_ZONE_GEO] = $localisation[C_ZONE_GEO];
732
		$localisation[C_ZONE_GEO] = $localisation[C_ZONE_GEO];
728
		$localisation[C_CE_ZONE_GEO] = $localisation[C_CE_ZONE_GEO];
733
		$localisation[C_CE_ZONE_GEO] = $localisation[C_CE_ZONE_GEO];
729
	}
734
	}
730
 
735
 
731
 
736
 
732
 
737
 
733
	/* HELPERS */
738
	/* HELPERS */
734
 
739
 
735
	// http://stackoverflow.com/questions/348410/sort-an-array-based-on-another-array
740
	// http://stackoverflow.com/questions/348410/sort-an-array-based-on-another-array
736
	static function sortArrayByArray($array, $orderArray) {
741
	static function sortArrayByArray($array, $orderArray) {
737
		$ordered = array();
742
		$ordered = array();
738
		foreach($orderArray as $key) {
743
		foreach($orderArray as $key) {
739
			if(array_key_exists($key, $array)) {
744
			if(array_key_exists($key, $array)) {
740
				$ordered[$key] = $array[$key];
745
				$ordered[$key] = $array[$key];
741
				unset($array[$key]);
746
				unset($array[$key]);
742
			}
747
			}
743
		}
748
		}
744
		return $ordered + $array;
749
		return $ordered + $array;
745
	}
750
	}
746
 
751
 
747
	// retourne une BBox [N,S,E,O) pour un référentiel donné
752
	// retourne une BBox [N,S,E,O) pour un référentiel donné
748
	static function getReferentielBBox($referentiel) {
753
	static function getReferentielBBox($referentiel) {
749
		if($referentiel == 'bdtfx:v1.01') return Array(
754
		if($referentiel == 'bdtfx:v1.01') return Array(
750
			'NORD' => 51.2, // Dunkerque
755
			'NORD' => 51.2, // Dunkerque
751
			'SUD' => 41.3, // Bonifacio
756
			'SUD' => 41.3, // Bonifacio
752
			'EST' => 9.7, // Corse
757
			'EST' => 9.7, // Corse
753
			'OUEST' => -5.2); // Ouessan
758
			'OUEST' => -5.2); // Ouessan
754
		return FALSE;
759
		return FALSE;
755
	}
760
	}
756
 
761
 
757
	// ces valeurs ne sont pas inséré via les placeholders du PDO::preparedStatement
762
	// ces valeurs ne sont pas inséré via les placeholders du PDO::preparedStatement
758
	// et doivent donc être échappées correctement.
763
	// et doivent donc être échappées correctement.
759
	public function initialiser_colonnes_statiques() {
764
	public function initialiser_colonnes_statiques() {
760
		$this->colonnes_statiques = array_merge($this->colonnes_statiques,
765
		$this->colonnes_statiques = array_merge($this->colonnes_statiques,
761
												Array(
766
												Array(
762
													"ce_utilisateur" => $this->id_utilisateur,
767
													"ce_utilisateur" => $this->id_utilisateur,
763
													"prenom_utilisateur" => $this->quoteNonNull($this->utilisateur['prenom']),
768
													"prenom_utilisateur" => $this->quoteNonNull($this->utilisateur['prenom']),
764
													"nom_utilisateur" => $this->quoteNonNull($this->utilisateur['nom']),
769
													"nom_utilisateur" => $this->quoteNonNull($this->utilisateur['nom']),
765
													"courriel_utilisateur" => $this->quoteNonNull($this->utilisateur['courriel']),
770
													"courriel_utilisateur" => $this->quoteNonNull($this->utilisateur['courriel']),
766
												));
771
												));
767
 
772
 
768
	}
773
	}
769
 
774
 
770
	static function initialiser_pdo_ordered_statements($colonnes_statiques) {
775
	static function initialiser_pdo_ordered_statements($colonnes_statiques) {
771
		return Array(
776
		return Array(
772
			// insert_ligne_pattern_ordre
777
			// insert_ligne_pattern_ordre
773
			sprintf('INSERT INTO cel_obs (%s, %s) VALUES',
778
			sprintf('INSERT INTO cel_obs (%s, %s) VALUES',
774
					implode(', ', array_keys($colonnes_statiques)),
779
					implode(', ', array_keys($colonnes_statiques)),
775
					implode(', ', array_diff(self::$ordre_BDD, array_keys($colonnes_statiques)))),
780
					implode(', ', array_diff(self::$ordre_BDD, array_keys($colonnes_statiques)))),
776
 
781
 
777
			// insert_ligne_pattern_ordre
782
			// insert_ligne_pattern_ordre
778
			sprintf('(%s, %s ?)',
783
			sprintf('(%s, %s ?)',
779
					implode(', ', $colonnes_statiques),
784
					implode(', ', $colonnes_statiques),
780
					str_repeat('?, ', count(self::$ordre_BDD) - count($colonnes_statiques) - 1))
785
					str_repeat('?, ', count(self::$ordre_BDD) - count($colonnes_statiques) - 1))
781
		);
786
		);
782
	}
787
	}
783
 
788
 
784
	static function initialiser_pdo_statements($colonnes_statiques) {
789
	static function initialiser_pdo_statements($colonnes_statiques) {
785
		return Array( 
790
		return Array( 
786
			// insert_prefix
791
			// insert_prefix
787
			sprintf('INSERT INTO cel_obs (%s) VALUES ',
792
			sprintf('INSERT INTO cel_obs (%s) VALUES ',
788
					implode(', ', self::$ordre_BDD)),
793
					implode(', ', self::$ordre_BDD)),
789
 
794
 
790
 
795
 
791
			// insert_ligne_pattern, cf: self::$insert_ligne_pattern
796
			// insert_ligne_pattern, cf: self::$insert_ligne_pattern
792
			'(' .
797
			'(' .
793
			// 3) créé une chaîne de liste de champ à inséré en DB
798
			// 3) créé une chaîne de liste de champ à inséré en DB
794
			implode(', ', array_values(
799
			implode(', ', array_values(
795
				// 2) garde les valeurs fixes (de $colonnes_statiques),
800
				// 2) garde les valeurs fixes (de $colonnes_statiques),
796
				// mais remplace les NULL par des "?"
801
				// mais remplace les NULL par des "?"
797
				array_map('__anonyme_5',
802
				array_map('__anonyme_5',
798
						  // 1) créé un tableau genre (nom_sel_nn => NULL) depuis self::$ordre_BDD
803
						  // 1) créé un tableau genre (nom_sel_nn => NULL) depuis self::$ordre_BDD
799
						  // et écrase certaines valeurs avec $colonnes_statiques (initilisé avec les données utilisateur)
804
						  // et écrase certaines valeurs avec $colonnes_statiques (initilisé avec les données utilisateur)
800
						  array_merge(array_map('__anonyme_6', array_flip(self::$ordre_BDD)), $colonnes_statiques
805
						  array_merge(array_map('__anonyme_6', array_flip(self::$ordre_BDD)), $colonnes_statiques
801
				)))) .
806
				)))) .
802
			')'
807
			')'
803
		);
808
		);
804
	}
809
	}
805
 
810
 
806
	// équivalent à CEL->Bdd->proteger() (qui wrap PDO::quote),
811
	// équivalent à CEL->Bdd->proteger() (qui wrap PDO::quote),
807
	// sans transformer NULL en ""
812
	// sans transformer NULL en ""
808
	private function quoteNonNull($chaine) {
813
	private function quoteNonNull($chaine) {
809
		if(is_null($chaine)) return "NULL";
814
		if(is_null($chaine)) return "NULL";
810
		if(!is_string($chaine)) die("erreur __FILE__, __LINE__");
815
		if(!is_string($chaine)) die("erreur __FILE__, __LINE__");
811
		return $this->bdd->quote($chaine);
816
		return $this->bdd->quote($chaine);
812
	}
817
	}
813
 
818
 
814
	public function erreurs_stock($errno, $errstr) {
819
	public function erreurs_stock($errno, $errstr) {
815
		$this->bilan[] = $errstr;
820
		$this->bilan[] = $errstr;
816
	}
821
	}
817
}
822
}