Subversion Repositories eFlore/Applications.cel

Rev

Rev 3334 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

 <?php
// declare(encoding='UTF-8');
/**
 * Service affichant les dernières photo publiques du CEL ouvrable sous forme de diaporama.
 * Encodage en entrée : utf8
 * Encodage en sortie : utf8
 *
 * Cas d'utilisation et documentation :
 * @link http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=AideCELWidgetPhoto
 *
 * Paramètres :
 * ===> extra = booléen (1 ou 0)  [par défaut : 1]
 * Affiche / Cache la vignette en taille plus importante au bas du widget.
 * ===> vignette = [0-9]+,[0-9]+  [par défaut : 4,3]
 * Indique le nombre de vignette par ligne et le nombre de ligne.
 *
 * @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   Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
 */
class Lg extends WidgetCommun {

        const DS = DIRECTORY_SEPARATOR;
        const SERVICE_DEFAUT = 'saisie';
        const WS_SAISIE = 'CelWidgetSaisie';
        const WS_UPLOAD = 'CelWidgetUploadImageTemp';
        const WS_IMG_LIST = 'celImage';
        const WS_OBS = 'CelObs';
        const WS_OBS_LIST = 'InventoryObservationList';
        const LANGUE_DEFAUT = 'fr';
        const PROJET_DEFAUT = 'lg';
        const WS_NOM = 'noms';
        const EFLORE_API_VERSION = '0.1';
        private $cel_url_tpl = null;
        /** Si spécifié, on ajoute une barre de navigation inter-applications */
        private $bar;
        //private $parametres_autorises = array('projet', 'type', 'langue', 'order');
        private $parametres_autorises = array(
                        'projet' => 'projet',
                        'type' => 'type',
                        'langue' => 'langue',
                        'order' => 'order'
        );
        /**
         * Méthode appelée par défaut pour charger ce widget.
         */
        public function executer() {
                $retour = null;
                // Pour la création de l'id du cache nous ne tenons pas compte du paramètre de l'url callback
                unset($this->parametres['callback']);
                extract($this->parametres);
                $this->bar = (isset($bar)) ? $bar : false;
                /* Le fichier Framework.php du Framework de Tela Botanica doit être appelé avant tout autre chose dans l'application.
                 Sinon, rien ne sera chargé.
                 L'emplacement du Framework peut varier en fonction de l'environnement (test, prod...). Afin de faciliter la configuration
                 de l'emplacement du Framework, un fichier framework.defaut.php doit être renommé en framework.php et configuré pour chaque installation de
                 l'application.
                 Chemin du fichier chargeant le framework requis */
                $framework = dirname(__FILE__).'/framework.php';
                if (!file_exists($framework)) {
                        $e = "Veuillez paramêtrer l'emplacement et la version du Framework dans le fichier $framework";
                        trigger_error($e, E_USER_ERROR);
                } else {
                        // Inclusion du Framework
                        require_once $framework;
                        // Ajout d'information concernant cette application
                        Framework::setCheminAppli(__FILE__);// Obligatoire
                        Framework::setInfoAppli(Config::get('info'));// Optionnel

                }
                $langue = (isset($langue)) ? $langue : self::LANGUE_DEFAUT;
                $this->langue = I18n::setLangue($langue);
                $this->parametres['langue'] = $langue;

                if (!isset($mode)) {
                        $mode = self::SERVICE_DEFAUT;
                }
                if (!isset($projet)) {
                        $this->parametres['projet'] = self::PROJET_DEFAUT;
                }

                $methode = $this->traiterNomMethodeExecuter($mode);
                if (method_exists($this, $methode)) {
                        $retour = $this->$methode();
                } else {
                        $this->messages[] = "Ce type de service '$methode' n'est pas disponible.";
                }

                $contenu = '';
                if (is_null($retour)) {
                        $this->messages[] = 'La ressource demandée a retourné une valeur nulle.';
                } else {
                        if (isset($retour['donnees'])) {
                                $retour['donnees']['conf_mode'] = $this->config['parametres']['modeServeur'];
                                $retour['donnees']['prod'] = ($this->config['parametres']['modeServeur'] == 'prod');
                                $retour['donnees']['bar'] = $this->bar;
                                $retour['donnees']['url_base'] = sprintf($this->config['chemins']['baseURLAbsoluDyn'], $this->config['lg']['cheminDos']);
                                $retour['donnees']['url_ws_annuaire'] = sprintf($this->config['chemins']['baseURLServicesAnnuaireTpl'], 'utilisateur/identite-par-courriel/');
                                $retour['donnees']['url_ws_lg'] = sprintf($this->config['chemins']['baseURLServicesCelTpl'], self::WS_SAISIE);
                                $retour['donnees']['url_ws_obs'] = sprintf($this->config['chemins']['baseURLServicesCelTpl'], self::WS_OBS);
                                $retour['donnees']['url_ws_obs_list'] = sprintf($this->config['chemins']['baseURLServicesCelTpl'], self::WS_OBS_LIST);
                                $retour['donnees']['url_ws_upload'] = sprintf($this->config['chemins']['baseURLServicesCelTpl'], self::WS_UPLOAD);
                                $retour['donnees']['url_ws_cel_imgs'] = sprintf($this->config['chemins']['baseURLServicesCelTpl'], self::WS_IMG_LIST) . '/liste-ids?obsId=';
                                $retour['donnees']['url_ws_cel_img_url'] = str_replace ( '%s.jpg', '{id}XS', $this->config['chemins']['celImgUrlTpl'] );
                                $retour['donnees']['mode'] = $mode;
                                $retour['donnees']['langue'] = $langue;
                                if( isset( $this->parametres['squelette'] ) ) {
                                        $squelette = dirname(__FILE__).self::DS.'squelettes'.self::DS. $this->parametres['squelette'].'.tpl.html';
                                } else {
                                        $squelette = dirname(__FILE__).self::DS.'squelettes'.self::DS.$retour['squelette'].'.tpl.html';
                                }
                                $contenu = $this->traiterSquelettePhp($squelette, $retour['donnees']);
                        } else {
                                $this->messages[] = 'Les données à transmettre au squelette sont nulles.';
                        }
                }
                $this->envoyer($contenu);
        }


        private function executerSaisie() {
                $retour = array();
                $retour['squelette'] = 'lg';
                $retour['donnees']['general'] = I18n::get('General');
                $retour['donnees']['observateur'] = I18n::get('Observateur');
        $retour['donnees']['observation'] = I18n::get('Observation');
        $retour['donnees']['arbres'] = I18n::get('Arbres');
        $retour['donnees']['image'] = I18n::get('Image');
        $retour['donnees']['lichens'] = I18n::get('Lichens');
        $retour['donnees']['chpsupp'] = I18n::get('Chpsupp');
        $retour['donnees']['resume'] = I18n::get('Resume');
                $retour['donnees']['widget'] = $this->rechercherProjet();
                return $retour;
        }

        /* Recherche si le projet existe sinon va chercher les infos de base */
        private function rechercherProjet() {
                // projet avec un squelette défini (et non juste un mot-clé d'observation)
                $estProjetDefini = true;
                $tab = array();
                $url = $this->config['lg']['celUrlTpl'].'?projet='.$this->parametres['projet'].'&langue='.$this->parametres['langue'];
                $json = $this->getDao()->consulter($url);

                if ( $json ) {
                        $tab = $this->rechercherChampsSupp();
                } else {
                        $url = $this->config['lg']['celUrlTpl'].'?projet=base&langue='.$this->parametres['langue'];
                        $json = $this->getDao()->consulter($url);
                        $estProjetDefini = false;
                }
                $tableau = json_decode($json, true);
                $tableau = $this->traiterParametres($estProjetDefini, $tableau[0]);
                if (isset($this->parametres['squelette']) && $this->parametres['squelette'] === 'lichens') {
                        $tableau['type_especes'] = 'liste';
                        $tableau['referentiel'] = 'taxref';
                }
                $tableau['especes'] = $this->rechercherInfosEspeces($tableau);
                if ($tableau['milieux'] != "") {
                        $tableau['milieux'] = explode(";", $tableau['milieux']);
                } else {
                        $tableau['milieux'] = array();
                }
                if (isset($tableau['motscles'])) {
                    $tableau['tag-obs'] = $tableau['tag-img'] = $tableau['motscles'];
                }
                $tableau['chpSupp'] = $tab;
                $langue_projet_url = ( isset ( $this->parametres['langue'] ) && $this->parametres['langue'] !== 'fr' ) ? '_' . $this->parametres['langue'] : '';
                $tableau['chemin_fichiers'] = sprintf( $this->config['chemins']['baseURLAbsoluDyn'], $this->config['lg']['imgProjet'] . '/' );
                return $tableau;
        }

        /* Recherche si un projet a des champs de saisie supplémentaire */
        private function rechercherChampsSupp() {
                $retour = array();
                $projet = $this->parametres['projet'];
                $url = $this->config['lg']['celChpSupTpl'] .'?projet=' . $projet . '&langue=' . $this->parametres['langue'];
                $json = $this->getDao()->consulter($url);
                $retour = (array) json_decode($json, true);

                foreach ( $retour[$projet]['champs-supp'] as $key => $chsup ) {

                        $retour[$projet]['champs-supp'][$key]['name'] = $this->clean_string( $chsup['name'] );
                        $retour[$projet]['champs-supp'][$key]['description'] = $this->clean_string( $chsup['description']);
                        $retour[$projet]['champs-supp'][$key]['unit'] = $this->clean_string( $chsup['unit'] );

                        if ( isset( $chsup['fieldValues'] ) ) {
                                $retour[$projet]['champs-supp'][$key]['fieldValues'] = json_decode( $chsup['fieldValues'], true );
                                if ( isset($retour[$projet]['champs-supp'][$key]['fieldValues']['placeholder'] ) ) {
                                        $retour[$projet]['champs-supp'][$key]['fieldValues']['placeholder'] = $this->clean_string( $retour[$projet]['champs-supp'][$key]['fieldValues']['placeholder'] );
                                }

                                if ( isset( $retour[$projet]['champs-supp'][$key]['fieldValues']['listValue'] ) ) {
                                        foreach( $retour[$projet]['champs-supp'][$key]['fieldValues']['listValue'] as $list_key => $list_value ) {
                                                $retour[$projet]['champs-supp'][$key]['fieldValues']['listValue'][$list_key] = $this->clean_string( $list_value );
                                                // Obtenir une liste de valeurs utilisables dans les attributs for id ou name par exemple
                                                $retour[$projet]['champs-supp'][$key]['fieldValues']['cleanListValue'][] = 'val-' . preg_replace( '/[^A-Za-z0-9_\-]/', '', $this->remove_accents( $list_value ) );
                                        }
                                }
                        }
                        $retour[$projet]['champs-supp'][$key]['mandatory'] = intval( $chsup['mandatory'] );
                }
                return $retour;
        }

        private function clean_string( $string ) {
                // les fonctions de base de php ne parviennent pas à une conversion satisfaisante des codes ascii
                // qui ont été générés automatiquement lors de la transmission des chaines en json
                // dans le widget cel manager vers la base
                // Pour les mêmes raisons, @apos@ et @quot@ est une autre astuces utilisée dans ce même widget
                // pour permettre la transmission des apostrophes et guillements sans erreur
                $patterns = array( '/\@apos\@/', '/\@quot\@/', '/u00c0/', '/u00c1/', '/u00c2/', '/u00c3/', '/u00c4/', '/u00c5/', '/u00c6/', '/u00c7/', '/u00c8/', '/u00c9/', '/u00ca/', '/u00cb/', '/u00cc/', '/u00cd/', '/u00ce/', '/u00cf/', '/u00d1/', '/u00d2/', '/u00d3/', '/u00d4/', '/u00d5/', '/u00d6/', '/u00d8/', '/u00d9/', '/u00da/', '/u00db/', '/u00dc/', '/u00dd/', '/u00df/', '/u00e0/', '/u00e1/', '/u00e2/', '/u00e3/', '/u00e4/', '/u00e5/', '/u00e6/', '/u00e7/', '/u00e8/', '/u00e9/', '/u00ea/', '/u00eb/', '/u00ec/', '/u00ed/', '/u00ee/', '/u00ef/', '/u00f0/', '/u00f1/', '/u00f2/', '/u00f3/', '/u00f4/', '/u00f5/', '/u00f6/', '/u00f8/', '/u00f9/', '/u00fa/', '/u00fb/', '/u00fc/', '/u00fd/', '/u00ff/' );
                $replacements = array( '&apos;', '&quot;', 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý','ÿ' );

                $clean_string = preg_replace( $patterns, $replacements, $string );

                return $clean_string;
        }

        // remplace certains parametres définis en bd par les parametres définis dans l'url
        private function traiterParametres($estProjetDefini, $tableau) {
                $criteres = array('tag-obs', 'tag-img', 'projet', 'titre', 'logo');
                $criteresProjetNonDefini = array('commune', 'num_nom', 'referentiel');
                foreach($this->parametres as $nom_critere => $valeur_critere) {
                        if (($estProjetDefini == false || $tableau['projet'] == 'base') && in_array($nom_critere, $criteresProjetNonDefini)) {
                                $tableau[$nom_critere] = $valeur_critere;
                        } else if (in_array($nom_critere, $criteres)) {
                                $tableau[$nom_critere] = $valeur_critere;
                        }
                }
                return $tableau;
        }

        private function rechercherInfosEspeces( $infos_projets ) { //print_r($infos_projets);exit;
                $retour = array();
                $referentiel = $infos_projets['referentiel'];
                $urlWsNsTpl = $this->config['chemins']['baseURLServicesEfloreTpl'];
                $retour['url_ws_autocompletion_ns'] = sprintf( $urlWsNsTpl, self::EFLORE_API_VERSION, $referentiel, self::WS_NOM );;
                $retour['url_ws_autocompletion_ns_tpl'] = sprintf( $urlWsNsTpl, self::EFLORE_API_VERSION, '{referentiel}', self::WS_NOM );
                $retour['ns_referentiel'] = $referentiel;

                if ( isset( $infos_projets['type_especes'] ) ) {

                        switch ( $infos_projets['type_especes'] ) {
                                case 'fixe' :
                                        $retour = $this->chargerInfosTaxon( $infos_projets['referentiel'], $infos_projets['especes'] );
                                        break;
                                case 'referentiel' : break;
                                case 'liste' :
                                        $referentiel = $infos_projets['referentiel'];
////////////////////// temporaire test transmission liste taxons
                                        $retour['taxons'] = $this->recupererListeNomsSci();
                                        break;
                        }
                } else if ( isset( $infos_projets['referentiel'] ) ) {
                        $referentiel = $infos_projets['referentiel'];
                        if ( isset($infos_projets['num_nom'] ) ) {
                                $retour = $this->chargerInfosTaxon( $infos_projets['referentiel'], $infos_projets['num_nom'] );
                        }
                }
                return $retour;
        }

        /**
         * Consulte un webservice pour obtenir des informations sur le taxon dont le
         * numéro nomenclatural est $num_nom (ce sont donc plutôt des infos sur le nom
         * et non le taxon?)
         * @param string|int $num_nom
         * @return array
         */
        protected function chargerInfosTaxon( $referentiel, $num_nom ) {
                $url_service_infos = sprintf( $this->config['chemins']['infosTaxonUrl'], $referentiel, $num_nom );
                $infos = json_decode( file_get_contents( $url_service_infos ) );
                // trop de champs injectés dans les infos espèces peuvent
                // faire planter javascript
                $champs_a_garder = array( 'id', 'nom_sci','nom_sci_complet', 'nom_complet', 'famille','nom_retenu.id', 'nom_retenu_complet', 'num_taxonomique' );
                $resultat = array();
                $retour = array();
                if ( isset( $infos ) && !empty( $infos ) ) {
                        $infos = (array) $infos;
                        if ( isset( $infos['nom_sci'] ) && $infos['nom_sci'] !== '' ) {
                                $resultat = array_intersect_key( $infos, array_flip($champs_a_garder ) );
                                $resultat['retenu'] = ( $infos['id'] == $infos['nom_retenu.id'] ) ? 'true' : 'false';
                                $retour['espece_imposee'] = true;
                                $retour['nn_espece_defaut'] = $nnEspeceImposee;
                                $retour['nom_sci_espece_defaut'] = $resultat['nom_complet'];
                                $retour['infos_espece'] = $this->array2js( $resultat, true );
                        }
                }
                return $retour;
        }

        protected function getReferentielImpose() {
                $referentiel_impose = true;
                if (!empty($_GET['referentiel']) && $_GET['referentiel'] !== 'autre') {
                        $this->ns_referentiel = $_GET['referentiel'];
                } else if (isset($this->configProjet['referentiel'])) {
                        $this->ns_referentiel = $this->configProjet['referentiel'];
                } else if (isset($this->configMission['referentiel'])) {
                        $this->ns_referentiel = $this->configMission['referentiel'];
                } else {
                        $referentiel_impose = false;
                }
                return $referentiel_impose;
        }

        /**
         * Trie par nom français les taxons lus dans le fichier tsv
         */
        protected function recupererListeNomsSci() {
                $taxons = $this->recupererListeTaxon();
                if (is_array($taxons)) {
                        $taxons = self::trierTableauMd($taxons, array('nom_fr' => SORT_ASC));
                }
                return $taxons;
        }

        /**
         * @TODO documenter
         * @return array
         */
        protected function recupererListeNoms() {
                $taxons = $this->recupererListeTaxon();
                $nomsAAfficher = array();
                $nomsSpeciaux = array();
                if (is_array($taxons)) {
                        foreach ($taxons as $taxon) {
                                $nomSciTitle = $taxon['nom_ret'].
                                ($taxon['nom_fr'] != '' ? ' - '.$taxon['nom_fr'] : '' ).
                                ($taxon['nom_fr_autre'] != '' ? ' - '.$taxon['nom_fr_autre'] : '' );
                                $nomFrTitle = $taxon['nom_sel'].
                                ($taxon['nom_ret'] != $taxon['nom_sel']? ' - '.$taxon['nom_ret'] : '' ).
                                ($taxon['nom_fr_autre'] != '' ? ' - '.$taxon['nom_fr_autre'] : '' );

                                if ($taxon['groupe'] == 'special') {
                                        $nomsSpeciaux[] = array(
                                                        'num_nom' => $taxon['num_nom_sel'],
                                                        'nom_a_afficher' => $taxon['nom_fr'],
                                                        'nom_a_sauver' => $taxon['nom_sel'],
                                                        'nom_title' => $nomSciTitle,
                                                        'nom_type' => 'nom-special');
                                } else {
                                        $nomsAAfficher[] = array(
                                                        'num_nom' => $taxon['num_nom_sel'],
                                                        'nom_a_afficher' => $taxon['nom_sel'],
                                                        'nom_a_sauver' => $taxon['nom_sel'],
                                                        'nom_title' => $nomSciTitle,
                                                        'nom_type' => 'nom-sci');
                                        $nomsAAfficher[] = array(
                                                        'num_nom' => $taxon['num_nom_sel'],
                                                        'nom_a_afficher' => $taxon['nom_fr'],
                                                        'nom_a_sauver' => $taxon['nom_fr'],
                                                        'nom_title' => $nomFrTitle,
                                                        'nom_type' => 'nom-fr');
                                }
                        }
                        $nomsAAfficher = self::trierTableauMd($nomsAAfficher, array('nom_a_afficher' => SORT_ASC));
                        $nomsSpeciaux = self::trierTableauMd($nomsSpeciaux, array('nom_a_afficher' => SORT_ASC));
                }
                return array('speciaux' => $nomsSpeciaux, 'sci-et-fr' => $nomsAAfficher);
        }

        /**
         * Lit une liste de taxons depuis un fichier tsv fourni
         */
        protected function recupererListeTaxon() {
                $taxons = array();
                $fichier_tsv = dirname(__FILE__) . self::DS . 'configurations' . self::DS . 'lichens_taxons.tsv';

                if ( file_exists( $fichier_tsv ) && is_readable( $fichier_tsv ) ) {
                        $taxons = $this->decomposerFichierTsv( $fichier_tsv );
                } else {
                        $this->debug[] = "Impossible d'ouvrir le fichier '$fichier_tsv'.";
                }
                return $taxons;
        }

        /**
         * Découpe un fihcier csv
         */
        protected function decomposerFichierTsv($fichier, $delimiter = "\t"){
                $header = null;
                $data = array();
                if (($handle = fopen($fichier, "r")) !== FALSE) {
                        while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE) {
                                if (!$header) {
                                        $header = $row;
                                } else {
                                        $data[] = array_combine($header, $row);
                                }
                        }
                        fclose($handle);
                }
                return $data;
        }

        /**
         * Convertit un tableau PHP en Javascript - @WTF pourquoi ne pas faire un json_encode ?
         * @param array $array
         * @param boolean $show_keys
         * @return une portion de JSON représentant le tableau
         */
        protected function array2js($array,$show_keys) {
                $tableauJs = '{}';
                if (!empty($array)) {
                        $total = count($array) - 1;
                        $i = 0;
                        $dimensions = array();
                        foreach ($array as $key => $value) {
                                if (is_array($value)) {
                                        $dimensions[$i] = array2js($value,$show_keys);
                                        if ($show_keys) {
                                                $dimensions[$i] = '\"'.$key.'\":'.$dimensions[$i];
                                        }
                                } else {
                                        $dimensions[$i] = '\"'.addslashes($value).'\"';
                                        if ($show_keys) {
                                                $dimensions[$i] = '\"'.$key.'\":'.$dimensions[$i];
                                        }
                                }
                                if ($i == 0) {
                                        $dimensions[$i] = '{'.$dimensions[$i];
                                }
                                if ($i == $total) {
                                        $dimensions[$i].= '}';
                                }
                                $i++;
                        }
                        $tableauJs = implode(',', $dimensions);
                }
                return $tableauJs;
        }

        private function remove_accents($string) {
            if ( !preg_match('/[\x80-\xff]/', $string) ) {
                return $string;
            }

        $chars = array(
            // Decompositions for Latin-1 Supplement
            chr(195).chr(128) => 'A', chr(195).chr(129) => 'A',
            chr(195).chr(130) => 'A', chr(195).chr(131) => 'A',
            chr(195).chr(132) => 'A', chr(195).chr(133) => 'A',
            chr(195).chr(135) => 'C', chr(195).chr(136) => 'E',
            chr(195).chr(137) => 'E', chr(195).chr(138) => 'E',
            chr(195).chr(139) => 'E', chr(195).chr(140) => 'I',
            chr(195).chr(141) => 'I', chr(195).chr(142) => 'I',
            chr(195).chr(143) => 'I', chr(195).chr(145) => 'N',
            chr(195).chr(146) => 'O', chr(195).chr(147) => 'O',
            chr(195).chr(148) => 'O', chr(195).chr(149) => 'O',
            chr(195).chr(150) => 'O', chr(195).chr(153) => 'U',
            chr(195).chr(154) => 'U', chr(195).chr(155) => 'U',
            chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y',
            chr(195).chr(159) => 's', chr(195).chr(160) => 'a',
            chr(195).chr(161) => 'a', chr(195).chr(162) => 'a',
            chr(195).chr(163) => 'a', chr(195).chr(164) => 'a',
            chr(195).chr(165) => 'a', chr(195).chr(167) => 'c',
            chr(195).chr(168) => 'e', chr(195).chr(169) => 'e',
            chr(195).chr(170) => 'e', chr(195).chr(171) => 'e',
            chr(195).chr(172) => 'i', chr(195).chr(173) => 'i',
            chr(195).chr(174) => 'i', chr(195).chr(175) => 'i',
            chr(195).chr(177) => 'n', chr(195).chr(178) => 'o',
            chr(195).chr(179) => 'o', chr(195).chr(180) => 'o',
            chr(195).chr(181) => 'o', chr(195).chr(182) => 'o',
            chr(195).chr(182) => 'o', chr(195).chr(185) => 'u',
            chr(195).chr(186) => 'u', chr(195).chr(187) => 'u',
            chr(195).chr(188) => 'u', chr(195).chr(189) => 'y',
            chr(195).chr(191) => 'y',
            // Decompositions for Latin Extended-A
            chr(196).chr(128) => 'A', chr(196).chr(129) => 'a',
            chr(196).chr(130) => 'A', chr(196).chr(131) => 'a',
            chr(196).chr(132) => 'A', chr(196).chr(133) => 'a',
            chr(196).chr(134) => 'C', chr(196).chr(135) => 'c',
            chr(196).chr(136) => 'C', chr(196).chr(137) => 'c',
            chr(196).chr(138) => 'C', chr(196).chr(139) => 'c',
            chr(196).chr(140) => 'C', chr(196).chr(141) => 'c',
            chr(196).chr(142) => 'D', chr(196).chr(143) => 'd',
            chr(196).chr(144) => 'D', chr(196).chr(145) => 'd',
            chr(196).chr(146) => 'E', chr(196).chr(147) => 'e',
            chr(196).chr(148) => 'E', chr(196).chr(149) => 'e',
            chr(196).chr(150) => 'E', chr(196).chr(151) => 'e',
            chr(196).chr(152) => 'E', chr(196).chr(153) => 'e',
            chr(196).chr(154) => 'E', chr(196).chr(155) => 'e',
            chr(196).chr(156) => 'G', chr(196).chr(157) => 'g',
            chr(196).chr(158) => 'G', chr(196).chr(159) => 'g',
            chr(196).chr(160) => 'G', chr(196).chr(161) => 'g',
            chr(196).chr(162) => 'G', chr(196).chr(163) => 'g',
            chr(196).chr(164) => 'H', chr(196).chr(165) => 'h',
            chr(196).chr(166) => 'H', chr(196).chr(167) => 'h',
            chr(196).chr(168) => 'I', chr(196).chr(169) => 'i',
            chr(196).chr(170) => 'I', chr(196).chr(171) => 'i',
            chr(196).chr(172) => 'I', chr(196).chr(173) => 'i',
            chr(196).chr(174) => 'I', chr(196).chr(175) => 'i',
            chr(196).chr(176) => 'I', chr(196).chr(177) => 'i',
            chr(196).chr(178) => 'IJ', chr(196).chr(179) => 'ij',
            chr(196).chr(180) => 'J', chr(196).chr(181) => 'j',
            chr(196).chr(182) => 'K', chr(196).chr(183) => 'k',
            chr(196).chr(184) => 'k', chr(196).chr(185) => 'L',
            chr(196).chr(186) => 'l', chr(196).chr(187) => 'L',
            chr(196).chr(188) => 'l', chr(196).chr(189) => 'L',
            chr(196).chr(190) => 'l', chr(196).chr(191) => 'L',
            chr(197).chr(128) => 'l', chr(197).chr(129) => 'L',
            chr(197).chr(130) => 'l', chr(197).chr(131) => 'N',
            chr(197).chr(132) => 'n', chr(197).chr(133) => 'N',
            chr(197).chr(134) => 'n', chr(197).chr(135) => 'N',
            chr(197).chr(136) => 'n', chr(197).chr(137) => 'N',
            chr(197).chr(138) => 'n', chr(197).chr(139) => 'N',
            chr(197).chr(140) => 'O', chr(197).chr(141) => 'o',
            chr(197).chr(142) => 'O', chr(197).chr(143) => 'o',
            chr(197).chr(144) => 'O', chr(197).chr(145) => 'o',
            chr(197).chr(146) => 'OE', chr(197).chr(147) => 'oe',
            chr(197).chr(148) => 'R', chr(197).chr(149) => 'r',
            chr(197).chr(150) => 'R', chr(197).chr(151) => 'r',
            chr(197).chr(152) => 'R', chr(197).chr(153) => 'r',
            chr(197).chr(154) => 'S', chr(197).chr(155) => 's',
            chr(197).chr(156) => 'S', chr(197).chr(157) => 's',
            chr(197).chr(158) => 'S', chr(197).chr(159) => 's',
            chr(197).chr(160) => 'S', chr(197).chr(161) => 's',
            chr(197).chr(162) => 'T', chr(197).chr(163) => 't',
            chr(197).chr(164) => 'T', chr(197).chr(165) => 't',
            chr(197).chr(166) => 'T', chr(197).chr(167) => 't',
            chr(197).chr(168) => 'U', chr(197).chr(169) => 'u',
            chr(197).chr(170) => 'U', chr(197).chr(171) => 'u',
            chr(197).chr(172) => 'U', chr(197).chr(173) => 'u',
            chr(197).chr(174) => 'U', chr(197).chr(175) => 'u',
            chr(197).chr(176) => 'U', chr(197).chr(177) => 'u',
            chr(197).chr(178) => 'U', chr(197).chr(179) => 'u',
            chr(197).chr(180) => 'W', chr(197).chr(181) => 'w',
            chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y',
            chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z',
            chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z',
            chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z',
            chr(197).chr(190) => 'z', chr(197).chr(191) => 's'
        );

        $string = strtr($string, $chars);

        return $string;
        }

}
?>