Subversion Repositories eFlore/Applications.cel

Compare Revisions

Ignore whitespace Rev 1648 → Rev 1649

/trunk/jrest/services/ImportXLS.php
1,5 → 1,4
<?php
 
/**
* @category PHP
* @package jrest
11,11 → 10,18
 
/**
* Service d'import de données d'observation du CEL au format XLS
*/
*
* Sont define()'d commme n° de colonne tous les abbrevs retournés par
* ExportXLS::nomEnsembleVersListeColonnes() préfixés par C_ cf: detectionEntete()
*
* Exemple d'un test:
* $ GET "/jrest/ExportXLS/22506?format=csv&range=*&limite=13" \
* | curl -F "upload=@-" -F utilisateur=22506 "/jrest/ImportXLS"
* # 13 observations importées
* + cf MySQL general_log = 1
*
**/
 
// sont define()'d commme n° de colonne tous les abbrevs retournés par ExportXLS::nomEnsembleVersListeColonnes()
// préfixés par C_ cf: detectionEntete()
 
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(dirname(realpath(__FILE__))) . '/lib');
// TERM
error_reporting(-1);
79,30 → 85,33
"lieudit",
"station",
"milieu",
"mots_cles_texte",
"commentaire",
"transmission",
"date_creation",
"date_modification",
"date_transmission",
"latitude",
"longitude",
"abondance",
"certitude",
"phenologie",
"code_insee_calcule"
);
 
// cf: initialiser_pdo_ordered_statements()
// eg: "INSERT INTO cel_obs (ce_utilisateur, ..., phenologie, code_insee_calcule) VALUES"
// colonnes statiques d'abord, les autres ensuite, dans l'ordre de $ordre_BDD
static $insert_prefix_ordre;
 
// seconde possibilité
// eg: "INSERT INTO cel_obs (ce_utilisateur, ..., date_creation, ...phenologie, code_insee_calcule) VALUES"
static $insert_prefix;
 
// eg: "(<id>, <prenom>, <nom>, <email>, now(), now(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
// dont le nombre de placeholder dépend du nombre de colonnes non-statiques
// colonnes statiques d'abord, les autres ensuite, dans l'ordre de $ordre_BDD
static $insert_ligne_pattern_ordre;
 
// seconde possibilité:
// seconde (meilleure) possibilité
// cf: initialiser_pdo_statements()
// eg: "INSERT INTO cel_obs (ce_utilisateur, ..., date_creation, ...phenologie, code_insee_calcule) VALUES"
static $insert_prefix;
// eg: "(<id>, <prenom>, <nom>, <email>, ?, ?, ?, now(), now(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
// dont le nombre de placeholder dépend du nombre de colonnes non-statiques
static $insert_ligne_pattern;
113,6 → 122,8
- sont indépendantes du numéro de lignes
- n'ont pas de valeur par défaut dans la structure de la table
- nécessitent une initialisation dans le cadre de l'upload
 
initialiser_colonnes_statiques() y merge les données d'identification utilisateur
*/
public $colonnes_statiques = Array(
"ce_utilisateur" => NULL,
128,9 → 139,11
);
 
public $id_utilisateur = NULL;
 
// erreurs d'import
public $bilan = Array();
 
 
function ExportXLS($config) {
parent::__construct($config);
}
139,6 → 152,7
if(!isset($pairs['utilisateur']) || trim($pairs['utilisateur']) == '') {
echo '0'; exit;
}
 
$id_utilisateur = intval($pairs['utilisateur']);
$this->id_utilisateur = $id_utilisateur; // pour traiterImage();
 
146,36 → 160,17
$this->controleUtilisateur($id_utilisateur);
 
$this->utilisateur = $this->getInfosComplementairesUtilisateur($id_utilisateur);
 
$this->initialiser_colonnes_statiques($id_utilisateur);
 
// initialisation du statement PDO/MySQL
self::$insert_prefix_ordre = 'INSERT INTO cel_obs ('.
implode(', ', array_keys($this->colonnes_statiques)) .
', ' .
implode(', ', array_diff(self::$ordre_BDD, array_keys($this->colonnes_statiques))) .
') VALUES ';
// première version, pattern de requête pas génial
/* list(self;;$insert_prefix_ordre, self::$insert_ligne_pattern_ordre) =
$this->initialiser_pdo_ordered_statements($this->colonnes_statiques); */
list(self::$insert_prefix, self::$insert_ligne_pattern) =
$this->initialiser_pdo_statements($this->colonnes_statiques);
 
self::$insert_prefix = 'INSERT INTO cel_obs ('.
implode(', ', self::$ordre_BDD) . ') VALUES ';
 
self::$insert_ligne_pattern_ordre =
'(' .
implode(', ', $this->colonnes_statiques) .
', ' .
str_repeat('?, ', count(self::$ordre_BDD) - count($this->colonnes_statiques) - 1) .
'?' .
')';
 
self::$insert_ligne_pattern =
'(' .
implode(', ', array_values(array_map(
function($item) { return is_null($item) ? '?' : $item; },
array_merge(
array_map(function() { return NULL; }, array_flip(self::$ordre_BDD)),
$this->colonnes_statiques
)))) .
')';
 
$infos_fichier = array_pop($_FILES);
/*$objPHPExcel = PHPExcel_IOFactory::load($infos_fichier['tmp_name']);
268,9 → 263,7
$donnees = array();
foreach($enregistrements as $e) $donnees = array_merge($donnees, array_values($e));
 
echo $sql_pattern;
var_dump($enregistrements);
var_dump($donnees);die;
/* debug ici: echo $sql_pattern . "\n"; var_dump($enregistrements, $donnees); die;*/
 
$stmt->execute($donnees);
 
410,7 → 403,12
}
}
 
 
/*
Aucune des valeurs présentes dans $enregistrement n'est quotée
cad aucune des valeurs retournée par traiter{Espece|Localisation}()
car ce tableau est passé à un PDO::preparedStatement() qui applique
proprement les règle d'échappement.
*/
static function chargerLigne($ligne, $dernier_ordre, $cel) {
// en premier car le résultat est utile pour
// traiter longitude et latitude (traiterLonLat())
425,12 → 423,15
$localisation = Array(C_ZONE_GEO => NULL, C_CE_ZONE_GEO => NULL);
self::traiterLocalisation($ligne, $localisation, $cel);
 
// $transmission est utilisé pour date_transmission
$transmission = in_array(strtolower(trim($ligne[C_TRANSMISSION])), array(1, 'oui')) ? 1 : 0;
 
 
// Dans ce tableau, seules devraient apparaître les données variable pour chaque ligne.
// Dans ce tableau, l'ordre des clefs n'importe pas (cf: self::sortArrayByArray())
$enregistrement = Array(
"ordre" => $dernier_ordre,
 
// $this->quoteNonNull() est déjà appliquée dans traiterEspece()
"nom_sel" => $espece[C_NOM_SEL],
"nom_sel_nn" => $espece[C_NOM_SEL_NN],
"nom_ret" => $espece[C_NOM_RET],
438,22 → 439,23
"nt" => $espece[C_NT],
"famille" => $espece[C_FAMILLE],
 
"nom_referentiel" => $cel->quoteNonNull($referentiel),
"nom_referentiel" => $referentiel,
 
// $this->quoteNonNull() est déjà appliquée dans traiterLocalisation()
"zone_geo" => $localisation[C_ZONE_GEO],
"ce_zone_geo" => $localisation[C_CE_ZONE_GEO],
 
// $ligne: uniquement pour les infos en cas de gestion d'erreurs (date incompréhensible)
"date_observation" => $cel->quoteNonNull(self::traiterDateObs($ligne[C_DATE_OBSERVATION], $ligne)),
"date_observation" => self::traiterDateObs($ligne[C_DATE_OBSERVATION], $ligne),
 
"lieudit" => $cel->quoteNonNull(trim($ligne[C_LIEUDIT])),
"station" => $cel->quoteNonNull(trim($ligne[C_STATION])),
"milieu" => $cel->quoteNonNull(trim($ligne[C_MILIEU])),
"commentaire" => NULL, //$cel->quoteNonNull(trim($ligne[C_COMMENTAIRE])), // TODO: foreign-key
"lieudit" => trim($ligne[C_LIEUDIT]),
"station" => trim($ligne[C_STATION]),
"milieu" => trim($ligne[C_MILIEU]),
 
"mots_cles_texte" => NULL, // TODO: foreign-key
"commentaire" => trim($ligne[C_COMMENTAIRE]),
 
"transmission" => in_array(strtolower(trim($ligne[C_TRANSMISSION])), array(1, 'oui')) ? 1 : 0,
"transmission" => $transmission,
"date_transmission" => $transmission ? date("Y-m-d H:i:s") : NULL, // pas de fonction SQL dans un PDO statement, <=> now()
 
// $ligne: uniquement pour les infos en cas de gestion d'erreurs (lon/lat incompréhensible)
"latitude" => self::traiterLonLat(NULL, $ligne[C_LATITUDE], $referentiel, $ligne),
464,7 → 466,7
"certitude" => @$ligne[C_CERTITUDE],
"phenologie" => @$ligne[C_PHENOLOGIE],
 
"code_insee_calcule" => $localisation[C_CE_ZONE_GEO] // TODO ?
"code_insee_calcule" => substr($localisation[C_CE_ZONE_GEO], -5) // varchar(5)
);
 
// passage de $enregistrement par référence, ainsi ['_images'] n'est défini
478,7 → 480,7
static function traiterImage($str, $cel, &$enregistrement) {
$liste_images = array_filter(explode("/", $str));
array_walk($liste_images,
function($item, $key, $obj) { $item = $obj->quoteNonNull_real(trim($item)); },
function($item, $key, $obj) { $item = $obj->quoteNonNull(trim($item)); },
$cel);
$requete = sprintf(
"SELECT id_image, nom_original FROM cel_images WHERE ce_utilisateur = %d AND nom_original IN (\"%s\")",
590,7 → 592,7
// on supprime les noms retenus et renvoi tel quel
// on réutilise les define pour les noms d'indexes, tant qu'à faire
if (empty($resultat_recherche_espece['en_id_nom'])) {
$espece[C_NOM_SEL] = $cel->quoteNonNull(trim($ligne[C_NOM_SEL]));
$espece[C_NOM_SEL] = trim($ligne[C_NOM_SEL]);
 
// le reste reste à NULL
// TODO: si empty(C_NOM_SEL) et !empty(C_NOM_SEL_NN) : recherche info à partir de C_NOM_SEL_NN
604,14 → 606,14
}
 
// succès de la détection, récupération des infos
$espece[C_NOM_SEL] = $cel->quoteNonNull($resultat_recherche_espece['nom_sel']);
$espece[C_NOM_SEL_NN] = $cel->quoteNonNull($resultat_recherche_espece['en_id_nom']);
$espece[C_NOM_SEL] = $resultat_recherche_espece['nom_sel'];
$espece[C_NOM_SEL_NN] = $resultat_recherche_espece['en_id_nom'];
 
$complement = $taxon_info_webservice->rechercherInformationsComplementairesSurNumNom($resultat_recherche_espece['en_id_nom']);
$espece[C_NOM_RET] = $cel->quoteNonNull($complement['Nom_Retenu']);
$espece[C_NOM_RET_NN] = $cel->quoteNonNull($complement['Num_Nom_Retenu']);
$espece[C_NT] = $cel->quoteNonNull($complement['Num_Taxon']);
$espece[C_FAMILLE] = $cel->quoteNonNull($complement['Famille']);
$espece[C_NOM_RET] = $complement['Nom_Retenu'];
$espece[C_NOM_RET_NN] = $complement['Num_Nom_Retenu'];
$espece[C_NT] = $complement['Num_Taxon'];
$espece[C_FAMILLE] = $complement['Famille'];
}
 
 
630,18 → 632,18
$nom_commune=$elements[1];
$code_commune=$elements[2];
$requete = sprintf("%s WHERE nom = %s AND code LIKE %s",
$select, $cel->quoteNonNull_real($nom_commune), $cel->quoteNonNull_real($code_commune.'%'));
$select, $cel->quoteNonNull($nom_commune), $cel->quoteNonNull($code_commune.'%'));
}
elseif (preg_match('/^(\d+|(2[ab]\d+))$/i', $identifiant_commune, $elements)) {
// Code insee seul
$code_insee_commune=$elements[1];
$requete = sprintf("%s WHERE code = %s", $select, $cel->quoteNonNull_real($code_insee_commune));
$requete = sprintf("%s WHERE code = %s", $select, $cel->quoteNonNull($code_insee_commune));
}
else {
// Commune seule (le departement sera recupere dans la colonne departement si elle est presente)
// on prend le risque ici de retourner une mauvaise Commune
$nom_commune = str_replace(" ", "%", iconv('UTF-8', 'ASCII//TRANSLIT', $identifiant_commune));
$requete = sprintf("%s WHERE nom LIKE %s", $select, $cel->quoteNonNull_real($nom_commune.'%'));
$requete = sprintf("%s WHERE nom LIKE %s", $select, $cel->quoteNonNull($nom_commune.'%'));
}
$resultat_commune = $cel->requeter($requete);
670,8 → 672,8
$departement = trim($departement); // TODO
 
protectloc:
$localisation[C_ZONE_GEO] = $cel->quoteNonNull($localisation[C_ZONE_GEO]);
$localisation[C_CE_ZONE_GEO] = $cel->quoteNonNull($localisation[C_CE_ZONE_GEO]);
$localisation[C_ZONE_GEO] = $localisation[C_ZONE_GEO];
$localisation[C_CE_ZONE_GEO] = $localisation[C_CE_ZONE_GEO];
}
 
 
700,28 → 702,54
return FALSE;
}
 
 
// ces valeurs ne sont pas inséré via les placeholders du PDO::preparedStatement
// et doivent donc être échappées correctement.
public function initialiser_colonnes_statiques() {
$this->colonnes_statiques = array_merge($this->colonnes_statiques,
Array(
"ce_utilisateur" => $this->id_utilisateur,
"prenom_utilisateur" => $this->quoteNonNull_real($this->utilisateur['prenom']),
"nom_utilisateur" => $this->quoteNonNull_real($this->utilisateur['nom']),
"courriel_utilisateur" => $this->quoteNonNull_real($this->utilisateur['courriel']),
"prenom_utilisateur" => $this->quoteNonNull($this->utilisateur['prenom']),
"nom_utilisateur" => $this->quoteNonNull($this->utilisateur['nom']),
"courriel_utilisateur" => $this->quoteNonNull($this->utilisateur['courriel']),
));
 
}
 
private function quoteNonNull_real($chaine) {
if(is_null($chaine)) return "NULL";
if(!is_string($chaine)) die("erreur __FILE__, __LINE__");
return $this->bdd->quote($chaine);
static function initialiser_pdo_ordered_statements($colonnes_statiques) {
return Array(
// insert_ligne_pattern_ordre
sprintf('INSERT INTO cel_obs (%s, %s) VALUES',
implode(', ', array_keys($colonnes_statiques)),
implode(', ', array_diff(self::$ordre_BDD, array_keys($colonnes_statiques)))),
 
// insert_ligne_pattern_ordre
sprintf('(%s, %s ?)',
implode(', ', $colonnes_statiques),
str_repeat('?, ', count(self::$ordre_BDD) - count($colonnes_statiques) - 1))
);
}
 
static function initialiser_pdo_statements($colonnes_statiques) {
return Array(
// insert_prefix
sprintf('INSERT INTO cel_obs (%s) VALUES ',
implode(', ', self::$ordre_BDD)),
 
// insert_ligne_pattern =
'(' .
implode(', ', array_values(array_map(
function($item) { return is_null($item) ? '?' : $item; },
array_merge(
array_map(function() { return NULL; }, array_flip(self::$ordre_BDD)),
$colonnes_statiques
)))) .
')'
);
}
 
// équivalent à CEL->Bdd->proteger() (qui wrap PDO::quote),
// sans transformer NULL en ""
private function quoteNonNull($chaine) {
return $chaine;
if(is_null($chaine)) return "NULL";
if(!is_string($chaine)) die("erreur __FILE__, __LINE__");
return $this->bdd->quote($chaine);