38,6 → 38,10 |
//define('NB_LIRE_LIGNE_SIMUL', 30); |
define('NB_LIRE_LIGNE_SIMUL', 5); |
|
// en cas d'import d'un fichier CSV, utilise fgetcsv() plutôt |
// que PHPExcel ce qui se traduit par un gain de performances très substanciel |
define('QUICK_CSV_IMPORT', TRUE); |
|
// Numbers of days between January 1, 1900 and 1970 (including 19 leap years) |
// see traiterDateObs() |
// define("MIN_DATES_DIFF", 25569); |
206,7 → 210,14 |
$objReader->setReadDataOnly(true); |
|
// TODO: is_a obsolete entre 5.0 et 5.3, retirer le @ à terme |
if(@is_a($objReader, 'PHPExcel_Reader_CSV')) { |
$IS_CSV = @is_a($objReader, 'PHPExcel_Reader_CSV') && QUICK_CSV_IMPORT; |
// en cas d'usage de fgetcsv, testons que nous pouvons compter les lignes |
if($IS_CSV) $nb_lignes = intval(exec("wc -l $fichier")); |
// et, le cas échéant, fallback sur PHPExcel à nouveau. La raison de ce test ici est |
// l'instabilité du serveur (safe_mode, safe_mode_exec_dir, symlink vers binaires pour exec(), ... multiples points-of-failure) |
if($IS_CSV && !$nb_lignes) $IS_CSV = FALSE; |
|
if($IS_CSV) { |
$objReader->setDelimiter(',') |
->setEnclosure('"') |
->setLineEnding("\n") |
220,11 → 231,22 |
|
$objPHPExcel = $objReader->load($fichier); |
$obj_infos = $objReader->listWorksheetInfo($fichier); |
// XXX: indépendant du readFilter ? |
$nb_lignes = $obj_infos[0]['totalRows']; |
|
$donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, TRUE, TRUE); |
$filtre->exclues = self::detectionEntete($donnees[1]); |
if($IS_CSV) { |
// $nb_lignes est déjà défini ci-dessus |
$csvFileHandler = fopen($fichier, 'r'); |
// nous utilisons la valeur de retour dans un but informatif de l'utilisateur à la |
// fin de l'import, *mais aussi* dans un array_diff_key() ci-dessous car bien que dans le |
// fond le "parser" fgetcsv() n'ait pas d'intérêt à connaître les colonnes à ignorer, |
// il se trouve que celles-ci peuvent interférer sur des fonctions comme traiterEspece() |
// cf test "ref-nom-num.test.php" pour lequel l'élément C_NOM_SEL vaudrait 3 et $ligne serait array(3 => -42) |
$filtre->exclues = self::detectionEntete(fgetcsv($csvFileHandler), TRUE); |
} else { |
// XXX: indépendant du readFilter ? |
$nb_lignes = $obj_infos[0]['totalRows']; |
$donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, TRUE, TRUE); |
$filtre->exclues = self::detectionEntete($donnees[1]); |
} |
|
$obs_ajouts = 0; |
$obs_maj = 0; |
237,33 → 259,47 |
|
// on catch to les trigger_error(E_USER_NOTICE); |
set_error_handler(array($this, 'erreurs_stock'), E_USER_NOTICE); |
$this->taxon_info_webservice = new RechercheInfosTaxonBeta($this->config, NULL); |
|
|
// lecture par morceaux (chunks), NB_LIRE_LIGNE_SIMUL lignes à fois |
// pour aboutir des requêtes SQL d'insert groupés. |
for($ligne = 2; $ligne < $nb_lignes + NB_LIRE_LIGNE_SIMUL; $ligne += NB_LIRE_LIGNE_SIMUL) { |
$filtre->def_interval($ligne, NB_LIRE_LIGNE_SIMUL); |
$objReader->setReadFilter($filtre); |
if(!$IS_CSV) { |
$filtre->def_interval($ligne, NB_LIRE_LIGNE_SIMUL); |
$objReader->setReadFilter($filtre); |
|
/* recharge avec $filtre actif (filtre sur lignes colonnes): |
- exclue les colonnes inutiles/inutilisables) |
- ne selectionne que les lignes dans le range [$ligne - $ligne + NB_LIRE_LIGNE_SIMUL] */ |
$objPHPExcel = $objReader->load($fichier)->getActiveSheet(); |
/* recharge avec $filtre actif (filtre sur lignes colonnes): |
- exclue les colonnes inutiles/inutilisables) |
- ne selectionne que les lignes dans le range [$ligne - $ligne + NB_LIRE_LIGNE_SIMUL] */ |
$objPHPExcel = $objReader->load($fichier)->getActiveSheet(); |
|
// set col typing |
if(C_CE_ZONE_GEO != 'C_CE_ZONE_GEO') |
$objPHPExcel->getStyle(C_CE_ZONE_GEO . '2:' . C_CE_ZONE_GEO . $objPHPExcel->getHighestRow())->getNumberFormat()->setFormatCode('00000'); |
// set col typing |
if(C_CE_ZONE_GEO != 'C_CE_ZONE_GEO') |
$objPHPExcel->getStyle(C_CE_ZONE_GEO . '2:' . C_CE_ZONE_GEO . $objPHPExcel->getHighestRow())->getNumberFormat()->setFormatCode('00000'); |
|
// TODO: set to string type |
if(C_ZONE_GEO != 'C_ZONE_GEO') |
$objPHPExcel->getStyle(C_ZONE_GEO . '2:' . C_ZONE_GEO . $objPHPExcel->getHighestRow())->getNumberFormat()->setFormatCode('00000'); |
// TODO: set to string type |
if(C_ZONE_GEO != 'C_ZONE_GEO') |
$objPHPExcel->getStyle(C_ZONE_GEO . '2:' . C_ZONE_GEO . $objPHPExcel->getHighestRow())->getNumberFormat()->setFormatCode('00000'); |
|
$donnees = $objPHPExcel->toArray(NULL, FALSE, TRUE, TRUE); |
$donnees = $objPHPExcel->toArray(NULL, FALSE, TRUE, TRUE); |
} |
else { |
$i = NB_LIRE_LIGNE_SIMUL; |
$donnees = array(); |
while($i--) { |
$tab = fgetcsv($csvFileHandler); |
if(!$tab) continue; |
$donnees[] = array_diff_key($tab, $filtre->exclues); |
} |
|
} |
|
// var_dump($donnees, get_defined_constants(true)['user']);die; |
// ici on appel la fonction qui fera effectivement l'insertion multiple |
// à partir des (au plus) NB_LIRE_LIGNE_SIMUL lignes |
|
// TODO: passer $this, ne sert que pour appeler des méthodes publiques qui pourraient être statiques |
$this->taxon_info_webservice = new RechercheInfosTaxonBeta($this->config, NULL); |
list($enregistrements, $images, $mots_cle) = |
self::chargerLignes($this, $donnees, $this->colonnes_statiques, $dernier_ordre); |
if(! $enregistrements) break; |
286,7 → 322,7 |
$donnees = array(); |
foreach($enregistrements as $e) $donnees = array_merge($donnees, array_values($e)); |
|
/* debug ici: echo $sql_pattern . "\n"; var_dump($enregistrements, $donnees); die;*/ |
// echo $sql_pattern . "\n"; var_dump($enregistrements, $donnees); die; // debug ici |
|
$stmt->execute($donnees); |
|
322,7 → 358,18 |
die(); |
} |
|
static function detectionEntete($entete) { |
/* detectionEntete() sert deux rôles: |
1) détecter le type de colonne attendu à partir des textes de la ligne d'en-tête afin de define() |
2) permet d'identifier les colonnes non-supportées/inutiles afin d'alléger le processus de parsing de PHPExcel |
grace au ReadFilter (C'est le rôle de la valeur de retour) |
|
La raison de la présence du paramètre $numeric_keys est que pour réussir à identifier les colonnes à exclure nous |
devons traiter un tableau représentant la ligne d'en-tête aussi bien: |
- sous forme associative pour PHPExcel (les clefs sont les lettres de l'alphabet) |
- sous forme de clefs numériques (fgetcsv()) |
Le détecter après coup est difficile et pourtant cette distinction est importante car le comportement |
d'array_merge() (réordonnancement des clefs numérique) n'est pas souhaitable dans le second cas. */ |
static function detectionEntete($entete, $numeric_keys = FALSE) { |
$colonnes_reconnues = Array(); |
$cols = FormateurGroupeColonne::nomEnsembleVersListeColonnes('standard,avance'); |
foreach($entete as $k => $v) { |
365,6 → 412,9 |
// ==> Array ( S => Ordre, AA => Phénologie ) |
$colonnesID_a_exclure = array_intersect($entete, $colonnes_automatiques); |
|
if($numeric_keys) { |
return $colonnesID_non_reconnues + $colonnesID_a_exclure; |
} |
// TODO: pourquoi ne pas comparer avec les abbrevs aussi ? |
// merge ( Array( I => rien ) , Array ( S => Ordre, AA => Phénologie ) ) |
// ==> Array ( I => rien, AA => Phénologie ) |
381,6 → 431,9 |
$tous_mots_cle = Array(); |
|
foreach($lignes as $ligne) { |
// dans le cas de fgetcsv, on peut avoir des false additionnel (cf do/while l. 279) |
if($ligne === false) continue; |
|
//$ligne = array_filter($ligne, function($cell) { return !is_null($cell); }); |
//if(!$ligne) continue; |
// on a besoin des NULL pour éviter des notice d'index indéfini |