Subversion Repositories eFlore/Applications.cel

Rev

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

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