Subversion Repositories eFlore/Applications.cel

Rev

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

<?php

class MigrationImages extends Cel {
        
        public static $bdd_cel_migration;
        public static $bdd_utilisateurs;
        
        const truncate = true; //Doit on vider les tables de destination ?
        
        const separateur_champs_metadonnees = ';';
        const separateur_valeurs_metadonnees = ':';
        
        private $id_cle_metadonnees = array();
        
        /** Tableau associatif permettant de stocker l'avancement dans une boucle.
        * La clé est un md5 du message à afficher au démarrage de la boucle.
        * @var array
        */
        private static $avancement = array();
        
        const dry_run = false;
        
        private $tableau_utilisateurs = array();
        private $tableau_observations = array();
        private $tableau_mots_cles = array();
        
        private $tableau_nouveau_ancien = array(        
                'id_image' => 'ci_id_image',
                'ordre' =>'ci_ordre',
                'ce_utilisateur' => 'traiterIdentifiantUtilisateur',
                'prenom_utilisateur' => 'traiterPrenomUtilisateur',
                'nom_utilisateur' => 'traiterNomUtilisateur',
                'courriel_utilisateur' => 'ci_ce_utilisateur',
                'hauteur' => 'ci_meta_height',
                'largeur' => 'ci_meta_width',
                'appareil_fabriquant' => 'ci_meta_make',
                'appareil_modele' => 'ci_meta_model',
                'date_prise_de_vue' => 'ci_meta_date_time',
                'note_qualite' => 'ci_note_image',
                'mots_cles_texte' => 'traiterMotsClesTexte',
                'commentaire' => 'ci_meta_comment',
                'nom_original' => 'ci_nom_original',
                'md5' => 'ci_md5',
                'meta_exif' => 'traiterExif',
                'meta_iptc' => 'traiterIptc',
                'meta_xmp' => 'traiterXmp',
                'meta_makernote' => 'traiterMakernote',
                'date_modification' => 'ci_meta_date',
                'date_creation' => 'ci_meta_date_ajout'
        );
        
        private $champs_exifs_non_gardes = array(
                'ci_meta_x_resolution',
                'ci_meta_y_resolution',
                'ci_meta_gps',
                'ci_meta_user_comment',
                'ci_meta_exif_exposure_time',
                'ci_meta_exif_f_number',
                'ci_meta_exif_exif_version',
                'ci_meta_exif_compressed_bits_per_pixel',
                'ci_meta_exif_shutter_speed_value',
                'ci_meta_exif_aperture_value',
                'ci_meta_exif_exposure_bias_value',
                'ci_meta_exif_max_aperture_value',
                'ci_meta_exif_metering_mode',
                'ci_meta_exif_light_source',
                'ci_meta_exif_flash',
                'ci_meta_exif_focal_length',
                'ci_meta_exif_flash_pix_version',
                'ci_meta_exif_color_space',
                'ci_meta_exif_interoperability_offset',
                'ci_meta_exif_focal_plane_x_resolution',
                'ci_meta_exif_focal_plane_y_resolution',
                'ci_meta_exif_focal_plane_resolution_unit',
                'ci_meta_exif_sensing_method',
                'ci_meta_exif_file_source',
                'ci_meta_exif_custom_rendered',
                'ci_meta_exif_exposure_mode',
                'ci_meta_exif_white_balance',
                'ci_meta_exif_digital_zoom_ratio',
                'ci_meta_exif_scene_capture_type',
                'ci_meta_exif_gain_control',
                'ci_meta_exif_contrast',
                'ci_meta_exif_saturation',
                'ci_meta_exif_sharpness',
                'ci_meta_exif_subject_distance_range'
        );
        
        private $champs_iptc_non_gardes = array(
                'ci_meta_iptc_category',
                'ci_meta_iptc_by_line',
                'ci_meta_iptc_by_line_title',
                'ci_meta_iptc_city',
                'ci_meta_iptc_sub_location',
                'ci_meta_iptc_province_state',
                'ci_meta_iptc_country_primary_location_code',
                'ci_meta_iptc_country_name',
                'ci_meta_iptc_headline',
                'ci_meta_iptc_credit',
                'ci_meta_iptc_copyright_notice',
                'ci_meta_iptc_contact'
        );
        
        private $champs_divers_non_gardes = array(
                'ci_publiable_eflore',
                'ci_meta_mots_cles'
        );
        
        /**
        * Utiliser cette méthode dans une boucle pour afficher un message suivi du nombre de tour de boucle effectué.
        * Vous devrez vous même gérer le retour à la ligne à la sortie de la boucle.
        *
        * @param string le message d'information.
        * @param int le nombre de départ à afficher.
        * @return void le message est affiché dans la console.
        */
        protected function afficherAvancement($message, $depart = 0) {
                if (! isset(self::$avancement[$message])) {
                        self::$avancement[$message] = $depart;
                        echo "$message : ";
                                
                        $actuel =& self::$avancement[$message];
                        echo $actuel++;
                } else {
                        $actuel =& self::$avancement[$message];
                                
                        // Cas du passage de 99 (= 2 caractères) à 100 (= 3 caractères)
                        $passage = 0;
                        if (strlen((string) ($actuel - 1)) < strlen((string) ($actuel))) {
                        $passage = 1;
                }
                                
                        echo str_repeat(chr(8), (strlen((string) $actuel) - $passage));
                        echo $actuel++;
                }
        }
        
        /**
         * Méthode appelée avec une requête de type GET.
         */
        public function getElement($params) {
                
                if(!isset($this->config['database_cel']['database_migration']) || $this->config['database_cel']['database_migration'] == '') {
                        echo 'Attention la variable de configuration database_migration dans la section database_cel, contenant la base de données d\'arrivée, doit être remplie '."\n";
                        exit;
                }
                
                if(!isset($this->config['database_ident']['database']) || $this->config['database_ident']['database'] == '') {
                        echo 'Attention la variable de configuration database dans la section database_ident, contenant la base de données utilisateurs, doit être remplie '."\n";
                        exit;
                }
                
                self::$bdd_cel_migration = $this->config['database_cel']['database_migration'];
                self::$bdd_utilisateurs = $this->config['database_ident']['database'];
                
                $this->id_cle_metadonnees = array_merge($this->tableau_ids_tags_exif, $this->tableau_ids_tags_iptc);

                echo "--MIGRATION DES IMAGES --------------------------------------\n";
                //1. TEMPORAIRE : vider les tables de destinations
                if (self::truncate) {
                        echo "-------------------------------------------------------------------\n\n";
                        echo "  ETAPE 0. Vider les tables ... \n\n";
                        echo "-------------------------------------------------------------------\n\n";
                        $nouvellesTables = array('`cel_images`', '`cel_obs_images`');
                        foreach ($nouvellesTables as $nomTable) {
                                echo 'Vider la table '.$nomTable.'...';
                                $requeteTruncate = 'TRUNCATE TABLE '.self::$bdd_cel_migration.'.'.$nomTable;
                                $resultatTruncate = $this->executerRequete($requeteTruncate);
                                echo "ok \n";
                        }
                                
                        echo "\n---------------------------------------------------------------- OK\n\n";
                }
                
                echo "-------------------------------------------------------------------\n\n";
                echo "  ETAPE 1. Paramétrage ... \n\n";
                echo "-------------------------------------------------------------------\n\n";
                $this->getUtilisateurs();
                $this->getMotsCles();
                $this->getObservations();
                
                echo "-------------------------------------------------------------------\n\n";
                echo "  ETAPE 2. Migration des images ... \n\n";
                echo "-------------------------------------------------------------------\n\n";
                $this->migrerImages();
                echo "\n"."\n"."\n";
                
                echo "-------------------------------------------------------------------\n\n";
                echo "  ETAPE 3. migration des liaisons obs images ... \n\n";
                echo "-------------------------------------------------------------------\n\n";
                $this->migrerLiaisonsObsImages();
                echo "\n"."\n"."\n";
        }
        
        private function getUtilisateurs() {
                echo "\n-------------------------------------------------------------------\n";
                echo "--SELECTION DES UTILISATEURS---------------------------------------\n\n";
                
                $requete_selection_utilisateurs = 'SELECT U_ID as id, U_MAIL as mail, U_NAME as nom, U_SURNAME as prenom, U_PASSWD as pass FROM '.self::$bdd_utilisateurs.'.annuaire_tela';
                $tableau_utilisateurs = $this->executerRequete($requete_selection_utilisateurs);
                
                foreach( $tableau_utilisateurs as &$utilisateur) {
                        $this->tableau_utilisateurs[$utilisateur['mail']] = $utilisateur;
                }
                
                echo sizeof($this->tableau_utilisateurs)." utilisateurs sélectionnés";
                echo "\n-----------------------------------------------------------------OK\n";
        }
        
        private function getMotsCles() {
                echo "\n-------------------------------------------------------------------\n";
                echo "--SELECTION DES MOTS-CLES -----------------------------------------\n\n";
                
                $requete_selection_mots_cles = 'SELECT cmc_id_proprietaire as id_utilisateur, cmc_id_mot_cle_utilisateur as id_mot_cle, cmc_mot_cle as mot_cle FROM cel_mots_cles_obs';
                $tableau_mots_cles = $this->executerRequete($requete_selection_mots_cles);

                foreach( $tableau_mots_cles as &$mot_cle) {
                        $this->tableau_mots_cles[$mot_cle['id_utilisateur']][$mot_cle['id_mot_cle']] = $mot_cle;
                }
                
                echo sizeof($this->tableau_mots_cles)." mots-clés sélectionnés";
                echo "\n-----------------------------------------------------------------OK\n";
                
        }
        
        private function getObservations() {
                
                $pas = 5000;
                
                $nObs = "SELECT COUNT(*) AS nb FROM cel_inventory";
                $resultatNbObs = $this->executerRequete($nObs);
                $nbObs = $resultatNbObs[0]['nb'];
                
                for ($i = 0; $i < 230000; $i += $pas ) {
                        $requete_selection_observations = 'SELECT id, ordre, identifiant FROM cel_inventory LIMIT '.$i.", $pas";
                        $tableau_observations = $this->executerRequete($requete_selection_observations);
                        foreach($tableau_observations as &$obs) {
                                $this->tableau_observations[$obs['identifiant']][$obs['ordre']] = $obs['id'];
                        }
                        
                        $this->afficherAvancement('Selection des observations (par '.$pas.' )', $nbObs);
                }
                
                echo "\n\n";
        }
                
        public function executerRequeteSimple($requete) {
                // Fonction de commodité pour afficher les requetes au lieu de les executer
                if (self::dry_run) {
                        echo str_replace('),','),'."\n", $requete)."\n";        
                        return true;
                } else {
                        return parent::executerRequeteSimple($requete);
                }
        }
        
        private function migrerImages() {
                
                $debut = 0;
                $pas = 200; 
                $fin = 150000; 
                
                //Selectionner le nombre d'images
                $requeteNbImg = "SELECT COUNT(*) as nb FROM cel_images";
                $resultatNbImg = $this->executerRequete($requeteNbImg);
                $fin = $resultatNbImg[0]['nb'];
                
                for ($i = $debut; $i <= $fin ; $i += $pas) {
                        $requete_selection_images = 'SELECT * FROM cel_images '.
                                                                                        'ORDER BY ci_id_image ASC LIMIT '.$i.','.$pas;
                                                                                        
                        $images = @$this->requeter($requete_selection_images);  
                        
                        $requete_insertion_images = 'INSERT INTO '.self::$bdd_cel_migration.'.cel_images (';
                        foreach ($this->tableau_nouveau_ancien as $nouveau_champ => $ancien_champ) {
                                $requete_insertion_images .= $nouveau_champ.',';
                        }               
                        $requete_insertion_images = rtrim($requete_insertion_images, ',');
                        
                        $requete_insertion_images = $requete_insertion_images.') VALUES ';
                        
                        if (is_array($images)) { 
                                
                                $nb_images_a_traiter = count($images);
                                
                                foreach($images as $image) {
                                        
                                        $nouvelle_image = $this->traiterLigneImage($image);
                                        
                                        $nouvelle_image = array_map(array($this,'proteger'),$nouvelle_image);
                                        $requete_insertion_images .= '('.join(',',array_values($nouvelle_image)).'),';
                                }
                                
                                $requete_insertion_images = rtrim($requete_insertion_images, ',');
                                $migration_images = $this->executer($requete_insertion_images);
                                
                                if (!$migration_images) {
                                        echo 'la migration des images '.$i.' à '.($i+$nb_images_a_traiter).' a échoué '."\n";
                                } else {
                                        $this->afficherAvancement('Migration des images (par '.$pas.' )', $fin);
                                } 
                        }
                        
                        if(count($images) < $pas) {
                                echo "\n---------------------------------------------------------------- OK\n\n";
                                return;
                        }
                }
        }
        
        private function migrerLiaisonsObsImages() {
                $debut = 0;
                $pas = 500; 
                $fin = 50000; 
                
                $liaisons_obs_inexistantes = 0;
                
                //Selectionner le nombre de liaisons
                $requeteNbImgObs = "SELECT COUNT(*) as nb FROM cel_obs_images";
                $resultatNbImgObs = $this->executerRequete($requeteNbImgObs);
                $fin = $resultatNbImgObs[0]['nb'];
                
                for ($i = $debut; $i <= $fin ; $i += $pas) {
                        
                        if($i > $fin) {
                                $i = $fin;
                        }
                        
                        $requete_selection_liaisons = 'SELECT * FROM cel_obs_images LIMIT '.$i.','.$pas;
                        $tableau_liaisons = $this->executerRequete($requete_selection_liaisons);
                        
                        $requete_migration_liaison = 'INSERT INTO '.self::$bdd_cel_migration.'.cel_obs_images '.
                                                                                        '(id_image, id_utilisateur, id_observation, date_liaison) '.
                                                                                        'VALUES ';
                                                                                        
                        $sous_requete_insertion = '';
                        
                        if(is_array($tableau_liaisons)) {
                                foreach($tableau_liaisons as &$liaison) {
                                        
                                        $mail_utilisateur = $liaison['coi_ce_utilisateur'];
                                        $utilisateur = $this->renvoyerIdPourMigration($mail_utilisateur);
                                        
                                        $id_obs = $liaison['coi_ce_observation'];
                                
                                        if (isset($this->tableau_observations[$mail_utilisateur][$id_obs])) {
                                                $id_obs =  $this->tableau_observations[$mail_utilisateur][$id_obs];
                                                
                                                $sous_requete_insertion .= '('.$this->proteger($liaison['coi_ce_image']).','.
                                                        $this->proteger($utilisateur).','.
                                                        $this->proteger($id_obs).','.
                                                        $this->proteger($liaison['coi_date_liaison']).
                                                '),';
                                        } else {
                                                // cas d'une observation inexistante, la liaison est ignorée
                                                $liaisons_obs_inexistantes++;
                                        }
                                }
                                
                                $sous_requete_insertion = rtrim($sous_requete_insertion,',');
                                $requete_migration_liaison = $requete_migration_liaison.$sous_requete_insertion;
                                
                                $migration_liaison = $this->executerRequeteSimple($requete_migration_liaison);
                                
                                if (!$migration_liaison) {
                                        echo 'la migration des liaisons obs images de '.$i.' à '.($i+$pas).' a échoué ! '."\n<br />";
                                } else {
                                        $this->afficherAvancement('Migration des liaisons obs images (par '.$pas.' )', $fin);
                                } 
                        }
                }
                echo "\n\n";
                echo $liaisons_obs_inexistantes ? $liaisons_obs_inexistantes." liaisons image obs ont été ignorées car les obs sont absentes" : '' ;
                echo "\n";
                echo "\n---------------------------------------------------------------- OK\n\n";
        }
        
        private function traiterLigneImage($image) {
                
                $nouvelle_image = array();
                
                foreach ($this->tableau_nouveau_ancien as $nouveau_champ_image => $ancien_champ_image) { 
                        
                        if ($this->estUnChampATraiter($ancien_champ_image)) {
                                if (method_exists($this,$ancien_champ_image)) {
                                        $nouvelle_image[$nouveau_champ_image] = $this->$ancien_champ_image($image);
                                } else {
                                        echo 'methode manquante : '.$ancien_champ_image."\n";
                                        $nouvelle_image[$nouveau_champ_image] = '';
                                }

                        } else {
                                $nouvelle_image[$nouveau_champ_image] = $image[$ancien_champ_image];
                        }
                }
                
                return $nouvelle_image;
        }
        
        private function estUnChampATraiter($champ) {
                                
                return strpos($champ, 'traiter') !== false;
        }
        
        private function traiterMotsClesTexte($ligne_image) {
                
                $mail_image = $ligne_image['ci_ce_utilisateur'];
                $retour = $ligne_image['ci_meta_mots_cles'];
                
                if (isset($this->tableau_mots_cles[$mail_image])) {
                        
                        $mots_cles_tableau = $this->parserMotsCles($mail_image, $ligne_image['ci_meta_mots_cles'], ',');
                        $retour =  join(';',$mots_cles_tableau);
                        $retour = ltrim($retour,';;') ;
                }
                
                return $retour;
        } 
        
        private function parserMotsCles($utilisateur, $mot_cles, $separateur = ',') {
                
                $tableau_mots_cles = explode($separateur,$mot_cles);
                $tableau_mots_cles_formates = array();
                
                foreach($tableau_mots_cles as $mot_cle) {
                        
                        $mot_cle = str_replace($separateur.$separateur,'',$mot_cle);
                        $mot_cle = str_replace('null','',$mot_cle);
                        
                        if ($this->estUnIdentifiantMotCle($mot_cle)) {
                                
                                // certains mots clés mal formatés contiennent des virgules
                                if (strpos($mot_cle,',') !== false) {
                                        $tab_mot_cle_mal_formate = explode(',',$mot_cle);
                                        
                                        foreach ($tab_mot_cle_mal_formate as $mot_cle_mal_formate) {
                                                if ($this->estUnIdentifiantMotCle($mot_cle_mal_formate)) {
                                                        $tableau_mots_cles_formates[$mot_cle_mal_formate] = $this->tableau_mots_cles[$utilisateur][$mot_cle_mal_formate]['mot_cle'];
                                                }
                                        }       
                                } else {
                                        // on met le mot clé dans sa propre case afin d'éviter
                                        // facilement les doublons provoqués par de mauvais formatages 
                                        if(isset($this->tableau_mots_cles[$utilisateur][$mot_cle])) {
                                                $tableau_mots_cles_formates[$mot_cle] = $this->tableau_mots_cles[$utilisateur][$mot_cle]['mot_cle'];
                                        }
                                }

                        }
                }
                
                return $tableau_mots_cles_formates;
        }
        
        private function estUnIdentifiantMotCle($chaine) {
                return trim($chaine) != '' && preg_match('/[0-9A-Z]+\.[0-9A-Z]+/i', $chaine) ;
        }
        
        private function traiterIdentifiantUtilisateur($ligne_image) {
                
                $mail_image = $ligne_image['ci_ce_utilisateur'];
                $retour = $this->renvoyerIdPourMigration($mail_image);
                
                return $retour;
        }
        
        private function traiterPrenomUtilisateur($ligne_image) {
                
                $mail_image = $ligne_image['ci_ce_utilisateur'];
                $retour = $mail_image;
                
                if (isset($this->tableau_utilisateurs[$mail_image])) {
                        $retour =  $this->tableau_utilisateurs[$mail_image]['prenom'];
                } else {
                        $retour = '';
                }
                
                return $retour;
        }
        
        private function traiterNomUtilisateur($ligne_image) {
                
                $mail_image = $ligne_image['ci_ce_utilisateur'];
                $retour = $mail_image;
                
                if (isset($this->tableau_utilisateurs[$mail_image])) {
                        $retour =  $this->tableau_utilisateurs[$mail_image]['nom'];
                } else {
                        $retour = '';
                }
                
                return $retour;
        }
        
        private function decoderTableauMetaDonnees($chaine) {
                
                $tableau_valeurs_decodees = array();

                if (trim($chaine) != '') { 
                        $tableau_meta = explode(self::separateur_champs_metadonnees,$chaine);
                        foreach ($tableau_meta as &$chaine_meta) {
                                
                                $cle_valeur = explode(self::separateur_valeurs_metadonnees, $chaine_meta);
                                if (is_array($cle_valeur) && count($cle_valeur) == 2) {
                                        $cle = ltrim($cle_valeur[0],' ');
                                        $tableau_valeurs_decodees[$cle] = $cle_valeur[1];
                                }
                        }
                }
                
                return $tableau_valeurs_decodees;
        }
        
        private function convertirTableauMetadonneesEnXml($tableau) {
                
                $xml = '';
                
                foreach($tableau as $cle => $valeur) {

                        $cle = str_replace('ci_meta_exif_','',$cle);
                        $cle = str_replace('ci_meta_iptc_','',$cle);
                        $cle = str_replace('ci_meta_','',$cle);
                        $cle = str_replace('_',' ',$cle);
                        $cle = str_replace(' ','',ucwords($cle));
                        $valeur = str_replace("\0",'',$valeur);
                        $id = isset($this->id_cle_metadonnees[$cle]) ? $this->id_cle_metadonnees[$cle] : $cle;
                        $xml .= '<'.$cle.' id="'.$id.'">'.$valeur.'</'.$cle.'>'."\n";
                }
                
                return $xml;
        }
        
        private function peutUtiliserExifTool() {
                return file_exists('/usr/bin/exiftool') && is_executable('/usr/bin/exiftool');
        }
        
        private function decoderMetadonnees($chemin_image) {
                
                $res = '';
                
                if($this->peutUtiliserExifTool()) {
                        $res = $this->decoderMetadonneesExifTool($chemin_image);
                        
                        $xml_meta = '<?xml version="1.0" encoding="UTF-8" ?>';
                        $xml_meta .= '<exif>';
                        
                        foreach($res['EXIF'] as $prop => $valeur) {
                                $xml_meta .= '    <'.$prop.' id="'.$valeur['id'].'">'.$valeur['valeur'].'</'.$prop.'>'."\n";
                        }
                        $xml_meta .= '</exif>'."\n";
                        
                        $xml_meta .= '<iptc>';
                        foreach($res['IPTC'] as $prop => $valeur) {
                                $xml_meta .= '    <'.$prop.' id="'.$valeur['id'].'">'.$valeur['valeur'].'</'.$prop.'>'."\n";
                        }
                        $xml_meta .= '</iptc>'."\n";
                        
                        $xml_meta .= '<xmp>';
                        foreach($res['XMP'] as $prop => $valeur) {
                                $xml_meta .= '    <'.$prop.' id="'.$valeur['id'].'">'.$valeur['valeur'].'</'.$prop.'>'."\n";
                        }
                        $xml_meta .= '</xmp>'."\n";
                } else {
                        
                }
                
                return $xml_meta;
        }
        
        private function decoderMetadonneesExifTool($chemin_image) {
                $metadata = array();
                $res = exec('/usr/bin/exiftool -g -D '.$chemin_image, $metadata);       
                
                $metadata_decodees = array();
                
                $categorie = '';
                foreach($metadata as &$data) {
                        if($this->estUnSeparateurCategorieExifTool($data)) {
                                $categorie = trim(str_replace('----','',$data));
                        } else {
                                $data_decodee = $this->parserValeurMetadonneeExifTool($data);
                                $cle_metadonnee = str_replace(' ', '', $data_decodee['cle']);
                                $metadata_decodees[$categorie][$cle_metadonnee] = $data_decodee;
                                $this->id_cle_metadonnees[$cle_metadonnee] = $data_decodee['id'];
                        }
                }
                
                return $metadata_decodees;
        }
        
        private function estUnSeparateurCategorieExifTool($data) {
                return preg_match('^---- (.)* ----^',$data);    
        }
        
        private function parserValeurMetadonneeExifTool($data) {
                $cle_valeur = explode(':',$data);
                
                $valeur = '';
                if(count($cle_valeur) == 2) {
                        $valeur = trim($cle_valeur[1]);
                }
                
                $id_cle = explode(' ',trim($cle_valeur[0]),2);
                
                $id_cle[1] = str_replace(array('-','/'),'',$id_cle[1]);
                                
                $cle_id_valeur = array('cle' => $id_cle[1], 'id' => str_replace('-','',$id_cle[0]), 'valeur' => $valeur);
                return $cle_id_valeur;          
        }
        
        private function traiterExif($ligne_image) {

                $metadonnees_autres = $this->decoderTableauMetaDonnees($ligne_image['ci_meta_exif_autres']);
                $metadonnees = array_intersect_key($ligne_image, array_flip($this->champs_exifs_non_gardes))+$metadonnees_autres;
                
                $xml_meta = '<?xml version="1.0" encoding="UTF-8" ?>';
                $xml_meta .= '<exif>';
                $xml_meta .= $this->convertirTableauMetadonneesEnXml($metadonnees);
                $xml_meta .= '</exif>';
                
                return $xml_meta;
        }
        
        private function traiterIptc($ligne_image) {
                
                $metadonnees_autres = $this->decoderTableauMetaDonnees($ligne_image['ci_meta_iptc_autres']);
                $metadonnees = array_intersect_key($ligne_image, array_flip($this->champs_iptc_non_gardes))+$metadonnees_autres;
                
                $xml_meta = '<?xml version="1.0" encoding="UTF-8" ?>';
                $xml_meta .= '<iptc>';
                $xml_meta .= $this->convertirTableauMetadonneesEnXml($metadonnees);
                $xml_meta .= '</iptc>';
                
                return $xml_meta;
        }
        
        private function traiterXmp($ligne_image) {
                
                $chemin = $this->obtenirCheminImageOriginale($ligne_image['ci_id_image']);
                // TODO décommenté car pour le moment ça n'est pas necessaire, à éxécuter à part
                //$res = $this->decoderMetadonneesExifTool($chemin);
                $xml = '<?xml version="1.0" encoding="UTF-8" ?>';
                $xml .= '<xmp>';
                if (isset($res['XMP'])) {
                        foreach ($res['XMP'] as $prop => $valeur) {
                                $xml .= '    <'.$prop.' id="'.$valeur['id'].'">'.$valeur['valeur'].'</'.$prop.'>'."\n";
                        }
                }
                $xml .= '</xmp>';
                
                return $xml;
        }
        
        private function traiterMakernote($ligne_image) {
                
                $chemin = $this->obtenirCheminImageOriginale($ligne_image['ci_id_image']);
                //$res = $this->decoderMetadonneesExifTool($chemin);
                $xml = '<?xml version="1.0" encoding="UTF-8" ?>';
                $xml .= '<makernote>';
                if (isset($res['MAKERNOTE'])) {
                        foreach ($res['MAKERNOTE'] as $prop => $valeur) {
                                $xml .= '    <'.$prop.' id="'.$valeur['id'].'">'.$valeur['valeur'].'</'.$prop.'>'."\n";
                        }
                }
                $xml .= '</makernote>';
                
                return '';
        }
        
        public function obtenirCheminImageOriginale($id_image) {
                $nom = $this->convertirIdBddVersNomFichier($id_image, 'O');
                $dossier = $this->obtenirDossierPourFormat($id_image,'O');
                
                return $dossier.'/'.$nom;
        }
        
        public function convertirIdBddVersNomFichier($id, $format, $extension = 'jpg') {
                // creation du format original
                $id_avec_zeros = sprintf('%09s', $id) ;
                $id_avec_zeros_underscores = wordwrap($id_avec_zeros, 3 , '_', true) ;
                
                $nom_fichier = $id_avec_zeros_underscores.'_'.$format.'.'.$extension;
                
                return $nom_fichier;
        }
        
        public function obtenirDossierPourFormat($id, $format) {
                $chemin_base = $this->config['cel']['chemin_images'];
        
                $chemin_sur_serveur = $chemin_base;
        
                $id = sprintf('%09s', $id);
                $id = wordwrap($id, 3 , '_', true);
        
                list($dossierNiveau1, $dossierNiveau2) = explode('_', $id);
        
                $chemin_sur_serveur_final = $chemin_sur_serveur.'/'.$dossierNiveau1.'/'.$dossierNiveau2.'/'.$format;
                
                return $chemin_sur_serveur_final;
        }
        
        private function renvoyerIdPourMigration($utilisateur) {
                // si tout les test suivant échouent, on garde l'utilisateur tel quel
                // (cas de la chaine de session des utilisateur anonymes)
                $retour = $utilisateur;
                // si le mail correspond a un utilisateur de la bdd
                if (isset($this->tableau_utilisateurs[$utilisateur])) {
                        // on renvoie son id
                        $retour =  $this->tableau_utilisateurs[$utilisateur]['id'];
                } else {
                        // sinon si c'est un mail inconnu, on garde le md5
                        if($this->mailValide($utilisateur)) {
                                $retour = md5($utilisateur);
                        }
                }
        
                return $retour;
        }
        
        public function mailValide($mail) {
                // vérification bidon mais ça suffit pour ici
                return !(strpos('@',$mail) === false); 
        }
        
        private $tableau_ids_tags_exif = array('InteropIndex' => '1',
                'InteropVersion' => '2',
                'ProcessingSoftware' => '11',
                'SubfileType' => '254',
                'OldSubfileType' => '255',
                'ImageWidth' => '256',
                'ImageHeight' => '257',
                'BitsPerSample' => '258',
                'Compression' => '259',
                'PhotometricInterpretation' => '262',
                'Thresholding' => '263',
                'CellWidth' => '264',
                'CellLength' => '265',
                'FillOrder' => '266',
                'DocumentName' => '269',
                'ImageDescription' => '270',
                'Make' => '271',
                'Model' => '272',
                'StripOffsets' => '273',
                'Orientation' => '274',
                'SamplesPerPixel' => '277',
                'RowsPerStrip' => '278',
                'StripByteCounts' => '279',
                'MinSampleValue' => '280',
                'MaxSampleValue' => '281',
                'XResolution' => '282',
                'YResolution' => '283',
                'PlanarConfiguration' => '284',
                'PageName' => '285',
                'XPosition' => '286',
                'YPosition' => '287',
                'FreeOffsets' => '288',
                'FreeByteCounts' => '289',
                'GrayResponseUnit' => '290',
                'GrayResponseCurve' => '291',
                'T4Options' => '292',
                'T6Options' => '293',
                'ResolutionUnit' => '296',
                'PageNumber' => '297',
                'ColorResponseUnit' => '300',
                'TransferFunction' => '301',
                'Software' => '305',
                'ModifyDate' => '306',
                'Artist' => '315',
                'HostComputer' => '316',
                'Predictor' => '317',
                'WhitePoint' => '318',
                'PrimaryChromaticities' => '319',
                'ColorMap' => '320',
                'HalftoneHints' => '321',
                'TileWidth' => '322',
                'TileLength' => '323',
                'TileOffsets' => '324',
                'TileByteCounts' => '325',
                'BadFaxLines' => '326',
                'CleanFaxData' => '327',
                'ConsecutiveBadFaxLines' => '328',
                'SubIFD' => '330',
                'InkSet' => '332',
                'InkNames' => '333',
                'NumberofInks' => '334',
                'DotRange' => '336',
                'TargetPrinter' => '337',
                'ExtraSamples' => '338',
                'SampleFormat' => '339',
                'SMinSampleValue' => '340',
                'SMaxSampleValue' => '341',
                'TransferRange' => '342',
                'ClipPath' => '343',
                'XClipPathUnits' => '344',
                'YClipPathUnits' => '345',
                'Indexed' => '346',
                'JPEGTables' => '347',
                'OPIProxy' => '351',
                'GlobalParametersIFD' => '400',
                'ProfileType' => '401',
                'FaxProfile' => '402',
                'CodingMethods' => '403',
                'VersionYear' => '404',
                'ModeNumber' => '405',
                'Decode' => '433',
                'DefaultImageColor' => '434',
                'T82Options' => '435',
                'JPEGTables' => '437',
                'JPEGProc' => '512',
                'ThumbnailOffset' => '513',
                'ThumbnailLength' => '514',
                'JPEGRestartInterval' => '515',
                'JPEGLosslessPredictors' => '517',
                'JPEGPointTransforms' => '518',
                'JPEGQTables' => '519',
                'JPEGDCTables' => '520',
                'JPEGACTables' => '521',
                'YCbCrCoefficients' => '529',
                'YCbCrSubSampling' => '530',
                'YCbCrPositioning' => '531',
                'ReferenceBlackWhite' => '532',
                'StripRowCounts' => '559',
                'ApplicationNotes' => '700',
                'USPTOMiscellaneous' => '999',
                'RelatedImageFileFormat' => '4096',
                'RelatedImageWidth' => '4097',
                'RelatedImageHeight' => '4098',
                'Rating' => '18246',
                'XP_DIP_XML' => '18247',
                'StitchInfo' => '18248',
                'RatingPercent' => '18249',
                'ImageID' => '32781',
                'WangTag1' => '32931',
                'WangAnnotation' => '32932',
                'WangTag3' => '32933',
                'WangTag4' => '32934',
                'Matteing' => '32995',
                'DataType' => '32996',
                'ImageDepth' => '32997',
                'TileDepth' => '32998',
                'Model2' => '33405',
                'CFARepeatPatternDim' => '33421',
                'CFAPattern2' => '33422',
                'BatteryLevel' => '33423',
                'KodakIFD' => '33424',
                'Copyright' => '33432',
                'ExposureTime' => '33434',
                'FNumber' => '33437',
                'MDFileTag' => '33445',
                'MDScalePixel' => '33446',
                'MDColorTable' => '33447',
                'MDLabName' => '33448',
                'MDSampleInfo' => '33449',
                'MDPrepDate' => '33450',
                'MDPrepTime' => '33451',
                'MDFileUnits' => '33452',
                'PixelScale' => '33550',
                'AdventScale' => '33589',
                'AdventRevision' => '33590',
                'UIC1Tag' => '33628',
                'UIC2Tag' => '33629',
                'UIC3Tag' => '33630',
                'UIC4Tag' => '33631',
                'IPTC-NAA' => '33723',
                'IntergraphPacketData' => '33918',
                'IntergraphFlagRegisters' => '33919',
                'IntergraphMatrix' => '33920',
                'INGRReserved' => '33921',
                'ModelTiePoint' => '33922',
                'Site' => '34016',
                'ColorSequence' => '34017',
                'IT8Header' => '34018',
                'RasterPadding' => '34019',
                'BitsPerRunLength' => '34020',
                'BitsPerExtendedRunLength' => '34021',
                'ColorTable' => '34022',
                'ImageColorIndicator' => '34023',
                'BackgroundColorIndicator' => '34024',
                'ImageColorValue' => '34025',
                'BackgroundColorValue' => '34026',
                'PixelIntensityRange' => '34027',
                'TransparencyIndicator' => '34028',
                'ColorCharacterization' => '34029',
                'HCUsage' => '34030',
                'TrapIndicator' => '34031',
                'CMYKEquivalent' => '34032',
                'SEMInfo' => '34118',
                'AFCP_IPTC' => '34152',
                'PixelMagicJBIGOptions' => '34232',
                'ModelTransform' => '34264',
                'WB_GRGBLevels' => '34306',
                'LeafData' => '34310',
                'PhotoshopSettings' => '34377',
                'ExifOffset' => '34665',
                'ICC_Profile' => '34675',
                'TIFF_FXExtensions' => '34687',
                'MultiProfiles' => '34688',
                'SharedData' => '34689',
                'T88Options' => '34690',
                'ImageLayer' => '34732',
                'GeoTiffDirectory' => '34735',
                'GeoTiffDoubleParams' => '34736',
                'GeoTiffAsciiParams' => '34737',
                'ExposureProgram' => '34850',
                'SpectralSensitivity' => '34852',
                'GPSInfo' => '34853',
                'ISO' => '34855',
                'Opto-ElectricConvFactor' => '34856',
                'Interlace' => '34857',
                'TimeZoneOffset' => '34858',
                'SelfTimerMode' => '34859',
                'SensitivityType' => '34864',
                'StandardOutputSensitivity' => '34865',
                'RecommendedExposureIndex' => '34866',
                'ISOSpeed' => '34867',
                'ISOSpeedLatitudeyyy' => '34868',
                'ISOSpeedLatitudezzz' => '34869',
                'FaxRecvParams' => '34908',
                'FaxSubAddress' => '34909',
                'FaxRecvTime' => '34910',
                'LeafSubIFD' => '34954',
                'ExifVersion' => '36864',
                'DateTimeOriginal' => '36867',
                'CreateDate' => '36868',
                'ComponentsConfiguration' => '37121',
                'CompressedBitsPerPixel' => '37122',
                'ShutterSpeedValue' => '37377',
                'ApertureValue' => '37378',
                'BrightnessValue' => '37379',
                'ExposureCompensation' => '37380',
                'MaxApertureValue' => '37381',
                'SubjectDistance' => '37382',
                'MeteringMode' => '37383',
                'LightSource' => '37384',
                'Flash' => '37385',
                'FocalLength' => '37386',
                'FlashEnergy' => '37387',
                'SpatialFrequencyResponse' => '37388',
                'Noise' => '37389',
                'FocalPlaneXResolution' => '37390',
                'FocalPlaneYResolution' => '37391',
                'FocalPlaneResolutionUnit' => '37392',
                'ImageNumber' => '37393',
                'SecurityClassification' => '37394',
                'ImageHistory' => '37395',
                'SubjectArea' => '37396',
                'ExposureIndex' => '37397',
                'TIFF-EPStandardID' => '37398',
                'SensingMethod' => '37399',
                'CIP3DataFile' => '37434',
                'CIP3Sheet' => '37435',
                'CIP3Side' => '37436',
                'StoNits' => '37439',
                'MakerNoteCanon' => '37500',
                'UserComment' => '37510',
                'SubSecTime' => '37520',
                'SubSecTimeOriginal' => '37521',
                'SubSecTimeDigitized' => '37522',
                'MSDocumentText' => '37679',
                'MSPropertySetStorage' => '37680',
                'MSDocumentTextPosition' => '37681',
                'ImageSourceData' => '37724',
                'XPTitle' => '40091',
                'XPComment' => '40092',
                'XPAuthor' => '40093',
                'XPKeywords' => '40094',
                'XPSubject' => '40095',
                'FlashpixVersion' => '40960',
                'ColorSpace' => '40961',
                'ExifImageWidth' => '40962',
                'ExifImageHeight' => '40963',
                'RelatedSoundFile' => '40964',
                'InteropOffset' => '40965',
                'FlashEnergy' => '41483',
                'SpatialFrequencyResponse' => '41484',
                'Noise' => '41485',
                'FocalPlaneXResolution' => '41486',
                'FocalPlaneYResolution' => '41487',
                'FocalPlaneResolutionUnit' => '41488',
                'ImageNumber' => '41489',
                'SecurityClassification' => '41490',
                'ImageHistory' => '41491',
                'SubjectLocation' => '41492',
                'ExposureIndex' => '41493',
                'TIFF-EPStandardID' => '41494',
                'SensingMethod' => '41495',
                'FileSource' => '41728',
                'SceneType' => '41729',
                'CFAPattern' => '41730',
                'CustomRendered' => '41985',
                'ExposureMode' => '41986',
                'WhiteBalance' => '41987',
                'DigitalZoomRatio' => '41988',
                'FocalLengthIn35mmFormat' => '41989',
                'SceneCaptureType' => '41990',
                'GainControl' => '41991',
                'Contrast' => '41992',
                'Saturation' => '41993',
                'Sharpness' => '41994',
                'DeviceSettingDescription' => '41995',
                'SubjectDistanceRange' => '41996',
                'ImageUniqueID' => '42016',
                'OwnerName' => '42032',
                'SerialNumber' => '42033',
                'LensInfo' => '42034',
                'LensMake' => '42035',
                'LensModel' => '42036',
                'LensSerialNumber' => '42037',
                'GDALMetadata' => '42112',
                'GDALNoData' => '42113',
                'Gamma' => '42240',
                'ExpandSoftware' => '44992',
                'ExpandLens' => '44993',
                'ExpandFilm' => '44994',
                'ExpandFilterLens' => '44995',
                'ExpandScanner' => '44996',
                'ExpandFlashLamp' => '44997',
                'PixelFormat' => '48129',
                'Transformation' => '48130',
                'Uncompressed' => '48131',
                'ImageType' => '48132',
                'ImageWidth' => '48256',
                'ImageHeight' => '48257',
                'WidthResolution' => '48258',
                'HeightResolution' => '48259',
                'ImageOffset' => '48320',
                'ImageByteCount' => '48321',
                'AlphaOffset' => '48322',
                'AlphaByteCount' => '48323',
                'ImageDataDiscard' => '48324',
                'AlphaDataDiscard' => '48325',
                'OceScanjobDesc' => '50215',
                'OceApplicationSelector' => '50216',
                'OceIDNumber' => '50217',
                'OceImageLogic' => '50218',
                'Annotations' => '50255',
                'PrintIM' => '50341',
                'USPTOOriginalContentType' => '50560',
                'DNGVersion' => '50706',
                'DNGBackwardVersion' => '50707',
                'UniqueCameraModel' => '50708',
                'LocalizedCameraModel' => '50709',
                'CFAPlaneColor' => '50710',
                'CFALayout' => '50711',
                'LinearizationTable' => '50712',
                'BlackLevelRepeatDim' => '50713',
                'BlackLevel' => '50714',
                'BlackLevelDeltaH' => '50715',
                'BlackLevelDeltaV' => '50716',
                'WhiteLevel' => '50717',
                'DefaultScale' => '50718',
                'DefaultCropOrigin' => '50719',
                'DefaultCropSize' => '50720',
                'ColorMatrix1' => '50721',
                'ColorMatrix2' => '50722',
                'CameraCalibration1' => '50723',
                'CameraCalibration2' => '50724',
                'ReductionMatrix1' => '50725',
                'ReductionMatrix2' => '50726',
                'AnalogBalance' => '50727',
                'AsShotNeutral' => '50728',
                'AsShotWhiteXY' => '50729',
                'BaselineExposure' => '50730',
                'BaselineNoise' => '50731',
                'BaselineSharpness' => '50732',
                'BayerGreenSplit' => '50733',
                'LinearResponseLimit' => '50734',
                'CameraSerialNumber' => '50735',
                'DNGLensInfo' => '50736',
                'ChromaBlurRadius' => '50737',
                'AntiAliasStrength' => '50738',
                'ShadowScale' => '50739',
                'SR2Private' => '50740',
                'MakerNoteSafety' => '50741',
                'RawImageSegmentation' => '50752',
                'CalibrationIlluminant1' => '50778',
                'CalibrationIlluminant2' => '50779',
                'BestQualityScale' => '50780',
                'RawDataUniqueID' => '50781',
                'AliasLayerMetadata' => '50784',
                'OriginalRawFileName' => '50827',
                'OriginalRawFileData' => '50828',
                'ActiveArea' => '50829',
                'MaskedAreas' => '50830',
                'AsShotICCProfile' => '50831',
                'AsShotPreProfileMatrix' => '50832',
                'CurrentICCProfile' => '50833',
                'CurrentPreProfileMatrix' => '50834',
                'ColorimetricReference' => '50879',
                'PanasonicTitle' => '50898',
                'PanasonicTitle2' => '50899',
                'CameraCalibrationSig' => '50931',
                'ProfileCalibrationSig' => '50932',
                'ProfileIFD' => '50933',
                'AsShotProfileName' => '50934',
                'NoiseReductionApplied' => '50935',
                'ProfileName' => '50936',
                'ProfileHueSatMapDims' => '50937',
                'ProfileHueSatMapData1' => '50938',
                'ProfileHueSatMapData2' => '50939',
                'ProfileToneCurve' => '50940',
                'ProfileEmbedPolicy' => '50941',
                'ProfileCopyright' => '50942',
                'ForwardMatrix1' => '50964',
                'ForwardMatrix2' => '50965',
                'PreviewApplicationName' => '50966',
                'PreviewApplicationVersion' => '50967',
                'PreviewSettingsName' => '50968',
                'PreviewSettingsDigest' => '50969',
                'PreviewColorSpace' => '50970',
                'PreviewDateTime' => '50971',
                'RawImageDigest' => '50972',
                'OriginalRawFileDigest' => '50973',
                'SubTileBlockSize' => '50974',
                'RowInterleaveFactor' => '50975',
                'ProfileLookTableDims' => '50981',
                'ProfileLookTableData' => '50982',
                'OpcodeList1' => '51008',
                'OpcodeList2' => '51009',
                'OpcodeList3' => '51022',
                'NoiseProfile' => '51041',
                'Padding' => '59932',
                'OffsetSchema' => '59933',
                'OwnerName' => '65000',
                'SerialNumber' => '65001',
                'Lens' => '65002',
                'KDC_IFD' => '65024',
                'RawFile' => '65100',
                'Converter' => '65101',
                'WhiteBalance' => '65102',
                'Exposure' => '65105',
                'Shadows' => '65106',
                'Brightness' => '65107',
                'Contrast' => '65108',
                'Saturation' => '65109',
                'Sharpness' => '65110',
                'Smoothness' => '65111',
                'MoireFilter' => '65112',
        );
        
        private $tableau_ids_tags_iptc = array('ApplicationRecordVersion' => '0',
                'ObjectTypeReference' => '3',
                'ObjectAttributeReference' => '4',
                'ObjectName' => '5',
                'EditStatus' => '7',
                'EditorialUpdate' => '8',
                'Urgency' => '16',
                'SubjectReference' => '18',
                'Category' => '21',
                'SupplementalCategories' => '32',
                'FixtureIdentifier' => '34',
                'Keywords' => '37',
                'ContentLocationCode' => '38',
                'ContentLocationName' => '39',
                'ReleaseDate' => '48',
                'ReleaseTime' => '53',
                'ExpirationDate' => '55',
                'ExpirationTime' => '56',
                'SpecialInstructions' => '64',
                'ActionAdvised' => '66',
                'ReferenceService' => '69',
                'ReferenceDate' => '71',
                'ReferenceNumber' => '80',
                'DateCreated' => '85',
                'TimeCreated' => '96',
                'DigitalCreationDate' => '98',
                'DigitalCreationTime' => '99',
                'OriginatingProgram' => '101',
                'ProgramVersion' => '112',
                'ObjectCycle' => '117',
                'By-line' => '128',
                'By-lineTitle' => '133',
                'City' => '144',
                'Sub-location' => '146',
                'Province-State' => '149',
                'Country-PrimaryLocationCode' => '256',
                'Country-PrimaryLocationName' => '257',
                'OriginalTransmissionReference' => '259',
                'Headline' => '261',
                'Credit' => '272',
                'Source' => '277',
                'CopyrightNotice' => '278',
                'Contact' => '280',
                'Caption-Abstract' => '288',
                'LocalCaption' => '289',
                'Writer-Editor' => '290',
                'RasterizedCaption' => '293',
                'ImageType' => '304',
                'ImageOrientation' => '305',
                'LanguageIdentifier' => '309',
                'AudioType' => '336',
                'AudioSamplingRate' => '337',
                'AudioSamplingResolution' => '338',
                'AudioDuration' => '339',
                'AudioOutcue' => '340',
                'JobID' => '388',
                'MasterDocumentID' => '389',
                'ShortDocumentID' => '390',
                'UniqueDocumentID' => '391',
                'OwnerID' => '392',
                'ObjectPreviewFileFormat' => '512',
                'ObjectPreviewFileVersion' => '513',
                'ObjectPreviewData' => '514',
                'Prefs' => '545',
                'ClassifyState' => '549',
                'SimilarityIndex' => '552',
                'DocumentNotes' => '560',
                'DocumentHistory' => '561',
                'ExifCameraInfo' => '562',
                'CatalogSets' => '597',
        );
}