Subversion Repositories eFlore/Applications.cel

Compare Revisions

No changes between revisions

Ignore whitespace Rev 3856 → Rev 3857

/branches/v3.01-serpe/scripts/cli.php
New file
0,0 → 1,37
<?php
// Encodage : UTF-8
// +-------------------------------------------------------------------------------------------------------------------+
/**
* Initialise le chargement et l'exécution des scripts
*
* Lancer ce fichier en ligne de commande avec :
* <code>/opt/lampp/bin/php cli.php mon_script -a test</code>
*
* @category CEL
* @package Scripts
* @author Mathias CHOUET <mathias@tela-botanica.org>
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @author Aurelien PERONNET <aurelien@tela-botanica.org>
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @copyright 1999-2014 Tela Botanica <accueil@tela-botanica.org>
*/
 
// Le fichier Framework.php du Framework de Tela Botanica doit être appelée avant tout autre chose dans l'application.
// Sinon, rien ne sera chargé.
// Chemin du fichier chargeant le framework requis
$framework = dirname(__FILE__).DIRECTORY_SEPARATOR.'framework.php';
if (!file_exists($framework)) {
$e = "Veuillez paramétrer l'emplacement et la version du Framework dans le fichier $framework";
trigger_error($e, E_USER_ERROR);
} else {
// Inclusion du Framework
require_once $framework;
 
// Ajout d'information concernant cette application
Framework::setCheminAppli(__FILE__);// Obligatoire
Framework::setInfoAppli(Config::get('info'));
 
// Initialisation et lancement du script appelé en ligne de commande
Cli::executer();
}
/branches/v3.01-serpe/scripts/tb_cel.sh
New file
0,0 → 1,54
#!/bin/sh
 
### BEGIN INIT INFO
# Provides: tb_cel
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Should-Start: $all
# Should-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start/stop scripts maintenance CEL
# Description: Start/stop les scripts de maintenance de CEL.
### END INIT INFO
 
#/etc/rc.d/init.d/
#
# Aurélien PERONNET [17 avril 2013]
# Service de lancement des scripts de maintenance du CEL
#
case "$1" in
 
start)
 
echo "Demarrage de code_insee_commune :"
nohup /usr/local/sbin/code_insee_commune.sh 1>/dev/null 2>/dev/null &
 
;;
 
stop)
 
echo "Arret de code_insee_commune"
PID=`ps -eaf | grep code_insee_commune | grep -v grep | tr -s ' ' | cut -d' ' -f2 | head -n1`
kill -9 ${PID}
 
;;
 
status)
 
echo -n "Voici les PID du processus code_insee_commune :"
PID=`ps -eaf | grep code_insee_commune | grep -v grep | tr -s ' ' | cut -d' ' -f2 | head -n1`
echo ${PID}
 
;;
 
 
*)
 
echo "Usage: {start|stop|status}"
 
exit 1
 
;;
 
esac
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/scripts/modules/code_zone_geo/bibliotheque/Dao.php
New file
0,0 → 1,197
<?php
class Dao extends Bdd {
 
private $temps_derniere_requete = 0;
 
public function rechercherCoordonnees($conditions = array()) {
if(!empty($conditions)) {
$where = 'WHERE '.implode(' AND ', $conditions);
}
$requete = "SELECT longitude, latitude ".
"FROM cel_obs ".
$where.
"GROUP BY longitude , latitude ";
$resultat = $this->recupererTous($requete);
$this->reinitialiserTempsDerniereRequete();
return $resultat;
}
 
public function rechercherCoordonneesFrancaisesSansCorrespondances() {
$conditions = array(
$this->getConditionCoordonneesValides(),
$this->getConditionInfosGeoIncompletes(),
$this->getConditionlimiteeALaFrance(),
$this->getConditionModifObsRecente()
);
return $this->rechercherCoordonnees($conditions);
}
public function rechercherCoordonneesFrancaisesSansCorrespondanceDepuisLeDebut() {
$conditions = array(
$this->getConditionCoordonneesValides(),
$this->getConditionInfosGeoIncompletes(),
$this->getConditionlimiteeALaFrance()
);
return $this->rechercherCoordonnees($conditions);
}
public function rechercherPaysSansCorrespondance() {
$conditions = array(
$this->getConditionCoordonneesValides(),
$this->getConditionSansPays(),
$this->getConditionModifObsRecente()
);
return $this->rechercherCoordonnees($conditions);
}
public function rechercherPaysSansCorrespondanceDepuisLeDebut() {
$conditions = array(
$this->getConditionCoordonneesValides(),
$this->getConditionSansPays()
);
return $this->rechercherCoordonnees($conditions);
}
public function rechercherToutSansCorrespondance() {
$conditions = array(
$this->getConditionCoordonneesValides(),
'('.
$this->getConditionInfosGeoIncompletes().' OR '.
$this->getConditionSansPays().
') ',
$this->getConditionModifObsRecente()
);
return $this->rechercherCoordonnees($conditions);
}
public function rechercherSansCorrespondanceDepuisLeDebut() {
$conditions = array(
$this->getConditionCoordonneesValides(),
'('.
$this->getConditionInfosGeoIncompletes().' OR '.
$this->getConditionSansPays().
') '
);
return $this->rechercherCoordonnees($conditions);
}
private function getConditionModifObsRecente() {
$condition = 'DATE_ADD(date_modification, INTERVAL 25 HOUR) >= CURDATE() ';
return $condition;
}
private function getConditionInfosGeoIncompletes() {
$condition = '('.
'ce_zone_geo IS NULL OR ce_zone_geo = "" OR '.
'zone_geo IS NULL OR zone_geo = "" '.
') ';
return $condition;
}
private function getConditionlimiteeALaFrance() {
$condition = '('.
'(latitude <= 51.071667 AND latitude >= 41.316667) AND '.
'(longitude <= 9.513333 AND longitude >= -5.140278) '.
') ';
return $condition;
}
private function getConditionSansPays() {
$condition = '(pays IS NULL OR pays = "XX" OR pays = "")';
return $condition;
}
private function getConditionCoordonneesValides() {
$condition = '(latitude IS NOT NULL AND longitude IS NOT NULL '.
' AND latitude != 0 AND latitude != "" '.
' AND longitude != 0 AND longitude != "" '.
' AND latitude >= -90 AND latitude <= 90 '.
' AND longitude >= -180 AND longitude <= 180) ';
return $condition;
}
 
public function creerColonneCodeInseeCalcule() {
$create = 'ALTER TABLE cel_obs '.
'ADD code_insee_calcule VARCHAR(5) NOT NULL ';
$this->requeter($create);
$this->reinitialiserTempsDerniereRequete();
}
 
public function ajouterCodeInseeCalcule($latitude, $longitude, $code_insee) {
$insert = 'UPDATE cel_obs '.
"SET ".
"code_insee_calcule = ".$this->proteger($code_insee)." ".
"WHERE latitude = ".$this->proteger($latitude)." ".
" AND longitude = ".$this->proteger($longitude)." ";
$this->requeter($insert);
$this->reinitialiserTempsDerniereRequete();
}
public function affecterPaysFranceAuxCommunesRenseignees() {
$update = "UPDATE cel_obs SET pays = 'FR' ".
"WHERE ".
"ce_zone_geo LIKE 'INSEE-C:_____' AND ".
"zone_geo != '' AND ".
"zone_geo IS NOT NULL AND ".
"(pays IS NULL OR pays = '') ";
return $this->executer($update);
}
 
public function modifierCodeInseeEtZoneGeo($coordonnees) {
$codeP = $this->proteger($coordonnees['code_insee']);
$codeInseeP = $this->proteger('INSEE-C:'.$coordonnees['code_insee']);
$nomP = $this->proteger($coordonnees['nom']);
$update = "UPDATE cel_obs ".
"SET ".
"pays = 'FR', ".
"code_insee_calcule = ".$codeP.", ".
"ce_zone_geo = ".$codeInseeP.", ".
"zone_geo = IF(zone_geo = '' OR zone_geo = NULL, ".$nomP.", zone_geo) ".
"WHERE ".
" latitude = ".$this->proteger($coordonnees['latitude'])." ".
" AND longitude = ".$this->proteger($coordonnees['longitude'])." ";
$this->requeter($update);
$this->reinitialiserTempsDerniereRequete();
}
public function modifierPays($coordonnees) {
$codePaysP = $this->proteger($coordonnees['code_pays']);
$nomP = $this->proteger($coordonnees['nom']);
$update = "UPDATE cel_obs ".
"SET ".
"pays = ".$codePaysP.", ".
"zone_geo = IF(zone_geo = '' OR zone_geo = NULL, ".$nomP.", zone_geo) ".
"WHERE ".
" latitude = ".$this->proteger($coordonnees['latitude'])." ".
" AND longitude = ".$this->proteger($coordonnees['longitude'])." ";
$this->requeter($update);
$this->reinitialiserTempsDerniereRequete();
}
 
// Il peut se passer assez de temps sans qu'aucune requete ne soit effectuée
// (cas d'un grand nombre d'enregistrements à la suite pour lesquels on ne trouve
// aucun département). Pour éviter cela on teste régulièrement la connection
public function testerActiviteConnection() {
$temps_courant = microtime(true);
$temps_depuis_derniere_requete = $temps_courant - $this->temps_derniere_requete;
if($temps_depuis_derniere_requete >= 18) {
$this->ping();
$this->reinitialiserTempsDerniereRequete();
}
}
 
private function reinitialiserTempsDerniereRequete() {
$this->temps_derniere_requete = microtime(true);
}
}
/branches/v3.01-serpe/scripts/modules/code_zone_geo/CodeZoneGeo.php
New file
0,0 → 1,312
<?php
// declare(encoding='UTF-8');
/**
* Traitement des codes INSEE et des codes pays de la base de données CEL
* Permet d'affecter des codes INSEE et des codes pays aux obs possédant des coordonnées mais pas de commune ou de pays.
*
* Utilisation :
* - Pour ? : <code>/opt/lamp/bin/php cli.php code_zone_geo -a tout</code>
* - Pour ? : <code>/opt/lamp/bin/php cli.php code_zone_geo -a colonne</code>
* - Pour ? : <code>/opt/lamp/bin/php cli.php code_zone_geo -a payssanscorrespondance</code>
* - Pour ? : <code>/opt/lamp/bin/php cli.php code_zone_geo -a codeinseesanscorrespondance</code>
*
* @category CEL
* @package Scripts
* @subpackage Zones Geo
* @author Mathias CHOUET <mathias@tela-botanica.org>
* @author Aurelien PERONNET <aurelien@tela-botanica.org>
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @copyright 1999-2014 Tela Botanica <accueil@tela-botanica.org>
*/
include_once dirname(__FILE__).'/bibliotheque/Dao.php';
 
class CodeZoneGeo extends Script {
 
protected $tableauTaxon;
protected $dao;
protected $observations;
protected $url_service_geo_tpl;
protected $url_service_pays_tpl;
 
protected $mode_verbeux = false;
 
// Paramêtres autorisées lors de l'appel au script en ligne de commande
protected $parametres_autorises = array(
'-n' => array(true, true, 'Nom du fichier ou du dossier à traiter'));
 
public function executer() {
$this->url_service_geo_tpl = Config::get('urlZoneGeoTpl');
$this->url_service_pays_tpl = Config::get('urlPaysTpl');
 
$this->dao = new Dao();
// Récupération de paramétres
// Lancement de l'action demandée
$cmd = $this->getParametre('a');
$this->mode_verbeux = $this->getParametre('v');
 
switch ($cmd) {
case 'tout' :
// à effectuer manuellement au premier lancement du script
$this->creerColonne();
$this->calculerToutSansCorrespondanceDepuisLeDebut();
break;
case 'colonne' :
$this->creerColonne();
break;
case 'codeinseesanscorrespondance' :
$this->calculerCodesInseeSansCorrespondance();
break;
case 'codeinseesanscorrespondancedepuisledebut' :
$this->calculerCodesInseeSansCorrespondanceDepuisLeDebut();
break;
case 'payssanscorrespondance' :
$this->calculerPaysSansCorrespondance();
break;
case 'payssanscorrespondancedepuisledebut' :
$this->calculerPaysSansCorrespondanceDepuisLeDebut();
break;
case 'toutsanscorrespondance' :
// devrait être être l'option utilisée dans le cron quotidien (avec l'option -v 0)
$this->calculerToutSansCorrespondance();
break;
case 'toutsanscorrespondancedepuisledebut' :
$this->calculerToutSansCorrespondanceDepuisLeDebut();
break;
default :
$this->traiterErreur('Erreur : la commande "%s" n\'existe pas!', array($cmd));
}
}
 
protected function creerColonne() {
$this->dao->creerColonneCodeInseeCalcule();
}
 
protected function calculerCodesInseeSansCorrespondance() {
$liste_coordonnees = $this->dao->rechercherCoordonneesFrancaisesSansCorrespondances();
$this->traiterCoordonnees($liste_coordonnees);
}
protected function calculerCodesInseeSansCorrespondanceDepuisLeDebut() {
$liste_coordonnees = $this->dao->rechercherCoordonneesFrancaisesSansCorrespondanceDepuisLeDebut();
$this->traiterCoordonnees($liste_coordonnees);
}
protected function calculerPaysSansCorrespondance() {
$liste_coordonnees = $this->dao->rechercherPaysSansCorrespondance();
$this->traiterCoordonnees($liste_coordonnees);
}
protected function calculerPaysSansCorrespondanceDepuisLeDebut() {
$liste_coordonnees = $this->dao->rechercherPaysSansCorrespondanceDepuisLeDebut();
$this->traiterCoordonnees($liste_coordonnees);
}
protected function calculerToutSansCorrespondance() {
$this->affecterPaysFranceAuxCommunes();
$liste_coordonnees = $this->dao->rechercherToutSansCorrespondance();
$this->traiterCoordonnees($liste_coordonnees);
}
 
protected function calculerToutSansCorrespondanceDepuisLeDebut() {
$this->affecterPaysFranceAuxCommunes();
$liste_coordonnees = $this->dao->rechercherSansCorrespondanceDepuisLeDebut();
$this->traiterCoordonnees($liste_coordonnees);
}
protected function affecterPaysFranceAuxCommunes() {
if ($this->mode_verbeux) {
echo "-------------------------------------------------------------------\n";
echo " Affectation du pays France aux communes ayant un code INSEE mais pas de pays ... ";
}
$maj = $this->dao->affecterPaysFranceAuxCommunesRenseignees();
if ($this->mode_verbeux) {
echo "OK \n";
echo " ".$maj." commune".($maj > 1 ? 's' : '')." affectée".($maj > 1 ? 's' : '')."\n";
echo "-------------------------------------------------------------------\n";
}
}
 
private function traiterCoordonnees($liste_coordonnees) {
$debut = microtime(true);
$nb_coordonnees_modifiees = 0;
$nb_coordonnees_ignorees = 0;
$total = count($liste_coordonnees);
 
if ($this->mode_verbeux) {
echo "-------------------------------------------------------------------\n";
echo " Calcul des codes INSEE, du code pays et modification (".count($liste_coordonnees)." coordonnées en tout) ... \n";
echo " Enrichissement des champs zone geo et ce_zone_geo vides ... \n";
echo "-------------------------------------------------------------------\n";
}
 
foreach ($liste_coordonnees as $coordonnees) {
$infos_coord = $this->obtenirInfosPourCoordonnees($coordonnees);
if ($infos_coord != null) {
// Le type renvoyé permet de connaitre ce qu'on peut modifier
if($infos_coord['type'] == 'france') {
// Cas d'une commune française
$coordonnee_a_traiter = array(
'latitude' => $coordonnees['latitude'],
'longitude' => $coordonnees['longitude'],
'code_insee' => $infos_coord['code_insee'],
'nom' => $infos_coord['nom']
);
$this->dao->modifierCodeInseeEtZoneGeo($coordonnee_a_traiter);
} else if($infos_coord['type'] == 'pays') {
// Cas d'un lieu à l'étranger
$coordonnee_a_traiter = array(
'latitude' => $coordonnees['latitude'],
'longitude' => $coordonnees['longitude'],
'code_pays' => $infos_coord['code_pays'],
'nom' => $infos_coord['nom']
);
$this->dao->modifierPays($coordonnee_a_traiter);
}
$nb_coordonnees_modifiees++;
} else {
$nb_coordonnees_ignorees++;
}
if ($this->mode_verbeux) {
$this->afficherAvancement(' Coordonnées traitées ', $nb_coordonnees_modifiees);
}
}
 
$fin = microtime(true);
if ($this->mode_verbeux) {
echo "\n";
echo "-------------------------------------------------------------------\n";
echo " Fin de la mise à jour des codes INSEE calculés, du pays et de l'enrichissement, \n";
echo " ".($fin - $debut)." secondes écoulées \n";
echo " ".$nb_coordonnees_modifiees." code insee calculés et modifiés \n";
echo " ".$nb_coordonnees_ignorees." coordonnées ignorées \n";
echo "-------------------------------------------------------------------\n";
echo "\n";
}
}
 
private function obtenirInfosPourCoordonnees($coordonnees) {
$infos_coord = null;
// Test facile qui permet d'abord de tenter une localisation bien plus rapide si les coordonnées
// sont dans la bounding box approximative de la France
if($this->testerCoordonneesWgsFrance($coordonnees['latitude'], $coordonnees['longitude'])) {
$infos_coord = $this->chercherInfosCommune('osm', $coordonnees['latitude'], $coordonnees['longitude']);
if ($infos_coord == null) {
// Sinon recherche par pays
$infos_coord = $this->chercherInfosPays($coordonnees['latitude'], $coordonnees['longitude']);
}
} else {
// Recherche par pays immédiate si en dehors de la bouding box française
$infos_coord = $this->chercherInfosPays($coordonnees['latitude'], $coordonnees['longitude']);
}
return $infos_coord;
}
 
private function chercherInfosCommune($projet, $latitude, $longitude) {
$noms_params = array('{projet}', '{latitude}', '{longitude}');
$valeurs_params = array($projet, $latitude, $longitude);
$url_service = str_replace($noms_params, $valeurs_params, $this->url_service_geo_tpl);
$url_service = str_replace(',', '.', $url_service);
 
$ch = curl_init($url_service);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$reponse = curl_exec($ch);
 
$infos_coord = $this->traiterReponseServiceCommune($reponse);
curl_close($ch);
 
return $infos_coord;
}
private function chercherInfosPays($latitude, $longitude) {
$noms_params = array('{latitude}', '{longitude}');
$valeurs_params = array($latitude, $longitude);
$url_service = str_replace($noms_params, $valeurs_params, $this->url_service_pays_tpl);
$url_service = str_replace(',', '.', $url_service);
 
$ch = curl_init($url_service);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$reponse = curl_exec($ch);
$res = json_decode($reponse, true);
$retour = null;
if(!empty($res)) {
// Cas où l'on a recherché des coordonnées en France
// On en profite pour remplir plus de données
// que le simple pays si elles sont présentes
if(isset($res[8]) && isset($res[8]['codeInsee'])) {
$retour = array(
'code_insee' => $res[8]['codeInsee'],
'nom' => $res[8]['intitule'],
'type' => 'france'
);
} else {
// Cas de la recherche en dehors de France
// La zone de plus haut niveau est toujours un pays
// (car le niveau de zone est limité à 2)
$infos_pays = $res[min(array_keys($res))];
// La zone de niveau le plus bas est la "localité"
// la plus précise qu'on a pu trouver
$infos_localite = $res[max(array_keys($res))];
// Cas où l'on a trouvé un code pays
if(!empty($infos_pays['codeIso31661'])) {
$retour = array(
'code_pays' => $infos_pays['codeIso31661'],
'nom' => ''
);
} elseif(!empty($infos_pays['codeIso31662'])) {
// Quelquefois la zone de plus haut niveau est une région ou une province
// heureusement son code est de forme XX-YY ou XX est le code iso du pays !
$retour = array(
'code_pays' => substr($infos_pays['codeIso31662'], 0, 2),
'nom' => ''
);
}
// Pas de sens de prendre un nom de localité si on a pas de pays
if(!empty($retour['code_pays'])) {
// Type sert à savoir quelle fonction de mise à jour on appellera
$retour['type'] = 'pays';
$retour['nom'] = $infos_localite['intitule'];
}
}
}
return $retour;
}
 
private function traiterReponseServiceCommune($reponse) {
$retour = null;
$reponse = json_decode($reponse);
// cas du service lion 1906 qui peut renvoyer plusieurs communes (on prend la première)
if (is_array($reponse)) {
$reponse = $reponse[0];
}
if (isset($reponse->codeINSEE)) {
// Type sert à savoir quelle fonction de mise à jour on appellera
$retour = array('code_insee' => $reponse->codeINSEE,
'nom' => $reponse->nom,
'type' => 'france');
}
return $retour;
}
private function testerCoordonneesWgsFrance($latitude, $longitude) {
$coord_france = false;
if ($latitude != '' && $longitude != '') {
if ($latitude < 51.071667 && $latitude > 41.316667) {
if ($longitude < 9.513333 && $longitude > -5.140278) {
$coord_france = true;
}
}
}
return $coord_france;
}
}
/branches/v3.01-serpe/scripts/modules/code_zone_geo/code_zone_geo.sh
New file
0,0 → 1,12
#!/bin/bash
#
# /usr/local/sbin/code_zone_geo.sh : traitement du calcul des codes INSEE et pays du cel
# Aurélien Peronnet [11 avril 2013]
#
while true
do
logger "Lancement script cel::code_zone_geo"
sudo -u apitela /usr/local/bin/php-cli-56 -f /home/apitela/www/scripts/cel/cli.php code_zone_geo -a toutsanscorrespondance -v 0
logger "Arret script cel::code_zone_geo"
sleep 86400
done
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:executable
+*
\ No newline at end of property
/branches/v3.01-serpe/scripts/modules/migrat2019/Migrat2019.php
New file
0,0 → 1,206
<?php
// declare(encoding='UTF-8');
/**
* Migration des données CEL vers la base 2019 après avoir lancer le script nettoyage
*
* Utilisation :
* - migrer les mots-clés obs : <code>/opt/lamp/bin/php cli.php migration_mots_cles -a obs</code>
* - migrer les mots-clés images : <code>/opt/lamp/bin/php cli.php migration_mots_cles -a images</code>
*
* @category CEL
* @package Scripts
* @subpackage Migration : Mots-Clés
* @author Mathias CHOUET <mathias@tela-botanica.org>
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @author Aurelien PERONNET <aurelien@tela-botanica.org>
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @copyright 1999-2014 Tela Botanica <accueil@tela-botanica.org>
*/
 
class Migrat2019 extends Script {
 
private $mode;
private $bd_new_cel = "tb_new_cel";
public function __construct($script_nom, $parametres_cli) {
parent::__construct($script_nom, $parametres_cli);
$this->bdd = new Bdd();
$this->bd_new_cel = Config::get('nettoyage.cel_new');
$this->bd_cel = Config::get('nettoyage.cel_nettoye');
}
 
public function executer() {
$cmd = $this->getParametre('a');
$this->mode_verbeux = $this->getParametre('v');
 
switch($cmd) {
case 'tout' :
$this->migrerObservations();
$this->migrerProjet();
$this->migrerObsEtendusChampsUtilisateur();
$this->migrerObsEtendusUtilisateur();
$this->migrerObsEtendusProjet();
$this->migrerMotsClesObs();
$this->migrerMotsClesObsLiaison();
$this->migrerImages();
$this->migrerMotsClesImages();
$this->migrerMotsClesImagesLiaison();
$this->ajouterIdProjet();
break;
case 'obs':
$this->migrerObservations();
break;
case 'projet':
$this->migrerProjet();
break;
case 'obs_etendus':
$this->migrerObsEtendusChampsUtilisateur();
$this->migrerObsEtendusUtilisateur();
$this->migrerObsEtendusProjet();
break;
case 'obs_mots_cles':
$this->migrerMotsClesObs();
$this->migrerMotsClesObsLiaison();
break;
case 'images':
$this->migrerImages();
break;
case 'images_tag':
$this->migrerMotsClesImages();
$this->migrerMotsClesImagesLiaison();
break;
case 'projet_id':
$this->ajouterIdProjet();
break;
default:
echo 'Méthode inconnue, les méthodes possibles sont obs et images'."\n";
}
}
 
private function migrerObservations() {
$requete = "ALTER TABLE ".$this->bd_new_cel.".`occurrence` ADD IF NOT EXISTS project varchar(50);";
$this->bdd->requeter($requete);
$requete = "INSERT INTO ".$this->bd_new_cel.".`occurrence`
(id, project, user_id, user_email, user_pseudo, date_observed, date_created, date_updated, date_published, user_sci_name, user_sci_name_id, accepted_sci_name, accepted_sci_name_id, family, certainty, annotation, coef, phenology, input_source, is_public, is_visible_in_cel, geometry, elevation, geodatum, locality, locality_insee_code, sublocality, environment, locality_consistency, station, published_location, osm_country, taxo_repo)
SELECT id_observation, CASE WHEN `mots_cles_texte` like '%sauvages%' then 'sauvages' WHEN `mots_cles_texte` like '%missions-flore%' then 'missions-flore' WHEN `mots_cles_texte` like '%arbres-tetards%' then 'arbres-tetards' WHEN `mots_cles_texte` like '%arbres-remarquables%' then 'arbres-remarquables' WHEN `mots_cles_texte` like '%bellesdemarue%' then 'bellesdemarue' WHEN `mots_cles_texte` like '%biodiversite34%' then 'biodiversite34' WHEN `mots_cles_texte` like '%messicoles%' then 'messicoles' WHEN `mots_cles_texte` like '%florileges%' then 'florileges' END,
ce_utilisateur, courriel_utilisateur, concat (prenom_utilisateur, ' ', nom_utilisateur), date_observation, date_creation, date_modification, date_transmission, nom_sel, nom_sel_nn, nom_ret, nom_ret_nn, famille, certitude, commentaire, abondance, phenologie, input_source, transmission, 1,
CONCAT('{\"type\":\"Point\",\"coordinates\":[', longitude, ',', latitude,']}'), altitude, geodatum, zone_geo, ce_zone_geo, lieudit, milieu, locality_consistency, station, published_location, pays, nom_referentiel
FROM ".$this->bd_cel.".`cel_obs`";
 
$this->bdd->requeter($requete);
}
private function migrerObsEtendusChampsUtilisateur() {
$requete = "ALTER TABLE ".$this->bd_new_cel.".`user_custom_field` ADD IF NOT EXISTS `field_id` VARCHAR(500) NOT NULL AFTER `default_value`;";
$this->bdd->requeter($requete);
$requete = "INSERT INTO ".$this->bd_new_cel.".`user_custom_field`
(name, data_type, default_value, field_id)
SELECT label, 'Texte', '', cle
FROM ".$this->bd_cel.".`cel_catalogue_champs_etendus`
WHERE `cle` not in (SELECT `champ` FROM ".$this->bd_cel.".`cel_catalogue_champs_etendus_liaison`)";
$this->bdd->requeter($requete);
}
private function migrerObsEtendusUtilisateur() {
$requete = "INSERT INTO ".$this->bd_new_cel.".`user_custom_field_occurrence`
(`occurrence_id`, `user_custom_field_id`, `value`)
SELECT `id_observation`, id, `valeur`
FROM ".$this->bd_cel.".`cel_obs_etendues`
RIGHT JOIN ".$this->bd_new_cel.".`user_custom_field` ON field_id = cle
WHERE id_observation in (select id FROM ".$this->bd_new_cel.".`occurrence`)";
$this->bdd->requeter($requete);
}
private function migrerObsEtendusProjet() {
$requete = "INSERT INTO ".$this->bd_new_cel.".`extended_field_occurrence`
(`occurrence_id`, `extended_field_id`, `value`)
SELECT `id_observation`, id, `valeur`
FROM ".$this->bd_cel.".`cel_obs_etendues`
RIGHT JOIN ".$this->bd_new_cel.".`extended_field` ON field_id = cle
WHERE id_observation in (select id FROM ".$this->bd_new_cel.".`occurrence`)";
$this->bdd->requeter($requete);
}
private function migrerProjet() {
$requete = "INSERT INTO ".$this->bd_new_cel.".`project_settings` (`id`, `project_id`, `project`, `language`, `title`, `logo`, `description`, `type`, `is_type`, `css_style`, `image_font`, `date_created`, `date_updated`, `taxo_restriction_type`, `taxo_restriction_value`, `location_type`, `location`, `published_location`, `environment`, `project_tag_name`, `info`)
SELECT * FROM ".$this->bd_cel.".`project_settings`";
$this->bdd->requeter($requete);
$requete = "INSERT INTO ".$this->bd_new_cel.".`extended_field` (`id`, `project_id`, `field_id`, `project`, `data_type`, `is_visible`, `is_mandatory`, `min_value`, `max_value`, `regexp`, `unit`)
SELECT * FROM ".$this->bd_cel.".`extended_field`";
$this->bdd->requeter($requete);
$requete = "INSERT INTO ".$this->bd_new_cel.".`extendedfield_translation`(`id`, `extended_field_id`, `project`, `label`, `description`, `default_value`, `error_message`, `language_iso_code`, `help`)
SELECT * FROM ".$this->bd_cel.".`extendedfield_translation`";
$this->bdd->requeter($requete);
}
private function migrerMotsClesObs() {
$requete = "INSERT INTO ".$this->bd_new_cel.".user_occurrence_tag
(id, user_id, name, path)
SELECT id_mot_cle, id_utilisateur, mot_cle, chemin
FROM ".$this->bd_cel.".`cel_arbre_mots_cles_obs`";
$this->bdd->requeter($requete);
}
private function migrerMotsClesObsLiaison() {
$requete = "INSERT INTO ".$this->bd_new_cel.".occurrence_user_occurrence_tag
(occurrence_id, user_occurrence_tag_id)
SELECT `id_element_lie`, `id_mot_cle` FROM ".$this->bd_cel.".`cel_mots_cles_obs_liaison`";
$this->bdd->requeter($requete);
}
private function migrerImages() {
$requete = "INSERT INTO ".$this->bd_new_cel.".photo
(id, occurrence_id, user_id, user_pseudo, user_email, date_shot, original_name, mime_type,
date_updated, date_created, date_linked_to_occurrence, content_url, size, url)
SELECT id_image, ce_observation, ce_utilisateur, prenom_utilisateur,
courriel_utilisateur, date_prise_de_vue, nom_original,'' , date_modification,
date_creation, date_liaison, '', '6444444',concat('https://api.tela-botanica.org/img:',
lpad(`id_image`, 9, '0'), 'O')
FROM ".$this->bd_cel.".cel_images";
$this->bdd->requeter($requete);
$requete_jpg = 'UPDATE `photo` SET `mime_type` = "image/jpeg", `content_url`= concat('.Config::get('nettoyage.chemin_photo').
',substr(lpad(id, 9, "0"),1,3),"/",substr(lpad(id, 9, "0"),4,3),"/O/",substr(lpad(id, 9, "0"),1,3),"_",substr(lpad(id, 9, "0"),4,3),"_",substr(lpad(id, 9, "0"),7,3),"_O",substr(`original_name` , char_length(`original_name`) - locate('.', reverse(`original_name`)) +1, locate('.', reverse(`original_name`))))
WHERE `original_name` like "%.jp%" and content_url = ""';
$this->bdd->requeter($requete_jpg);
$requete_png = 'UPDATE `photo` SET `mime_type` = "image/png", `content_url`= concat('.Config::get('nettoyage.chemin_photo').
',substr(lpad(id, 9, "0"),1,3),"/",substr(lpad(id, 9, "0"),4,3),"/O/",substr(lpad(id, 9, "0"),1,3),"_",substr(lpad(id, 9, "0"),4,3),"_",substr(lpad(id, 9, "0"),7,3),"_O",substr(`original_name` , char_length(`original_name`) - locate('.', reverse(`original_name`)) +1, locate('.', reverse(`original_name`))))
WHERE `original_name` like "%.png" and content_url = ""';
$this->bdd->requeter($requete_png);
'UPDATE `photo` SET `mime_type` = "image/jpeg", `content_url`= concat('.Config::get('nettoyage.chemin_photo').
',substr(lpad(id, 9, "0"),1,3),"/",substr(lpad(id, 9, "0"),4,3),"/O/",substr(lpad(id, 9, "0"),1,3),"_",substr(lpad(id, 9, "0"),4,3),"_",substr(lpad(id, 9, "0"),7,3),"_O.jpg")
WHERE content_url = "" and (`original_name` != "" or `original_name` is null)';
}
 
private function migrerMotsClesImages() {
$requete = "INSERT INTO ".$this->bd_new_cel.".photo_tag
(id, user_id, name, path)
SELECT id_mot_cle, id_utilisateur, mot_cle, chemin
FROM ".$this->bd_cel.".`cel_arbre_mots_cles_images`";
$this->bdd->requeter($requete);
}
private function migrerMotsClesImagesLiaison() {
$requete = "INSERT INTO ".$this->bd_new_cel.".photo_tag_photo
(photo_id, photo_tag_id)
SELECT `id_element_lie`, `id_mot_cle` FROM ".$this->bd_cel.".`cel_mots_cles_images_liaison`";
$this->bdd->requeter($requete);
}
private function ajouterIdProjet() {
$requete = "UPDATE ".$this->bd_new_cel.".`project_settings` SET `project_id` = `id`";
$this->bdd->requeter($requete);
$requete = "INSERT INTO ".$this->bd_new_cel.".`tb_project`(`id`, `label`, `is_private`) SELECT `id`, `project`, '0' FROM ".$this->bd_new_cel.".`project_settings` ";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_new_cel.".`extended_field` f right join ".$this->bd_new_cel.".`project_settings` s on
s.`project` = f.`project` SET f.`project_id` = s.`project_id`";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_new_cel.".`occurrence` o right join ".$this->bd_new_cel.".`project_settings` s on
s.`project` = o.`project` SET o.`project_id` = s.`project_id`";
$this->bdd->requeter($requete);
}
 
 
}
/branches/v3.01-serpe/scripts/modules/nettoyage/Nettoyage.php
New file
0,0 → 1,955
<?php
// declare(encoding='UTF-8');
/**
* Classe de nettoyage de la base de données du CEL.
* Suppression des antislash
* Remplacement des chaines vides par des NULL
* Unifier les référentiels : pas de nom de version, majuscule...
* Unifier les certitudes
* Supprimer les INSEE-C: non rempli, les dates 0000-00
*
* Utilisation :
* - <code>/opt/lamp/bin/php cli.php nettoyage -a (voir méthode executer)</code>
*
* @category CEL
* @package Scripts
* @subpackage Nettoyage
* @author Delphine CAUQUIL <delphine@tela-botanica.org>
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @copyright 1999-2016 Tela Botanica <accueil@tela-botanica.org>
*/
class Nettoyage extends Script {
 
protected $bdd;
protected $colonnes;
protected $bd_cel = "tb_nettoye_cel";
protected $bd_del = "tb_del";
protected $bd_flore = "tb_eflore";
 
 
public function __construct($script_nom, $parametres_cli) {
parent::__construct($script_nom, $parametres_cli);
$this->bdd = new Bdd();
$this->bd_cel = Config::get('nettoyage.cel_nettoye');
$this->bd_del = Config::get('nettoyage.del');
$this->bd_flore = Config::get('nettoyage.flore');
}
 
public function executer() {
$cmd = $this->getParametre('a');
$requete_colonnes = "SELECT column_name FROM information_schema.columns WHERE table_name = 'cel_obs' AND table_schema='".$this->bd_cel."';";
$this->colonnes = $this->bdd->recupererTous($requete_colonnes);
try {
switch ($cmd) {
case 'tout' :
$this->supprimerRetourLigne();
$this->supprimerAntislash();
$this->supprimerGuillemet();
$this->unifierNull();
$this->unifierNomReferentiel();
$this->unifierCertitude();
//$this->supprimerCertitudeAutre();
$this->unifierUtilisateur();
$this->unifierPhenologie();
$this->verifierCodeInsee();
$this->verifierGeodatum();
$this->supprimerInfosLiesObsInexistante();
$this->supprimerImagesetTagAnonymes();
$this->analyserMotsCles();
$this->changerSensible();
$this->unifierNull();
break;
case 'supprimerRetourLigne' :
$this->supprimerRetourLigne();
break;
case 'supprimerAntislash' :
$this->supprimerAntislash();
break;
case 'supprimerGuillemet' :
$this->supprimerGuillemet();
break;
case 'unifierNomReferentiel' :
$this->unifierNomReferentiel();
break;
case 'unifierCertitude' :
$this->unifierCertitude();
break;
case 'supprimerCertitudeAutre' : // après unifier certitude si les autres valeurs sont bien à supprimer
$this->supprimerCertitudeAutre();
break;
case 'analyserMotsCles' : // après unifier certitude si les autres valeurs sont bien à supprimer
$this->analyserMotsCles();
break;
case 'verifierGeodatum' :
$this->verifierGeodatum();
break;
case 'verifierCodeInsee' :
$this->verifierCodeInsee();
break;
case 'sensible' :
$this->changerSensible();
break;
case 'unifierNull' : // lancer en dernier pour bien réussir
$this->unifierNull();
break;
case 'supprimerImagesetTagAnonymes' :
$this->supprimerImagesetTagAnonymes();
break;
case 'supprimerInfosLiesObsInexistante' :
$this->supprimerInfosLiesObsInexistante();
break;
case 'unifierUtilisateur' :
$this->unifierUtilisateur();
break;
case 'unifierInfosEspece' :
$this->unifierInfosEspeces();
break;
case 'unifierPhenologie' :
$this->unifierPhenologie();
break;
case 'unifierTag' :
$this->unifierUtilisateurTag("cel_arbre_mots_cles_obs");
$this->unifierUtilisateurTag("cel_arbre_mots_cles_images");
break;
default :
$msg = "Erreur : la commande '$cmd' n'existe pas!\n".
"Commandes existantes : regenererMotsClesTexteObs, regenererMotsClesTexteImages"
. ", regenererMotsClesTexteObsTout, regenererMotsClesTexteImagesTout"
. ", viderMotsClesTexteImagesSansMotsCles, viderMotsClesTexteObsSansMotsCles"
. ", regenererChampsTailleImage, reparerLiaisonsOublieesObs, reparerLiaisonsOublieesImages"
. ", reparerLiaisonsObsParMotsClesTexte, reductionMotsClesImages, reductionMotsClesImagesUtil"
. ", reduireEtNormaliserMotsClesImagesUtil, reduireEtNormaliserMotsClesImages"
. ", reductionMotsClesObs, reductionMotsClesObsUtil, reduireEtNormaliserMotsClesObsUtil"
. ", reduireEtNormaliserMotsClesObs";
throw new Exception($msg);
}
} catch (Exception $e) {
$this->traiterErreur($e->getMessage());
}
}
 
private function supprimerRetourLigne() {
foreach ($this->colonnes as $id=>$colonne) {
echo "Suppression des retour ligne dans la colonne ".$colonne['column_name']." ...";
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET ".$colonne['column_name']." = REPLACE(".$colonne['column_name'].', "\n", "")';
$this->bdd->requeter($requete);
echo "effectuée \n";
}
}
private function supprimerAntislash() {
foreach ($this->colonnes as $id=>$colonne) {
echo "Suppression des antislash dans la colonne ".$colonne['column_name']." ...";
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET ".$colonne['column_name']." = REPLACE(".$colonne['column_name'].', "\\\", "")';
$this->bdd->requeter($requete);
echo "effectuée \n";
}
}
private function supprimerGuillemet() {
foreach ($this->colonnes as $id=>$colonne) {
echo "Suppression des guillements dans la colonne ".$colonne['column_name']." ...";
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET ".$colonne['column_name']." = REPLACE(".$colonne['column_name'].',"\"", "")';
$this->bdd->requeter($requete);
echo "effectuée \n";
}
}
private function unifierNull() {
foreach ($this->colonnes as $id=>$colonne) {
echo "Suppression des vides dans la colonne ".$colonne['column_name']." ...";
$dsl = array( 'transmission', 'altitude');
if (isset($dsl[$colonne['column_name']])) {
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET ".$colonne['column_name']." = NULL WHERE trim(".$colonne['column_name'].") = '' and ".$colonne['column_name']." != '0'";
} else {
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET ".$colonne['column_name']." = NULL WHERE trim(".$colonne['column_name'].") = '' OR ".$colonne['column_name']." IN ('INSEE-C:', '0000-00-00 00:00:00', '0.00000')";
}
$this->bdd->requeter($requete);
echo "effectuée \n";
}
}
private function unifierCertitude() {
echo "Uniformisation du champ certitude/identification";
$certitude = array("A déterminer" => "à déterminer",
"À déterminer, voir photo" => "à déterminer",
"A déterminer" => "à déterminer",
"aDeterminer" => "à déterminer",
"déterminer" => "à déterminer",
"Inconnue" => "à déterminer",
"Ceraine" => "certain",
"certain" => "certain",
"Certainaaua" => "certain",
"Certaine" => "certain",
"Certaine K- rhizines blanche" => "certain",
"Certaine ( mais voir notes)" => "certain",
"Certaine (à 99%)" => "certain",
"Certaine Anett" => "certain",
"Certaine Anette" => "certain",
"Certaine Valériane officinale" => "certain",
"Certaine, Faite et confirmée par JM BERAUD" => "certain",
"Certaine, par Jean Lebail" => "certain",
"Certaine, subsp. minus" => "certain",
"Certainea" => "certain",
"Certaineanno" => "certain",
"Certainearia n" => "certain",
"Certainee" => "certain",
"Certainej" => "certain",
"Certainel" => "certain",
"CertaineNom de travai" => "certain",
"CertaineNom de travail" => "certain",
"Certainesites" => "certain",
"Certainesous-bois de feuillus en versant sud à sud-ouest" => "certain",
"Certaineu" => "certain",
"sure" => "certain",
"validée sur forum Naturalistes de l'ouest" => "certain",
"à confirmer" => "douteux",
"à approfondir" => "douteux",
"à cofirmer" => "douteux",
"À confiermer" => "douteux",
"A confirlmer" => "douteux",
"A confirmer" => "douteux",
"à confirmer vs. pumilum" => "douteux",
"à conirmer" => "douteux",
"à vérifier" => "douteux",
"douteuse" => "douteux",
"Douteuse (canadensis ?)" => "douteux",
"Douteuse ?" => "douteux",
"Douteuse à confirmer" => "douteux",
"Douteuse peut-être cordata" => "douteux",
"Douteuse, fleurs rouges" => "douteux",
"douteux" => "douteux",
"espèce bisannuelle mais non bien déterminée" => "douteux",
"Incertaine" => "douteux",
"Pavot douteux" => "douteux",
"Potentille ansérine, supposé" => "douteux",
"presque certaine" => "douteux",
"Quasi Certaine" => "douteux",
"ssp déterminer" => "douteux",
"subsp à vérifier" => "douteux",
"subsp. microphyllum ?" => "douteux",
"très douteuse" => "douteux",
"Très probable" => "douteux");
foreach ($certitude as $valeur=>$saisie) {
$requete = 'UPDATE '.$this->bd_cel.'.cel_obs SET commentaire = concat(commentaire, " Certitude : ", certitude), certitude = "'.$saisie.'" WHERE certitude ="'.$valeur.'"';
$this->bdd->requeter($requete);
echo "effectuée \n";
}
$requete_verif = "SELECT certitude FROM ".$this->bd_cel.".cel_obs WHERE certitude NOT IN ('douteux', 'certain', 'à déterminer', '') and certitude is not NULL";
$verif = $this->bdd->recupererTous($requete_verif);
if ($verif != array()) print_r($verif);
}
private function supprimerCertitudeAutre() {
echo "suppression des valeurs non compréhensible du champ certitude/identification";
$requete = "UPDATE ".$this->bd_cel.".cel_obs
SET commentaire = case isnull(commentaire) when 1 THEN certitude ELSE concat(commentaire, ' Certitude : ', certitude) END,
certitude = '' WHERE `certitude` NOT IN ('douteux', 'certain', 'à déterminer', '') and certitude is not NULL";
$this->bdd->requeter($requete);
echo "effectuée \n";
$requete_verif = "SELECT certitude FROM ".$this->bd_cel.".cel_obs WHERE certitude NOT IN ('douteux', 'certain', 'à déterminer', '') and certitude is not NULL";
$verif = $this->bdd->recupererTous($requete_verif);
if ($verif != array()) print_r($verif);
}
private function unifierPhenologie() {
echo "Uniformisation du champ phenologie";
$phenologie = array("2" => "00-09: germination, développement des bourgeons",
"5" => "00-09: germination, développement des bourgeons",
"5" => "00-09: germination, développement des bourgeons",
"8" => "00-09: germination, développement des bourgeons",
"8" => "00-09: germination, développement des bourgeons",
"9" => "00-09: germination, développement des bourgeons",
"00-09" => "00-09: germination, développement des bourgeons",
"Germination, développement des bourgeons" => "00-09: germination, développement des bourgeons",
"10" => "10-19: développement des feuilles",
"11" => "10-19: développement des feuilles",
"12" => "10-19: développement des feuilles",
"14" => "10-19: développement des feuilles",
"15" => "10-19: développement des feuilles",
"16" => "10-19: développement des feuilles",
"17" => "10-19: développement des feuilles",
"18" => "10-19: développement des feuilles",
"19" => "10-19: développement des feuilles",
"10-19" => "10-19: développement des feuilles",
"10-19: développement des feui" => "10-19: développement des feuilles",
"10-19: développement des feuilles" => "10-19: développement des feuilles",
"15: environ % des feuilles épanouies" => "10-19: développement des feuilles",
"19 environ 50% des feuilles épanouies" => "10-19: développement des feuilles",
"en feuilles" => "10-19: développement des feuilles",
"Feuille" => "10-19: développement des feuilles",
"feuille peu dvt, a confirmer" => "10-19: développement des feuilles",
"feuilles seulement" => "10-19: développement des feuilles",
"20" => "20-29: formation de pousses latérales, tallage",
"Formation de pousses latérales, tallage" => "20-29: formation de pousses latérales, tallage",
"30" => "30-39: développement des tiges, croissance des rosettes",
"35" => "30-39: développement des tiges, croissance des rosettes",
"36" => "30-39: développement des tiges, croissance des rosettes",
"38" => "30-39: développement des tiges, croissance des rosettes",
"39" => "30-39: développement des tiges, croissance des rosettes",
"3: développement des tiges, croissance des rosettes" => "30-39: développement des tiges, croissance des rosettes",
"Développement des tiges, croissance des rosettes" => "30-39: développement des tiges, croissance des rosettes",
"40" => "40-49: développement des organes de propagation végétative",
"43" => "40-49: développement des organes de propagation végétative",
"45" => "40-49: développement des organes de propagation végétative",
"46" => "40-49: développement des organes de propagation végétative",
"48" => "40-49: développement des organes de propagation végétative",
"49" => "40-49: développement des organes de propagation végétative",
"40-49" => "40-49: développement des organes de propagation végétative",
"40-49: développement des organes de propagation végétative" => "40-49: développement des organes de propagation végétative",
"40-49: développement des organes de propagation végétativegt" => "40-49: développement des organes de propagation végétative",
"40-49: développement des organes de propagation végétativepas d'inflorescence" => "40-49: développement des organes de propagation végétative",
"50" => "50-59 : apparition de l’inflorescence",
"56" => "50-59 : apparition de l’inflorescence",
"57" => "50-59 : apparition de l’inflorescence",
"58" => "50-59 : apparition de l’inflorescence",
"59" => "50-59 : apparition de l’inflorescence",
"10x En bouton" => "50-59 : apparition de l’inflorescence",
"14x En bouton" => "50-59 : apparition de l’inflorescence",
"20x En bouton" => "50-59 : apparition de l’inflorescence",
"30-39" => "50-59 : apparition de l’inflorescence",
"50-59" => "50-59 : apparition de l’inflorescence",
"50-59: apparition de l'inflorescence, épiais" => "50-59 : apparition de l’inflorescence",
"50-59: apparition de l'inflorescence, épiaison" => "50-59 : apparition de l’inflorescence",
"59: apparition de l'inflorescence, épiaison" => "50-59 : apparition de l’inflorescence",
"8x En bouton" => "50-59 : apparition de l’inflorescence",
"60" => "60-69 : floraison",
"62" => "60-69 : floraison",
"63" => "60-69 : floraison",
"64" => "60-69 : floraison",
"66" => "60-69 : floraison",
"67" => "60-69 : floraison",
"68" => "60-69 : floraison",
"69" => "60-69 : floraison",
" floraison " => "60-69 : floraison",
"-69: floraison" => "60-69 : floraison",
"10x Fin de floraison" => "60-69 : floraison",
"12x Pleine floraison" => "60-69 : floraison",
"14x Début de floraison" => "60-69 : floraison",
"150x Pleine floraison" => "60-69 : floraison",
"17x Fin de floraison" => "60-69 : floraison",
"1x Début de floraison" => "60-69 : floraison",
"1x En fleur" => "60-69 : floraison",
"1x Fin de floraison" => "60-69 : floraison",
"1x Pleine floraison" => "60-69 : floraison",
"20x Début de floraison" => "60-69 : floraison",
"20x Pleine floraison" => "60-69 : floraison",
"25x Pleine floraison" => "60-69 : floraison",
"27x En fleur" => "60-69 : floraison",
"30x Fin de floraison" => "60-69 : floraison",
"35x Début de floraison" => "60-69 : floraison",
"35x Fin de floraison" => "60-69 : floraison",
"35x Pleine floraison" => "60-69 : floraison",
"3x Fin de floraison" => "60-69 : floraison",
"3x Pleine floraison" => "60-69 : floraison",
"40x Début de floraison" => "60-69 : floraison",
"44x Pleine floraison" => "60-69 : floraison",
"48x Pleine floraison" => "60-69 : floraison",
"4x Pleine floraison" => "60-69 : floraison",
"50x Pleine floraison" => "60-69 : floraison",
"5x Pleine floraison" => "60-69 : floraison",
"6: floraison" => "60-69 : floraison",
"60 : floraison en amorce, pétales jaunes, corolle non ouverte encore" => "60-69 : floraison",
"60-" => "60-69 : floraison",
"60-6: floraison" => "60-69 : floraison",
"60-65" => "60-69 : floraison",
"60-69" => "60-69 : floraison",
"60-69 floraison" => "60-69 : floraison",
"60-69 floraison +70-79: fructification" => "60-69 : floraison",
"60-69: florai" => "60-69 : floraison",
"60-69: florais" => "60-69 : floraison",
"60-69: floraison" => "60-69 : floraison",
"60-69: floraison - fructification" => "60-69 : floraison",
"60-69: floraison (8" => "60-69 : floraison",
"60-69: floraison 1 individu fleuri sur une trentaine" => "60-69 : floraison",
"60-69: floraison à 50 pour" => "60-69 : floraison",
"60-69: floraison Fleurs déjà fanées ou en cours de l'être" => "60-69 : floraison",
"60-69: floraison floraison" => "60-69 : floraison",
"60-69: floraison pour le 09/04/2019" => "60-69 : floraison",
"60-69: floraison5" => "60-69 : floraison",
"60-69: floraison6" => "60-69 : floraison",
"60-69: floraisondi" => "60-69 : floraison",
"60-69: floraisonentre les pierres du mur des quai" => "60-69 : floraison",
"60-69: floraisonfleurs et fruit" => "60-69 : floraison",
"60-69: floraisonl" => "60-69 : floraison",
"60-69: floraisonvi" => "60-69 : floraison",
"60-69: fructification" => "60-69 : floraison",
"60: floraison" => "60-69 : floraison",
"63: floraison" => "60-69 : floraison",
"63: environ 3% des fleurs épanouies" => "60-69 : floraison",
"64: floraison" => "60-69 : floraison",
"66, avec quelques fruits" => "60-69 : floraison",
"66: floraison" => "60-69 : floraison",
"67 : floraison" => "60-69 : floraison",
"67 Nbses fleurs épanouies," => "60-69 : floraison",
"67: floraison" => "60-69 : floraison",
"67: environ 70% des fleurs épanouies + formation de gousses." => "60-69 : floraison",
"68: environ 0% des fleurs épanouies" => "60-69 : floraison",
"68: floraison" => "60-69 : floraison",
"68: environ 50% des fleurs épanouies" => "60-69 : floraison",
"68: environ 80% des fleurs épanouies + formation des gousses." => "60-69 : floraison",
"68floraison" => "60-69 : floraison",
"69 (floraison de toutes fleurs)" => "60-69 : floraison",
"69-70" => "60-69 : floraison",
"69-70: fin de floraisonfructification" => "60-69 : floraison",
"69-70n" => "60-69 : floraison",
"69: 100% des fleurs épanouies" => "60-69 : floraison",
"69s" => "60-69 : floraison",
"82x Pleine floraison" => "60-69 : floraison",
"9: floraison" => "60-69 : floraison",
"début de ffloraison" => "60-69 : floraison",
"début floraison" => "60-69 : floraison",
"en fleurs" => "60-69 : floraison",
"environ 30% des fleurs épanouies" => "60-69 : floraison",
"environ 950% des fleurs épanouies" => "60-69 : floraison",
"fin d floraison" => "60-69 : floraison",
"fin de floraison" => "60-69 : floraison",
"fin floraison" => "60-69 : floraison",
"fl" => "60-69 : floraison",
"fl2" => "60-69 : floraison",
"fleur" => "60-69 : floraison",
"Fleurs" => "60-69 : floraison",
"fleurs épanouies; fin" => "60-69 : floraison",
"floraison" => "60-69 : floraison",
"Nombreux plants en début de floraison" => "60-69 : floraison",
"61" => "61: environ 10% des fleurs épanouies",
"10% des fleurs épanouies" => "61: environ 10% des fleurs épanouies",
"61 :" => "61: environ 10% des fleurs épanouies",
"61 : environ 10% des fleurs épanouies" => "61: environ 10% des fleurs épanouies",
"61: début defloraison" => "61: environ 10% des fleurs épanouies",
"61: floraison" => "61: environ 10% des fleurs épanouies",
"61: environ 10% des fleurs épanouie" => "61: environ 10% des fleurs épanouies",
"61: environ 10% des fleurs épanouies" => "61: environ 10% des fleurs épanouies",
"61: environ 10% des fleurs épanouies63" => "61: environ 10% des fleurs épanouies",
"61: environ 10% des fleurs épanouies68" => "61: environ 10% des fleurs épanouies",
"61: environ 2% des fleurs épanouies" => "61: environ 10% des fleurs épanouies",
"61: environ20% des fleurs épanouies" => "61: environ 10% des fleurs épanouies",
"Fleurs (environ 10% des fleurs épanouies)" => "61: environ 10% des fleurs épanouies",
"65" => "65: environ 50% des fleurs épanouies",
"65" => "65: environ 50% des fleurs épanouies",
"6: environ 50% des fleurs épanouies" => "65: environ 50% des fleurs épanouies",
"65 , avec quelques fruits" => "65: environ 50% des fleurs épanouies",
"65 : environ 80% des fleurs épanouies" => "65: environ 50% des fleurs épanouies",
"65 : environ 10% des fleurs ép" => "65: environ 50% des fleurs épanouies",
"65 : environ 50% des fleurs épa" => "65: environ 50% des fleurs épanouies",
"65 : environ 50% des fleurs épanouies" => "65: environ 50% des fleurs épanouies",
"65 : environ 50% des fleurs épanouies-75" => "65: environ 50% des fleurs épanouies",
"65-6: floraison" => "65: environ 50% des fleurs épanouies",
"65-69: floraison" => "65: environ 50% des fleurs épanouies",
"65-7: floraison" => "65: environ 50% des fleurs épanouies",
"65-72" => "65: environ 50% des fleurs épanouies",
"65:" => "65: environ 50% des fleurs épanouies",
"65: floraison" => "65: environ 50% des fleurs épanouies",
"65: environ 10% des fleurs épanouies" => "65: environ 50% des fleurs épanouies",
"65: environ 50% des fleurs épanoui" => "65: environ 50% des fleurs épanouies",
"65: environ 50% des fleurs épanouie6" => "65: environ 50% des fleurs épanouies",
"65: environ 50% des fleurs épanouies" => "65: environ 50% des fleurs épanouies",
"65: environ 50% des fleurs épanouies et fructification" => "65: environ 50% des fleurs épanouies",
"65: environ 50% des fleurs épanouies75" => "65: environ 50% des fleurs épanouies",
"65: environ 50% des fleurs épanouies78" => "65: environ 50% des fleurs épanouies",
"65:-70" => "65: environ 50% des fleurs épanouies",
"65:-75" => "65: environ 50% des fleurs épanouies",
"avec quelques fruits, 65" => "65: environ 50% des fleurs épanouies",
"nviron 50% des fleurs épanouies" => "65: environ 50% des fleurs épanouies",
"70" => "70-79: fructification",
"71" => "70-79: fructification",
"72" => "70-79: fructification",
"73" => "70-79: fructification",
"74" => "70-79: fructification",
"75" => "70-79: fructification",
"76" => "70-79: fructification",
"77" => "70-79: fructification",
"78" => "70-79: fructification",
"79" => "70-79: fructification",
"7: fructification" => "70-79: fructification",
"70-: fructification" => "70-79: fructification",
"70-71" => "70-79: fructification",
"70-79" => "70-79: fructification",
"70-79: floraison" => "70-79: fructification",
"70-79: fructification" => "70-79: fructification",
"70-79: fructification ?" => "70-79: fructification",
"70-79: fructification +floraison" => "70-79: fructification",
"70-79: fructification Entre autre" => "70-79: fructification",
"70-79: fructification, mais fruits verts" => "70-79: fructification",
"70-79: fructificationfleurs et fruit" => "70-79: fructification",
"70-79:fin floraison fructification" => "70-79: fructification",
"709: fructification" => "70-79: fructification",
"75: fructification" => "70-79: fructification",
"Début de ruits" => "70-79: fructification",
"fin floraison et fructification" => "70-79: fructification",
"fleur, fruit" => "70-79: fructification",
"fleurs e fructification" => "70-79: fructification",
"Fleurs et début fruits" => "70-79: fructification",
"Fleurs et début ruits" => "70-79: fructification",
"Fleurs et fructification" => "70-79: fructification",
"floraison - fructification" => "70-79: fructification",
"floraison zet fructification" => "70-79: fructification",
"Floraison, fructification" => "70-79: fructification",
"floraison(fin) fructification" => "70-79: fructification",
"floraison+ ou - finie" => "70-79: fructification",
"fr1" => "70-79: fructification",
"quelques fruits rares" => "70-79: fructification",
"stérile70-79: fructification" => "70-79: fructification",
"toutes les fleurs épanouies et début fructification" => "70-79: fructification",
"fleurs et fruits" => "70-79: fructification",
"Fleurs et jeunes fruits" => "70-79: fructification",
"floraison + fructification" => "70-79: fructification",
"Fructificaiton" => "70-79: fructification",
"fleurs et quelques fruits" => "70-79: fructification",
"Fleurs et surtout début defruits" => "70-79: fructification",
"floraison et fructification" => "70-79: fructification",
"fructification" => "70-79: fructification",
"Fleurs/fruits" => "70-79: fructification",
"fructification ?" => "70-79: fructification",
"80" => "80-89: maturité des fruits et des graines",
"81" => "80-89: maturité des fruits et des graines",
"82" => "80-89: maturité des fruits et des graines",
"83" => "80-89: maturité des fruits et des graines",
"84" => "80-89: maturité des fruits et des graines",
"86" => "80-89: maturité des fruits et des graines",
"87" => "80-89: maturité des fruits et des graines",
"88" => "80-89: maturité des fruits et des graines",
"89" => "80-89: maturité des fruits et des graines",
"-89: maturité des fruits et des graines" => "80-89: maturité des fruits et des graines",
"80-89" => "80-89: maturité des fruits et des graines",
"80-89: maturité des fruits et des graines" => "80-89: maturité des fruits et des graines",
"80-89: maturité des fruits et des graines,début sénescence" => "80-89: maturité des fruits et des graines",
"80-95" => "80-89: maturité des fruits et des graines",
"88 maturité des fruits et des graines" => "80-89: maturité des fruits et des graines",
"89: maturité des fruits et des graines" => "80-89: maturité des fruits et des graines",
"floraison et fructification, graines mûres" => "80-89: maturité des fruits et des graines",
"floraison et maturation des graines" => "80-89: maturité des fruits et des graines",
"fructification passée" => "80-89: maturité des fruits et des graines",
"Fruit" => "80-89: maturité des fruits et des graines",
"Fruits" => "80-89: maturité des fruits et des graines",
"85" => "85: 50% des fruits matures",
"50% des fruits matures (fructification d'Août)î" => "85: 50% des fruits matures",
"85, mais avec encore des fleurs" => "85: 50% des fruits matures",
"85:" => "85: 50% des fruits matures",
"85: fruits matures 20" => "85: 50% des fruits matures",
"85: 50% des fruits mature8" => "85: 50% des fruits matures",
"85: 50% des fruits matures" => "85: 50% des fruits matures",
"85: 50% des fruits matures0" => "85: 50% des fruits matures",
"85: 50% des fruits matures56" => "85: 50% des fruits matures",
"85: 50% des fruits matures88" => "85: 50% des fruits matures",
"88: 50% des fruits matures" => "85: 50% des fruits matures",
"90" => "90-99: sénescence et dormance",
"91" => "90-99: sénescence et dormance",
"92" => "90-99: sénescence et dormance",
"94" => "90-99: sénescence et dormance",
"95" => "90-99: sénescence et dormance",
"97" => "90-99: sénescence et dormance",
"98" => "90-99: sénescence et dormance",
"99" => "90-99: sénescence et dormance",
"100% de feuilles jaunes" => "90-99: sénescence et dormance",
"80% feuillage d'automne" => "90-99: sénescence et dormance",
"90-99" => "90-99: sénescence et dormance",
"90-99: sénescence et dormance" => "90-99: sénescence et dormance",
"95: environ 9% des feuilles jaunes" => "90-99: sénescence et dormance"
);
foreach ($phenologie as $valeur=>$saisie) {
$requete = 'UPDATE '.$this->bd_cel.'.cel_obs SET commentaire = concat(commentaire, " Certitude : ", certitude), phenologie = "'.$saisie.'" WHERE phenologie ="'.$valeur.'"';
$this->bdd->requeter($requete);
echo "effectuée \n";
}
$requete_verif = "SELECT certitude FROM ".$this->bd_cel.".cel_obs WHERE certitude NOT IN ('douteux', 'certain', 'à déterminer', '') and certitude is not NULL";
$verif = $this->bdd->recupererTous($requete_verif);
if ($verif != array()) print_r($verif);
}
private function unifierUtilisateur() {
echo "vérification de la présence de l'annuaire \n";
$requete = "SELECT * FROM ".$this->bd_cel.".`users`;";
$result = $this->bdd->requeter($requete);
if ($result === NULL) {echo $requete;
echo "Il manque la table annuaire (à recopier de telaorg users\n";
exit;
}
echo "suppression de le colonne ordre \n";
$requete = "ALTER TABLE ".$this->bd_cel.".cel_obs DROP INDEX id_obs;";
$this->bdd->requeter($requete);
$requete = "ALTER TABLE ".$this->bd_cel.".cel_obs DROP INDEX ordre;";
$this->bdd->requeter($requete);
$requete = "ALTER TABLE ".$this->bd_cel.".`cel_obs` DROP IF EXISTS `ordre`;";
$this->bdd->requeter($requete);
$requete = "ALTER TABLE ".$this->bd_cel.".`cel_obs` ADD IF NOT EXISTS pseudo varchar(250);";
$this->bdd->requeter($requete);
echo "modification des observations ayant une adresse mail en identifiant";
$requete_annu_mail = "UPDATE ".$this->bd_cel.".`cel_obs` right join ".$this->bd_cel.".`users` ON `user_email` = ce_utilisateur SET `ce_utilisateur` = `ID`, pseudo = user_nicename,
`courriel_utilisateur` = `user_email` WHERE ce_utilisateur like '%@%'";
$utilisateur_mail = $this->bdd->recupererTous($requete_annu_mail);
echo "modification des observations ayant une adresse mail mais pas d'identifiant";
$requete_annu_mail = "UPDATE ".$this->bd_cel.".`cel_obs` join ".$this->bd_cel.".`users` ON `user_email` = courriel_utilisateur SET `ce_utilisateur` = `ID`, pseudo = user_nicename,
`courriel_utilisateur` = `user_email` WHERE (ce_utilisateur IS NULL OR CHAR_LENGTH(ce_utilisateur) > 6
OR ce_utilisateur = 0) and courriel_utilisateur like '%@%'";
$utilisateur_mail = $this->bdd->recupererTous($requete_annu_mail);
echo "modification des observations ayant un identifiant";
$requete_annu_mail = "UPDATE ".$this->bd_cel.".`cel_obs` join ".$this->bd_cel.".`users` ON ID = ce_utilisateur SET pseudo = user_nicename,
`courriel_utilisateur` = `user_email` WHERE (ce_utilisateur IS NULL OR char_length(ce_utilisateur) > 6) and (courriel_utilisateur is null or courriel_utilisateur='')";
$utilisateur_mail = $this->bdd->recupererTous($requete_annu_mail);
echo "suppression des autres valeurs ce_utilisateur";
$requete_annu_mail = "UPDATE ".$this->bd_cel.".`cel_obs` SET ce_utilisateur = NULL, courriel_utilisateur = if (ce_utilisateur like '%@%'and (courriel_utilisateur is null or courriel_utilisateur='') , ce_utilisateur, courriel_utilisateur) WHERE ce_utilisateur IS NOT NULL AND char_length(ce_utilisateur) > 6";
$utilisateur_mail = $this->bdd->recupererTous($requete_annu_mail);
echo "suppression des obs anonymes";
$requete_anonyme = "DELETE FROM ".$this->bd_cel.".`cel_obs` WHERE (ce_utilisateur IS NULL OR char_length(ce_utilisateur) > 6
OR ce_utilisateur = 0) and (`courriel_utilisateur` is null or `courriel_utilisateur` not like '%@%')";
$this->bdd->requeter($requete_anonyme);
$requete_verif = "SELECT `ce_utilisateur`, `prenom_utilisateur`, `nom_utilisateur`, `courriel_utilisateur` FROM ".$this->bd_cel.".cel_obs
WHERE ce_utilisateur IS NOT NULL OR char_length(ce_utilisateur) > 6";
$verif = $this->bdd->recupererTous($requete_verif);
if ($verif != array()) print_r($verif);
echo "effectuée \n";
$this->unifierUtilisateurTag("cel_arbre_mots_cles_obs");
$this->unifierUtilisateurTag("cel_arbre_mots_cles_images");
}
private function unifierUtilisateurTag($table) {
echo "séparation des identifiants en ce_utilisateur et courriel";
$requete = "ALTER TABLE ".$this->bd_cel.".".$table." ADD courriel varchar(255);";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".".$table." SET courriel = id_utilisateur,
id_utilisateur = 0 WHERE id_utilisateur like '%@%';";
$this->bdd->requeter($requete);
echo "recherche des identifiants pour les tags ayant que des courriels dans users";
$requete = "UPDATE ".$this->bd_cel.".".$table." join ".$this->bd_cel.".`users` ON `user_email` = courriel SET `id_utilisateur` = `ID`
WHERE courriel like '%@%';";
$this->bdd->requeter($requete);
echo "recherche des identifiants pour les tags ayant que des courriels dans obs";
$requete = "UPDATE ".$this->bd_cel.".".$table." t join ".$this->bd_cel.".`cel_obs` o ON
`courriel` = courriel_utilisateur SET t.`id_utilisateur` = o.`ce_utilisateur`
WHERE courriel_utilisateur like '%@%';";
$this->bdd->requeter($requete);
echo "suppression des tags sans identifiant";
$requete_anonyme = "DELETE FROM ".$this->bd_cel.".".$table." WHERE
(id_utilisateur IS NULL OR trim(id_utilisateur) = '') OR char_length(id_utilisateur) > 6";
$this->bdd->requeter($requete_anonyme);
if ($table == "cel_arbre_mots_cles_obs") {
$requete_anonyme = "DELETE FROM ".$this->bd_cel.".`cel_mots_cles_obs_liaison`
WHERE `id_element_lie` not in (SELECT `id_observation` FROM ".$this->bd_cel.".`cel_obs`)
OR `id_mot_cle` NOT IN (SELECT `id_mot_cle` FROM ".$this->bd_cel.".`cel_arbre_mots_cles_obs`);";
$this->bdd->requeter($requete_anonyme);
} else {
$requete_anonyme = "DELETE FROM ".$this->bd_cel.".`cel_mots_cles_images_liaison`
WHERE `id_element_lie` not in (SELECT `id_image` FROM ".$this->bd_cel.".`cel_images`)
OR `id_mot_cle` NOT IN (SELECT `id_mot_cle` FROM ".$this->bd_cel.".`cel_arbre_mots_cles_images`);";
$this->bdd->requeter($requete_anonyme);
}
}
private function unifierInfosEspeces() {
echo "maj infos espèces \n";
/*$requete = "ALTER TABLE ".$this->bd_cel.".`cel_obs` ADD infosnn varchar(2),
ADD bd_nom_sci varchar(250), ADD bd_num_nom int(11), ADD bd_nom_sci_retenu varchar(250),
ADD bd_num_nom_retenu int(11) ;";
$this->bdd->requeter($requete);
*/
$liste_referentiels = array("bdtfx" => "bdtfx_v6_00", "bdtre" => "bdtre_v1_00",
"isfan" => "isfan_v2013", "apd" => "apd_v3_4_0", "bdtxa" => "bdtxa_v1_01",
"aublet" => "aublet_v2016_09", "florical" => "florical_v2016_04_22", "lbf" => "lbf_v1_00");
$this->unifierInfosEspecesBDTFX();
foreach ($liste_referentiels as $ref => $version) {
//Num nom et nom sci sont les mêmes
// chercher les versions
$requete = "UPDATE ".$this->bd_cel.".`cel_obs`
join (SELECT `num_nom`, `num_nom_retenu`, `nom_sci`,
case when annee = '' THEN concat(`nom_sci`, ' ', auteur) ELSE concat(`nom_sci`, ' ', auteur, ' [',annee,']') END as nom_sci_complet,
nom_sci_complet_ret FROM ".$this->bd_flore.".".$version.
'left join (select `num_nom` as nn, `nom_sci` as nom_sci_ret,
case when annee = "" THEN concat(`nom_sci`, " ", auteur) ELSE concat(`nom_sci`, " ", auteur, " [",annee,"]") END as nom_sci_complet_ret
from ".$this->bd_flore.".".$version." where `num_nom` = `num_nom_retenu`) ret
on `num_nom_retenu` = nn) bdtfx
on `nom_sel_nn` = num_nom and `nom_sel` like concat(nom_sci,"%")
SET `nom_sel` = nom_sci_complet, `nom_sel_nn` = num_nom , `nom_ret` = nom_sci_complet_ret, `nom_ret_nn` = num_nom_retenu,
infosnn = 1
WHERE nom_referentiel = "'.$ref.'"';
$this->bdd->requeter($requete);
//Num nom id, nom sci !=
$requete = "UPDATE ".$this->bd_cel.".`cel_obs`
join (SELECT `num_nom`, `num_nom_retenu`, `nom_sci`,
case when annee = '' THEN concat(`nom_sci`, ' ', auteur) ELSE concat(`nom_sci`, ' ', auteur, ' [',annee,']') END as nom_sci_complet,
nom_sci_complet_ret FROM ".$this->bd_flore.".".$version.
'left join (select `num_nom` as nn, `nom_sci` as nom_sci_ret,
case when annee = "" THEN concat(`nom_sci`, " ", auteur) ELSE concat(`nom_sci`, " ", auteur, " [",annee,"]") END as nom_sci_complet_ret
from ".$this->bd_flore.".".$version." where `num_nom` = `num_nom_retenu`) ret
on `num_nom_retenu` = nn) bdtfx
on `nom_sel_nn` = num_nom and and (nom_sel like concat(nom_sci,"%") and nom_ret like concat(nom_sci,"%"))
and (nom_sel like concat(nom_sci_ret,"%") and nom_ret like concat(nom_sci_ret,"%"))
SET `nom_sel` = nom_sci_complet, `nom_sel_nn` = num_nom , `nom_ret` = nom_sci_complet_ret, `nom_ret_nn` = num_nom_retenu,
infosnn = 2
WHERE nom_referentiel = "'.$ref.'" and infosnn != 1';
$this->bdd->requeter($requete);
//
}
}
private function unifierInfosEspecesBDTFX() {
echo "maj infos espèces \n";
/*$requete = "ALTER TABLE ".$this->bd_cel.".`cel_obs` ADD infosnn varchar(2),
ADD bd_nom_sci varchar(250), ADD bd_num_nom int(11), ADD bd_nom_sci_retenu varchar(250),
ADD bd_num_nom_retenu int(11) ;";
$this->bdd->requeter($requete);
*/
//Num nom et nom sci sont les mêmes
// chercher les versions
$requete = "UPDATE ".$this->bd_cel.".`cel_obs`"
.' join bdtfx on `nom_sel_nn` = num_nom and `nom_sel` like concat(nom_sci, "%")
SET `nom_sel` = nom_sci_complet, `nom_sel_nn` = num_nom ,
`nom_ret` = nom_ret_complet, `nom_ret_nn` = num_nom_retenu,
infosnn = 1
where `nom_referentiel` = "bdtfx" ';
$this->bdd->requeter($requete);
//Num nom id, nom sci +-=
$requete = "UPDATE ".$this->bd_cel.".`cel_obs`"
.' join bdtfx on `nom_sel_nn` = num_nom and and (nom_sel like concat(nom_sci,"%") and nom_ret like concat(nom_sci,"%"))
and (nom_sel like concat(nom_sci_ret,"%") and nom_ret like concat(nom_sci_ret,"%"))
SET `nom_sel` = nom_sci_complet, `nom_sel_nn` = num_nom ,
`nom_ret` = nom_ret_complet, `nom_ret_nn` = num_nom_retenu,
infosnn = 2
where `nom_referentiel` = "bdtfx" and infosnn != "1"';
$this->bdd->requeter($requete);
//Num nom id, nom sci +-=
$requete = "UPDATE ".$this->bd_cel.".`cel_obs`"
.' join bdtfx on `nom_sel_nn` = num_nom and and (nom_sel not like concat(nom_sci,"%") and nom_ret not like concat(nom_sci,"%"))
and (nom_sel not like concat(nom_sci_ret,"%") and nom_ret not like concat(nom_sci_ret,"%"))
SET `bd_nom_sci` = nom_sci_complet, `bd_num_nom` = num_nom ,
`bd_nom_sci_retenu` = nom_ret_complet, `bd_num_nom_retenu` = num_nom_retenu,
infosnn = 3
where `nom_referentiel` = "bdtfx" and infosnn not in ("1", "2")';
$this->bdd->requeter($requete);
}
private function supprimerImagesetTagAnonymes() {
echo "vérification de la présence de l'annuaire \n";
$requete = "SELECT * FROM ".$this->bd_cel.".`users`;";
$result = $this->bdd->requeter($requete);
if ($result === NULL) {
echo $requete;
echo "Il manque la table annuaire (à recopier de telaorg users\n";
exit;
}
echo "suppression de le colonne ordre \n";
$requete = "ALTER TABLE ".$this->bd_cel.".cel_images DROP INDEX id_img;";
$this->bdd->requeter($requete);
$requete = "ALTER TABLE ".$this->bd_cel.".`cel_images` DROP IF EXISTS `ordre`;";
$this->bdd->requeter($requete);
$requete = "ALTER TABLE ".$this->bd_cel.".`cel_images` ADD IF NOT EXISTS pseudo varchar(250);";
$this->bdd->requeter($requete);
echo "modification des images ayant une adresse mail en identifiant";
$requete_annu_mail = "UPDATE ".$this->bd_cel.".`cel_images` right join ".$this->bd_cel.".`users` ON `user_email` = ce_utilisateur SET `ce_utilisateur` = `ID`, pseudo = user_nicename,
`courriel_utilisateur` = `user_email` WHERE ce_utilisateur like '%@%'";
$utilisateur_mail = $this->bdd->recupererTous($requete_annu_mail);
echo "modification des images ayant une adresse mail mais pas d'identifiant";
$requete_annu_mail = "UPDATE ".$this->bd_cel.".`cel_images` join ".$this->bd_cel.".`users` ON `user_email` = courriel_utilisateur SET `ce_utilisateur` = `ID`, pseudo = user_nicename,
`courriel_utilisateur` = `user_email` WHERE (ce_utilisateur IS NULL OR char_length(ce_utilisateur) > 6
OR ce_utilisateur = 0) and courriel_utilisateur like '%@%'";
$utilisateur_mail = $this->bdd->recupererTous($requete_annu_mail);
echo "modification des images ayant un identifiant";
$requete_annu_mail = "UPDATE ".$this->bd_cel.".`cel_images` join ".$this->bd_cel.".`users` ON ID = ce_utilisateur SET pseudo = user_nicename,
`courriel_utilisateur` = `user_email` WHERE (ce_utilisateur IS NULL OR char_length(ce_utilisateur) > 6) and (courriel_utilisateur is null or courriel_utilisateur='')";
$utilisateur_mail = $this->bdd->recupererTous($requete_annu_mail);
echo "suppression des autres valeurs ce_utilisateur";
$requete_annu_mail = "UPDATE ".$this->bd_cel.".`cel_images` SET ce_utilisateur = NULL, courriel_utilisateur = if (ce_utilisateur like '%@%'and (courriel_utilisateur is null or courriel_utilisateur='') , ce_utilisateur, courriel_utilisateur)
WHERE ce_utilisateur IS NOT NULL AND (LENGTH(ce_utilisateur) > 6 OR trim(ce_utilisateur) = '')";
$utilisateur_mail = $this->bdd->recupererTous($requete_annu_mail);
echo "suppression des images\n";
$requete_anonyme = "DELETE FROM ".$this->bd_cel.".`cel_images` WHERE (ce_utilisateur IS NULL OR char_length(ce_utilisateur) > 6
OR ce_utilisateur = 0) and (`courriel_utilisateur` is null or `courriel_utilisateur` not like '%@%')";
$this->bdd->requeter($requete_anonyme);
 
/* echo "suppression des tags obs anonymes";
$requete_create = "CREATE TABLE ".$this->bd_cel.".user_mot_cle_absent AS SELECT distinct id_utilisateur FROM ".$this->bd_cel.".cel_arbre_mots_cles_obs WHERE id_utilisateur not in
(SELECT distinct id_utilisateur FROM ".$this->bd_cel.".cel_arbre_mots_cles_obs WHERE id_utilisateur in
(select distinct ce_utilisateur from ".$this->bd_cel.".cel_obs) or
id_utilisateur in (SELECT distinct courriel_utilisateur FROM ".$this->bd_cel.".cel_obs))";
$this->bdd->requeter($requete_create);
$requete_index = "ALTER TABLE ".$this->bd_cel.".`user_mot_cle_absent` ADD PRIMARY KEY(`id_utilisateur`);";
$this->bdd->requeter($requete_index);
$requete_anonyme = "DELETE FROM ".$this->bd_cel.".`cel_arbre_mots_cles_obs` WHERE `id_utilisateur` in (SELECT * FROM ".$this->bd_cel.".`user_mot_cle_absent`);";
$this->bdd->requeter($requete_anonyme);
$requete_anonyme = "DROP TABLE ".$this->bd_cel.".user_mot_cle_absent;";
$this->bdd->requeter($requete_anonyme);
$requete_anonyme = "UPDATE ".$this->bd_cel.".`cel_arbre_mots_cles_obs` a join ".$this->bd_cel.".cel_obs b on a.`id_utilisateur` = b.courriel_utilisateur SET a.`id_utilisateur` = b.ce_utilisateur
WHERE b.ce_utilisateur IS NOT NULL AND b.ce_utilisateur != ''";
$this->bdd->requeter($requete_anonyme);*/
}
private function unifierNomReferentiel() {
echo "Uniformisation du nom de référentiel";
$referentiels = array("bdtfx", "bdtre", "bdtxa", "apd", "lbf", "isfan");
foreach ($referentiels as $referentiel) {
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET nom_referentiel = '".$referentiel."' WHERE nom_referentiel like '".$referentiel."%'";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET nom_referentiel = 'Autre/inconnu' WHERE nom_sel_nn IS NULL or nom_sel_nn = '0'";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET nom_referentiel = 'apd' WHERE nom_referentiel like 'bdtao%'";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET nom_referentiel = 'bdtfx' WHERE nom_referentiel like 'bdnff%'";
$this->bdd->requeter($requete);
echo "effectuée \n";
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET nom_referentiel = 'Autre/inconnu' WHERE nom_referentiel IS NULL or nom_referentiel = ''";
$this->bdd->requeter($requete);
echo "effectuée \n";
}
$requete_verif = "SELECT nom_referentiel FROM ".$this->bd_cel.".cel_obs WHERE nom_referentiel NOT IN ('".implode("', '", $referentiels)."', 'Autre/inconnu')";
$verif = $this->bdd->recupererTous($requete_verif);
if ($verif != array()) print_r($verif);
}
private function supprimerInfosLiesObsInexistante() {
echo "Supprimer infos liés à obs inexistante";
$requete = "DELETE FROM ".$this->bd_cel.".`cel_obs_etendues` WHERE `id_observation` not in (select `id_observation` from ".$this->bd_cel.".cel_obs);";
$this->bdd->requeter($requete);
$requete = "DELETE FROM ".$this->bd_cel.".`cel_mots_cles_obs_liaison` WHERE `id_element_lie` not in (select `id_observation` from ".$this->bd_cel.".cel_obs);";
$this->bdd->requeter($requete);
$requete = "DELETE FROM ".$this->bd_cel.".`cel_mots_cles_obs_liaison` WHERE `id_mot_cle` not in (SELECT `id_mot_cle` FROM ".$this->bd_cel.".`cel_arbre_mots_cles_obs`);";
$this->bdd->requeter($requete);
$requete = "DELETE FROM ".$this->bd_cel.".`cel_images` WHERE `ce_observation` is not null and `ce_observation` not in (select id_observation from ".$this->bd_cel.".cel_obs)";
$this->bdd->requeter($requete);
$requete = "DELETE FROM ".$this->bd_cel.".`cel_mots_cles_images_liaison` WHERE `id_element_lie` not in (select `id_image` from ".$this->bd_cel.".cel_images);";
$this->bdd->requeter($requete);
$requete = "DELETE FROM ".$this->bd_cel.".`cel_mots_cles_images_liaison` WHERE `id_mot_cle` not in (SELECT `id_mot_cle` FROM ".$this->bd_cel.".`cel_arbre_mots_cles_images`);";
$this->bdd->requeter($requete);
echo "effectuée \n";
}
private function verifierGeodatum() {
echo "Uniformisation du geodatum";
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET geodatum = 'WGS84' WHERE (latitude IS NOT NULL or latitude != '0.00000') AND geodatum IS NULL";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET geodatum = NULL WHERE (latitude IS NULL or latitude = '0.00000')";
$this->bdd->requeter($requete);
echo "effectuée \n";
echo "Suppression des coordonnées fausses : ";
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET latitude = NULL, longitude = NULL WHERE latitude < -90 OR latitude > 90 OR longitude < -180 OR longitude > 180";
$this->bdd->requeter($requete);
echo "effectuée \n";
}
private function verifierCodeInsee() {
echo "Mise à jour des valeurs code_insee";
$requete = 'UPDATE `cel_obs` SET `ce_zone_geo` = NULL,
commentaire = concat(if(commentaire is null, "", concat(commentaire, ", ")), if(ce_zone_geo is null, "", concat("Zone geo : ",ce_zone_geo))) where `ce_zone_geo` not like "insee-c%"';
$this->bdd->requeter($requete);
$requete = 'UPDATE `cel_obs` SET `ce_zone_geo` = substr(`ce_zone_geo`, 9, 5) where `ce_zone_geo` like "insee-c:%"';
$this->bdd->requeter($requete);
$requete = 'UPDATE `cel_obs` SET `ce_zone_geo` = NULL where trim(`ce_zone_geo`) = ""';
$this->bdd->requeter($requete);
echo "effectuée \n";
echo "Vérification du code insee";
$requete = "ALTER TABLE ".$this->bd_cel.".`cel_obs` ADD IF NOT EXISTS `locality_consistency` INT(1) ;";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET locality_consistency = '0' WHERE
((ce_zone_geo != 'INSEE-C:' and ce_zone_geo like 'INSEE-C:%') and code_insee_calcule != '') and
replace(`ce_zone_geo`, 'INSEE-C:', '') != `code_insee_calcule`";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET locality_consistency = '1' WHERE
((ce_zone_geo != 'INSEE-C:' and ce_zone_geo like 'INSEE-C:%') and code_insee_calcule != '') and
replace(`ce_zone_geo`, 'INSEE-C:', '') = `code_insee_calcule`";
$this->bdd->requeter($requete);
$requete_verif = "SELECT `ce_zone_geo`, `code_insee_calcule`, `locality_consistency` FROM `cel_obs` WHERE `locality_consistency` IS NOT NULL";
$verif = $this->bdd->recupererTous($requete_verif);
if ($verif != array()) print_r($verif);
echo "effectuée \n";
}
private function analyserMotsCles(){
echo "Input source \n";
$requete = "ALTER TABLE ".$this->bd_cel.".`cel_obs` ADD IF NOT EXISTS `input_source` VARCHAR(15)";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET input_source = 'PlantNet' WHERE `mots_cles_texte` like '%plantnet%'";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET input_source = 'autre' WHERE `mots_cles_texte` like '%MobileSauvages%'";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET input_source = 'widget' WHERE `mots_cles_texte` like '%Projets coopératifs%' and (input_source = '' OR input_source IS NULL)";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET input_source = 'widget' WHERE `mots_cles_texte` like '%widget%' and (input_source = '' OR input_source IS NULL)";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET input_source = 'CEL' WHERE input_source = '' OR input_source IS NULL";
$this->bdd->requeter($requete);
echo "Suppression motcle du chemin \n";
$requete = "UPDATE ".$this->bd_cel.".`cel_arbre_mots_cles_obs` SET chemin =
if(CHAR_LENGTH(chemin)-CHAR_LENGTH(`mot_cle`) = 2, '\/', substr(`chemin`, 1, CHAR_LENGTH(chemin)-CHAR_LENGTH(`mot_cle`)-2))";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".`cel_arbre_mots_cles_images` SET chemin =
substr(`chemin`, 1, CHAR_LENGTH(chemin)-CHAR_LENGTH(`mot_cle`)-1)";
$this->bdd->requeter($requete);
echo "Certitude à certaine quand obs validée sur ip \n";
$requete = "UPDATE ".$this->bd_cel.".`cel_obs` c left join
(SELECT distinct `ce_observation`, `nom_sel_nn`
FROM ".$this->bd_del.".`del_commentaire` WHERE `proposition_retenue` = 1) d on
`ce_observation` = `id_observation` SET `certitude` = 'certain'
WHERE (c.`mots_cles_texte` LIKE '%adeterminer%'
or c.`certitude` = 'à déterminer') and c.`nom_sel_nn` = d.`nom_sel_nn`";
$this->bdd->requeter($requete);
echo "Certitude à douteux quand obs validée sur ip mais num_nom diff entre ip et cel \n";
$requete = "UPDATE ".$this->bd_cel.".`cel_obs` c left join
(SELECT distinct `ce_observation`, `nom_sel_nn`
FROM ".$this->bd_del.".`del_commentaire` WHERE `proposition_retenue` = 1 ) d on
`ce_observation` = `id_observation` SET `certitude` = 'douteux'
WHERE (c.`mots_cles_texte` LIKE '%adeterminer%'
or c.`certitude` = 'à déterminer') and c.`nom_sel_nn` != d.`nom_sel_nn`";
$this->bdd->requeter($requete);
echo "Certitude à aDeterminer quand obs non validée sur ip \n";
$requete = "UPDATE ".$this->bd_cel.".`cel_obs` c SET `certitude` = 'à déterminer'
WHERE c.`mots_cles_texte` LIKE '%adeterminer%' AND
(c.`certitude` = '' or c.certitude IS NULL)";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".`cel_obs` SET
`mots_cles_texte` = REPLACE(`mots_cles_texte`, 'aDeterminer,', '')
WHERE `mots_cles_texte` LIKE '%adeterminer,%'";
$this->bdd->requeter($requete);
 
}
 
private function changerSensible(){
echo "Sensible \n";
$requete = "ALTER TABLE ".$this->bd_cel.".`cel_obs` ADD IF NOT EXISTS `published_location` varchar(50)";
$this->bdd->requeter($requete);
$requete = "UPDATE ".$this->bd_cel.".cel_obs SET published_location = 'localité' WHERE `mots_cles_texte` like '%sensible%'";
$this->bdd->requeter($requete);
}
}
/branches/v3.01-serpe/scripts/modules/generation_images/GenerationImages.php
New file
0,0 → 1,76
<?php
// declare(encoding='UTF-8');
/**
* Génère des miniatures.
*
* Utilisation :
* - Pour ? : <code>/opt/lamp/bin/php cli.php generation_images -a genererMinaturesEnAttente</code>
* - Pour ? : <code>/opt/lamp/bin/php cli.php generation_images -a genererMinaturesEnAttente</code>
*
* @category CEL
* @package Scripts
* @subpackage Génération Images
* @author Mathias CHOUET <mathias@tela-botanica.org>
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @author Aurelien PERONNET <aurelien@tela-botanica.org>
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @copyright 1999-2014 Tela Botanica <accueil@tela-botanica.org>
*/
class GenerationImages extends Script {
 
protected $bdd;
protected $parametres_autorises = array(
'-id' => array(false, '1', 'Identifiants des images à traiter (séparés par des virgules')
);
 
public function __construct($script_nom, $parametres_cli) {
parent::__construct($script_nom, $parametres_cli);
$this->bdd = new Bdd();
}
 
public function executer() {
$cmd = $this->getParametre('a');
switch($cmd) {
case 'genererMinaturesEnAttente';
$this->genererMiniaturesEnAttente();
break;
case 'genererMinaturesPourId';
$this->genererMinaturesPourId();
break;
default :
$msg = "Erreur : la commande '$cmd' n'existe pas!\n";
throw new Exception($msg);
}
}
 
private function genererMinaturesPourId() {
$id = $this->getParametre('id');
$ids = explode(',',$id);
if ($id == null) {
echo "le paramètre id doit être un ensemble de nombres séparés par des virgules";
} else {
include_once dirname(__FILE__).'/bibliotheque/ImageRecreation.php';
$createur_images = new ImageRecreation();
foreach ($ids as $id_image) {
$createur_images->regenererMiniaturesPourId(array($id_image));
}
}
}
 
private function genererMiniaturesEnAttente() {
$requete = 'SELECT id_image '.
'FROM cel_images '.
'WHERE date_creation >= DATE_SUB(NOW(), INTERVAL 15 MINUTE)';
$images_attente = $this->bdd->recupererTous($requete);
 
if (!empty($images_attente)) {
// iterer sur config pour formats
include_once dirname(__FILE__).'/bibliotheque/ImageRecreation.php';
$createur_images = new ImageRecreation();
foreach ($images_attente as $image) {
$createur_images->regenererMiniaturesPourId(array($image['id_image']));
}
}
}
}
/branches/v3.01-serpe/scripts/modules/generation_images/bibliotheque/ImageRecreation.php
New file
0,0 → 1,669
<?php
// declare(encoding='UTF-8');
/**
* Cette classe est un quasi copier-coller de la classe éponyme dans
* le dossier lib de jrest mais pas de mécanisme commun pour les classes
*
* @category CEL
* @package Scripts
* @subpackage Génération Images
* @author Mathias CHOUET <mathias@tela-botanica.org>
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @author Aurelien PERONNET <aurelien@tela-botanica.org>
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @copyright 1999-2014 Tela Botanica <accueil@tela-botanica.org>
*/
// TODO: utiliser la même classe pour jrest ainsi que les scripts => créer un projet cel-commun (même principe que del-commun)
Class ImageRecreation {
 
private $droits = 0755;
private $formats = array('CRX2S','CRXS','CXS','CS','CRS','XS','S','M','L','XL','X2L','X3L');
const MODE_GD = 'gd';
const MODE_IMAGEMAGICK = 'imagemagick';
private $mode;
 
private $verbose = true;
 
public function __construct() {
if (extension_loaded('imagick')) {
$this->mode = self::MODE_IMAGEMAGICK;
} else {
$this->mode = self::MODE_GD;
}
}
 
public function recreerMiniaturesRecursivement() {
$this->itererRecursivement(Config::get('dossierImages'));
}
 
public function regenererMiniaturesIntervalle($params) {
$id_debut = $params[0];
$id_fin = $params[1];
 
if (is_numeric($id_debut) && is_numeric($id_fin)) {
for ($i = $id_debut; $i <= $id_fin; $i++) {;
$tab_param = array($i);
$this->regenererMiniaturesPourId($tab_param);
}
}
}
 
public function regenererMiniaturesPourId($params) {
$id = $params[0];
 
if (!is_numeric($id)) {
return;
}
 
$dossier_fichier = $this->obtenirDossierPourFormat($id, 'O');
$nom_fichier = $this->convertirIdBddVersNomFichier($id, 'O');
 
$chemin_fichier = $dossier_fichier.'/'.$nom_fichier;
 
if (file_exists($chemin_fichier)) {
$infos_image_originale = $this->obtenirImageEtInfosPourChemin($chemin_fichier);
// obtention d'un verrou sur le fichier original pour empecher d'autres scripts
// d'effectuer la création des miniatures
$fp = fopen($chemin_fichier, "r");
$verrou = flock($fp, LOCK_EX);
// creation de miniatures pour chacuns des formats définis
foreach ($this->formats as $format) {
$this->creerEtStockerMiniatureFichierImageSelonFormat($id, $infos_image_originale, $format);
};
$verrou = flock($fp, LOCK_UN);
fclose($fp);
}
}
 
public function itererRecursivement($dossier) {
// on ne parse que le dossier des images originales
$dossiers_a_exclure = $this->getFormats();
 
foreach (new DirectoryIterator($dossier) as $fichier_ou_dossier) {
if ($fichier_ou_dossier->isDot()) {
continue;
}
 
if (in_array($fichier_ou_dossier->getBasename(), $dossiers_a_exclure)) {
continue;
}
 
if ($fichier_ou_dossier->isDir()) {
$this->itererRecursivement($fichier_ou_dossier->getPathname());
} else {
$nom_fichier = $fichier_ou_dossier->getFilename();
 
$infos_image_originale = $this->obtenirImageEtInfosPourChemin($fichier_ou_dossier->getPathname());
$id = $this->convertirBaseNomFichierVersIdBdd($nom_fichier, $this->formats);
 
// creation de miniatures pour chacuns des formats définis
foreach ($this->formats as $format) {
$this->creerEtStockerMiniatureFichierImageSelonFormat($id, $infos_image_originale, $format);
}
}
}
}
 
public function creerOuRenvoyerImage($id, $format) {
$dossier = $this->obtenirDossierPourFormat($id, $format);
$nom_fichier = $this->convertirIdBddVersNomFichier($id, $format);
$chemin_image = $dossier.'/'.$nom_fichier;
 
$image = false;
if(!file_exists($chemin_image)) {
$infos_image_originale = $this->obtenirImageEtInfosPourChemin($this->obtenirCheminImageOriginale($id));
if($infos_image_originale) {
$debut = microtime();
$this->creerEtStockerMiniatureFichierImageSelonFormat($id, $infos_image_originale, $format);
 
$image = file_get_contents($chemin_image);
}
} else {
$image = file_get_contents($chemin_image);
}
 
return $image;
}
 
public function creerMiniatureImageSelonFormat($infos_image_originale, $format = 'O') {
if ($format == 'O') {
// format original : rien à faire
$image_redimensionnee = $infos_image_originale['image'];
 
} else {
if ($this->estUnFormatRogne($format)) {
if ($this->mode == self::MODE_IMAGEMAGICK) {
// si l'on dispose de la librairie imageMagick
// on applique l'algorithme d'auto détection de sujets
// qui centre la miniature sur le sujet de l'image
$image_redimensionnee = $this->opticrop($infos_image_originale, $format);
} else {
// si l'on ne dispose que de gd
// la minature est une image redimensionnée rognée au centre
$image_redimensionnee = $this->creerMiniatureCarreeRognee($infos_image_originale, $format);
}
} else if ($this->estUnFormatCarre($format)) {
// le format carre et une image redimensionnée en gardant son ratio, insérée dans un carré blanc
$image_redimensionnee = $this->creerMiniatureCarree($infos_image_originale, $format);
} else {
$image_redimensionnee = $this->creerMiniature($infos_image_originale, $format);
}
}
 
return $image_redimensionnee;
}
 
public function stockerFichierOriginal($fichier, $id) {
$chemin_fichier_origine = is_array($fichier) ? $fichier['tmp_name'] : $fichier;
 
$chemin_base_fichier = $this->creerSiNecessaireEtRenvoyerCheminStockageFichierPourIdEtFormat($id, 'O');
$nom_fichier = $this->convertirIdBddVersNomFichier($id, 'O');
 
$chemin_fichier = $chemin_base_fichier.'/'.$nom_fichier;
 
$deplacement_fichier = $this->stockerImageExterne($chemin_fichier_origine, $chemin_fichier);
 
if ($deplacement_fichier) {
$infos_image_originale = $this->obtenirImageEtInfosPourChemin($chemin_fichier);
$taux_compression = $this->renvoyerTauxCompressionPourPoids($infos_image_originale['poids_octets']);
 
if ($taux_compression < 100 && $this->mode == self::MODE_IMAGEMAGICK) {
$this->ecrireImageSurDisqueAvecMeta($chemin_fichier, $taux_compression);
}
 
return $infos_image_originale;
 
} else {
$erreur = 'ERROR : probleme durant le déplacement du fichier temporaire \n' ;
$this->logger('CEL_bugs',$erreur);
return false ;
}
}
 
public function stockerFichierEtCreerMiniatures($fichier, $id) {
 
$infos_image_originale_stockee = $this->stockerFichierOriginal($fichier, $id);
if($infos_image_originale_stockee) {
$formats = $this->getFormats();
 
// creation de miniatures pour chacuns des formats définis
foreach($formats as $format) {
$this->creerEtStockerMiniatureFichierImageSelonFormat($id, $infos_image_originale_stockee, $format);
}
} else {
$erreur = 'ERROR : impossible d\'obtenir les informations sur l\'image originale \n' ;
$this->logger('CEL_bugs',$erreur);
return false ;
}
 
return true ;
}
 
public function creerEtStockerMiniatureFichierImageSelonFormat($id ,$infos_image_originale, $format = 'O') {
$image_redimensionnee = $this->creerMiniatureImageSelonFormat($infos_image_originale, $format);
 
$taux_compression = $this->renvoyerTauxCompressionPourPoids($infos_image_originale['poids_octets']);
$this->ecrireImageSurDisque($image_redimensionnee, $id, $format, $taux_compression);
 
return true;
}
 
public function creerImageRedimensionnee($infos_image_originale, $hauteur_redimension, $largeur_redimension) {
$image_redimensionnee = imagecreatetruecolor($largeur_redimension, $hauteur_redimension);
 
imagecopyresampled($image_redimensionnee,
$infos_image_originale['image'],
0, 0,
0, 0,
$largeur_redimension,
$hauteur_redimension,
$infos_image_originale['largeur'],
$infos_image_originale['hauteur']
);
 
return $image_redimensionnee;
}
 
public function creerMiniature($informations_images, $format) {
$taille_reference_pour_format = $this->obtenirDimensionsPourFormat($format);
 
$taille_image_redimensionnee = $this->calculerTailleImage($informations_images, $taille_reference_pour_format['hauteur']);
$image_redimensionnee = $this->creerImageRedimensionnee($informations_images, $taille_image_redimensionnee['hauteur'], $taille_image_redimensionnee['largeur']);
 
return $image_redimensionnee;
}
 
public function creerMiniatureCarree($informations_image, $format) {
$taille_reference_pour_format = $this->obtenirDimensionsPourFormat($format);
$cote_carre = $taille_reference_pour_format['largeur'];
 
$image_redimensionnee_avec_rapport = $this->creerMiniature($informations_image, $format);
$taille_redimensionnee_avec_rapport = $this->calculerTailleImage($informations_image, $taille_reference_pour_format['hauteur']);
 
if ($this->estPaysage($informations_image)) {
$debut_largeur_a_copier = 0 ;
$debut_hauteur_a_copier = ($cote_carre - $taille_redimensionnee_avec_rapport['hauteur'])/2 ;
} else {
$debut_largeur_a_copier = ($cote_carre - $taille_redimensionnee_avec_rapport['largeur'])/2 ;
$debut_hauteur_a_copier = 0 ;
}
 
$image_carre_blanc_cible = $this->renvoyerEtCreerImageCarreeBlancheSelonFormat($cote_carre);
 
imagecopy($image_carre_blanc_cible, $image_redimensionnee_avec_rapport,
$debut_largeur_a_copier ,$debut_hauteur_a_copier, 0, 0,
$taille_redimensionnee_avec_rapport['largeur'], $taille_redimensionnee_avec_rapport['hauteur']
);
 
return $image_carre_blanc_cible;
}
 
public function creerMiniatureCarreeRognee($informations_image, $format) {
$taille_reference_pour_format = $this->obtenirDimensionsPourFormat($format);
$cote_carre = $taille_reference_pour_format['largeur'];
$cote_carre_non_redimensionne = 0;
 
if ($this->estPaysage($informations_image)) {
$cote_carre_non_redimensionne = $informations_image['hauteur'];
$debut_largeur_a_copier = ($informations_image['hauteur'] - $cote_carre)/2 ;
$debut_hauteur_a_copier = 0;
 
if($debut_largeur_a_copier <= 0) {
$debut_largeur_a_copier = 0;
}
 
$nb_pixels_largeur_a_copier = $cote_carre_non_redimensionne;
$nb_pixels_hauteur_a_copier = $cote_carre_non_redimensionne;
} else {
$cote_carre_non_redimensionne = $informations_image['largeur'];
$debut_largeur_a_copier = 0 ;
$debut_hauteur_a_copier = ($informations_image['largeur'] - $cote_carre)/2;
 
if ($debut_hauteur_a_copier <= 0) {
$debut_hauteur_a_copier = 0;
}
 
$nb_pixels_largeur_a_copier = $cote_carre_non_redimensionne;
$nb_pixels_hauteur_a_copier = $cote_carre_non_redimensionne;
}
 
$image_carre_temporaire = imagecreatetruecolor($cote_carre_non_redimensionne, $cote_carre_non_redimensionne);
 
imagecopyresampled($image_carre_temporaire,
$informations_image['image'],
0, 0,
$debut_largeur_a_copier,
$debut_hauteur_a_copier,
$cote_carre_non_redimensionne,
$cote_carre_non_redimensionne,
$nb_pixels_largeur_a_copier,
$nb_pixels_hauteur_a_copier
);
 
$image_redimensionnee = imagecreatetruecolor($cote_carre, $cote_carre);
 
imagecopyresampled($image_redimensionnee,
$image_carre_temporaire,
0, 0,
0, 0,
$cote_carre,
$cote_carre,
$cote_carre_non_redimensionne,
$cote_carre_non_redimensionne
);
 
return $image_redimensionnee;
}
 
public function stockerImageExterne($chemin_fichier_temp, $chemin_destination) {
if (is_uploaded_file($chemin_fichier_temp)) {
$deplacement = move_uploaded_file($chemin_fichier_temp, $chemin_destination);
} else {
$deplacement = rename($chemin_fichier_temp, $chemin_destination);
}
 
return $deplacement;
}
 
public function creerSiNecessaireEtRenvoyerCheminStockageFichierPourIdEtFormat($id, $format) {
$chemin_sur_serveur_final = $this->obtenirDossierPourFormat($id, $format);
 
if (!file_exists($chemin_sur_serveur_final)) {
umask(0);
if (!mkdir($chemin_sur_serveur_final, $this->droits, true)) {
$erreur = 'ERROR : probleme durant l\'écriture du dossier '.$format.' \n' ;
$this->logger('CEL_bugs', $erreur);
return false;
}
}
 
return $chemin_sur_serveur_final;
}
 
public function obtenirDossierPourFormat($id, $format) {
$chemin_base = Config::get('dossierImages');
 
$chemin_sur_serveur = $chemin_base;
 
$id = sprintf('%09s', $id);
$id = wordwrap($id, 3 , '_', true);
 
list($dossierNiveau1, $dossierNiveau2) = explode('_', $id);
 
$chemin_sur_serveur_final = $chemin_sur_serveur.'/'.$dossierNiveau1.'/'.$dossierNiveau2.'/'.$format;
 
return $chemin_sur_serveur_final;
}
 
public function obtenirCheminImageOriginale($id_image) {
$nom = $this->convertirIdBddVersNomFichier($id_image, 'O');
$dossier = $this->obtenirDossierPourFormat($id_image,'O');
 
return $dossier.'/'.$nom;
}
 
public function obtenirImageEtInfosPourId($id_image) {
$chemin_image_o = $this->obtenirCheminImageOriginale($id_image);
return $this->obtenirImageEtInfosPourChemin($chemin_image_o);
}
 
public function obtenirImageEtInfosPourChemin($chemin_fichier) {
$image_et_infos = false;
 
if (file_exists($chemin_fichier)) {
$image_et_infos = array();
list($image_et_infos['largeur'], $image_et_infos['hauteur']) = getimagesize($chemin_fichier);
$image_et_infos['poids_octets'] = filesize($chemin_fichier);
$image_et_infos['image'] = imagecreatefromjpeg($chemin_fichier);
$image_et_infos['chemin'] = $chemin_fichier;
}
 
return $image_et_infos;
}
 
public function obtenirDimensionsPourFormat($format) {
$dimensions = array('largeur' => 0, 'hauteur' => 0);
 
if (Config::get('format_'.$format) != null) {
list($dimensions['largeur'], $dimensions['hauteur']) = explode('_', Config::get('format_'.$format));
}
 
return $dimensions;
}
 
public function calculerTailleImage($informations_images, $taille_max) {
$HL_redimension = array();
 
if ($this->estPaysage($informations_images)) {
$rapport = $informations_images['hauteur']/$informations_images['largeur'] ;
$HL_redimension['largeur'] = round($taille_max) ;
$HL_redimension['hauteur'] = round($taille_max*$rapport) ;
} else {
$rapport = $informations_images['largeur']/$informations_images['hauteur'] ;
$HL_redimension['hauteur'] = round($taille_max) ;
$HL_redimension['largeur'] = round($taille_max*$rapport) ;
}
 
return $HL_redimension;
}
 
public function getFormats() {
return $this->formats;
}
 
public function estUnFormatCarre($format) {
return (strpos($format,'C') === 0);
}
 
public function estUnFormatRogne($format) {
return (strpos($format,'R') === 1);
}
 
public function estPaysage($informations_images) {
return $informations_images['largeur'] > $informations_images['hauteur'];
}
 
public function estPortait($informations_images) {
return $informations_images['largeur'] < $informations_images['hauteur'];
}
 
public function renvoyerTauxCompressionPourPoids($poids_octets) {
$poids_max_octets = Config::get('tailleMaxImages');
 
$ratio_compression = 100 ;
 
if ($poids_octets >= $poids_max_octets) {
$ratio_compression = 75 ;
}
 
return $ratio_compression;
}
 
public function convertirIdBddVersNomFichier($id, $format, $extension = 'jpg') {
// creation du format original
$id_avec_zeros = sprintf('%09s', $id) ;
$id_avec_zeros_underscores = wordwrap($id_avec_zeros, 3 , '_', true) ;
 
$nom_fichier = $id_avec_zeros_underscores.'_'.$format.'.'.$extension;
 
return $nom_fichier;
}
 
public function convertirBaseNomFichierVersIdBdd($nom_fichier, $formats) {
$nom_fichier_sans_extension = trim($nom_fichier, '.jpg');
 
foreach($formats as $format) {
$nom_fichier_sans_extension = trim($nom_fichier_sans_extension, '_'.$format);
}
 
$id_image = str_replace('_', '', $nom_fichier_sans_extension);
 
// suppression des 0 devant
$id_image += 0;
 
return $id_image;
}
 
public function ecrireImageSurDisque($image_binaire, $id, $format, $compression = 100) {
umask(0);
 
$chemin_sur_serveur_final = $this->creerSiNecessaireEtRenvoyerCheminStockageFichierPourIdEtFormat($id, $format);
$nom_fichier = $this->convertirIdBddVersNomFichier($id, $format);
 
if (file_exists($chemin_sur_serveur_final.'/'.$nom_fichier)) {
unlink($chemin_sur_serveur_final.'/'.$nom_fichier);
}
 
// attention, ceci ne preserve pas les metadonnées
imagejpeg($image_binaire, $chemin_sur_serveur_final.'/'.$nom_fichier, $compression);
chmod($chemin_sur_serveur_final.'/'.$nom_fichier,$this->droits);
}
 
public function ecrireImageSurDisqueAvecMeta($chemin_image_a_stocker, $compression = 100) {
$img = new Imagick($chemin_image_a_stocker);
 
// l'utilisation d'image magick préserve les métadonnées lors d'une recompression
$img->setformat("jpeg");
$img->setImageCompression(imagick::COMPRESSION_JPEG);
$img->setCompressionQuality($compression);
$img->writeImage($chemin_image_a_stocker);
$img->destroy();
 
chmod($chemin_image_a_stocker, $this->droits);
}
 
public function renvoyerEtCreerImageCarreeBlancheSelonFormat($cote) {
$image_blanche = imagecreatetruecolor($cote, $cote);
$blanc = imagecolorallocate($image_blanche, 255, 255, 255);
imagefilledrectangle($image_blanche, 0, 0, $cote, $cote, $blanc);
 
return $image_blanche;
}
 
public function detruireImageEnMemoire($image) {
imagedestroy($image);
}
 
public function detruireImageSurDisque($id) {
$formats = $this->getFormats();
 
// on detruit aussi l'image originale
$formats[] = 'O';
 
$destruction_formats_fichier = false;
 
// destructions de chacuns des formats définis
foreach($formats as $format) {
 
$dossier_format = $this->obtenirDossierPourFormat($id, $format);
$nom_fichier = $this->convertirIdBddVersNomFichier($id, $format);
 
if (file_exists($dossier_format.'/'.$nom_fichier)) {
$destruction_formats_fichier = unlink($dossier_format.'/'.$nom_fichier);
} else {
$destruction_formats_fichier = true;
}
}
 
return $destruction_formats_fichier;
}
 
/*
* edge-maximizing crop
* determines center-of-edginess, then tries different-sized crops around it.
* picks the crop with the highest normalized edginess.
* see documentation on how to tune the algorithm
*
* $informations_image - le tableau d'informations sur l'image tel que renvoyé par la fonction obtenirImageEtInfosPourChemin
* $format - le format (ex. : CS, XS, XL, CRS)
*/
public function opticrop($informations_image, $format) {
umask(0);
 
$nom_temp = md5(time());
$chemin_temp =
 
$out = Config::get('dossierImagesStockageTemp').'/'.$nom_temp;
 
$dimension_vignettes = $this->obtenirDimensionsPourFormat($format);
 
$largeur_vignette = $dimension_vignettes['largeur'];
$hauteur_vignette = $dimension_vignettes['hauteur'];
 
// source dimensions
$largeur_image_originale = $informations_image['largeur'];
$hauteur_image_originale = $informations_image['hauteur'];
 
$chemin_image = $informations_image['chemin'];
 
//if ($largeur_vignette > $largeur_image_originale || $hauteur_vignette > $hauteur_image_originale)
// die("Target dimensions must be smaller or equal to source dimensions.");
 
// parameters for the edge-maximizing crop algorithm
$r = 1; // radius of edge filter
$nk = 9; // scale count: number of crop sizes to try
$gamma = 0.2; // edge normalization parameter -- see documentation
$ar = $largeur_vignette/$hauteur_vignette; // target aspect ratio (AR)
$ar0 = $largeur_image_originale/$hauteur_image_originale; // original aspect ratio (AR)
 
$img = new Imagick($chemin_image);
$imgcp = clone $img;
 
// compute center of edginess
$img->edgeImage($r);
$img->modulateImage(100,0,100); // grayscale
$img->blackThresholdImage("#0f0f0f");
$img->writeImage($out);
// use gd for random pixel access
$im = ImageCreateFromJpeg($out);
$xcenter = 0;
$ycenter = 0;
$sum = 0;
$n = 100000;
for ($k=0; $k<$n; $k++) {
$i = mt_rand(0,$largeur_image_originale-1);
$j = mt_rand(0,$hauteur_image_originale-1);
$val = imagecolorat($im, $i, $j) & 0xFF;
$sum += $val;
$xcenter += ($i+1)*$val;
$ycenter += ($j+1)*$val;
}
$xcenter /= $sum;
$ycenter /= $sum;
 
// crop source img to target AR
if ($largeur_image_originale/$hauteur_image_originale > $ar) {
// source AR wider than target
// crop width to target AR
$wcrop0 = round($ar*$hauteur_image_originale);
$hcrop0 = $hauteur_image_originale;
} else {
// crop height to target AR
$wcrop0 = $largeur_image_originale;
$hcrop0 = round($largeur_image_originale/$ar);
}
 
// crop parameters for all scales and translations
$params = array();
 
// crop at different scales
$hgap = $hcrop0 - $hauteur_vignette;
$hinc = ($nk == 1) ? 0 : $hgap / ($nk - 1);
$wgap = $wcrop0 - $largeur_vignette;
$winc = ($nk == 1) ? 0 : $wgap / ($nk - 1);
 
// find window with highest normalized edginess
$n = 10000;
$maxbetanorm = 0;
$maxfile = '';
$maxparam = array('w'=>0, 'h'=>0, 'x'=>0, 'y'=>0);
 
for ($k = 0; $k < $nk; $k++) {
$hcrop = round($hcrop0 - $k*$hinc);
$wcrop = round($wcrop0 - $k*$winc);
$xcrop = $xcenter - $wcrop / 2;
$ycrop = $ycenter - $hcrop / 2;
//echo("crop: $wcrop, $hcrop, $xcrop, $ycrop");
 
if ($xcrop < 0) $xcrop = 0;
if ($xcrop+$wcrop > $largeur_image_originale) $xcrop = $largeur_image_originale-$wcrop;
if ($ycrop < 0) $ycrop = 0;
if ($ycrop+$hcrop > $hauteur_image_originale) $ycrop = $hauteur_image_originale-$hcrop;
 
$beta = 0;
for ($c=0; $c<$n; $c++) {
$i = mt_rand(0,$wcrop-1);
$j = mt_rand(0,$hcrop-1);
$beta += imagecolorat($im, $xcrop+$i, $ycrop+$j) & 0xFF;
}
$area = $wcrop * $hcrop;
$betanorm = $beta / ($n*pow($area, $gamma-1));
// echo("beta: $beta; betan: $betanorm");
// echo("image$k.jpg:<br/>\n<img src=\"$currfile\"/>");
// best image found, save it
 
if ($betanorm > $maxbetanorm) {
 
$maxbetanorm = $betanorm;
$maxparam['w'] = $wcrop;
$maxparam['h'] = $hcrop;
$maxparam['x'] = $xcrop;
$maxparam['y'] = $ycrop;
}
}
 
// return image
$imgcp->cropImage($maxparam['w'], $maxparam['h'], $maxparam['x'], $maxparam['y']);
$imgcp->scaleImage($largeur_vignette, $hauteur_vignette);
$imgcp->writeImage($out);
chmod($out, 0777);
$img->destroy();
$imgcp->destroy();
 
$image_sortie = ImageCreateFromJpeg($out);
unlink($out);
 
return $image_sortie;
}
}
/branches/v3.01-serpe/scripts/modules/pull_plantnet/PullPlantnet.php
New file
0,0 → 1,802
<?php
 
/*
PHP 7
 
Script used to synchronize PN occ with Flora Data
 
Écrit en franglish pour une meilleure compréhension (lol)
*/
 
class PullPlantnet extends Script {
 
protected $bdd;
 
protected $debug = false;
 
protected $allowedPartners = ['tb', 'pn'];
 
// Nom du fichier contenant les correspondances d'ID TB/PN
protected $correspondingIdsFilename = '';
 
// Cache d'informations utilisateurs provenant de l'annuaire TB
protected $userInfos = [];
 
// Paramètre de suivi et de pagination de l'API des obs PN
protected $currentPage = '';
protected $lastTimestamp = '';
protected $hasMore = false;
 
// Traduction des organes de PN
protected $tagsImageTraduits = [
'flower' => 'fleur',
'fruit' => 'fruit',
'leaf' => 'feuille',
'bark' => 'écorce',
'branch' => 'branche',
'habit' => 'port',
];
 
// Différents types de lifecle possible pour filtrer les obs
// Modified renvoi les obs en fonction de leur date de modif
// Created, en fonction de la date de création
// Deleted, well, you already got it
protected $lifecycles = [
'created',
'modified',
'deleted', // deleted peut être très lent (pas d'index coté PN pour le moment)
];
 
/**
* Paramêtres par défaut disponibles pour la ligne de commande
* le tableau se construit de la forme suivante :
* - clé = nom du paramêtre '-foo'
* - value = contient un nouveau tableau composé de cette façon :
* - booléen: true si le paramêtre est obligatoire
* - booléen ou var : true si le paramêtre nécessite un valeur à sa suite ou la valeur par défaut
* - string: description du contenu du paramêtre
* Les paramêtres optionels devraient être déclaré à la fin du tableau.
* Le dernier parametre du tableau peut avoir la valeur '...',
* il contiendra alors l'ensemble des paramêtres suivant trouvés sur la ligne de commande.
* @var array
*/
protected $parametres_autorises = array(
'-startDate' => array(false, true, 'Date de début (parsée par strtotime). Ex: "YYYY:MM:DD HH:II:SS"'),
'-lifecycle' => array(false, true, 'Par défaut : modified ; Au choix parmi : created/modified/deleted (deleted est lent)'),
'-pnObsId' => array(false, true, "ID de l'obs chez PlantNet"),
'-project' => array(false, true, "projectId de l'obs chez PlantNet"),
'-tbObsId' => array(false, true, "ID de l'obs chez Tela"),
'-debug' => array(false, false, "Mode débug (ajoute du log) Au choix parmi : debug/log (log est plus verbeux)"),
);
 
public function __construct($script_nom, $parametres_cli) {
parent::__construct($script_nom, $parametres_cli);
$this->bdd = new Bdd();
 
$this->correspondingIdsFilename = Config::get('correspondingIdsFilename');
 
$this->debug = $this->getParametre('debug');
}
 
public function executer() {
$cmd = $this->getParametre('a');
 
switch ($cmd) {
case 'updateLatest':
$this->updateLatest($this->getParametre('startDate'), $this->getParametre('lifecycle'));
break;
case 'updateOnePN':
$this->updateOnePN((int)$this->getParametre('pnObsId'), $this->getParametre('project'));
break;
case 'updateOneTB':
$this->updateOneTB((int)$this->getParametre('tbObsId'));
break;
case 'updateCorrespondingIdsTable':
$this->updateCorrespondingIdsTable();
break;
default:
$msg = "Erreur : la commande '$cmd' n'existe pas!\n"
. ', utilisez plutôt :' . "\n"
. 'php cli.php PullPlantnet -a updateLatest -startDate "YYYY:MM:DD HH:II:SS" [[-lifecycle [modified]/created/deleted]]' . "\n"
. 'php cli.php PullPlantnet -a updateOnePN -pnObsId "1234567890" -project "xxxxxx"' . "\n"
. 'php cli.php PullPlantnet -a updateOneTB -tbObsId "1234567890"' . "\n"
. 'php cli.php PullPlantnet -a updateCorrespondingIdsTable' . "\n"
;
throw new Exception($msg);
}
}
 
/**
* Considering all modified pn obs since startDate
* Inserting obs in tb db (if new and matching user email)
*/
private function updateLatest(string $startDate = '1917:03:15 00:00:00', string $lifecycle = 'modified') {
$startDate = strtotime($startDate) * 1000; // we need a microtimestamp
 
do {
$observations_PN = $this->getLatest($startDate, $lifecycle);
$this->updateObs($observations_PN);
} while ($this->hasMore);
}
 
private function getLatest(int $startDate, string $lifecycle): array {
$this->refreshBddConnexion();
 
if (!$this->currentPage) {
// hop, on appelle le service de PN
$url_service = str_replace(
['{token}', '{startDate}', '{lifecycle}'],
[Config::get('tokenPlantnet'), $startDate, $lifecycle],
Config::get('urlPlantnetBase').Config::get('urlPlantnetLatestChanges')
);
 
$this->debug("URL service derniers changements : $url_service");
 
$this->currentPage = $url_service;
}
 
$ch = curl_init($this->currentPage);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$reponse = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$temps = curl_getinfo($ch, CURLINFO_TOTAL_TIME);
curl_close($ch);
 
$this->debug('Temps total en secondes : '.$temps);
 
// cool, maintenant on va trier ce qu'on a reçu
if (!$reponse) {
throw new Exception("\nPN ne répond rien à l'adresse {$this->currentPage}\n");
} elseif (200 != $code) {
// l'api répond avec une 404 quand y'a une date dans le futur ou simplement pas de nouvelle obs...
if (404 == $code && strpos($reponse, 'No more results')) {
$this->log("Pas d'autres résultats");
$this->hasMore = false;
$this->currentPage = '';
return [];
}
throw new Exception("\nPN répond avec une $code à l'adresse {$this->currentPage} : $reponse\n");
}
$responseJson = json_decode($reponse, true);
$observations_PN = $responseJson['data'] ?? [];
 
$this->hasMore = $responseJson['hasMore'];
$this->lastTimestamp = end($observations_PN)['dateUpdated'];
if ($this->hasMore) {
// $url_service = Config::get('urlPlantnetBase').$responseJson['next'];
// Build next page url with last read timestamp, to avoid pagination latency
$url_service = str_replace(
['{token}', '{startDate}', '{lifecycle}'],
[Config::get('tokenPlantnet'), $this->lastTimestamp, $lifecycle],
Config::get('urlPlantnetBase').Config::get('urlPlantnetLatestChanges')
);
$this->currentPage = $url_service;
$this->debug("URL service derniers changements, page suivante : {$this->currentPage}");
} else {
$this->currentPage = '';
}
 
return $observations_PN;
}
 
private function getProjects(): array {
// get PN projects list (useless since we have a single source)
$url = str_replace('{token}', Config::get('tokenPlantnet'), Config::get('urlPlantnetBase').Config::get('urlPlantnetProjects'));
 
$this->debug("URL service liste projets : $url");
 
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$reponse = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
 
if (!$reponse || 200 != $code) {
throw new Exception("\nPN répond avec une $code à l'adresse $url : $reponse\n");
}
$pnProjects = json_decode($reponse, true);
 
echo 'Liste de projets récupérée : ' . count($pnProjects) . " projets dans la liste\n";
 
$this->debug("Liste projets : " . json_encode($pnProjects));
 
return $pnProjects;
}
 
/**
* For a given bunch of plantnet obs, post new one threw saisie widget service
*/
private function updateObs(array $observations_PN) {
 
$url_cel_widget_saisie = Config::get('urlCelWidgetSaisie');
 
foreach ($observations_PN as $obs) {
// on ne teste pas la suppression de l'obs ici, faut le faire après avoir vérifié si on l'a déjà synchro
if (!isset($obs['currentName'])) {
$this->log("Obs {$obs['id']} sans nom de taxon, on zap");
continue; // pas de nom de taxon, obs inutile
}
if (!isset($obs['geo'])) {
$this->log("Obs {$obs['id']} sans geom, on zap");
continue; // pas de position, obs inutile
}
if (!isset($obs['dateObs'])) {
$this->log("Obs {$obs['id']} sans date, on zap");
continue; // pas de date, obs inutile
}
 
if (isset($obs['partner']['id']) && 'tela' === $obs['partner']['id']) {
// c'est une obs tela
// si c'est mis à jour récemment coté PN et qu'on l'a pas supprimée chez nous entre temps
// on update les votes PN
// on update l'identification proposée par PN
 
// @TODO
$this->log("Obs {$obs['id']} venant de Tela, mise à jour pas implémentée, on zap");
continue;
} elseif (!isset($obs['partner']['id'])) {
// ce n'est pas une obs d'un partenaire, c'est donc une obs PN
// on récupère l'id utilisateur tela via son mail
$email = $obs['author']['email'];
$infos_utilisateur = $this->findUserInfo($email);
if (!$infos_utilisateur) {
$this->log("Obs {$obs['id']} email $email ne provient pas d'un telabotaniste");
continue; // c'est pas un telabotaniste
}
$this->log("Obs {$obs['id']} email $email provient d'un telabotaniste");
$this->log(json_encode($obs));
// die(var_dump($obs));
 
// vérification que l'obs n'a pas déjà été ajoutée à la BdD de Tela
$sql = "SELECT date_maj, id_observation FROM cel_plantnet WHERE id_plantnet = '{$obs['id']}'"
. ' -- ' . __FILE__ . ':' . __LINE__;
$res = $this->bdd->recupererTous($sql);
// die(var_dump($res));
if ($res) {
// l'obs existe déjà, on vérifie si il faut màj puis on passe à la suite
// la date de l'obs est un microtime, donc on coupe les millièmes
// die(var_dump((int)($obs['dateUpdated']/1000), strtotime($res[0]['date_maj'])));
if ((int)($obs['dateUpdated']/1000) > strtotime($res[0]['date_maj'])) {
echo "Obs déjà en base, mise à jour : ID PN {$obs['id']} ; ID TB {$res[0]['id_observation']} ; utilisateur_tb $email\n";
$this->updateFromPN($obs, $res[0]['id_observation']);
} else {
echo "Obs déjà en base, déjà à jour : ID PN {$obs['id']} ; ID TB {$res[0]['id_observation']} ; utilisateur_tb $email\n";
}
continue;
}
 
if (isset($obs['deleted']) && (true === $obs['deleted'])) {
$this->log("Obs {$obs['id']} supprimée coté PlantNet");
continue; // obs supprimée chez PN sans être passée par nos serveurs
}
 
$images = [];
$tags_images = [];
$images_size = 0;
foreach ($obs['images'] ?? [] as $i => $image) {
if ($image['deleted']) {
$this->log("Obs {$obs['id']} image {$image['id']} supprimée coté PlantNet");
continue;
}
 
// téléchargement de l'image PN
$img = false;
$retry = 3;
do {
$img = file_get_contents($image['o']);
if (!$img) {
$retry--;
$this->log("Obs {$obs['id']} lecture image {$image['id']} tentatives restantes : $retry");
}
} while (!$img && $retry);
 
if (!$img) {
echo "Abandon, image impossible à télécharger : {$image['o']}\n";
continue;
}
 
// Écriture dans un fichier temporaire
$tempfile = tempnam("/tmp", "PullPN_") . ".jpg";
$handle = fopen($tempfile, "w");
fwrite($handle, $img);
fclose($handle);
$images_size += filesize($tempfile);
 
$this->log("Obs {$obs['id']} image {$image['id']} créée " . number_format(filesize($tempfile), 0, ',', ' ') . " octets : $tempfile");
 
$params = [
'name' => 'image' . $i,
'fichier' => new CURLFile($tempfile, 'image/jpg')
];
 
// envoi de l'image PN à l'api de création
$ch = curl_init(Config::get('urlCelUploadImageTemp'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
$reponse = curl_exec($ch);
$this->log("Obs {$obs['id']} image {$image['id']} envoyée à l'api de création. Réponse : $reponse");
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
 
unlink($tempfile);
 
$reponse = simplexml_load_string($reponse);
/* Response format if success:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<miniature-url>https://api-test.tela-botanica.org/tmp/cel/imgtmp/chaflipe_min.jpg</miniature-url>
<image-nom>chaflipe.jpg</image-nom>
<message></message>
<debogage></debogage>
</root>
*/
// var_dump($reponse);
if ($reponse && '' == $reponse->message /* && '' != $reponse->{'image-nom'} */) {
$images[] = (string)$reponse->{'image-nom'};
 
$tag = $this->tagsImageTraduits[$image['organ']] ?? $image['organ'];
if (trim($tag)) {
$tags_images[] = $tag;
}
}
}
// var_dump($images, $tags_images);
// die();
 
$geo = $this->getGeoInfo($obs['geo']);
$this->log("Obs {$obs['id']} décodage du geom : " . json_encode($obs['geo']));
$this->log("Obs {$obs['id']} geom décodé : " . json_encode($geo));
 
// on insère l'obs via le service CelWidgetSaisie
$infos_obs = [
'obsId1[date]' => date('d/m/Y', intdiv($obs['dateObs'], 1000)),
'obsId1[latitude]' => $geo['lat'] ?? null,
'obsId1[longitude]' => $geo['lon'] ?? null,
'obsId1[pays]' => $geo['countryCode'] ?? null,
'obsId1[code_postal]' => $geo['postcode'] ?? null,
'obsId1[commune_nom]' => $geo['city'] ?? null,
// 'obsId1[commune_code_insee]' => '',
// 'obsId1[lieudit]' => '',
// 'obsId1[milieu]' => '',
'obsId1[nom_sel]' => $obs['currentName'],
// 'obsId1[nom_ret]' => '',
// 'obsId1[famille]' => '',
'obsId1[certitude]' => 'douteux',
// 'obsId1[notes]' => '',
// 'obsId1[num_nom_ret]' => '',
// 'obsId1[num_nom_sel]' => '',
// 'obsId1[num_taxon]' => '',
'obsId1[referentiel]' => $this->findProbableTaxoRepos($obs['project']), // @TODO faire une fois et mettre en cache
// 'obsId1[station]' => '',
'obsId1[obs_id]' => $obs['id'],
'projet' => 'PlantNet',
'tag-img' => implode(', ', $tags_images ?? []),
'tag-obs' => 'plantnet, plantnet-mobile, pn:referentiel-' . $obs['project'],
'utilisateur[courriel]' => $email,
'utilisateur[id_utilisateur]' => $infos_utilisateur['id'],
'utilisateur[nom]' => $infos_utilisateur['nom'],
'utilisateur[prenom]' => $infos_utilisateur['prenom'],
'origin' => 'pullPlantnet',
];
 
foreach ($images as $i => $image) {
$infos_obs["obsId1[image_nom][$i]"] = $image;
}
 
$this->log("Obs {$obs['id']} prête à être insérée : " . json_encode($infos_obs));
 
// curl post $infos_obs
$ch = curl_init($url_cel_widget_saisie);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $infos_obs);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$reponse = curl_exec($ch);
$this->log("Obs {$obs['id']} réponse de la requête d'insertion : " . json_encode($reponse));
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
 
if (!$reponse || 200 != $code) {
throw new Exception("Ça a pété à l'envoi de l'obs :\n $reponse\n avec l'obs : " . json_encode($infos_obs) . "\n");
}
 
$id_obs_tb = json_decode($reponse, true)['id'];
$id_obs_pn = $obs['id'];
// on insère les ids de correspondance obsPN obsTB dans la table cel_plantnet
$sql = 'INSERT INTO cel_plantnet (id_observation, id_plantnet, date_maj)'
.' VALUES (%s, %s, NOW())'
. ' -- ' . __FILE__ . ':' . __LINE__;
$sql = sprintf($sql, $this->bdd->proteger($id_obs_tb), $this->bdd->proteger($id_obs_pn));
$this->bdd->requeter($sql);
 
$date = date('d/m/Y H:i:s', intdiv($obs['dateObs'], 1000));
$count_img = count($images);
$images_size = number_format($images_size, 0, ',', ' ');
echo "Obs insérée en base : ID PN $id_obs_pn ; ID TB $id_obs_tb ; utilisateur_tb $email ; date_obs $date ; images $count_img ; taille_octets $images_size \n";
}
}
}
 
/**
* Return TB taxo repos names for given PN project
*
* @return string
*/
private function findProbableTaxoRepos($pnProjectId) {
$selectedRepos = [];
// Référentiels tela botanica indexés par référentiels PN (version octobre 2019)
// @TODO à revoir en fonction des nouvelles mises en prod de nouveaux référentiels
$tbTaxoRepos = [
'afn' => [/*'apd', */'isfan'],
'aft' => ['apd'],
'antilles' => ['bdtxa', 'taxref'],
'canada' => ['vascan'],
'comores' => ['apd'],
'endemia' => ['florical', 'taxref'],
'taxref ' => ['bdtfx'],
'guyane' => ['aublet', 'taxref'],
'hawai' => [],
'lapaz' => ['aublet', 'taxref'],
'martinique' => ['bdtxa', 'taxref'],
'maurice' => ['apd'],
'medor' => ['lbf'],
'namerica' => [],
'polynesiefr' => ['taxref'],
'prosea' => ['asia'],
'prota' => ['isfan', 'apd'],
'provence' => ['bdtfx', 'taxref'],
'reunion' => ['bdtre', 'taxref'],
'salad' => ['bdtfx', 'taxref'],
'useful' => [],
'weurope' => ['bdtfx'],
'the-plant-list' => [],
'iscantree' => ['apd'],
'central-america' => [],
'invasion' => ['bdtfx'],
'weeds' => ['bdtfx'],
'malaysia' => [],
];
 
if (array_key_exists($pnProjectId, $tbTaxoRepos)) {
array_map(function($repo) use ($selectedRepos) {
$selectedRepos[] = $repo;
}, $tbTaxoRepos[$pnProjectId]);
}
 
// @TODO chercher le nom dans plusieurs référentiels avant d'envoyer l'obs
// prendre "enrichirDonneesTaxonomiques" du service de saisie et le coller ici
// en attendant on envoi juste le premier référentiel trouvé
return $selectedRepos[0] ?? '';
}
 
/*
* Retrouve les infos d'un utilisateur tela à partir de son email
* @param string $email User email
* @return mixed Tableau des infos de l'utilisateur
* False si l'email n'est pas trouvé dans l'annuaire
*/
private function findUserInfo($email) {
// cherche dans le cache
if (array_key_exists($email, $this->userInfos)) {
$infosUtilisateur = $this->userInfos[$email];
// echo("Email in cache : $email\n");
} else {
$infosUtilisateur = false;
$urlInfosUtilisateur = str_replace('{email}', $email, Config::get('urlAnnuaireIdParEmail'));
 
$reponse = false;
$retry = 3;
do {
$ch = curl_init($urlInfosUtilisateur);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$reponse = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$retry--;
if (!$reponse) {
sleep(1);
$this->log("Echec annuaire pour la requête $urlInfosUtilisateur tentatives restantes : $retry");
}
} while (!$reponse && $retry);
 
if (!$reponse) {
echo "Abandon, l'annuaire semble injoignable, impossible à télécharger : $urlInfosUtilisateur\n";
return false;
}
 
// on peut pas tester le code de réponse de cette api, si l'utilisateur n'est pas trouvé ça fait une 500 >_<
// une bonne réponse ressemble à ça :
// {"killian@tela-botanica.org":{"id":"30489","prenom":"Killian","nom":"Stefanini","pseudo":"Killian Stefanini","pseudoUtilise":true,"intitule":"Killian Stefanini","avatar":"\/\/www.gravatar.com\/avatar\/a9b9b8484076540924c03af816c77fc8?s=50&r=g&d=mm","groupes":{"19226":"adm","18943":"","23152":"","21684":"","21598":"adm","23184":"","23516":""},"permissions":["editor"],"nomWiki":"KillianStefanini"}}
$reponse = json_decode($reponse, true);
if (!isset($reponse)) {
throw new Exception("\nL'annuaire n'a pas répondu avec du json : code $code à l'adresse $urlInfosUtilisateur : $reponse\n");
}
 
if (!isset($reponse['error'])) {
$infosUtilisateur = array_shift($reponse);
}
 
// met en cache
$this->userInfos[$email] = $infosUtilisateur;
// echo("Email cached : $email\n");
}
 
return $infosUtilisateur;
}
 
private function getGeoInfo($obs) {
$geo = [];
if (!isset($obs['lat']) && !isset($obs['lon'])) {
return $geo;
}
 
// $data = [
// 'hitsPerPage' => 1,
// 'aroundLatLng' => "{$obs['lat']},{$obs['lon']}"
// ];
$headers = [
'X-Algolia-Application-Id' => Config::get('algoliaApplicationId'),
'X-Algolia-API-Key' => Config::get('algoliaAPIKey'),
];
 
$lat = number_format($obs['lat'], 6, '.', '');
$lon = number_format($obs['lon'], 6, '.', '');
 
$ch = curl_init(Config::get('urlReverseGeocodingLatLng')."$lat,$lon");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$reponse = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
 
if ($reponse) {
$reponse = json_decode($reponse, true);
// die(var_dump($reponse));
$infos = $reponse['hits'][0];
 
$geo = [
'lat' => (string) $obs['lat'],
'lon' => (string) $obs['lon'],
'country' => $infos['country']['fr'] ?? $infos['country']['default'],
'city' => $infos['city']['default'][0] ?? null,
'postcode' => $infos['postcode'][0] ?? null,
'countryCode' => strtoupper($infos['country_code']),
];
}
 
return $geo;
}
 
private function updateFromPN(array $pnObs, string $tbObsId) {
if (!is_array($pnObs) || !is_string($tbObsId)) {
// die(var_dump($pnObs, $tbObsId));
throw new Exception("\nBad params types, give me an array and an integer plz\n");
}
// die(var_dump($pnObs));
 
// log update date to cel_plantnet
$sql = "UPDATE cel_plantnet SET date_maj = NOW() WHERE id_observation = $tbObsId"
. ' -- ' . __FILE__ . ':' . __LINE__;
$this->bdd->requeter($sql);
 
// check for deleted
if (isset($pnObs['deleted']) && (true === $pnObs['deleted'])) {
// est-ce une obs issue de PN ?
//// faut regarder le champ input_source == PlantNet
$sql = "SELECT input_source FROM occurrence WHERE id = '$tbObsId'"
. ' -- ' . __FILE__ . ':' . __LINE__;
$res = $this->bdd->recupererTous($sql);
 
if (isset($res[0]) && ('PlantNet' === $res[0]['input_source'])) {
// oui ? alors supprimer obs !
echo "Obs supprimée coté PN, suppression : ID PN {$pnObs['id']} ; ID TB {$res[0]['id_observation']}\n";
 
$sql = "UPDATE photo SET occurrence_id = NULL WHERE occurrence_id = '$tbObsId'"
. ' -- ' . __FILE__ . ':' . __LINE__;
$this->bdd->requeter($sql);
 
$sql = "DELETE FROM occurrence WHERE id = '$tbObsId'"
. ' -- ' . __FILE__ . ':' . __LINE__;
$this->bdd->requeter($sql);
}
}
 
// check for deleted images
foreach ($pnObs['images'] as $image) {
if ($image['deleted']) {
// no idea
// y'a pas encore de lien tangible entre les images PN et les notres
}
}
 
// @TODO : finir la comparaison des proposition entre celles de Tela et celles PN
// // check for votes (notes et taxon)
// $names = [];
// foreach ($pnObs['computed']['votes'] as $vote) {
// echo($vote['name']);
// echo($vote['score']['pn']);
// echo($vote['score']['total']);
 
// $names[$vote['score']['pn']] = $vote['name'];
// }
// ksort($names, SORT_NUMERIC); // votes sorted by score asc
// $pn_sorted_votes = array_reverse($names, true); // desc
 
// // get existing votes
// $sql = "SELECT id_commentaire, nom_sel, nom_sel_nn, nom_referentiel, nom_referentiel, utilisateur_courriel, proposition_initiale, proposition_retenue"
// . "WHERE ce_observation = '$tbObsId' AND ce_commentaire_parent = 0"
// . ' -- ' . __FILE__ . ':' . __LINE__;
// $existing_votes = $this->bdd->recupererTous($sql);
 
// // @TODO : compare votes
// // insert_new_votes($pn_sorted_votes, $existing_votes);
}
 
private function updateOnePN($pnObsId, $pnProjectId) {
if (!is_int($pnObsId) || !is_string($pnProjectId)) {
throw new Exception("\nBad params types, give me an integer and a string plz\n");
}
// get PN project list
$list = [];
$pnProjects = $this->getProjects(); // refresh projects list
foreach ($pnProjects as $project) {
$list[$project['id']] = $project['name'];
}
 
// if project not in list display list
if (!array_key_exists($pnProjectId, $list)) {
echo "Available projects:\n";
foreach ($list as $projectId => $projectName) {
echo " - $projectId ($projectName)\n";
}
throw new Exception("Project $pnProjectId does not exist\n");
}
 
// get PN obs
$urlInfosObs = str_replace(
['{token}', '{project}', '{id}'],
[Config::get('tokenPlantnet'), $pnProjectId, $pnObsId],
Config::get('urlPlantnetBase').Config::get('urlPlantnetObsById')
);
$ch = curl_init($urlInfosObs);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
 
if (!$response || 200 != $code) {
throw new Exception("\nPlantnet api ($urlInfosObs) replied with code $code : $response\n");
}
 
// change last modification date to force update
$obs = json_decode($response, true);
$date = new DateTime();
$date->setTimestamp(intdiv($obs['dateUpdated'], 1000) - 1);
$date = $this->bdd->proteger($date->format('Y-m-d H:i:s'));
$sql = "UPDATE cel_plantnet SET date_maj = $date WHERE id_plantnet = '$pnObsId'"
. ' -- ' . __FILE__ . ':' . __LINE__;
$this->bdd->requeter($sql);
 
$this->updateObs([$obs]);
}
 
private function updateOneTB($id) {
$corres = $this->findMatchingPartnerId($id, 'tb');
echo "L'obs tela avec l'id $id a été trouvée chez plantnet avec l'id : " .$corres['pn'] . "\n";
echo "La suite n'a pas été implémentée.\n";
}
 
/*
* Trouve les ids d'une obs chez les partenaires
* Il faut lancer updateMatchingPartnersIds pour obtenir une liste fraiche
*
* @param string $id L'id de l'obs
* @param string $partner Le partenaire correspondant à l'id de l'obs
*
* @return mixed Le tableau de correspondances d'ids
* False si l'id n'est pas trouvé
*/
private function findMatchingPartnerId($id, $partner) {
if (!in_array($partner, $this->allowedPartners)) {
throw new Exception("\nUnknown partner : $partner. Available Partners : " . implode(', ', $this->allowedPartners) . "\n");
}
 
// le json ressemble à ça :
// {"tb":"2369732","pn":"1001020199"}, {"tb":"2369733","pn":"1001020176"}, ...
$ids = json_decode(file_get_contents($this->correspondingIdsFilename), true);
// extrait la colonne du partenaire recherché du tableau multidimensionnel fraichement décodé
$partnerColumn = array_column($ids, $partner);
// cherche l'index de l'id recherché
$index = array_search($id, $partnerColumn);
 
return $index ? $ids[$index] : false;
}
 
private function updateCorrespondingIdsTable() {
// first update cache file if necessary
if (!file_exists($this->correspondingIdsFilename) || time() > (filemtime($this->correspondingIdsFilename) + (24 * 3600))) {
$this->updateMatchingPartnersIds();
}
 
$data = file_get_contents($this->correspondingIdsFilename);
$data = json_decode($data, true);
 
$now = new DateTime;
$now = $this->bdd->proteger($now->format('Y-m-d H:i:s'));
 
$sqlInsert = 'INSERT INTO cel_plantnet (id_observation, id_plantnet, date_maj)'
. ' VALUES %s'
. ' ON DUPLICATE KEY UPDATE id_observation=VALUES(id_observation), id_plantnet=VALUES(id_plantnet)'
. ' -- ' . __FILE__ . ':' . __LINE__;
$values = '';
 
echo "Updating matching partners ids table\n";
foreach ($data as $id => $corres) {
$id_obs_tb = $this->bdd->proteger($corres['tb']);
$id_obs_pn = $this->bdd->proteger($corres['pn']);
// on insère les ids de correspondance obsPN obsTB dans la table cel_plantnet
$values .= " ($id_obs_tb, $id_obs_pn, $now),";
 
if (0 === $id % 100) {
$values = substr($values, 0, -1); // retire la dernière virgule
$sql = sprintf($sqlInsert, $values);
// var_dump($sql);
$this->bdd->requeter($sql);
$values = '';
}
}
// Faut envoyer les dernières données qui sont pas passées dans le modulo
$values = substr($values, 0, -1); // retire la dernière virgule
$sql = sprintf($sqlInsert, $values);
// var_dump($sql);
$this->bdd->requeter($sql);
 
$count = count($data);
echo "Success: #$count updated\n";
}
 
private function updateMatchingPartnersIds() {
// curl -X GET --header 'Accept: application/json' 'https://bourbonnais.cirad.fr:8081/v1/edi/observations/partnerids?token=f0ca433febe320675c24ee2ddfab8b82f65d556b' > partnerids.txt
$matchingPartnersIdsServiceUrl = str_replace(
'{token}',
Config::get('tokenPlantnet'),
Config::get('urlPlantnetBase').Config::get('urlPlantnetMatchingPartner')
);
$ch = curl_init($matchingPartnersIdsServiceUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 
echo "Updating matching partners ids...\n";
$reponse = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
 
 
if (!$reponse || 200 != $code) {
throw new Exception("\nError updating partners ids, http error code \"$code\" whith url \"$matchingPartnersIdsServiceUrl\"...\n");
}
echo "Response data from PN api gathered, know computing...\n";
 
if (!file_put_contents($this->correspondingIdsFilename, $reponse)) {
throw new Exception("\nError writing correspondingIdsFilename with path : " . $this->correspondingIdsFilename . "\n");
}
echo "Matching partners ids saved!";
}
 
private function debug($text) {
if ($this->debug) {
echo 'DEBUG - ' . $text . "\n";
}
}
 
private function log($text) {
if ('log' == $this->debug) {
echo 'LOG - ' . $text . "\n";
}
}
 
private function refreshBddConnexion() {
$this->bdd = null;
$this->log("Fermeture et création d'une nouvelle connexion à la BdD");
$this->bdd = new Bdd();
}
}
/branches/v3.01-serpe/scripts/modules/pull_plantnet/config.defaut.ini
New file
0,0 → 1,22
; URL de base du service (test 8081 ou prod 8080)
urlPlantnetBase = 'https://bourbonnais.cirad.fr:8081'
; Liste des projets (ref) de PlantNet
urlPlantnetProjects = '/v1/edi/partners/projects?token={token}'
; Url pour avoir les correspondandes des ids des obs chez les partenaires
urlPlantnetMatchingPartner = '/v1/edi/partners/observations/partnerids?token={token}'
; Url de base du service de suivi des obs plantnet
urlPlantnetLatestChanges = '/v1/edi/partners/observations/{lifecycle}/latest?token={token}&startDate={startDate}';
; Url pour obtenir une obs PN
urlPlantnetObsById = '/v1/edi/partners/projects/{project}/observations/{id}?token={token}'
; token (prod ou test)
tokenPlantnet = 'celuiquilitcaestuntron';
; Url d'appel du service CelWidgetSaisie
urlCelWidgetSaisie = 'https://api-test.tela-botanica.org/service:cel:CelWidgetSaisie'
; Url pour les infos d'un utilisateur par email
urlAnnuaireIdParEmail = 'https://beta.tela-botanica.org/service:annuaire:utilisateur/identite-par-courriel/{email}'
; Url pour envoyer les images temporaires
urlCelUploadImageTemp = 'https://api-test.tela-botanica.org/service:cel:CelWidgetUploadImageTemp'
; Fichier de cache pour les correspondances d'id des obs PN et TB
correspondingIdsFilename = '/home/test/www/scripts/cel/modules/pull_plantnet/idstbpn.json'
; API de reverse geocoding Algolia (remplacer 'places' au début par le Application ID)
urlReverseGeocodingLatLng = 'https://places-dsn.algolia.net/1/places/reverse?hitsPerPage=1&aroundLatLng='
/branches/v3.01-serpe/scripts/configurations/config.defaut.ini
New file
0,0 → 1,73
; Encodage : UTF-8
; +------------------------------------------------------------------------------------------------------+
; Info sur l'application
info.nom = Scripts du CEL
; Abréviation de l'application
info.abr = CEL-SCRIPTS
; Version du Framework nécessaire au fonctionnement de cette application
info.framework.version = 0.4
; Encodage de l'application
encodage_appli = "UTF-8"
; Chemin de l'application (pour l'utiliser dans ce fichier)
chemin_scripts = "php:Framework::getCheminAppli()"
; +------------------------------------------------------------------------------------------------------+
; Débogage
; Indique si oui ou non on veut afficher le débogage.
debogage = true
; Indique si oui ou non on veut lancer le chronométrage
chronometrage = false
 
+------------------------------------------------------------------------------------------------------+
; Paramètrage de la base de données.
; bdd_abstraction : abstraction de la base de données.
; bdd_protocole : Protocole de la base de données.
; bdd_serveur : Nom du serveur de bases de données.
; bdd_utilisateur : Nom de l'utilisateur de la base de données.
; bdd_mot_de_passe : Mot de passe de l'utilisateur de la base de données.
; bdd_nom : Nom de la base de données principale.
; bdd_encodage : Encodage de la base de données principale. Normalement le même que l'application mais au format base de
; données : voir ici : http://dev.mysql.com/doc/refman/5.0/en/charset-charsets.html
; et là: http://www.postgresql.org/docs/8.1/static/multibyte.html pour les correspondances
 
bdd_abstraction = pdo
bdd_protocole = mysql
bdd_serveur = localhost
bdd_utilisateur = "root"
bdd_mot_de_passe = ""
bdd_nom = "tb_cel"
bdd_encodage = "utf8"
 
format_XS = 150_100
format_S = 400_300
format_CRS = 300_300
format_M = 600_450
format_L = 800_600
format_XL = 1024_768
format_X2L = 1280_960
format_X3L = 1600_1200
format_CRX2S = 63_63
format_CS = 300_300
format_CXS = 100_100
format_CRXS = 100_100
 
; Dossier de base contenant les données d'eFlore (Fichiers TSV et SQL)
dossierDonneesEflore = "/home/telabotap/www/eflore/donnees/"
 
; Dossier de base des images du cel (attention pas de / terminal nécessaire)
dossierImages = "/home/apitela/www/images";
; dossier de stockage temporaire des imagers
dossierImagesStockageTemp = "/home/apitela/www/tmp";
tailleMaxImages = 2097152;
 
+------------------------------------------------------------------------------------------------------+
; Url de base du service fournissant les zones geographiques
urlZoneGeoTpl = "http://api.tela-botanica.org/service:eflore:0.1/{projet}/nom-commune?lat={latitude}&lon={longitude}";
urlPaysTpl = "http://api.tela-botanica.org/service:eflore:0.1/osm/zone-admin?lat={latitude}&lon={longitude}";
 
+------------------------------------------------------------------------------------------------------+
[nettoyage]
cel_nettoye = "tb_nettoye_cel"
cel_new = "tb_new_cel"
chemin_photo = "/home/test/www/images/"
flore = "tb_eflore"
del = "tb_del"
/branches/v3.01-serpe/scripts/configurations
New file
Property changes:
Added: svn:ignore
+config.ini
/branches/v3.01-serpe/scripts/framework.defaut.php
New file
0,0 → 1,6
<?php
// Inclusion du Framework
// Renomer ce fichier en "framework.php"
// Indiquer ci-dessous le chemin absolu vers le fichier autoload.inc.php de la bonne version du Framework
require_once '/home/www/commun/framework/0.3/Framework.php';
?>
/branches/v3.01-serpe/scripts/bibliotheque/SqlUtil.php
New file
0,0 → 1,37
<?php
// declare(encoding='UTF-8');
/**
* Contient des méthodes utiles pour manipuler le SQL.
*
* @category CEL
* @package Scripts
* @subpackage Bibliotheque
* @author Mathias CHOUET <mathias@tela-botanica.org>
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @author Aurelien PERONNET <aurelien@tela-botanica.org>
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @copyright 1999-2014 Tela Botanica <accueil@tela-botanica.org>
*/
class SqlUtil {
 
public static function extraireRequetes($contenuSql) {
$contenuSansCommentaire = self::supprimerCommentaires($contenuSql);
$requetesExtraites = preg_split("/;\e*\t*\r*\n/", $contenuSansCommentaire);
if (count($requetesExtraites) == 0){
throw new Exception("Aucune requête n'a été trouvée dans le contenu SQL.");
}
 
$requetes = array();
foreach ($requetesExtraites as $requete) {
if (trim($requete) != '') {
$requetes[] = rtrim(trim($requete), ';');
}
}
return $requetes;
}
 
private static function supprimerCommentaires($contenuSql) {
return preg_replace('/(## |--).*?\r*\n/', '', $contenuSql);
}
}
/branches/v3.01-serpe/scripts/bibliotheque/Conteneur.php
New file
0,0 → 1,100
<?php
// declare(encoding='UTF-8');
/**
* Le conteneur encapsule les classes servant aux scripts.
* Il gère leur instanciation, ainsi que la récupération des paramètres depuis le fichier de configuration.
*
* @category CEL
* @package Scripts
* @subpackage Bibliotheque
* @author Mathias CHOUET <mathias@tela-botanica.org>
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @author Aurelien PERONNET <aurelien@tela-botanica.org>
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @copyright 1999-2014 Tela Botanica <accueil@tela-botanica.org>
*/
//TODO : initialiser tous les objets dans le conteneur
class Conteneur {
 
protected $parametres = array();
protected $partages = array();
 
/**
* Constructeur de la classe
* @param Array $parametres (optionnel) les paramètres additionnels à ajouter à ceux des fichiers de config
* */
public function __construct(array $parametres = null) {
$this->parametres = is_null($parametres) ? array() : $parametres;
}
 
/**
* Obtenir un paramètre depuis le tableau de paramètres ou depuis le fichier de config
* @param String $cle le nom du paramètre
* @return la valeur du paramètre
*/
public function getParametre($cle) {
$valeur = isset($this->parametres[$cle]) ? $this->parametres[$cle] : Config::get($cle);
return $valeur;
}
 
/**
* Obtenir un paramètre depuis le tableau de paramètres ou depuis le fichier de config
* et le transformer en tableau s'il est de la forme : "cle=valeur,cle=valeur,..."
* @param String $cle le nom du paramètre
* @return la valeur du paramètre
*/
public function getParametreTableau($cle) {
$tableau = array();
$parametre = $this->getParametre($cle);
if (empty($parametre) === false) {
$tableauPartiel = explode(',', $parametre);
foreach ($tableauPartiel as $champ) {
if (strpos($champ, '=') === false) {
$tableau[] = trim($champ);
} else {
list($cle, $val) = explode('=', $champ);
$tableau[trim($cle)] = trim($val);
}
}
}
return $tableau;
}
 
/**
* Enregistrer la valeur d'un paramètre
* */
public function setParametre($cle, $valeur) {
$this->parametres[$cle] = $valeur;
}
 
/**
* Permet d'obtenir un objet GestionBdd.
*/
public function getBdd() {
if (!isset($this->partages['Bdd'])){
$this->partages['Bdd'] = new Bdd();
}
return $this->partages['Bdd'];
}
 
/**
* Permet d'obtenir un objet RestClient.
*/
public function getRestClient() {
if (!isset($this->partages['RestClient'])) {
$this->partages['RestClient'] = new RestClient();
}
return $this->partages['RestClient'];
}
 
/**
* Permet d'obtenir un objet SquelettePhp.
*/
public function getSquelettePhp() {
if (!isset($this->partages['SquelettePhp'])) {
$this->partages['SquelettePhp'] = new SquelettePhp();
}
return $this->partages['SquelettePhp'];
}
}
/branches/v3.01-serpe/scripts/bibliotheque/FichierUtil.php
New file
0,0 → 1,24
<?php
// declare(encoding='UTF-8');
/**
* Contient des méthodes utiles pour manipuler les fichiers.
*
* @category CEL
* @package Scripts
* @subpackage Bibliotheque
* @author Mathias CHOUET <mathias@tela-botanica.org>
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @author Aurelien PERONNET <aurelien@tela-botanica.org>
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @copyright 1999-2014 Tela Botanica <accueil@tela-botanica.org>
*/
class FichierUtil {
public static function recupererContenu($chemin) {
$contenu = file_get_contents($chemin);
if ($contenu === false){
throw new Exception("Impossible d'ouvrir le fichier SQL : $chemin");
}
return $contenu;
}
}
/branches/v3.01-serpe/scripts/bibliotheque/CelScript.php
New file
0,0 → 1,27
<?php
// declare(encoding='UTF-8');
/**
* Classe mère des scripts CEL
*
* @category CEL
* @package Scripts
* @subpackage Bibliotheque
* @author Mathias CHOUET <mathias@tela-botanica.org>
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @author Aurelien PERONNET <aurelien@tela-botanica.org>
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @copyright 1999-2014 Tela Botanica <accueil@tela-botanica.org>
*/
abstract class CelScript extends Script {
 
private $projetNom = null;
 
public function getProjetNom() {
return $this->projetNom;
}
 
protected function initialiserProjet($projetNom) {
$this->projetNom = $projetNom;
}
}
/branches/v3.01-serpe/scripts/.
New file
Property changes:
Added: svn:ignore
+framework.php
Added: svn:mergeinfo
Merged /branches/topic-dbsingleton/scripts:r1720-1764
Merged /branches/v1.8-debroussailleuse/scripts:r1981,1987,1992,2014-2020
Merged /branches/v2.3-faux/scripts:r2228
Merged /branches/v1.7-croissant/scripts:r1855,1879-1880,1885-1886,1917,1923,1983