Subversion Repositories eFlore/Applications.cel

Rev

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

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