Subversion Repositories eFlore/Applications.cel

Rev

Rev 1927 | Rev 1933 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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