Rev 1950 | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php/** Paramêtres indiquant que l'on est en français pour permettre l'affichage des dates en français. */setlocale(LC_TIME, 'fr_FR.UTF-8');/** Définition de l'encodage interne des fichiers. */mb_internal_encoding('UTF-8');/*** Classe mère abstraite contenant les méthodes génériques des services.* Encodage en entrée : utf8* Encodage en sortie : utf8** @author Jean-Pascal MILCENT <jpm@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>* @version $Id$* @copyright 2009*/abstract class Coel {const ETAT_AJOUTER = 1;const ETAT_MODIFIER = 2;const ETAT_SUPPRIMER = 3;protected $sessionName = 'CoelSession';protected $sessionExpireTime = 8640000;// 60*60*24*100 = 100 joursprotected static $cookieChemin = '';public $config;protected $bdd;protected $log = array();protected $messages = array();protected $debug = array();protected $distinct = false;protected $orderby = null;protected $formatRetour = 'objet';protected $start = 0;protected $limit = 150;public function __construct($config, $demarrer_session = true) {// Tableau contenant la config de Jrest$this->config = $config;// Connection à la base de données$this->bdd = $this->connecterPDO($this->config, 'coel');$this->gererSession($demarrer_session);$this->gererIdentificationPermanente();if(isset($_GET['start'])) $this->start = intval($_GET['start']);if(isset($_GET['limit'])) $this->limit = intval($_GET['limit']);// Nettoyage du $_GET (non-sécurisé)if (isset($_GET)) {$get_params = array('orderby', 'distinct', 'formatRetour', 'searchCity');foreach ($get_params as $get) {$verifier = array('NULL', "\n", "\r", "\\", "'", '"', "\x00", "\x1a", ';');if (isset($_GET[$get]) && $_GET[$get] != '') {$_GET[$get] = str_replace($verifier, '', $_GET[$get]);$this->$get = $_GET[$get];} else {$_GET[$get] = null;}}}}/*** Méthode appelée quand aucun paramètre n'est passé dans l'url et avec une requête de type GET.*/public function getRessource() {$this->getElement(array());}protected function creerXmlHisto($donnees) {// Création du xml de l'enregistrement à historiser$info = null;$xml_tpl = '<?xml version="1.0" encoding="UTF-8" ?>'."\n<resultset>\n<row>\n%s</row>\n</resultset>";$xml = null;foreach ($donnees as $cle => $valeur) {if (!is_null($valeur) && $valeur != '') {$xml .= "<$cle>$valeur</$cle>\n";}}if ($xml !== null) {$info = sprintf($xml_tpl, $xml);$info = $this->bdd->quote($info);}return $info;}protected function getTableauDepuisXmlHisto($xml) {// Création du xml de l'enregistrement à historiser$info = array();if (!empty($xml) && preg_match_all('|<([^>]+)>(.*)</[^>]+>|U', $xml, $matches, PREG_SET_ORDER)) {foreach ($matches as $val) {$info[$val[1]] = $val[2];}}return $info;}protected function historiser($table_id, $ligne_cle, $info, $id_utilisateur, $etat, $id_session) {date_default_timezone_set('Europe/Paris');// Pré-traitement des variables$info = (is_null($info)) ? 'NULL' : $info;// Historisation (Ajout des méta-données)$requete = 'INSERT INTO coel_meta_historique_ligne '.' (cmhl_ce_table, cmhl_cle_ligne, cmhl_enregistrement, cmhl_date_modification, cmhl_ce_modifier_par, cmhl_ce_etat, cmhl_ip, cmhl_session_id) '.'VALUES ('." $table_id, ".' "'.$ligne_cle.'", '." $info, ".' "'.date('Y-m-d H:i:s', time()).'", '." $id_utilisateur, "." $etat, ".' "'.$_SERVER['REMOTE_ADDR'].'", '.' "'.$id_session.'") ';// Exécution de la requêtre SQL et test d'éventuelles erreurs$resultat = $this->bdd->exec($requete);if ($resultat === false ) {$this->log[] = "Des données de la table '$table_id' (enrg. $ligne_cle) n'ont pas été historisées car la requête a échouée.";}return $this->bdd->lastInsertId();}protected function envoyer($donnees = null, $mime = 'application/json', $encodage = 'utf-8', $json = true) {// Traitements des messages d'erreurs et donnéesif (count($this->messages) != 0) {header('HTTP/1.1 500 Internal Server Error');$mime = 'text/html';$encodage = 'utf-8';$json = true;$sortie = $this->messages;} else {$sortie = $donnees;if (is_null($donnees)) {$sortie = 'OK';}}// Gestion de l'envoie du déboguage$this->envoyerDebogage();// Encodage au format et JSON et envoie sur la sortie standard$contenu = $json ? json_encode($sortie) : $sortie;$this->envoyerContenu($encodage, $mime, $contenu);}protected function envoyerHTML($donnees = null) {// Traitements des messages d'erreurs et données$contenu = '';if (count($this->messages) > 0) {$contenu = '<p>'.implode('<br />', $this->messages).'</p>';} else {$contenu = $donnees;if (is_null($donnees)) {$contenu = 'OK';}}// Gestion de l'envoie du déboguage$this->envoyerDebogage();// Envoie sur la sortie standard$this->envoyerContenu(null, null, $contenu);}protected function envoyerEnteteMessage() {if (!is_array($this->messages)) {$this->messages[] = $this->messages;}if (count($this->messages) != 0) {foreach ($this->messages as $cle => $val) {if (is_array($val)) {$this->messages[$cle] = print_r($val, true);}}header('X-MessageJrest-Data: '.json_encode($this->messages));}}protected function envoyerDebogage() {$this->envoyerEnteteDebogage();}protected function envoyerEnteteDebogage() {if (!is_array($this->debug)) {$this->debug[] = $this->debug;}if (count($this->debug) != 0) {foreach ($this->debug as $cle => $val) {if (is_array($val)) {$this->debug[$cle] = print_r($val, true);}}header('X-DebugJrest-Data: '.json_encode($this->debug));}}protected function envoyerContenu($encodage, $mime, $contenu) {if (!is_null($mime) && !is_null($encodage)) {header("Content-Type: $mime; charset=$encodage");} else if (!is_null($mime) && is_null($encodage)) {header("Content-Type: $mime");}print $contenu;}private function connecterPDO($config, $base = 'database') {$cfg = $config[$base];$dsn = $cfg['phptype'].':dbname='.$cfg['database'].';host='.$cfg['hostspec'];try {$PDO = new PDO($dsn, $cfg['username'], $cfg['password']);} catch (PDOException $e) {echo 'La connexion à la base de donnée via PDO a échouée : ' . $e->getMessage();}// Passe en UTF-8 la connexion à la BDD$PDO->exec("SET NAMES 'utf8'");// Désactive les controles strict de mysql$PDO->exec("SET SESSION sql_mode = ''");// Affiche les erreurs détectées par PDO (sinon mode silencieux => aucune erreur affiché)$PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);return $PDO;}protected function getTxt($id) {$sortie = '';switch ($id) {case 'sql_erreur' : $sortie = 'Requête echec. Fichier : "%s". Ligne : "%s". Message : %s'; break;case 'sql_erreur_requete' : $sortie = "Requête echec.\nFichier : %s.\nLigne : %s.\nMessage : %s.\nRequête : %s"; break;default : $sortie = $id;}return $sortie;}protected function concatenerChamps($champs, $prefixe = null) {$chaine = '';foreach ($champs as $cle => $valeur) {if (is_null($prefixe) || (!is_null($prefixe) && stristr($cle, $prefixe.'_'))) {$chaine .= ", $cle = $valeur";}}return ltrim($chaine, ', ');}protected function separerChampsValeurs($donnees, $prefixe = null) {$sortie = array('', '');// Concaténation des champs et des valeurs dans des chaines séparéesforeach ($donnees as $cle => $valeur) {if (is_null($prefixe) || (!is_null($prefixe) && stristr($cle, $prefixe.'_'))) {$sortie[0] .= "$cle, ";$sortie[1] .= "$valeur, ";}}// Suppression de la virgule finale$sortie[0] = rtrim($sortie[0], ', ');$sortie[1] = rtrim($sortie[1], ', ');return $sortie;}protected function traiterParametresUrl($params_attendu, $params, $pourBDD = true) {$sortie = array();foreach ($params_attendu as $num => $nom) {if (isset($params[$num]) && $params[$num] != '*') {if ($pourBDD) {$params[$num] = $this->bdd->quote($params[$num]);}$sortie[$nom] = $params[$num];}}return $sortie;}protected function traiterBddClauseIn($chaine) {$sortie = '';$chaine = trim($chaine, " '");if ($chaine != '') {$valeurs = explode(',', $chaine);foreach ($valeurs as $id => $valeur) {$valeurs[$id] = $this->bdd->quote($valeur);}$sortie = implode(',', $valeurs);}return $sortie;}protected function traiterParametresPost($params) {$sortie = array();foreach ($params as $cle => $valeur) {$sortie[$cle] = $this->bdd->quote($valeur);}return $sortie;}protected function getIdentification(&$params) {// Initialisation des variables$utilisateur = array(0, session_id());// L'id utilisateur est soit passé par le POST soit dans l'urlif (is_array($params) && isset($params['cmhl_ce_modifier_par'])) {$utilisateur[0] = $params['cmhl_ce_modifier_par'];unset($params['cmhl_ce_modifier_par']);} else if (is_string($params)) {$utilisateur[0] = $params;}return $utilisateur;}protected function etreAutorise($id_utilisateur) {$autorisation = false;if (!array_key_exists('coel_utilisateur', $_SESSION) || (($_SESSION['coel_utilisateur'] != '') && $_SESSION['coel_utilisateur']['id'] != $id_utilisateur)) {$this->messages[] = 'Accès interdit.';} else if ($_SESSION['coel_utilisateur'] == '') {$this->messages[] = 'Veuillez vous identifiez pour accéder à cette fonction.';} else {$autorisation = true;}return $autorisation;}protected function recupererCle($table) {$cle = null;if (isset($table['champs_valeurs_id'])) {$identifiants = array();// Trie des clés primaire pour avoir toujours le même ordre dans la table historique pour les clés multiplesksort($table['champs_valeurs_id']);foreach ($table['champs_valeurs_id'] as $id) {$identifiants[] = $id;}$cle = implode('-', $identifiants);}return $cle;}protected function avoirCleComplete($table) {$cle_complete = false;if (isset($table['champs_valeurs_id'])) {$ok = true;foreach ($table['id'] as $id) {if (!isset($table['champs_valeurs_id'][$id]) || $table['champs_valeurs_id'][$id] == '') {$ok = false;break;}}$cle_complete = $ok;}return $cle_complete;}protected function recupererEtat($table) {$etat = 1;// Ajoutif ($this->avoirEnregistrement($table) === true) {$etat = 2;// Modification}return $etat;}protected function avoirEnregistrement($table) {$avoir_enregistrement = false;$requete = 'SELECT * '."FROM {$table['nom']} "."WHERE %s ";$where = $this->construireWhere($table['champs_valeurs_id']);$requete = sprintf($requete, $where);// Exécution de la requêtre SQL et test d'éventuelles erreurs$resultat = $this->bdd->query($requete, PDO::FETCH_ASSOC)->fetch();if ($resultat !== false) {$avoir_enregistrement = true;}return $avoir_enregistrement;}protected function contenirDonnees($requete) {$nbre = $this->bdd->query($requete)->fetchColumn();$presence = false;if ($nbre != 0) {$presence = true;}return $presence;}protected function construireWhere($table) {$where = '1';if (is_array($table) && count($table) > 0) {$table_where = array();foreach ($table as $chp => $id) {$table_where[] = "$chp = '$id'";}$where = implode(' AND ', $table_where);}return $where;}protected function recupererTablesAModifier($parametres) {$tables_a_modifier = $this->tables;foreach ($this->tables as $table_id => $table) {$tables_a_modifier[$table_id]['champs'] = null;foreach ($parametres as $cle => $valeur) {if (preg_match('/^'.$table['prefixe'].'_/', $cle)) {// Contient les noms des champs seulements$tables_a_modifier[$table_id]['champs'][] = $cle;// Contient un tableau de résultats protégé pour l'inclusion en bdd$tables_a_modifier[$table_id]['champs_valeurs_protege'][$cle] = is_null($valeur) ? 'NULL' : $this->bdd->quote($valeur);// Contient un tableau de résultats non protégé$tables_a_modifier[$table_id]['champs_valeurs_brut'][$cle] = $valeur;if (preg_match('/_id_/', $cle)) {$tables_a_modifier[$table_id]['champs_valeurs_id'][$cle] = $valeur;}}}}return $tables_a_modifier;}protected function mettreAJourAvecCle($id_utilisateur, $id_session, $table_id, $table) {if (!is_null($table['champs'])) {// Historisation (Ajout des méta-données)$cle = $this->recupererCle($table);$etat = $this->recupererEtat($table);$info = $this->creerXmlHisto($table['champs_valeurs_brut']);$id_meta = $this->historiser($table_id, $cle, $info, $id_utilisateur, $etat, $id_session);$champ_meta = "{$table['prefixe']}_ce_meta";$table['champs_valeurs_protege'][$champ_meta] = $this->bdd->quote($id_meta);// Mise à jour des données ou ajout en fonction de l'étatif ($etat == 1) { // Ajout$this->ajouter($table);} else if ($etat == 2) { // Modif$this->modifier($table);}}}protected function ajouter($table) {$requete = "INSERT INTO {$table['nom']} ".' (%s) '.' VALUES (%s) ';$champs = $valeurs = '';foreach ($table['champs_valeurs_protege'] as $chp => $val) {$champs .= "$chp, ";$valeurs .= "$val, ";}$requete = sprintf($requete, rtrim($champs, ', '), rtrim($valeurs, ', '));$resultat = $this->bdd->exec($requete);$dernier_id = false;if ($resultat === false) {$cle = $this->recupererCle($table);$this->log[] = "L'enregistrement '$cle' de la table {$table['nom']} n'a pas été ajouté car la requête a échouée.";} else {$dernier_id = $this->bdd->lastInsertId();}return $dernier_id;}protected function modifier($table) {// nous ne voulons pas qu'une requête malheureuse affecte toute la base de données. Par exemple:// POST "/jrest/CoelStructure/1"<<<"var=val&" // écraserait tous les enregistrements// car on ne peut garantir que tout le code existant wrap'era ses appels dans un if(avoirCleComplete())if(!array_key_exists('champs_valeurs_id', $table)) die('erreur: ' . __FILE__ . ':' . __LINE__);$requete = "UPDATE {$table['nom']} ".'SET %s '.'WHERE %s ';$champs_requete = '';foreach ($table['champs_valeurs_protege'] as $chp => $val) {$champs_requete .= "$chp = $val, ";}$where = $this->construireWhere($table['champs_valeurs_id']);$requete = sprintf($requete, rtrim($champs_requete, ', '), $where);$resultat = $this->bdd->exec($requete);if ($resultat === false) {$cle = $this->recupererCle($table);$this->log[] = "L'enregistrement '$cle' de la table {$table['nom']} n'a pas été mis à jour car la requête a échouée.";} else {$resultat = true;}return $resultat;}protected function supprimer($table) {$requete = "DELETE FROM {$table['nom']} ".'WHERE %s ';$where = $this->construireWhere($table['champs_valeurs_id']);$requete = sprintf($requete, $where);$resultat = $this->bdd->exec($requete);if ($resultat === false) {$cle = $this->recupererCle($table);$this->messages[] = "L'enregistrement '$cle' de la table {$table['nom']} n'a pas été supprimé car la requête a échouée.";} else {$resultat = true;}return $resultat;}private function gererSession($demarrage) {session_name($this->sessionName);// Configuration du cookie de session// Détermination du chemin pour les cookies nécessaire à Jrest/// ATTENTION : comme les cookies sont passés à Jrest, il faut utiliser l'url de Jrest pour établir le chemin$url_morceaux = parse_url($this->config['coel']['urlBaseJrest']);self::$cookieChemin = $this->reparerCheminCookie($url_morceaux['path']);unset($url_morceaux);session_set_cookie_params($this->sessionExpireTime, self::$cookieChemin);// Démarrage de la sessionif ($demarrage) {session_start();}}private function reparerCheminCookie($chemin) {// dirname renvoit / si le chemin vaut seulement /dossier/, cela renvoit /dossier si le chemin vaut /dossier//.$chemin = dirname($chemin.'/.');// Fixe la gestion des chemins pour les cookies sous les OS utilisant le \ comme séparteur de chemin$chemin = str_replace('\\', '/', $chemin);// Ajoute un '/' terminal sauf si on est à la racine web$chemin = ($chemin != '/' ? $chemin.'/' : '');return $chemin;}private function gererIdentificationPermanente() {// Pour maintenir l'utilisateur tjrs réellement identifié nous sommes obligé de recréer une SESSION et de le recharger depuis la bddif ($this->getUtilisateur() == ''&& isset($_COOKIE['coel_login'])&& ($utilisateur = $this->chargerUtilisateur($_COOKIE['coel_login'], $_COOKIE['coel_mot_de_passe']))) {$this->setUtilisateur($utilisateur, $_COOKIE['coel_permanence']);}}/*protected function rechargerCookieUtilisateur() {$utilisateur = $this->chargerUtilisateur($_COOKIE['coel_login']);$this->setUtilisateur($utilisateur, $_COOKIE['coel_permanence']);}*/protected function getUtilisateur() {return (isset($_SESSION['coel_utilisateur']) ? $_SESSION['coel_utilisateur'] : '');}/*** Tente de trouver un utilisateur dans la table Personnes de CoeL, en fonction de son* courriel ($login); si le mot de passe est fournie, le vérifie, sinon l'ignore** MàJ 2017 : le mot de passe n'est plus stocké en local, tout se fait via l'annuaire*/protected function chargerUtilisateur($login, $mot_de_passe = null) {$sortie = false;$requete = 'SELECT cp_id_personne AS id, cp_fmt_nom_complet AS nom_complet, cp_prenom AS prenom, '.' cp_nom AS nom, cp_login AS login, cp_mot_de_passe AS mot_de_passe, cp_parametre AS parametre, '.' cp_ville AS ville, cp_code_postal AS code_postal, '.' cp_mark_licence AS licence '.'FROM coel_personne '."WHERE cp_login = {$this->bdd->quote($login)} ";//((!is_null($mot_de_passe)) ? "AND cp_mot_de_passe = {$this->bdd->quote($mot_de_passe)} " : '');try {$resultat = $this->bdd->query($requete)->fetch();if ($resultat === false) {$this->debug[] = "L'utilisateur n'est pas enregistré comme utilisateur de COEL.";} else {$sortie = array('id' => $resultat['id'],'login' => $login,'mot_de_passe' => $resultat['mot_de_passe'],'nom_complet' => $resultat['nom_complet'],'nom' => $resultat['nom'],'prenom' => $resultat['prenom'],'parametre' => $resultat['parametre'],'ville' => $resultat['ville'],'code_postal' => $resultat['code_postal'],'licence' => $resultat['licence']);}} catch (PDOException $e) {$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage());}return $sortie;}/*** Définit un utilisateur comme "actif" en plaçant un objet Utilisateur dans la session;* Ne pose plus de cookies depuis l'adaptation au SSO, sauf pour la licence (acceptée ou non)* @param unknown $utilisateur* @param number $permanence*/protected function setUtilisateur($utilisateur, $permanence = 1) {$_SESSION['coel_utilisateur'] = $utilisateur;//$this->setCookiePersistant('coel_licence', $utilisateur['licence'], $permanence);}protected function setCookiePersistant($cookie_nom, $valeur, $permanence = 1) {setCookie($cookie_nom, $valeur, time() + ($permanence ? 100*24*60*60 : 60*60), self::$cookieChemin);$_COOKIE[$cookie_nom] = $valeur;}protected function supprimerCookie($cookie_nom) {setCookie($cookie_nom, '', 1, self::$cookieChemin);$_COOKIE[$cookie_nom] = '';}/*** Méthode prenant en paramètre un chemin de fichier squelette et un tableau associatif de données,* en extrait les variables, charge le squelette et retourne le résultat des deux combinés.** @param String $fichier le chemin du fichier du squelette* @param Array $donnees un tableau associatif contenant les variables a injecter dans le squelette.** @return boolean false si le squelette n'existe pas, sinon la chaine résultat.*/public static function traiterSquelettePhp($fichier, Array $donnees = array()) {$sortie = false;if (file_exists($fichier)) {// Extraction des variables du tableau de donnéesextract($donnees);// Démarage de la bufferisation de sortieob_start();// Si les tags courts sont activésif ((bool) @ini_get('short_open_tag') === true) {// Simple inclusion du squeletteinclude $fichier;} else {// Sinon, remplacement des tags courts par la syntaxe classique avec echo$html_et_code_php = self::traiterTagsCourts($fichier);// Pour évaluer du php mélangé dans du html il est nécessaire de fermer la balise php ouverte par eval$html_et_code_php = '?>'.$html_et_code_php;// Interprétation du html et du php dans le bufferecho eval($html_et_code_php);}// Récupèration du contenu du buffer$sortie = ob_get_contents();// Suppression du buffer@ob_end_clean();} else {$msg = "Le fichier du squelette '$fichier' n'existe pas.";trigger_error($msg, E_USER_WARNING);}// Retourne le contenureturn $sortie;}/*** Fonction chargeant le contenu du squelette et remplaçant les tags court php (<?= ...) par un tag long avec echo.** @param String $chemin_squelette le chemin du fichier du squelette** @return string le contenu du fichier du squelette php avec les tags courts remplacés.*/private static function traiterTagsCourts($chemin_squelette) {$contenu = file_get_contents($chemin_squelette);// Remplacement de tags courts par un tag long avec echo$contenu = str_replace('<?=', '<?php echo ', $contenu);// Ajout systématique d'un point virgule avant la fermeture php$contenu = preg_replace("/;*\s*\?>/", "; ?>", $contenu);return $contenu;}public static function debug($var) {echo '<pre>'.print_r($var, true).'</pre>';}/** Retourne une paire de coordonnée depuis un tableau représentant une adresse* ou une adresse partielle à l'aide du service Nominatim.* (http://wiki.openstreetmap.org/wiki/Nominatim)** @param in data: un tableau associatif doté de *toutes* les clefs suivantes:* 'adresse', 'cp', 'ville', 'pays'* @param out lonlat: un tableau associatif contenant 'lon' et 'lat' si elles ont été déterminées* Celles-ci sont sous la forme de deux chaînes de caractères numériques représentant* un FLOAT() dont le séparateur des décimales est le "." (point).* @param in opts: un tableau associatif optionnel écrasant ou ajoutant des valeurs d'API* @return boolean: selon que la fonction à réussi ou non** opts['force-q']: force l'utilisation d'une requête en texte libre* quelque soit le remplissage des composants individuels** Note: le code postal est contre-productif pour Nominatim:* https://lists.openstreetmap.org/pipermail/talk-fr/2013-April/057084.html*/static function coordGuess(Array $data, Array &$lonlat, Array $opts = NULL) {if(!$data) return FALSE;$common_query = array('accept_language' => 'fr', 'format' => 'json', 'limit' => 1);if(! $data['adresse'] || (! $data['cp'] && ! $data['ville']) || @$opts['force-q']) {unset($opts['force-q']);$query = array_merge($common_query,array('q' => implode(', ', array_filter($data))),$opts ? $opts : array());}else {$query = array_merge($common_query,array_filter(array('street' => $data['adresse'],'city' => $data['ville'],'postalcode' => $data['cp'],'country' => $data['pays'])),$opts ? $opts : array());}$fullquery = 'http://nominatim.openstreetmap.org/search.php?' . http_build_query($query);$ctx = stream_context_create(array('http' => array( 'timeout' => '4' )));$r = json_decode(file_get_contents($fullquery, FALSE, $ctx));error_log(sprintf("COEL: Nominatim request returned %d result(s) [%s]", count($r), $fullquery));if($r && isset($r[0])) {$lonlat['lon'] = $r[0]->lon;$lonlat['lat'] = $r[0]->lat;return TRUE;}return FALSE;}/** Retourne un tableau prêt à être utilisé par coordGuess(), c'est à dire initialisant toutes* les clefs nécessaires (même si NULL) et disposant systématiquement d'un pays.* Cela à partir d'un tableau au format de clefs prédéterminé.* S'occupe du filtrage basique des éléments pour maximiser les chances de détection.** @param in: un tableau associatif contenant les clefs telles que nommées à l'issue du* du formulaire de saisie: 'cs_adresse_01', 'cs_code_postal', 'cs_ville'* @param db: une db optionnelle, utilisée si nécessaire pour converir les code pays* du formulaire de saisie: 'cs_adresse_01', 'cs_code_postal', 'cs_ville'* @return un tableau associatif contenant une ou plusieurs des clefs suivantes:* 'adresse', 'cp', 'ville', 'pays'*/static function addrReStruct(Array $in, $db = NULL) {$pays = FALSE;if(is_numeric(@$in['cs_ce_truk_pays'])) {if($db) {$pays= $db->query(sprintf("SELECT cmlv_nom FROM coel_meta_liste_valeur "."WHERE cmlv_ce_parent = 1074 AND cmlv_id_valeur = %d",intval($in['cs_ce_truk_pays'])))->fetchColumn();}}else $pays = @trim($in['cs_ce_truk_pays']);// pas de précision au n°, mais Nominatim peine avec des préfixes trop élaborés// coupons jusqu'à un élément reconnaissable s'il existe$adresse = @trim($in['cs_adresse_01']);$adresse = substr($adresse, stripos($adresse, "ville de "));$adresse = substr($adresse, stripos($adresse, "impasse"));$adresse = substr($adresse, stripos($adresse, "chemin"));$adresse = substr($adresse, stripos($adresse, "route"));$adresse = substr($adresse, stripos($adresse, "rue"));$adresse = substr($adresse, stripos($adresse, "avenue"));$adresse = substr($adresse, stripos($adresse, "boulevard"));$adresse = substr($adresse, stripos($adresse, "place"));$adresse = substr($adresse, stripos($adresse, "promenade"));$adresse = substr($adresse, stripos($adresse, "allée"));$adresse = substr($adresse, stripos($adresse, "cours"));$adresse = preg_replace("/[\r\n].*/", "", $adresse);$ville = preg_replace('/cedex.*/i', '', @trim($in['cs_ville']));return array('adresse' => $adresse,'cp' => @trim($in['cs_code_postal']) ? $in['cs_code_postal'] : '','ville' => $ville,'pays' => $pays !== FALSE ? $pays : 'France');}}?>