* @license GPL v3 * @license CECILL v2 * @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 jours protected 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 = ''."\n\n\n%s\n"; $xml = null; foreach ($donnees as $cle => $valeur) { if (!is_null($valeur) && $valeur != '') { $xml .= "<$cle>$valeur\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ées if (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 = '

'.implode('
', $this->messages).'

'; } 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'"); // 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ées foreach ($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'url if (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 multiples ksort($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;// Ajout if ($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'état if ($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 session if ($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 bdd if ($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 */ 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ées extract($donnees); // Démarage de la bufferisation de sortie ob_start(); // Si les tags courts sont activés if ((bool) @ini_get('short_open_tag') === true) { // Simple inclusion du squelette include $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 buffer echo 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 contenu return $sortie; } /** * Fonction chargeant le contenu du squelette et remplaçant les tags court php (/", "; ?>", $contenu); return $contenu; } public static function debug($var) { echo '
'.print_r($var, true).'
'; } /* * 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' ); } } ?>