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); |