| 3755 | killian | 1 | <?php
 | 
        
           |  |  | 2 |   | 
        
           |  |  | 3 | /*
 | 
        
           |  |  | 4 | 	PHP 7
 | 
        
           |  |  | 5 |   | 
        
           |  |  | 6 | 	Script used to synchronize PN occ with CEL
 | 
        
           |  |  | 7 | */
 | 
        
           |  |  | 8 |   | 
        
           |  |  | 9 | class PullPlantnet extends Script {
 | 
        
           |  |  | 10 |   | 
        
           |  |  | 11 | 	protected $bdd;
 | 
        
           |  |  | 12 |   | 
        
           |  |  | 13 | 	protected $allowedPartners = ['tb', 'pn'];
 | 
        
           |  |  | 14 |   | 
        
           |  |  | 15 | 	// Nom du fichier contenant les correspondances d'ID TB/PN
 | 
        
           |  |  | 16 | 	protected $correspondingIdsFilename = '';
 | 
        
           |  |  | 17 |   | 
        
           |  |  | 18 | 	// Cache d'informations utilisateurs provenant de l'annuaire TB
 | 
        
           |  |  | 19 | 	protected $userInfos = [];
 | 
        
           |  |  | 20 |   | 
        
           | 3758 | killian | 21 | 	// Cache des obs id PN traitées pendant cette run
 | 
        
           |  |  | 22 | 	protected $processedObsId = [];
 | 
        
           |  |  | 23 |   | 
        
           | 3755 | killian | 24 | 	// Paramètre de suivi et de pagination de l'API des obs PN
 | 
        
           |  |  | 25 | 	protected $currentPage = '';
 | 
        
           |  |  | 26 | 	protected $currentProject = '';
 | 
        
           |  |  | 27 | 	protected $hasMore = false;
 | 
        
           |  |  | 28 | 	protected $count = 0;
 | 
        
           |  |  | 29 |   | 
        
           |  |  | 30 | 	// Traduction des organes de PN
 | 
        
           |  |  | 31 | 	protected $tagsImageTraduits = [
 | 
        
           |  |  | 32 | 		'flower' => 'fleur',
 | 
        
           |  |  | 33 | 		'fruit' => 'fruit',
 | 
        
           |  |  | 34 | 		'leaf' => 'feuille',
 | 
        
           |  |  | 35 | 		'bark' => 'écorce',
 | 
        
           |  |  | 36 | 		'branch' => 'branche',
 | 
        
           |  |  | 37 | 		'habit' => 'port',
 | 
        
           |  |  | 38 | 	];
 | 
        
           |  |  | 39 |   | 
        
           | 3768 | killian | 40 | 	// Différents types de lifecle possible pour filtrer les obs
 | 
        
           |  |  | 41 | 	// Modified renvoi les obs en fonction de leur date de modif
 | 
        
           |  |  | 42 | 	// Created, en fonction de la date de création
 | 
        
           |  |  | 43 | 	// Deleted, well, you already got it
 | 
        
           |  |  | 44 | 	protected $lifecycles = [
 | 
        
           |  |  | 45 | 		'created',
 | 
        
           |  |  | 46 | 		'modified',
 | 
        
           |  |  | 47 | 		'deleted', // deleted peut être très lent
 | 
        
           |  |  | 48 | 	];
 | 
        
           |  |  | 49 |   | 
        
           | 3755 | killian | 50 | 	/**
 | 
        
           |  |  | 51 | 	 * Paramêtres par défaut disponibles pour la ligne de commande
 | 
        
           |  |  | 52 | 	 * le tableau se construit de la forme suivante :
 | 
        
           |  |  | 53 | 	 * - clé =  nom du paramêtre '-foo'
 | 
        
           |  |  | 54 | 	 * - value = contient un nouveau tableau composé de cette façon :
 | 
        
           |  |  | 55 | 	 *  - booléen: true si le paramêtre est obligatoire
 | 
        
           |  |  | 56 | 	 *  - booléen ou var : true si le paramêtre nécessite un valeur à sa suite ou la valeur par défaut
 | 
        
           |  |  | 57 | 	 *  - string: description du contenu du paramêtre
 | 
        
           |  |  | 58 | 	 * Les paramêtres optionels devraient être déclaré à la fin du tableau.
 | 
        
           |  |  | 59 | 	 * Le dernier parametre du tableau peut avoir la valeur '...',
 | 
        
           |  |  | 60 | 	 * il contiendra alors l'ensemble des paramêtres suivant trouvés sur la ligne de commande.
 | 
        
           |  |  | 61 | 	 * @var array
 | 
        
           |  |  | 62 | 	 */
 | 
        
           |  |  | 63 | 	protected $parametres_autorises = array(
 | 
        
           | 3768 | killian | 64 | 		'-startDate' => array(false, true, 'Date de début (parsée par strtotime). Ex: "YYYY:MM:DD HH:II:SS"'),
 | 
        
           |  |  | 65 | 		'-lifecycle' => array(false, true, 'Par défaut : modified ; Au choix parmi : created/modified/deleted (deleted est lent)'),
 | 
        
           | 3755 | killian | 66 | 		'-pnObsId' => array(false, true, "ID de l'obs chez PlantNet"),
 | 
        
           | 3763 | killian | 67 | 		'-project' => array(false, true, "projectId de l'obs chez PlantNet"),
 | 
        
           | 3755 | killian | 68 | 		'-tbObsId' => array(false, true, "ID de l'obs chez Tela"),
 | 
        
           |  |  | 69 | 	);
 | 
        
           |  |  | 70 |   | 
        
           |  |  | 71 | 	public function __construct($script_nom, $parametres_cli) {
 | 
        
           |  |  | 72 | 		parent::__construct($script_nom, $parametres_cli);
 | 
        
           |  |  | 73 | 		$this->bdd = new Bdd();
 | 
        
           |  |  | 74 |   | 
        
           |  |  | 75 | 		$this->correspondingIdsFilename = Config::get('correspondingIdsFilename');
 | 
        
           |  |  | 76 | 	}
 | 
        
           |  |  | 77 |   | 
        
           |  |  | 78 | 	public function executer() {
 | 
        
           |  |  | 79 | 		$cmd = $this->getParametre('a');
 | 
        
           |  |  | 80 |   | 
        
           |  |  | 81 | 		switch ($cmd) {
 | 
        
           |  |  | 82 | 			case 'updateLatest':
 | 
        
           |  |  | 83 | 				$this->updateLatest($this->getParametre('startDate'));
 | 
        
           |  |  | 84 | 				break;
 | 
        
           |  |  | 85 | 			case 'updateOnePN':
 | 
        
           | 3763 | killian | 86 | 				$this->updateOnePN((int)$this->getParametre('pnObsId'), $this->getParametre('project'));
 | 
        
           | 3755 | killian | 87 | 				break;
 | 
        
           |  |  | 88 | 			case 'updateOneTB':
 | 
        
           |  |  | 89 | 				$this->updateOneTB($this->getParametre('tbObsId'));
 | 
        
           |  |  | 90 | 				break;
 | 
        
           |  |  | 91 | 			case 'updateCorrespondingIdsTable':
 | 
        
           |  |  | 92 | 				$this->updateCorrespondingIdsTable();
 | 
        
           |  |  | 93 | 				break;
 | 
        
           |  |  | 94 | 			default:
 | 
        
           |  |  | 95 | 				$msg = "Erreur : la commande '$cmd' n'existe pas!\n"
 | 
        
           |  |  | 96 | 						. ', utilisez plutôt :' . "\n"
 | 
        
           | 3768 | killian | 97 | 						. 'php cli.php PullPlantnet -a updateLatest -startDate "YYYY:MM:DD HH:II:SS" [[-lifecycle [modified]/created/deleted]]' . "\n"
 | 
        
           | 3763 | killian | 98 | 						. 'php cli.php PullPlantnet -a updateOnePN -pnObsId "xxxxxx" -project "xxxxxx"' . "\n"
 | 
        
           | 3755 | killian | 99 | 						. 'php cli.php PullPlantnet -a updateOneTB -tbObsId "xxxxxx"' . "\n"
 | 
        
           |  |  | 100 | 						. 'php cli.php PullPlantnet -a updateCorrespondingIdsTable' . "\n"
 | 
        
           |  |  | 101 | 						;
 | 
        
           |  |  | 102 | 				throw new Exception($msg);
 | 
        
           |  |  | 103 | 		}
 | 
        
           |  |  | 104 | 	}
 | 
        
           |  |  | 105 |   | 
        
           |  |  | 106 | 	/**
 | 
        
           |  |  | 107 | 	 * Considering all modified pn obs since startDate
 | 
        
           |  |  | 108 | 	 * One pn project after an other
 | 
        
           |  |  | 109 | 	 * Inserting obs in tb db (if new and matching user email)
 | 
        
           |  |  | 110 | 	 */
 | 
        
           | 3768 | killian | 111 | 	private function updateLatest(string $startDate = '1917:03:15 00:00:00', string $lifecycle = 'modified') {
 | 
        
           |  |  | 112 | 		$startDate = strtotime($startDate) * 1000; // we need a microtimestamp
 | 
        
           | 3755 | killian | 113 |   | 
        
           |  |  | 114 | 		$pnProjects = $this->getProjects(); // refresh projects list
 | 
        
           |  |  | 115 | 		foreach ($pnProjects as $project) {
 | 
        
           |  |  | 116 | 			do {
 | 
        
           | 3768 | killian | 117 | 				$observations_PN = $this->getProjectLatest($project, $startDate, $lifecycle);
 | 
        
           | 3755 | killian | 118 | 				$this->updateObs($observations_PN);
 | 
        
           |  |  | 119 | 			} while ($this->hasMore);
 | 
        
           |  |  | 120 | 		}
 | 
        
           |  |  | 121 | 	}
 | 
        
           |  |  | 122 |   | 
        
           | 3768 | killian | 123 | 	private function getProjectLatest(array $project, int $startDate, string $lifecycle): array {
 | 
        
           | 3755 | killian | 124 | 		$this->currentProject = $project;
 | 
        
           |  |  | 125 |   | 
        
           |  |  | 126 | 		if (!$this->currentPage) {
 | 
        
           |  |  | 127 | 			echo 'Projet ' . $project['name'] . "\n";
 | 
        
           |  |  | 128 |   | 
        
           |  |  | 129 | 			// hop, on appelle le service de PN
 | 
        
           |  |  | 130 | 			$url_service = str_replace(
 | 
        
           | 3768 | killian | 131 | 				['{project}', '{token}', '{startDate}', '{lifecycle}'],
 | 
        
           |  |  | 132 | 				[$project['id'], Config::get('tokenPlantnet'), $startDate, $lifecycle],
 | 
        
           | 3755 | killian | 133 | 				Config::get('urlPlantnetBase').Config::get('urlPlantnetLatestChanges')
 | 
        
           |  |  | 134 | 			);
 | 
        
           |  |  | 135 | 			// die(var_dump($url_service));
 | 
        
           |  |  | 136 | 			$this->currentPage = $url_service;
 | 
        
           |  |  | 137 | 		}
 | 
        
           |  |  | 138 |   | 
        
           |  |  | 139 | 		$ch = curl_init($this->currentPage);
 | 
        
           |  |  | 140 | 		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 | 
        
           |  |  | 141 | 		$reponse = curl_exec($ch);
 | 
        
           |  |  | 142 | 		$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
 | 
        
           |  |  | 143 | 		curl_close($ch);
 | 
        
           |  |  | 144 |   | 
        
           |  |  | 145 | 		// cool, maintenant on va trier ce qu'on a reçu
 | 
        
           |  |  | 146 | 		if (!$reponse) {
 | 
        
           |  |  | 147 | 			throw new Exception("\nPN ne répond rien à l'adresse {$this->currentPage}\n");
 | 
        
           |  |  | 148 | 		} elseif (200 != $code) {
 | 
        
           |  |  | 149 | 			// l'api répond avec une 404 quand y'a une date dans le futur ou simplement pas de nouvelle obs...
 | 
        
           |  |  | 150 | 			if (404 == $code && strpos($reponse, 'No more results')) {
 | 
        
           |  |  | 151 | 				$this->hasMore = false;
 | 
        
           |  |  | 152 | 				$this->currentPage = '';
 | 
        
           |  |  | 153 | 				return [];
 | 
        
           |  |  | 154 | 			}
 | 
        
           |  |  | 155 | 			throw new Exception("\nPN répond avec une $code à l'adresse {$this->currentPage} : $reponse\n");
 | 
        
           |  |  | 156 | 		}
 | 
        
           |  |  | 157 | 		$responseJson = json_decode($reponse, true);
 | 
        
           |  |  | 158 | 		$observations_PN = $responseJson['data'] ?? [];
 | 
        
           |  |  | 159 |   | 
        
           |  |  | 160 | 		$this->hasMore = $responseJson['hasMore'];
 | 
        
           |  |  | 161 | 		if ($this->hasMore) {
 | 
        
           |  |  | 162 | 			$this->count += count($observations_PN);
 | 
        
           | 3763 | killian | 163 | 			$this->currentPage = Config::get('urlPlantnetBase').$responseJson['next'];
 | 
        
           | 3755 | killian | 164 | 		} else {
 | 
        
           |  |  | 165 | 			$this->currentPage = '';
 | 
        
           |  |  | 166 | 			$this->count = 0;
 | 
        
           |  |  | 167 | 		}
 | 
        
           |  |  | 168 |   | 
        
           |  |  | 169 | 		return $observations_PN;
 | 
        
           |  |  | 170 | 	}
 | 
        
           |  |  | 171 |   | 
        
           |  |  | 172 | 	private function getProjects(): array {
 | 
        
           |  |  | 173 | 		// get PN projects list
 | 
        
           |  |  | 174 | 		$url = str_replace('{token}', Config::get('tokenPlantnet'), Config::get('urlPlantnetBase').Config::get('urlPlantnetProjects'));
 | 
        
           |  |  | 175 |   | 
        
           |  |  | 176 | 		$ch = curl_init($url);
 | 
        
           |  |  | 177 | 		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 | 
        
           |  |  | 178 | 		$reponse = curl_exec($ch);
 | 
        
           |  |  | 179 | 		$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
 | 
        
           |  |  | 180 | 		curl_close($ch);
 | 
        
           |  |  | 181 |   | 
        
           |  |  | 182 | 		if (!$reponse || 200 != $code) {
 | 
        
           | 3768 | killian | 183 | 			throw new Exception("\nPN répond avec une $code à l'adresse $url : $reponse\n");
 | 
        
           | 3755 | killian | 184 | 		}
 | 
        
           |  |  | 185 | 		$pnProjects = json_decode($reponse, true);
 | 
        
           |  |  | 186 |   | 
        
           |  |  | 187 | 		echo 'Liste de projets récupérée : ' . count($pnProjects) . " projets dans la liste\n";
 | 
        
           |  |  | 188 |   | 
        
           |  |  | 189 | 		return $pnProjects;
 | 
        
           |  |  | 190 | 	}
 | 
        
           |  |  | 191 |   | 
        
           |  |  | 192 | 	/**
 | 
        
           |  |  | 193 | 	 * For a given bunch of plantnet obs, post new one threw saisie widget service
 | 
        
           |  |  | 194 | 	 */
 | 
        
           |  |  | 195 | 	private function updateObs(array $observations_PN) {
 | 
        
           |  |  | 196 |   | 
        
           |  |  | 197 | 		$url_cel_widget_saisie = Config::get('urlCelWidgetSaisie');
 | 
        
           |  |  | 198 |   | 
        
           |  |  | 199 | 		foreach ($observations_PN as $obs) {
 | 
        
           | 3758 | killian | 200 | 			// est-ce qu'on a déjà traité cette obs ? (oui une même obs peut être dans plusieurs projects)
 | 
        
           |  |  | 201 | 			if (in_array($obs['id'], $this->processedObsId)) {
 | 
        
           |  |  | 202 | 				continue;
 | 
        
           |  |  | 203 | 			} else {
 | 
        
           |  |  | 204 | 				$this->processedObsId[] = $obs['id'];
 | 
        
           |  |  | 205 | 			}
 | 
        
           |  |  | 206 |   | 
        
           | 3755 | killian | 207 | 			// 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
 | 
        
           |  |  | 208 | 			if (!isset($obs['currentName'])) {
 | 
        
           |  |  | 209 | 				continue; // pas de nom de taxon, obs inutile
 | 
        
           |  |  | 210 | 			}
 | 
        
           |  |  | 211 | 			if (!isset($obs['geo'])) {
 | 
        
           |  |  | 212 | 				continue; // pas de position, obs inutile
 | 
        
           |  |  | 213 | 			}
 | 
        
           |  |  | 214 | 			if (!isset($obs['dateObs'])) {
 | 
        
           |  |  | 215 | 				continue; // pas de date, obs inutile
 | 
        
           |  |  | 216 | 			}
 | 
        
           |  |  | 217 |   | 
        
           |  |  | 218 | 			if (isset($obs['partner']['id']) && 'tela' === $obs['partner']['id']) {
 | 
        
           |  |  | 219 | 				// c'est une obs tela
 | 
        
           |  |  | 220 | 				// si c'est mis à jour récemment coté PN et qu'on l'a pas supprimée chez nous entre temps
 | 
        
           |  |  | 221 | 					// on update les votes PN
 | 
        
           |  |  | 222 | 					// on update l'identification proposée par PN
 | 
        
           |  |  | 223 |   | 
        
           |  |  | 224 | 				// @TODO
 | 
        
           |  |  | 225 | 				continue;
 | 
        
           |  |  | 226 | 			} elseif (!isset($obs['partner']['id'])) {
 | 
        
           |  |  | 227 | 				// ce n'est pas une obs d'un partenaire, c'est donc une obs PN
 | 
        
           |  |  | 228 | 				// on récupère l'id utilisateur tela via son mail
 | 
        
           |  |  | 229 | 				$email = $obs['author']['email'];
 | 
        
           |  |  | 230 | 				$infos_utilisateur = $this->findUserInfo($email);
 | 
        
           |  |  | 231 | 				if (!$infos_utilisateur) {
 | 
        
           |  |  | 232 | 					continue; // c'est pas un telabotaniste
 | 
        
           |  |  | 233 | 				}
 | 
        
           | 3763 | killian | 234 | 				//echo "Synchro d'une obs d'un telabotaniste : $email";
 | 
        
           | 3755 | killian | 235 | 				// echo json_encode($obs);
 | 
        
           |  |  | 236 | 				// die(var_dump($obs));
 | 
        
           |  |  | 237 |   | 
        
           |  |  | 238 | 				// vérification que l'obs n'a pas déjà été ajoutée à la BdD de Tela
 | 
        
           |  |  | 239 | 				$sql = "SELECT date_maj, id_observation FROM cel_plantnet WHERE id_plantnet = '{$obs['id']}'"
 | 
        
           |  |  | 240 | 						. ' -- ' . __FILE__ . ':' . __LINE__;
 | 
        
           |  |  | 241 | 				$res = $this->bdd->recupererTous($sql);
 | 
        
           |  |  | 242 | 				// die(var_dump($res));
 | 
        
           |  |  | 243 | 				if ($res) {
 | 
        
           |  |  | 244 | 					// l'obs existe déjà, on vérifie si il faut màj puis on passe à la suite
 | 
        
           |  |  | 245 | 					// la date de l'obs est un microtime, donc on coupe les millièmes
 | 
        
           |  |  | 246 | 					// die(var_dump((int)($obs['dateUpdated']/1000), strtotime($res[0]['date_maj'])));
 | 
        
           |  |  | 247 | 					if ((int)($obs['dateUpdated']/1000) > strtotime($res[0]['date_maj'])) {
 | 
        
           | 3763 | killian | 248 | 						echo "Obs déjà en base, mise à jour : ID PN {$obs['id']} ; ID TB {$res[0]['id_observation']} ; utilisateur_tb $email\n";
 | 
        
           | 3755 | killian | 249 | 						$this->updateFromPN($obs, $res[0]['id_observation']);
 | 
        
           |  |  | 250 | 					} else {
 | 
        
           | 3763 | killian | 251 | 						echo "Obs déjà en base, déjà à jour : ID PN {$obs['id']} ; ID TB {$res[0]['id_observation']} ; utilisateur_tb $email\n";
 | 
        
           | 3755 | killian | 252 | 					}
 | 
        
           |  |  | 253 | 					continue;
 | 
        
           |  |  | 254 | 				}
 | 
        
           |  |  | 255 |   | 
        
           |  |  | 256 | 				if (isset($obs['deleted']) && (true === $obs['deleted'])) {
 | 
        
           |  |  | 257 | 					continue; // obs supprimée chez PN sans être passée par nos serveurs
 | 
        
           |  |  | 258 | 				}
 | 
        
           |  |  | 259 |   | 
        
           |  |  | 260 | 				$images = [];
 | 
        
           |  |  | 261 | 				$tags_images = [];
 | 
        
           |  |  | 262 | 				foreach ($obs['images'] ?? [] as $i => $image) {
 | 
        
           |  |  | 263 | 					if ($image['deleted']) {
 | 
        
           |  |  | 264 | 						continue;
 | 
        
           |  |  | 265 | 					}
 | 
        
           |  |  | 266 |   | 
        
           |  |  | 267 | 					// téléchargement de l'image PN
 | 
        
           | 3763 | killian | 268 | 					$img = false;
 | 
        
           |  |  | 269 | 					$retry = 3;
 | 
        
           |  |  | 270 | 					do {
 | 
        
           |  |  | 271 | 						$img = file_get_contents($image['o']);
 | 
        
           |  |  | 272 | 						$retry--;
 | 
        
           |  |  | 273 | 					} while (!$img && $retry);
 | 
        
           |  |  | 274 |   | 
        
           |  |  | 275 | 					if (!$img) {
 | 
        
           |  |  | 276 | 						echo "Abandon, image impossible à télécharger : {$image['o']}\n";
 | 
        
           |  |  | 277 | 						continue;
 | 
        
           |  |  | 278 | 					}
 | 
        
           |  |  | 279 |   | 
        
           |  |  | 280 | 					// Écriture dans un fichier temporaire
 | 
        
           | 3755 | killian | 281 | 					$tempfile = tempnam("/tmp", "PullPN_") . ".jpg";
 | 
        
           |  |  | 282 | 					$handle = fopen($tempfile, "w");
 | 
        
           | 3763 | killian | 283 | 					fwrite($handle, $img);
 | 
        
           | 3755 | killian | 284 | 					fclose($handle);
 | 
        
           |  |  | 285 |   | 
        
           | 3763 | killian | 286 | 					echo "Image de " . number_format(filesize($tempfile), 0, ',', ' ') . " octets créé : $tempfile\n";
 | 
        
           | 3755 | killian | 287 |   | 
        
           |  |  | 288 | 					$params = [
 | 
        
           |  |  | 289 | 						'name' => 'image' . $i,
 | 
        
           |  |  | 290 | 						'fichier' => new CURLFile($tempfile, 'image/jpg')
 | 
        
           |  |  | 291 | 					];
 | 
        
           |  |  | 292 |   | 
        
           |  |  | 293 | 					// envoi de l'image PN à l'api de création
 | 
        
           |  |  | 294 | 					$ch = curl_init(Config::get('urlCelUploadImageTemp'));
 | 
        
           |  |  | 295 | 					curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 | 
        
           |  |  | 296 | 					curl_setopt($ch, CURLOPT_POST, true);
 | 
        
           |  |  | 297 | 					curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
 | 
        
           |  |  | 298 | 					$reponse = curl_exec($ch);
 | 
        
           |  |  | 299 | 					// var_dump($reponse);
 | 
        
           |  |  | 300 | 					$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
 | 
        
           |  |  | 301 | 					curl_close($ch);
 | 
        
           |  |  | 302 |   | 
        
           |  |  | 303 | 					unlink($tempfile);
 | 
        
           |  |  | 304 |   | 
        
           |  |  | 305 | 					$reponse = simplexml_load_string($reponse);
 | 
        
           |  |  | 306 | 					/* Response format if success:
 | 
        
           |  |  | 307 | 					<?xml version="1.0" encoding="UTF-8"?>
 | 
        
           |  |  | 308 | 					<root>
 | 
        
           |  |  | 309 | 						<miniature-url>https://api-test.tela-botanica.org/tmp/cel/imgtmp/chaflipe_min.jpg</miniature-url>
 | 
        
           |  |  | 310 | 						<image-nom>chaflipe.jpg</image-nom>
 | 
        
           |  |  | 311 | 						<message></message>
 | 
        
           |  |  | 312 | 						<debogage></debogage>
 | 
        
           |  |  | 313 | 					</root>
 | 
        
           |  |  | 314 | 					*/
 | 
        
           |  |  | 315 | 					// var_dump($reponse);
 | 
        
           |  |  | 316 | 					if ($reponse && '' == $reponse->message /* && '' != $reponse->{'image-nom'} */) {
 | 
        
           |  |  | 317 | 						$images[] = (string)$reponse->{'image-nom'};
 | 
        
           | 3765 | killian | 318 | 						$tags_images[] = $this->tagsImageTraduits[$image['organ']] ?? $image['organ'];
 | 
        
           | 3755 | killian | 319 | 					}
 | 
        
           |  |  | 320 | 				}
 | 
        
           |  |  | 321 | 				// var_dump($images, $tags_images);
 | 
        
           |  |  | 322 | 				// die();
 | 
        
           |  |  | 323 |   | 
        
           | 3763 | killian | 324 | 				$geo = $this->getGeoInfo($obs['geo']);
 | 
        
           |  |  | 325 |   | 
        
           | 3755 | killian | 326 | 				// on insère l'obs via le service CelWidgetSaisie
 | 
        
           |  |  | 327 | 				$infos_obs = [
 | 
        
           | 3763 | killian | 328 | 					'obsId1[date]' => date('d/m/Y', intdiv($obs['dateObs'], 1000)),
 | 
        
           |  |  | 329 | 					'obsId1[latitude]' => $geo['lat'] ?? null,
 | 
        
           |  |  | 330 | 					'obsId1[longitude]' => $geo['lon'] ?? null,
 | 
        
           |  |  | 331 | 					'obsId1[pays]' => $geo['countryCode'] ?? null,
 | 
        
           |  |  | 332 | 					'obsId1[code_postal]' => $geo['postcode'] ?? null,
 | 
        
           |  |  | 333 | 					'obsId1[commune_nom]' => $geo['city'] ?? null,
 | 
        
           | 3755 | killian | 334 | 					// 'obsId1[commune_code_insee]' => '',
 | 
        
           |  |  | 335 | 					// 'obsId1[lieudit]' => '',
 | 
        
           |  |  | 336 | 					// 'obsId1[milieu]' => '',
 | 
        
           | 3763 | killian | 337 | 					'obsId1[nom_sel]' => $obs['currentName'],
 | 
        
           | 3755 | killian | 338 | 					// 'obsId1[nom_ret]' => '',
 | 
        
           | 3763 | killian | 339 | 					// 'obsId1[famille]' => '',
 | 
        
           | 3755 | killian | 340 | 					'obsId1[certitude]' => 'douteux',
 | 
        
           |  |  | 341 | 					// 'obsId1[notes]' => '',
 | 
        
           |  |  | 342 | 					// 'obsId1[num_nom_ret]' => '',
 | 
        
           |  |  | 343 | 					// 'obsId1[num_nom_sel]' => '',
 | 
        
           |  |  | 344 | 					// 'obsId1[num_taxon]' => '',
 | 
        
           |  |  | 345 | 					'obsId1[referentiel]' => $this->findProbableTaxoRepos($this->currentProject['id']),
 | 
        
           |  |  | 346 | 					// 'obsId1[station]' => '',
 | 
        
           |  |  | 347 | 					'obsId1[obs_id]' => $obs['id'],
 | 
        
           |  |  | 348 | 					'projet' => 'PlantNet',
 | 
        
           |  |  | 349 | 					'tag-img' => implode(', ', $tags_images ?? []),
 | 
        
           |  |  | 350 | 					'tag-obs' => 'plantnet, plantnet-mobile, pn:referentiel-' . $this->currentProject['id'],
 | 
        
           |  |  | 351 | 					'utilisateur[courriel]' => $email,
 | 
        
           |  |  | 352 | 					'utilisateur[id_utilisateur]' => $infos_utilisateur['id'],
 | 
        
           |  |  | 353 | 					'utilisateur[nom]' => $infos_utilisateur['nom'],
 | 
        
           |  |  | 354 | 					'utilisateur[prenom]' => $infos_utilisateur['prenom'],
 | 
        
           |  |  | 355 | 					'origin' => 'pullPlantnet',
 | 
        
           |  |  | 356 | 				];
 | 
        
           |  |  | 357 |   | 
        
           |  |  | 358 | 				foreach ($images as $i => $image) {
 | 
        
           |  |  | 359 | 					$infos_obs["obsId1[image_nom][$i]"] = $image;
 | 
        
           |  |  | 360 | 				}
 | 
        
           | 3763 | killian | 361 | 				// var_dump($infos_obs);
 | 
        
           | 3755 | killian | 362 |   | 
        
           |  |  | 363 | 				// curl post $infos_obs
 | 
        
           |  |  | 364 | 				$ch = curl_init($url_cel_widget_saisie);
 | 
        
           |  |  | 365 | 				curl_setopt($ch, CURLOPT_POST, true);
 | 
        
           |  |  | 366 | 				curl_setopt($ch, CURLOPT_POSTFIELDS, $infos_obs);
 | 
        
           |  |  | 367 | 				curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 | 
        
           |  |  | 368 | 				$reponse = curl_exec($ch);
 | 
        
           |  |  | 369 | 				$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
 | 
        
           |  |  | 370 | 				curl_close($ch);
 | 
        
           |  |  | 371 |   | 
        
           |  |  | 372 | 				if (!$reponse || 200 != $code) {
 | 
        
           |  |  | 373 | 					throw new Exception("Ça a pété à l'envoi de l'obs :\n $reponse\n avec l'obs : " . json_encode($infos_obs) . "\n");
 | 
        
           |  |  | 374 | 				}
 | 
        
           |  |  | 375 |   | 
        
           |  |  | 376 | 				// var_dump($reponse);
 | 
        
           | 3763 | killian | 377 | 				$id_obs_tb = json_decode($reponse, true)['id'];
 | 
        
           |  |  | 378 | 				$id_obs_pn = $obs['id'];
 | 
        
           | 3755 | killian | 379 | 				// on insère les ids de correspondance obsPN obsTB dans la table cel_plantnet
 | 
        
           |  |  | 380 | 				$sql = 'INSERT INTO cel_plantnet (id_observation, id_plantnet, date_maj)'
 | 
        
           |  |  | 381 | 						.' VALUES (%s, %s, NOW())'
 | 
        
           |  |  | 382 | 						. ' -- ' . __FILE__ . ':' . __LINE__;
 | 
        
           | 3763 | killian | 383 | 				$sql = sprintf($sql, $this->bdd->proteger($id_obs_tb), $this->bdd->proteger($id_obs_pn));
 | 
        
           | 3755 | killian | 384 | 				$this->bdd->requeter($sql);
 | 
        
           | 3763 | killian | 385 |   | 
        
           |  |  | 386 | 				echo "Obs insérée en base : ID PN $id_obs_pn ; ID TB $id_obs_tb ; utilisateur_tb $email\n";
 | 
        
           | 3755 | killian | 387 | 			}
 | 
        
           |  |  | 388 | 		}
 | 
        
           |  |  | 389 | 	}
 | 
        
           |  |  | 390 |   | 
        
           |  |  | 391 | 	/**
 | 
        
           |  |  | 392 | 	 * Return TB taxo repos names for given PN project
 | 
        
           |  |  | 393 | 	 *
 | 
        
           |  |  | 394 | 	 * @return string
 | 
        
           |  |  | 395 | 	 */
 | 
        
           |  |  | 396 | 	private function findProbableTaxoRepos($pnProjectId) {
 | 
        
           |  |  | 397 | 		$selectedRepos = [];
 | 
        
           |  |  | 398 | 		// Référentiels tela botanica indexés par référentiels PN (version octobre 2019)
 | 
        
           |  |  | 399 | 		// @TODO à revoir en fonction des nouvelles mises en prod de nouveaux référentiels
 | 
        
           |  |  | 400 | 		$tbTaxoRepos = [
 | 
        
           |  |  | 401 | 			'afn' => [/*'apd', */'isfan'],
 | 
        
           |  |  | 402 | 			'aft' => ['apd'],
 | 
        
           |  |  | 403 | 			'antilles' => ['bdtxa', 'taxref'],
 | 
        
           |  |  | 404 | 			'canada' => ['vascan'],
 | 
        
           |  |  | 405 | 			'comores' => ['apd'],
 | 
        
           |  |  | 406 | 			'endemia' => ['florical', 'taxref'],
 | 
        
           |  |  | 407 | 			'taxref	' => ['bdtfx'],
 | 
        
           |  |  | 408 | 			'guyane' => ['aublet', 'taxref'],
 | 
        
           |  |  | 409 | 			'hawai' => [],
 | 
        
           |  |  | 410 | 			'lapaz' => ['aublet', 'taxref'],
 | 
        
           |  |  | 411 | 			'martinique' => ['bdtxa', 'taxref'],
 | 
        
           |  |  | 412 | 			'maurice' => ['apd'],
 | 
        
           |  |  | 413 | 			'medor' => ['lbf'],
 | 
        
           |  |  | 414 | 			'namerica' => [],
 | 
        
           |  |  | 415 | 			'polynesiefr' => ['taxref'],
 | 
        
           |  |  | 416 | 			'prosea' => ['asia'],
 | 
        
           |  |  | 417 | 			'prota' => ['isfan', 'apd'],
 | 
        
           |  |  | 418 | 			'provence' => ['bdtfx', 'taxref'],
 | 
        
           |  |  | 419 | 			'reunion' => ['bdtre', 'taxref'],
 | 
        
           |  |  | 420 | 			'salad' => ['bdtfx', 'taxref'],
 | 
        
           |  |  | 421 | 			'useful' => [],
 | 
        
           |  |  | 422 | 			'weurope' => ['bdtfx'],
 | 
        
           |  |  | 423 | 			'the-plant-list' => [],
 | 
        
           |  |  | 424 | 			'iscantree' => ['apd'],
 | 
        
           |  |  | 425 | 			'central-america' => [],
 | 
        
           |  |  | 426 | 			'invasion' => ['bdtfx'],
 | 
        
           |  |  | 427 | 			'weeds' => ['bdtfx'],
 | 
        
           |  |  | 428 | 			'malaysia' => [],
 | 
        
           |  |  | 429 | 		];
 | 
        
           |  |  | 430 |   | 
        
           |  |  | 431 | 		if (array_key_exists($pnProjectId, $tbTaxoRepos)) {
 | 
        
           |  |  | 432 | 			array_map(function($repo) use ($selectedRepos) {
 | 
        
           |  |  | 433 | 				$selectedRepos[] = $repo;
 | 
        
           |  |  | 434 | 			}, $tbTaxoRepos[$pnProjectId]);
 | 
        
           |  |  | 435 | 		}
 | 
        
           |  |  | 436 |   | 
        
           |  |  | 437 | 		// @TODO chercher le nom dans plusieurs référentiels avant d'envoyer l'obs
 | 
        
           |  |  | 438 | 		// prendre "enrichirDonneesTaxonomiques" du service de saisie et le coller ici
 | 
        
           |  |  | 439 | 		// en attendant on envoi juste le premier référentiel trouvé
 | 
        
           |  |  | 440 | 		return $selectedRepos[0] ?? '';
 | 
        
           |  |  | 441 | 	}
 | 
        
           |  |  | 442 |   | 
        
           |  |  | 443 | 	/*
 | 
        
           |  |  | 444 | 	 * Retrouve les infos d'un utilisateur tela à partir de son email
 | 
        
           |  |  | 445 | 	 * @param string $email User email
 | 
        
           |  |  | 446 | 	 * @return mixed 		Tableau des infos de l'utilisateur
 | 
        
           |  |  | 447 | 	 *						False si l'email n'est pas trouvé dans l'annuaire
 | 
        
           |  |  | 448 | 	 */
 | 
        
           |  |  | 449 | 	private function findUserInfo($email) {
 | 
        
           |  |  | 450 | 		// cherche dans le cache
 | 
        
           |  |  | 451 | 		if (array_key_exists($email, $this->userInfos)) {
 | 
        
           |  |  | 452 | 			$infosUtilisateur = $this->userInfos[$email];
 | 
        
           |  |  | 453 | 			// echo("Email in cache : $email\n");
 | 
        
           |  |  | 454 | 		} else {
 | 
        
           |  |  | 455 | 			$infosUtilisateur = false;
 | 
        
           |  |  | 456 | 			$urlInfosUtilisateur = str_replace('{email}', $email, Config::get('urlAnnuaireIdParEmail'));
 | 
        
           |  |  | 457 |   | 
        
           |  |  | 458 | 			$ch = curl_init($urlInfosUtilisateur);
 | 
        
           |  |  | 459 | 			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 | 
        
           |  |  | 460 | 			$reponse = curl_exec($ch);
 | 
        
           |  |  | 461 | 			$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
 | 
        
           |  |  | 462 | 			curl_close($ch);
 | 
        
           |  |  | 463 |   | 
        
           |  |  | 464 | 			// on peut pas tester le code de réponse de cette api, si l'utilisateur n'est pas trouvé ça fait une 500 >_<
 | 
        
           |  |  | 465 | 			// une bonne réponse ressemble à ça :
 | 
        
           |  |  | 466 | 			// {"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"}}
 | 
        
           |  |  | 467 | 			$reponse = json_decode($reponse, true);
 | 
        
           |  |  | 468 | 			if (!isset($reponse)) {
 | 
        
           |  |  | 469 | 				throw new Exception("\nL'annuaire n'a pas répondu avec du json : code $code à l'adresse $urlInfosUtilisateur : $reponse\n");
 | 
        
           |  |  | 470 | 			}
 | 
        
           |  |  | 471 |   | 
        
           |  |  | 472 | 			if (!isset($reponse['error'])) {
 | 
        
           |  |  | 473 | 				$infosUtilisateur = array_shift($reponse);
 | 
        
           |  |  | 474 | 			}
 | 
        
           |  |  | 475 |   | 
        
           |  |  | 476 | 			// met en cache
 | 
        
           |  |  | 477 | 			$this->userInfos[$email] = $infosUtilisateur;
 | 
        
           |  |  | 478 | 			// echo("Email cached : $email\n");
 | 
        
           |  |  | 479 | 		}
 | 
        
           |  |  | 480 |   | 
        
           |  |  | 481 | 		return $infosUtilisateur;
 | 
        
           |  |  | 482 | 	}
 | 
        
           |  |  | 483 |   | 
        
           | 3763 | killian | 484 | 	private function getGeoInfo($obs) {
 | 
        
           |  |  | 485 | 		$geo = [];
 | 
        
           |  |  | 486 | 		if (!isset($obs['lat']) && !isset($obs['lon'])) {
 | 
        
           |  |  | 487 | 			return $geo;
 | 
        
           |  |  | 488 | 		}
 | 
        
           |  |  | 489 |   | 
        
           |  |  | 490 | 		// $data = [
 | 
        
           |  |  | 491 | 		// 	'hitsPerPage' => 1,
 | 
        
           |  |  | 492 | 		// 	'aroundLatLng' => "{$obs['lat']},{$obs['lon']}"
 | 
        
           |  |  | 493 | 		// ];
 | 
        
           |  |  | 494 | 		$headers = [
 | 
        
           |  |  | 495 | 			'X-Algolia-Application-Id' => Config::get('algoliaApplicationId'),
 | 
        
           |  |  | 496 | 			'X-Algolia-API-Key' => Config::get('algoliaAPIKey'),
 | 
        
           |  |  | 497 | 		];
 | 
        
           |  |  | 498 |   | 
        
           |  |  | 499 | 		$lat = number_format($obs['lat'], 6, '.', '');
 | 
        
           |  |  | 500 | 		$lon = number_format($obs['lon'], 6, '.', '');
 | 
        
           |  |  | 501 |   | 
        
           |  |  | 502 | 		$ch = curl_init(Config::get('urlReverseGeocodingLatLng')."$lat,$lon");
 | 
        
           |  |  | 503 | 		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
 | 
        
           |  |  | 504 | 		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 | 
        
           |  |  | 505 | 		$reponse = curl_exec($ch);
 | 
        
           |  |  | 506 | 		$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
 | 
        
           |  |  | 507 | 		curl_close($ch);
 | 
        
           |  |  | 508 |   | 
        
           |  |  | 509 | 		if ($reponse) {
 | 
        
           |  |  | 510 | 			$reponse = json_decode($reponse, true);
 | 
        
           |  |  | 511 | 			// die(var_dump($reponse));
 | 
        
           |  |  | 512 | 			$infos = $reponse['hits'][0];
 | 
        
           |  |  | 513 |   | 
        
           |  |  | 514 | 			$geo = [
 | 
        
           |  |  | 515 | 				'lat' => (string) $obs['lat'],
 | 
        
           |  |  | 516 | 				'lon' => (string) $obs['lon'],
 | 
        
           |  |  | 517 | 				'country' => $infos['country']['fr'] ?? $infos['country']['default'],
 | 
        
           |  |  | 518 | 				'city' => $infos['city']['default'][0] ?? null,
 | 
        
           |  |  | 519 | 				'postcode' => $infos['postcode'][0] ?? null,
 | 
        
           |  |  | 520 | 				'countryCode' => strtoupper($infos['country_code']),
 | 
        
           |  |  | 521 | 			];
 | 
        
           |  |  | 522 | 		}
 | 
        
           |  |  | 523 |   | 
        
           |  |  | 524 | 		return $geo;
 | 
        
           |  |  | 525 | 	}
 | 
        
           |  |  | 526 |   | 
        
           | 3755 | killian | 527 | 	private function updateFromPN(array $pnObs, string $tbObsId) {
 | 
        
           |  |  | 528 | 		if (!is_array($pnObs) || !is_string($tbObsId)) {
 | 
        
           |  |  | 529 | 			// die(var_dump($pnObs, $tbObsId));
 | 
        
           | 3763 | killian | 530 | 			throw new Exception("\nBad params types, give me an array and an integer plz\n");
 | 
        
           | 3755 | killian | 531 | 		}
 | 
        
           |  |  | 532 | 		// die(var_dump($pnObs));
 | 
        
           |  |  | 533 |   | 
        
           | 3763 | killian | 534 | 		// log update date to cel_plantnet
 | 
        
           |  |  | 535 | 		$sql = "UPDATE cel_plantnet SET date_maj = NOW() WHERE id_observation = $tbObsId"
 | 
        
           |  |  | 536 | 				. ' -- ' . __FILE__ . ':' . __LINE__;
 | 
        
           |  |  | 537 | 		$this->bdd->requeter($sql);
 | 
        
           |  |  | 538 |   | 
        
           | 3755 | killian | 539 | 		// check for deleted
 | 
        
           |  |  | 540 | 		if (isset($pnObs['deleted']) && (true === $pnObs['deleted'])) {
 | 
        
           |  |  | 541 | 			// est-ce une obs issue de PN ?
 | 
        
           |  |  | 542 | 			//// faut regarder le champ input_source == PlantNet
 | 
        
           |  |  | 543 | 			$sql = "SELECT input_source FROM occurrence WHERE id = '$tbObsId'"
 | 
        
           |  |  | 544 | 					. ' -- ' . __FILE__ . ':' . __LINE__;
 | 
        
           |  |  | 545 | 			$res = $this->bdd->recupererTous($sql);
 | 
        
           | 3763 | killian | 546 |   | 
        
           | 3755 | killian | 547 | 			if (isset($res[0]) && ('PlantNet' === $res[0]['input_source'])) {
 | 
        
           |  |  | 548 | 				// oui ? alors supprimer obs !
 | 
        
           | 3763 | killian | 549 | 				echo "Obs supprimée coté PN, suppression : ID PN {$obs['id']} ; ID TB {$res[0]['id_observation']}\n";
 | 
        
           |  |  | 550 |   | 
        
           |  |  | 551 | 				$sql = "UPDATE photos SET occurrence_id = NULL WHERE occurrence_id = '$tbObsId'"
 | 
        
           | 3755 | killian | 552 | 						. ' -- ' . __FILE__ . ':' . __LINE__;
 | 
        
           |  |  | 553 | 				$this->bdd->requeter($sql);
 | 
        
           | 3763 | killian | 554 |   | 
        
           |  |  | 555 | 				$sql = "DELETE FROM occurrence WHERE id = '$tbObsId'"
 | 
        
           | 3755 | killian | 556 | 						. ' -- ' . __FILE__ . ':' . __LINE__;
 | 
        
           |  |  | 557 | 				$this->bdd->requeter($sql);
 | 
        
           |  |  | 558 | 			}
 | 
        
           |  |  | 559 | 		}
 | 
        
           |  |  | 560 |   | 
        
           |  |  | 561 | 		// check for deleted images
 | 
        
           |  |  | 562 | 		foreach ($pnObs['images'] as $image) {
 | 
        
           |  |  | 563 | 			if ($image['deleted']) {
 | 
        
           |  |  | 564 | 				// no idea
 | 
        
           |  |  | 565 | 				// y'a pas encore de lien tangible entre les images PN et les notres
 | 
        
           |  |  | 566 | 			}
 | 
        
           |  |  | 567 | 		}
 | 
        
           |  |  | 568 |   | 
        
           |  |  | 569 | 		// @TODO : finir la comparaison des proposition entre celles de Tela et celles PN
 | 
        
           |  |  | 570 | 		// // check for votes (notes et taxon)
 | 
        
           |  |  | 571 | 		// $names = [];
 | 
        
           |  |  | 572 | 		// foreach ($pnObs['computed']['votes'] as $vote) {
 | 
        
           |  |  | 573 | 		// 	echo($vote['name']);
 | 
        
           |  |  | 574 | 		// 	echo($vote['score']['pn']);
 | 
        
           |  |  | 575 | 		// 	echo($vote['score']['total']);
 | 
        
           |  |  | 576 |   | 
        
           |  |  | 577 | 		// 	$names[$vote['score']['pn']] = $vote['name'];
 | 
        
           |  |  | 578 | 		// }
 | 
        
           |  |  | 579 | 		// ksort($names, SORT_NUMERIC); // votes sorted by score asc
 | 
        
           |  |  | 580 | 		// $pn_sorted_votes = array_reverse($names, true); // desc
 | 
        
           |  |  | 581 |   | 
        
           |  |  | 582 | 		// // get existing votes
 | 
        
           |  |  | 583 | 		// $sql = "SELECT id_commentaire, nom_sel, nom_sel_nn, nom_referentiel, nom_referentiel, utilisateur_courriel, proposition_initiale, proposition_retenue"
 | 
        
           |  |  | 584 | 		// 		. "WHERE ce_observation = '$tbObsId' AND ce_commentaire_parent = 0"
 | 
        
           |  |  | 585 | 		// 		. ' -- ' . __FILE__ . ':' . __LINE__;
 | 
        
           |  |  | 586 | 		// $existing_votes = $this->bdd->recupererTous($sql);
 | 
        
           |  |  | 587 |   | 
        
           |  |  | 588 | 		// // @TODO : compare votes
 | 
        
           |  |  | 589 | 		// // insert_new_votes($pn_sorted_votes, $existing_votes);
 | 
        
           |  |  | 590 | 	}
 | 
        
           |  |  | 591 |   | 
        
           | 3763 | killian | 592 | 	private function updateOnePN($pnObsId, $pnProjectId) {
 | 
        
           |  |  | 593 | 		if (!is_int($pnObsId) || !is_string($pnProjectId)) {
 | 
        
           |  |  | 594 | 			die(var_dump($pnObsId, $pnProjectId));
 | 
        
           |  |  | 595 | 			throw new Exception("\nBad params types, give me an integer and a string plz\n");
 | 
        
           | 3755 | killian | 596 | 		}
 | 
        
           | 3763 | killian | 597 | 		// get PN project list
 | 
        
           |  |  | 598 | 		$list = [];
 | 
        
           |  |  | 599 | 		$pnProjects = $this->getProjects(); // refresh projects list
 | 
        
           |  |  | 600 | 		foreach ($pnProjects as $project) {
 | 
        
           |  |  | 601 | 			$list[$project['id']] = $project['name'];
 | 
        
           |  |  | 602 | 		}
 | 
        
           | 3755 | killian | 603 |   | 
        
           | 3763 | killian | 604 | 		// if project not in list display list
 | 
        
           |  |  | 605 | 		if (!array_key_exists($pnProjectId, $list)) {
 | 
        
           |  |  | 606 | 			echo "Available projects:\n";
 | 
        
           |  |  | 607 | 			foreach ($list as $projectId => $projectName) {
 | 
        
           |  |  | 608 | 				echo " - $projectId ($projectName)\n";
 | 
        
           |  |  | 609 | 			}
 | 
        
           |  |  | 610 | 			throw new Exception("Project $pnProjectId does not exist\n");
 | 
        
           |  |  | 611 | 		} else {
 | 
        
           |  |  | 612 | 			$this->currentProject = [
 | 
        
           |  |  | 613 | 				'id' => $pnProjectId,
 | 
        
           |  |  | 614 | 				'name' => $list[$pnProjectId],
 | 
        
           |  |  | 615 | 			];
 | 
        
           |  |  | 616 | 		}
 | 
        
           |  |  | 617 |   | 
        
           |  |  | 618 | 		// get PN obs
 | 
        
           | 3755 | killian | 619 | 		$urlInfosObs = str_replace(
 | 
        
           | 3763 | killian | 620 | 			['{token}', '{project}', '{id}'],
 | 
        
           |  |  | 621 | 			[Config::get('tokenPlantnet'), $pnProjectId, $pnObsId],
 | 
        
           | 3755 | killian | 622 | 			Config::get('urlPlantnetBase').Config::get('urlPlantnetObsById')
 | 
        
           |  |  | 623 | 		);
 | 
        
           |  |  | 624 | 		$ch = curl_init($urlInfosObs);
 | 
        
           |  |  | 625 | 		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 | 
        
           | 3763 | killian | 626 | 		$response = curl_exec($ch);
 | 
        
           | 3755 | killian | 627 | 		$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
 | 
        
           |  |  | 628 | 		curl_close($ch);
 | 
        
           |  |  | 629 |   | 
        
           | 3763 | killian | 630 | 		if (!$response || 200 != $code) {
 | 
        
           |  |  | 631 | 			throw new Exception("\nPlantnet api ($urlInfosObs) replied with code $code : $response\n");
 | 
        
           | 3755 | killian | 632 | 		}
 | 
        
           |  |  | 633 |   | 
        
           | 3763 | killian | 634 | 		// change last modification date to force update
 | 
        
           |  |  | 635 | 		$obs = json_decode($response, true);
 | 
        
           |  |  | 636 | 		$date = new DateTime();
 | 
        
           |  |  | 637 | 		$date->setTimestamp(intdiv($obs['dateUpdated'], 1000) - 1);
 | 
        
           |  |  | 638 | 		$date = $this->bdd->proteger($date->format('Y-m-d H:i:s'));
 | 
        
           |  |  | 639 | 		$sql = "UPDATE cel_plantnet SET date_maj = $date WHERE id_plantnet = '$pnObsId'"
 | 
        
           |  |  | 640 | 				. ' -- ' . __FILE__ . ':' . __LINE__;
 | 
        
           |  |  | 641 | 		$this->bdd->requeter($sql);
 | 
        
           |  |  | 642 |   | 
        
           |  |  | 643 | 		$this->updateObs([$obs]);
 | 
        
           | 3755 | killian | 644 | 	}
 | 
        
           |  |  | 645 |   | 
        
           |  |  | 646 | 	private function updateOneTB($id) {
 | 
        
           |  |  | 647 | 		$corres = $this->findMatchingPartnerId($id, 'tb');
 | 
        
           |  |  | 648 | 		echo "L'obs tela avec l'id $id a été trouvée chez plantnet avec l'id : " .$corres['pn'] . "\n";
 | 
        
           |  |  | 649 | 		echo "La suite n'a pas été implémentée.\n";
 | 
        
           |  |  | 650 | 	}
 | 
        
           |  |  | 651 |   | 
        
           |  |  | 652 | 	/*
 | 
        
           |  |  | 653 | 	 * Trouve les ids d'une obs chez les partenaires
 | 
        
           |  |  | 654 | 	 * Il faut lancer updateMatchingPartnersIds pour obtenir une liste fraiche
 | 
        
           |  |  | 655 | 	 *
 | 
        
           |  |  | 656 | 	 * @param 	string $id			L'id de l'obs
 | 
        
           |  |  | 657 | 	 * @param 	string $partner		Le partenaire correspondant à l'id de l'obs
 | 
        
           |  |  | 658 | 	 *
 | 
        
           |  |  | 659 | 	 * @return  mixed 				Le tableau de correspondances d'ids
 | 
        
           |  |  | 660 | 	 *								False si l'id n'est pas trouvé
 | 
        
           |  |  | 661 | 	 */
 | 
        
           |  |  | 662 | 	private function findMatchingPartnerId($id, $partner) {
 | 
        
           |  |  | 663 | 		if (!in_array($partner, $this->allowedPartners)) {
 | 
        
           |  |  | 664 | 			throw new Exception("\nUnknown partner : $partner. Available Partners : " . implode(', ', $this->allowedPartners) . "\n");
 | 
        
           |  |  | 665 | 		}
 | 
        
           |  |  | 666 |   | 
        
           |  |  | 667 | 		// le json ressemble à ça :
 | 
        
           |  |  | 668 | 		// {"tb":"2369732","pn":"1001020199"}, {"tb":"2369733","pn":"1001020176"}, ...
 | 
        
           |  |  | 669 | 		$ids = json_decode(file_get_contents($this->correspondingIdsFilename), true);
 | 
        
           |  |  | 670 | 		// extrait la colonne du partenaire recherché du tableau multidimensionnel fraichement décodé
 | 
        
           |  |  | 671 | 		$partnerColumn = array_column($ids, $partner);
 | 
        
           |  |  | 672 | 		// cherche l'index de l'id recherché
 | 
        
           |  |  | 673 | 		$index = array_search($id, $partnerColumn);
 | 
        
           |  |  | 674 |   | 
        
           |  |  | 675 | 		return $index ? $ids[$index] : false;
 | 
        
           |  |  | 676 | 	}
 | 
        
           |  |  | 677 |   | 
        
           |  |  | 678 | 	private function updateCorrespondingIdsTable() {
 | 
        
           |  |  | 679 | 		// first update cache file if necessary
 | 
        
           |  |  | 680 | 		if (!file_exists($this->correspondingIdsFilename) || time() > (filemtime($this->correspondingIdsFilename) + (24 * 3600))) {
 | 
        
           |  |  | 681 | 			$this->updateMatchingPartnersIds();
 | 
        
           |  |  | 682 | 		}
 | 
        
           |  |  | 683 |   | 
        
           |  |  | 684 | 		$data = file_get_contents($this->correspondingIdsFilename);
 | 
        
           |  |  | 685 | 		$data = json_decode($data, true);
 | 
        
           |  |  | 686 |   | 
        
           |  |  | 687 | 		$now = new DateTime;
 | 
        
           |  |  | 688 | 		$now = $this->bdd->proteger($now->format('Y-m-d H:i:s'));
 | 
        
           |  |  | 689 |   | 
        
           |  |  | 690 | 		$sqlInsert = 'INSERT INTO cel_plantnet (id_observation, id_plantnet, date_maj)'
 | 
        
           |  |  | 691 | 					. ' VALUES %s'
 | 
        
           |  |  | 692 | 					. ' ON DUPLICATE KEY UPDATE id_observation=VALUES(id_observation), id_plantnet=VALUES(id_plantnet)'
 | 
        
           |  |  | 693 | 					. ' -- ' . __FILE__ . ':' . __LINE__;
 | 
        
           |  |  | 694 | 		$values = '';
 | 
        
           |  |  | 695 |   | 
        
           | 3763 | killian | 696 | 		echo "Updating matching partners ids table\n";
 | 
        
           | 3755 | killian | 697 | 		foreach ($data as $id => $corres) {
 | 
        
           |  |  | 698 | 			$id_obs_tb = $this->bdd->proteger($corres['tb']);
 | 
        
           |  |  | 699 | 			$id_obs_pn = $this->bdd->proteger($corres['pn']);
 | 
        
           |  |  | 700 | 			// on insère les ids de correspondance obsPN obsTB dans la table cel_plantnet
 | 
        
           |  |  | 701 | 			$values .= " ($id_obs_tb, $id_obs_pn, $now),";
 | 
        
           |  |  | 702 |   | 
        
           |  |  | 703 | 			if (0 === $id % 100) {
 | 
        
           |  |  | 704 | 				$values = substr($values, 0, -1); // retire la dernière virgule
 | 
        
           |  |  | 705 | 				$sql = sprintf($sqlInsert, $values);
 | 
        
           |  |  | 706 | 				// var_dump($sql);
 | 
        
           |  |  | 707 | 				$this->bdd->requeter($sql);
 | 
        
           |  |  | 708 | 				$values = '';
 | 
        
           |  |  | 709 | 			}
 | 
        
           |  |  | 710 | 		}
 | 
        
           |  |  | 711 | 		// Faut envoyer les dernières données qui sont pas passées dans le modulo
 | 
        
           |  |  | 712 | 		$values = substr($values, 0, -1); // retire la dernière virgule
 | 
        
           |  |  | 713 | 		$sql = sprintf($sqlInsert, $values);
 | 
        
           |  |  | 714 | 		// var_dump($sql);
 | 
        
           |  |  | 715 | 		$this->bdd->requeter($sql);
 | 
        
           |  |  | 716 |   | 
        
           | 3763 | killian | 717 | 		$count = count($data);
 | 
        
           |  |  | 718 | 		echo "Success: #$count updated\n";
 | 
        
           | 3755 | killian | 719 | 	}
 | 
        
           |  |  | 720 |   | 
        
           |  |  | 721 | 	private function updateMatchingPartnersIds() {
 | 
        
           |  |  | 722 | 		// curl -X GET --header 'Accept: application/json' 'https://bourbonnais.cirad.fr:8081/v1/edi/observations/partnerids?token=f0ca433febe320675c24ee2ddfab8b82f65d556b' > partnerids.txt
 | 
        
           |  |  | 723 | 		$matchingPartnersIdsServiceUrl = str_replace(
 | 
        
           |  |  | 724 | 			'{token}',
 | 
        
           |  |  | 725 | 			Config::get('tokenPlantnet'),
 | 
        
           |  |  | 726 | 			Config::get('urlPlantnetBase').Config::get('urlPlantnetMatchingPartner')
 | 
        
           |  |  | 727 | 		);
 | 
        
           |  |  | 728 | 		$ch = curl_init($matchingPartnersIdsServiceUrl);
 | 
        
           |  |  | 729 | 		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 | 
        
           |  |  | 730 |   | 
        
           |  |  | 731 | 		echo "Updating matching partners ids...\n";
 | 
        
           |  |  | 732 | 		$reponse = curl_exec($ch);
 | 
        
           |  |  | 733 | 		$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
 | 
        
           |  |  | 734 | 		curl_close($ch);
 | 
        
           |  |  | 735 |   | 
        
           |  |  | 736 |   | 
        
           |  |  | 737 | 		if (!$reponse || 200 != $code) {
 | 
        
           |  |  | 738 | 			throw new Exception("\nError updating partners ids, http error code \"$code\" whith url \"$matchingPartnersIdsServiceUrl\"...\n");
 | 
        
           |  |  | 739 | 		}
 | 
        
           |  |  | 740 | 		echo "Response data from PN api gathered, know computing...\n";
 | 
        
           |  |  | 741 |   | 
        
           |  |  | 742 | 		if (!file_put_contents($this->correspondingIdsFilename, $reponse)) {
 | 
        
           |  |  | 743 | 			throw new Exception("\nError writing correspondingIdsFilename with path : " . $this->correspondingIdsFilename . "\n");
 | 
        
           |  |  | 744 | 		}
 | 
        
           |  |  | 745 | 		echo "Matching partners ids saved!";
 | 
        
           |  |  | 746 | 	}
 | 
        
           |  |  | 747 | }
 |