From 60b3b776868b4b3d08c46db1b0682db2b5c45529 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Carretero?=
 <frederic.carretero@veremes.com>
Date: Fri, 23 Nov 2018 08:58:54 +0100
Subject: [PATCH] =?UTF-8?q?Mise=20=C3=A0=20jour=20de=20gtf.engines?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 gtf.engine/gtf.engines/Traitement.class.inc   |  887 ++++++---
 gtf.engine/gtf.engines/engine.exe             |  Bin 75276 -> 75643 bytes
 gtf.engine/gtf.engines/engine.php             | 1661 ++++++++++-------
 gtf.engine/gtf.engines/engine.sql.inc         |    8 +-
 .../gtf.engines/lang_engines/fr-lang.inc      |    6 +-
 gtf.engine/gtf.engines/licenses/license.txt   |    7 -
 gtf.engine/gtf.engines/php_engine_conf.inc    |    4 +-
 gtf.engine/gtf.engines/string.inc             |   20 +
 gtf.engine/gtf.engines/subscription.php       |    4 +-
 9 files changed, 1673 insertions(+), 924 deletions(-)
 delete mode 100755 gtf.engine/gtf.engines/licenses/license.txt

diff --git a/gtf.engine/gtf.engines/Traitement.class.inc b/gtf.engine/gtf.engines/Traitement.class.inc
index f00fcf53..1d3c1717 100755
--- a/gtf.engine/gtf.engines/Traitement.class.inc
+++ b/gtf.engine/gtf.engines/Traitement.class.inc
@@ -16,7 +16,10 @@
 require_once ("vmlib/phpUtil.inc");
 require_once ("vmlib/logUtil.inc");
 require_once ("vmlib/stringUtil.inc");
+require_once ("vmlib/cryptUtil.inc");
 require_once ("gtf_lib/GtfFmwParser.class.inc");
+require_once ("vmlib/Email.class.inc");
+require_once ("gtf_lib/gtf_object/Order.class.inc");
 require_once 'string.inc';
 
 class Traitement {
@@ -82,6 +85,37 @@ class Traitement {
     var $sSource;
     var $sSourceTemp = "";
 
+    /**
+     * Paramètres de cryptage du résultat.
+     */
+    var $bDataEncrypt = false;
+    var $sSecretKey;
+    
+    /**
+    Pramaètre pour modifir la GTF_CONNECTION_STRING
+    */
+    var $bUseExternalDbConnection = false;
+    
+    /**
+     * Formatage des paramètres différent si le traitement est envoyé vers Fme Server.
+     */
+    var $bFmeServer = false;
+    
+    /**
+     * Nom de répertoire du résultat de la demande.
+     */
+    var $sResultDirectoryName = '';
+    
+    /**
+     * Chemin vers le répertoire du résultat de la demande.
+     */
+    var $sResultDirectoryPath = '';
+    
+    /**
+     * Tableau contenant la liste des fichiers de destination.
+     */
+    var $aDestinationFiles = array();
+
     /**
      * Cette méthode permet d'initialiser les variables.
      * \param $oBd Connexion à la base de données.
@@ -113,15 +147,6 @@ class Traitement {
      * \param $sFmwFileName Nom du fichier FMW associé à la demande.
      */
 
-    /**
-     * Cette méthode permet de générer un nom de fichier unique.
-     * \return une chaîne de caractères.
-     */
-    function UniqFileName() {
-        $sUniqFileName = date('YmdHis') . rand(1, 100000);
-        return $sUniqFileName;
-    }
-
     /**
      * Cette méthode permet de générer un tableau de paramètres à partir d'une chaîne dont les délimiteurs sont "|" et "=".
      * \param $sAllParams Chaine composé de tous les paramètres.
@@ -132,7 +157,7 @@ class Traitement {
         $aLigne = explode("|", $sAllParams);
         //$aLigne = stringExplode($sAllParams, "|", "\"", "\"");
         foreach ($aLigne as $sValeur) {
-            $aValeurs = explode("=", $sValeur);
+            $aValeurs = explode("=", $sValeur, 2);
             if ($aValeurs[1] == "") {
                 writeToLog(INFO_NULL_ELEMENT . $aValeurs[0] . ".", $this->sRobotLogFile);
             }
@@ -154,6 +179,8 @@ class Traitement {
         $sExeName = "FME";
         if (!$this->bErreur) {
             set_time_limit(0);
+            // Déclaration du tableau de résultat (IMPORTANT!).
+            $aResult = array();
             //$sResultCommande = exec('"'.$this->aProperties["fme_path"].'" APPLY_SETTINGS "Python/Python Interpreter"', $aResult, $iResult);
             $sResultCommande = exec('"' . $this->aProperties["fme_path"] . '" APPLY_SETTINGS "Python/Use Custom Python" false', $aResult, $iResult);
             //writeToLog(INFO_INFORM.$sExeName."| ".'"'.$this->aProperties["fme_path"].'" APPLY_SETTINGS "Python/Python Interpreter"', $this->sRobotLogFile);
@@ -168,7 +195,7 @@ class Traitement {
                 $aResultCommande = explode("|", $sResultCommande);
             }
             //Récupération d'une erreur.
-			if ($iResult !=0){
+            if ($iResult !=0){
             //if ($iResult || ($aResultCommande[0] != 0)) {
                 $this->bErreur = true;
                 if (sizeOf($aResultCommande) == 1)
@@ -184,17 +211,17 @@ class Traitement {
                 } else {
                     $this->sMessageErreur = "Erreur lors de l exécution de la commande. Consultez le log du robot.";
                 }
-				$bExistFMELogFile = true;
-				 if (file_exists($sFMELogFile) === false) {
-					$bExistFMELogFile = false;
-				}
+                $bExistFMELogFile = true;
+                 if (file_exists($sFMELogFile) === false) {
+                    $bExistFMELogFile = false;
+                }
                 foreach ($aResult as $sValeur) {
                     writeToLog(INFO_ERROR . "   " . "| " . $sValeur, $this->sRobotLogFile);
-					if ($bExistFMELogFile === false){
-						$monfichier = fopen($sFMELogFile, 'a');
-						fputs($monfichier, $sValeur. "\n");
-						fclose($monfichier);
-					}
+                    if ($bExistFMELogFile === false){
+                        $monfichier = fopen($sFMELogFile, 'a');
+                        fputs($monfichier, $sValeur. "\n");
+                        fclose($monfichier);
+                    }
                 }
                 writeToLog(INFO_COMMAND_ERROR . $sCommand . ".", $this->sRobotLogFile);
             } else {
@@ -218,7 +245,7 @@ class Traitement {
      */
     function zipFile($sZipDir, $sZipFileDir, $sZipUrl, $sZipFileName) {
         writeToLog(str_replace('[sZipDir]', $sZipDir, INFO_FILE_COMPRESSION), $this->sRobotLogFile);
-        if (createZip($sZipDir, $sZipFileDir . '/' . $sZipFileName . '.zip', 'log')) {
+        if (createZip($sZipDir, $sZipFileDir . '/' . $sZipFileName . '.zip', 'log', $this->sSecretKey, true)) {
             $sZipFile = $sZipUrl . "/" . $sZipFileName . ".zip";
             writeToLog(INFO_COMPRESSED_FILES . $sZipFile . ".", $this->sRobotLogFile);
         } else {
@@ -234,8 +261,11 @@ class Traitement {
     function unZipSource($sParam) {
         $this->sSource = $sParam;
         // Si la chaine contient un accent, la chaine sera en UTF-8, la fonction file_exists et la fonction de dézippage ne gèrent pas utf-8, il faut donc convertir la chaine en ISO-8859-1
-        if (mb_check_encoding($sParam, 'UTF-8'))
+        $bUtf8Param = false;
+        if (mb_check_encoding($sParam, 'UTF-8')) {
             $sParam = utf8_decode($sParam);
+            $bUtf8Param = true;
+        }
         // Si le fichier n'est pas trouvé alors il se trouve dans le répertoire upload
         if (!file_exists($sParam))
             $sParam = $this->aProperties["upload_dir"] . "/" . $sParam;
@@ -248,6 +278,9 @@ class Traitement {
             $sDir = $sParam;
             $this->sSourceTemp = "";
         }
+        // Si le paramètre passé était encodé en UTF-8 il faut le réencoder sinon problème avec les accents.
+        if ($bUtf8Param)
+            $sDir = utf8_encode($sDir);
         return $sDir;
     }
 
@@ -261,7 +294,9 @@ class Traitement {
             writeToLog(INFO_DECOMPRESSING_FILE . $sZipFile . ".", $this->sRobotLogFile);
             // Les backslashes du chemin de la variable d'environnement TEMP sont remplacés par des slashes
             $this->aProperties["extract_dir"] = str_replace("\\", "/", $this->aProperties["extract_dir"]);
-            $sExtractDir = $this->aProperties["extract_dir"] . "/" . $this->UniqFileName() . "/";
+            do {
+                $sExtractDir = $this->aProperties["extract_dir"] . "/" . getUniqRandomId() . "/";
+            }while(file_exists($sExtractDir));
             $this->sSourceTemp = $sExtractDir;
             if (unZip($sZipFile, $sExtractDir)) {
                 writeToLog(INFO_FILE_COMPRESSION_DIRECTORY . $sExtractDir . ".", $this->sRobotLogFile);
@@ -281,40 +316,51 @@ class Traitement {
      * $oGtfFmwParser : Objet GtfFmwParser contenant les GUI
      * $oGui : Objet GUI de la source
      * $sDirSource : Chaine de caractère contenant le chemin d'accés à la source de données
+     * \return Tableau des fichiers pour le paramètre "source".
      */
 
-    function updateSourceParam($oGui, $oGtfFmwParser, $sDirSource) {
-        $sdelimiterFichier = '""';
-        $sdelimiterParam = '""';
-        $sSourceMacro = $sdelimiterFichier;
+    function getSourceParam($oGui, $oGtfFmwParser, $sDirSource, $bUsePattern) {
+        $aSourceMacro = array();
         $i = 0;
-
+        $aSourceFiles = array();
         if (is_dir($sDirSource)) {
             $this->aExtension = $oGui->getExtensionArray($oGui->sFiltreSource);
             $iExtension = count($this->aExtension);
             if (($this->aExtension[0] == "*.*" and $oGui->sType == "FILE_OR_URL") or $oGui->sType == "DIRNAME_SRC" or $oGui->sType == "SOURCE_GEODATABASE") {
                 writeToLog(INFO_VALID_DATA_SOURCE_FILE_EXTENSION . $this->aExtension[0], $this->sRobotLogFile);
-                $sSourceMacro.= $sdelimiterParam . $sDirSource . '/**/' . $sdelimiterParam;
+                $aSourceFiles[] = $sDirSource . '/**/';
             } else {
-                foreach ($this->aExtension as $sExtension) {
-                    if ($sExtension != "*.*" or ( $sExtension == "*.*" and $iExtension == 1)) { // Si le filtre est différent de *.* (ex : *.mdb) ou si le filtre est seulement *.*. Si le filtre est multiple et que l'un d'eux est *.* (ex : *.*, *.mdb...), il ne sera pas pris en compte
-                        $aExtension = explode(".", $sExtension);
-                        if ($this->countFilesExtension($sDirSource, $aExtension[1]) > 0) {
-                            if ($i != 0)
-                                $sSourceMacro.= "<space>";
-                            writeToLog(INFO_VALID_DATA_SOURCE_FILE_EXTENSION . $sExtension, $this->sRobotLogFile);
-                            $sSourceMacro.= $sdelimiterParam . $sDirSource . '/**/' . $sExtension . $sdelimiterParam;
-                            $i++;
+                if ($bUsePattern){
+                        writeToLog(INFO_USE_PATTERN, $this->sRobotLogFile);
+                        foreach ($this->aExtension as $sExtension) {
+                                if ($sExtension != "*.*" or ( $sExtension == "*.*" and $iExtension == 1)) { // Si le filtre est différent de *.* (ex : *.mdb) ou si le filtre est seulement *.*. Si le filtre est multiple et que l'un d'eux est *.* (ex : *.*, *.mdb...), il ne sera pas pris en compte
+                                        $aExtension = explode(".", $sExtension);
+                                        if ($this->countFilesExtension($sDirSource, $aExtension[1]) > 0) {
+                                                writeToLog(INFO_VALID_DATA_SOURCE_FILE_EXTENSION . $sExtension, $this->sRobotLogFile);
+                                                $aSourceFiles[] = $sDirSource . '/**/' . $sExtension;
+                                                $i++;
+                                        }
+                                }
+                        }
+                }else{
+                        writeToLog(INFO_NO_USE_PATTERN, $this->sRobotLogFile);
+                        foreach ($this->aExtension as $sExtension) {
+                                if ($sExtension != "*.*" or ( $sExtension == "*.*" and $iExtension == 1)) { // Si le filtre est différent de *.* (ex : *.mdb) ou si le filtre est seulement *.*. Si le 
+                                        $aExtension = explode(".", $sExtension);
+                                        $aSourceMacroTmp = array_merge($aSourceMacro, $this->returnFileListToString($sDirSource, $aExtension[1]));
+                                        $aSourceMacro = array_unique($aSourceMacroTmp);
+                                        $i++;
+                                }
+                        }
+                        foreach ($aSourceMacro as $source) {
+                                $aSourceFiles[] = $source;
                         }
-                    }
                 }
             }
-        }else {
-            $sSourceMacro.= $sdelimiterParam . $sDirSource . $sdelimiterParam;
-        }
-        $sSourceMacro .= $sdelimiterFichier;
-        $this->aParametre[$oGui->sDefault_Macro] = $sSourceMacro;
-        return $sSourceMacro;
+        }else
+            $aSourceFiles[] = $sDirSource;
+        
+        return $aSourceFiles;
     }
 
     // Compte le nombre de fichier
@@ -324,7 +370,7 @@ class Traitement {
         $num = 0;
         if (!is_dir($sDirSource)) {
             $path_parts = pathinfo($sDirSource);
-            if (is_file($sDirSource) && strtoupper($path_parts['extension']) == strtoupper($sExtension))
+            if (is_file($sDirSource) && $path_parts['extension'] == $sExtension)
                 return 1;
             else
                 return false;
@@ -336,6 +382,26 @@ class Traitement {
         return $num;
     }
 
+    function returnFileListToString($sDirSource, $sExtension) {
+    $aFileList = array();
+    if (!is_dir($sDirSource)) {
+        $path_parts = pathinfo($sDirSource);
+        if (is_file($sDirSource) && strtolower($path_parts['extension']) == strtolower($sExtension)){
+            array_push($aFileList,$sDirSource);
+        }
+
+    }else{
+            foreach (scandir($sDirSource) AS $entry) {
+                    if (!in_array($entry, array('..', '.'))){
+                            $aFileListTmp = $aFileList;
+                            $aFileList = array_merge($aFileListTmp,$this->returnFileListToString($sDirSource . "/" . $entry, $sExtension));
+                    }
+
+            }
+        }
+        return $aFileList;
+    }
+
     /*
      * Fonction qui se charge de la mise à jour du paramètre "source" s'il existe
      * $oGtfFmwParser : Objet GtfFmwParser contenant les GUI
@@ -343,16 +409,15 @@ class Traitement {
      * $sDirSource : Chaine de caractère contenant le chemin d'accés à la source de données
      */
 
-    function updateDestParam($oGui, $oGtfFmwParser, $sNewDir, $sDest) {
+    function updateDestParam($oGui, $oGtfFmwParser, $sDest) {
         $this->aExtension = $oGui->getExtensionArray($oGui->sFiltreDest);
-        if ($sDest == "" && $oGui->sType != "DIRNAME") {
-            $sDest = $sNewDir;
-        }
+        if ($sDest == "" && $oGui->sType != "DIRNAME")
+            $sDest = $this->sResultDirectoryName;
         $this->aParametre[$oGui->sDefault_Macro] = "";
         $sDest = normalizeString($sDest);
         $aDest = explode(".", $sDest);
         if ($oGui->sType == "DIRNAME" or $oGui->sType == "DEST_GEODATABASE") {
-            $this->aParametre[$oGui->sDefault_Macro] = $this->aProperties["dir_export"] . "/gtf/" . $sNewDir . "/" . $sDest;
+            $this->aParametre[$oGui->sDefault_Macro] = $this->aProperties["dir_export"] . "/gtf/" . $this->sResultDirectoryName . "/" . $sDest;
             writeToLog(INFO_OUTPUT_DATA_DIRECTORY . $this->aParametre[$oGui->sDefault_Macro], $this->sRobotLogFile);
         }
         if ($oGui->sType == "FILENAME") {
@@ -361,7 +426,7 @@ class Traitement {
             } else {
                 $sResult = str_replace("*", $sDest, $this->aExtension[0]);
             }
-            $this->aParametre[$oGui->sDefault_Macro].= $this->aProperties["dir_export"] . "/gtf/" . $sNewDir . '/' . $sResult;
+            $this->aParametre[$oGui->sDefault_Macro].= $this->aProperties["dir_export"] . "/gtf/" . $this->sResultDirectoryName . '/' . $sResult;
             $this->sDestination = $sResult;
 
             writeToLog(INFO_OUTPUT_DATA_FILE . $this->aParametre[$oGui->sDefault_Macro], $this->sRobotLogFile);
@@ -419,7 +484,7 @@ class Traitement {
             }
         }
 
-        // on encode les balises UTF-8 		
+        // on encode les balises UTF-8      
 
         $offset = 0;
         $iPos = 0;
@@ -456,7 +521,7 @@ class Traitement {
             }
         }
 
-        // on decode les balises UTF-8 		
+        // on decode les balises UTF-8      
         $matches = array();
 
         preg_match_all("/<u[0-9a-fA-F]{4}>/", $sStr, $matches);
@@ -466,9 +531,6 @@ class Traitement {
             $cChr = $this->unichr($iCode);
             $sReplaced = str_replace($matches[0][$i], $cChr, $sReplaced);
         }
-		if (mb_detect_encoding($sReplaced, "UTF-8, ISO-8859-1") != "ISO-8859-1") {
-			$sReplaced = iconv("UTF-8", "ISO-8859-1", $sReplaced);
-		}
         return $sReplaced;
     }
 
@@ -484,7 +546,6 @@ class Traitement {
     function isEncode($sStr) {
         for ($i = 0; $i < count($this->aReplaceFME); $i++) {
             if (strpos($sStr, $this->aReplaceFME[$i]) === false && strpos($sStr, $this->aReplaceGTF[$i]) !== false) {
-                error_log($this->aReplaceFME[$i]);
                 return false;
             }
         }
@@ -499,89 +560,32 @@ class Traitement {
      *  $oGtfFmwParser : Objet GtfFmwParser contenant les GUI
      */
 
-    function getTclParams($oGtfFmwParser, $sNewDir) {
-        $aTGui = array();
+    function getTclParams($oGtfFmwParser) {
         $sChaine = "";
-        foreach ($oGtfFmwParser->aGuiObject as $aGui) {
-            if ($aGui->sDefault_Macro != "") {
-                array_push($aTGui, $aGui);
-            }
-        }
-        foreach ($aTGui as $oGui) {
-            //Teste si le paramètre est une source
-            if ($oGui->bIsSource) {
-                if ($this->aParametre[$oGui->sDefault_Macro] != "" && substr($this->aParametre[$oGui->sDefault_Macro], 0, 7) != "<quote>") {
-                    $sDirSource = $this->unZipSource($this->aParametre[$oGui->sDefault_Macro]);
-                    $this->updateSourceParam($oGui, $oGtfFmwParser, $sDirSource);
-                }
-            }
-            if ($oGui->bIsDest) {
-                $sDest = $this->aParametre[$oGui->sDefault_Macro];
-                $this->updateDestParam($oGui, $oGtfFmwParser, $sNewDir, $sDest);
-            }
-
-            if ($this->aParametre[$oGui->sDefault_Macro] != "") {
-
-                if (!$oGui->bIsSource) {
-                    // Protection des guillemets de chaque valeur pour qu'ils soient correctement envoyé à traitement.tcl
-                    // Cette protection s'effectue uniquement pour les paramètre qui ne sont pas sources (un paramètre source est de ce type : """"param1"" ""param2"" ""param3"""" : les guillemets seraient donc protégé et cela fait planter l'exécution)
-                    //$this->aParametre[$oGui->sDefault_Macro] = str_replace('"', '""', $this->aParametre[$oGui->sDefault_Macro]);
-                }
-                $aBaliseToReplace = array('<GTF_EQUAL>', '<GTF_PIPE>');
-                $aReplacedBalise = array('=', '|');
-                $sGTFOutput = str_replace($aBaliseToReplace, $aReplacedBalise, $this->aParametre[$oGui->sDefault_Macro]);
-                switch ($oGui->sType) {
-                    case "FLOAT":
-                        $sGTFOutput = str_replace(",", ".", $sGTFOutput);
-                        if (!$this->isDecode($sGTFOutput))
-                            $sGTFOutput = $this->decoderFME($sGTFOutput);
-                        break;
-                    case "LOOKUP_CHOICE":
-                        if (!$this->isEncode($sGTFOutput))
-                            $sGTFOutput = $this->encoderFME($sGTFOutput);
-                        break;
-                    case "TEXT_EDIT" :
-                    case "TEXT_EDIT_OR_NUM" :
-                        if (!$this->isEncode($sGTFOutput)) {
-                            //$sGTFOutput = $this->decoderFME($sGTFOutput);
-                            $sGTFOutput = $this->encoderFME($sGTFOutput);
-                        }
-                        break;
-                    case "CHOICE":
-                    case "LOOKUP_LISTBOX":
-                        $sGTFOutput = str_replace('"', '""', $sGTFOutput);
-                        if (!$this->isDecode($sGTFOutput))
-                            $sGTFOutput = $this->decoderFME($sGTFOutput);
-                        break;
-                    default :
-                        $sGTFOutput = str_replace('"', '""', $sGTFOutput);
-                        if (!$this->isDecode($sGTFOutput))
-                            $sGTFOutput = $this->decoderFME($sGTFOutput);
-                        break;
-                }
-
-                $sChaine .= " --" . $oGui->sDefault_Macro . " \"" . $sGTFOutput . "\"";
-            }
+        $aFmeParameters = $this->getFmeParameters($oGtfFmwParser);
+        foreach ($aFmeParameters as $sFmeParamKey => $sFmeParamValue) {
+            // Echappement des doubles quotes pour FME.
+            $sFmeParamValue = str_replace('"', '\"', $sFmeParamValue);
+            // Ajout du paramètre en ligne de commande.
+            $sChaine .= " --" . $sFmeParamKey . " \"" . $sFmeParamValue . "\"";
         }
-
         // $sChaine = substr($sChaine, 0, -1)."\"";
         //$sChaine = substr($sChaine, 0, -1);
-
         return $sChaine;
     }
 
-    function listDir($sDossier, $iDemandeId) {
-        $ouverture = @opendir($sDossier);
+    function listDir($iDemandeId) {
+        $ouverture = @opendir($this->sResultDirectoryPath);
         if (!$ouverture)
             return false;
         while ($sFichier = readdir($ouverture)) {
             if ($sFichier == '.' || $sFichier == '..')
                 continue;
-            if (is_dir($sDossier . $sFichier)) {
+            if (is_dir($this->sResultDirectoryPath . $sFichier)) {
                 closedir($ouverture);
                 return true;
             } else {
-                $path_parts = pathinfo($sDossier . $sFichier);
+                $path_parts = pathinfo($this->sResultDirectoryPath . $sFichier);
                 if ($sFichier != "fme_" . $iDemandeId . ".log") {
                     closedir($ouverture);
                     return true;
@@ -594,29 +598,27 @@ class Traitement {
 
     /*
      * Fonction qui retourne le nom du fichier résultat qui sera zippé.
-     *  $sDossier correspond au chemin complet dans lequel les fichiers/dossiers résultats seront générés
-     *  $sNewDir correspond au numéro unique du dossier dans lequel les fichiers/dossiers résultats seront générés
      *  $iDemandeId correspond au numéro de la demande
      * \return Retourne NULL (s'il y a plusieurs fichiers résultat à zipper) ou le fichier résultat qui sera zippé sous la forme 20140324141501876/ventes.xlsx
      */
 
-    function CheckResult($sDossier, $sNewDir, $iDemandeId) {
-        $ouverture = @opendir($sDossier);
+    function CheckResult($iDemandeId) {
+        $ouverture = @opendir($this->sResultDirectoryPath);
         $NbFile = 0;
         while ($sFichier = readdir($ouverture)) {
             if ($sFichier == '.' || $sFichier == '..')
                 continue;
-            if (is_dir($sDossier . $sFichier)) {
+            if (is_dir($this->sResultDirectoryPath . $sFichier)) {
                 $NbFile = $NbFile + 2;
             } else {
-                $path_parts = pathinfo($sDossier . $sFichier);
+                $path_parts = pathinfo($this->sResultDirectoryPath . $sFichier);
                 if ($sFichier != "fme_" . $iDemandeId . ".log") {
                     $NbFile = $NbFile + 1;
                 }
             }
         }
         closedir($ouverture);
-        $ouverture = @opendir($sDossier);
+        $ouverture = @opendir($this->sResultDirectoryPath);
         if ($NbFile != 1) {
             return "";
         } else {
@@ -625,8 +627,8 @@ class Traitement {
                 if ($sFichier == '.' || $sFichier == '..')
                     continue;
                 if ($sFichier != "fme_" . $iDemandeId . ".log") {
-                    if (preg_match($pattern, $sFichier)) {
-                        return $sNewDir . "/" . $sFichier;
+                    if (preg_match($pattern, $sFichier) && !$this->bDataEncrypt) {
+                        return $this->sResultDirectoryName . "/" . $sFichier;
                     } else {
                         return "";
                     }
@@ -643,131 +645,142 @@ class Traitement {
 
     function Process() {
         $oGtfFmwParser = new GtfFmwParser($this->aProperties["workspace_dir"] . "/" . $this->sFmwFileName);
-        // Création du répertoire de sortie des données
-        $sNewDir = $this->UniqFileName();
-		 if (!file_exists($this->aProperties["dir_export"] . "/gtf/")){
-			mkdir($this->aProperties["dir_export"] . "/gtf/");
-		}
-        $sDestDir = $this->aProperties["dir_export"] . "/gtf/" . $sNewDir;
-        mkdir($sDestDir);
-        // Création de l'URL de téléchargement des données
-        $sDestUrl = $this->aProperties["url_export"] . "/gtf/" . $sNewDir;
+        // Création du répertoire de résultat.
+        $this->sResultDirectoryName = $this->createResultDirectory();
 
         //1 Initialisation & calcul du chemin d'accés du fichier TCL
         $sCommandLine = '"' . $this->aProperties["fme_path"] . '" "' . getenv("GTF_HOME") . "/" . utf8_decode($this->sFmwFileName) . '"';
 
         //3 Ajout des paramètres propres au traitement
-        $sTclParams = $this->getTclParams($oGtfFmwParser, $sNewDir);
+        $sTclParams = $this->getTclParams($oGtfFmwParser);
         if ($sTclParams != "")
             $sCommandLine .= $sTclParams;
-        // Ajout de trois paramètres GTF_ORDER_ID, GTF_SHARED_DIR et GTF_CONNECTION_STRING qui seront passés à chaque demande de traitement
-        $sCommandLine .= " --GTF_ORDER_ID \"" . $this->iDemandeId . "\" --GTF_SHARED_DIR \"" . $this->aProperties["shared_dir"] . "\" --GTF_CONNECTION_STRING \"" . $this->aProperties["server"] . "," . $this->aProperties["port"] . "," . $this->aProperties["database"] . "," . $this->aProperties["login"] . "\" --GTF_REST_URL \"" . $this->aProperties["web_server_name"] . "/" . $this->aProperties["services_alias"] . "/\"" ;
+        $aTGui = array();
+        $sChaine = "";
+        
+        // Ajout des paramètres GTF_ s'ils sont associés à un paramètre publié du traitement
+        $aGtfParameters = $this->getGtfParameters($oGtfFmwParser);
+        foreach ($aGtfParameters as $sGtfParamKey => $sGtfParamValue) {
+            $sCommandLine .= ' --' . $sGtfParamKey . ' "' . $sGtfParamValue . '"';
+        }
         /*
          * 2 Passage des paramètres généraux
          * - FMWFILENAME : fichier Fmw
          * - LOG_ROBOT : fichier log du robot
          * - LOG_FILENAME : fichier log pour FME
          */
-        $sCommandLine.= " -LOG_FILENAME \"" . $sDestDir . "/fme_" . $this->iDemandeId . ".log\" 2>&1";
+        $sCommandLine.= " -LOG_FILENAME \"" . $this->getFmeLogFilePath($this->sResultDirectoryPath) . "\" 2>&1";
         writeToLog(INFO_GTF_HOME . getenv("GTF_HOME"), $this->sRobotLogFile);
         writeToLog(INFO_FME_PATH . getenv("FME_PATH"), $this->sRobotLogFile);
         writeToLog(INFO_TREATMENT_COMMAND_LINE . $sCommandLine, $this->sRobotLogFile);
 
         //4 Lancement de la ligne de commande
-        $this->sLogFme = $sNewDir . "/fme_" . $this->iDemandeId . ".log";
+        $this->sLogFme = $this->getFmeLogFilePath($this->sResultDirectoryName);
         $sSql = "UPDATE " . $this->aProperties['schema_gtf'] . ".order SET log_url='" . $this->sLogFme . "' WHERE order_id=" . $this->iDemandeId;
         $this->oBd->execute($sSql);
-        $this->execute($sCommandLine, $sDestDir . "/fme_" . $this->iDemandeId . ".log");
+        $this->execute($sCommandLine, $this->getFmeLogFilePath($this->sResultDirectoryPath));
         writeToLog(INFO_TREATMENT_COMMAND_LINE . $sCommandLine, $this->sRobotLogFile);
-        if (file_exists($sDestDir . "/fme_" . $this->iDemandeId . ".log") == false) {
+        if (file_exists($this->getFmeLogFilePath($this->sResultDirectoryPath)) == false) {
             $this->sLogFme = "";
         }
-        $bHasFile = $this->listDir($sDestDir, $this->iDemandeId);
-        if ($this->sSourceTemp != "" && $this->aProperties["debug_mode"] == false) {
-            clearDir($this->sSourceTemp);
-        }
-        if ($bHasFile) {
-            $sIsToZip = $this->CheckResult($sDestDir, $sNewDir, $this->iDemandeId);
-
-            if ($sIsToZip == "") {
-                //Compression en zip des fichiers résultant. Le parametres Array() permet de filtrer les extensions à compresser. Exemples : Array("shp","shx","dbf") ; Array("*")		
-                $sZipFile = $this->zipFile($sDestDir, $sDestDir, $sDestUrl, $this->iDemandeId);
-                $sZipFile = str_replace($sDestUrl, $sNewDir, $sZipFile);
-            } else {
-                $sZipFile = str_replace($sDestUrl, $sNewDir, $sIsToZip);
-            }
-        } else {
-            $sZipFile = "";
-        }
+        // Tous les fichiers de résultat dans une archive .zip.
+        $sZipFile = $this->zipResultFiles();
         return $sZipFile;
     }
     
     /**
-     * Get the log file of a job.
+     * Submit a job on Fme Server.
      * @param {object} $oFmeServer FmeServer class object.
      * @param {array} $aOrder Order parameters.
      * @param {array} $aWorkspace Workpace parameters.
      * @param {array} $aUser User infos.
+     * @param {object} $oAmazonS3 AmazonS3 class object.
+     * @param {boolean} $bAsync Asynchronous job.
+     * @return string
      */
-    function processFmeServerOrder($oFmeServer, $aOrder, $aWorkspace, $aUser, $oAmazonS3 = null) {
-        $sNewDir = $this->UniqFileName();
-        $oGtfFmwParser = new GtfFmwParser($this->aProperties["workspace_dir"] . "/" . $this->sFmwFileName);
+    function submitFmeServerJob($oFmeServer, $aOrder, $aWorkspace, $aUser, $oAmazonS3 = null, $bAsync = false) {
+        $this->oFmeServer = $oFmeServer;
+        $this->oAmazonS3 = $oAmazonS3;
+        // Création du répertoire de résultat.
+        $this->sResultDirectoryName = $this->createResultDirectory();
         // Fichiers sources en entrée et sortie.
+        $oGtfFmwParser = new GtfFmwParser($this->aProperties["workspace_dir"] . "/" . $this->sFmwFileName);
+        $aTGui = array();
         $aSourceFiles = array();
-        $aDestinationFiles = '';
+        $aDestinationFiles = array();
         foreach ($oGtfFmwParser->aGuiObject as $oGui) {
             if ($oGui->sDefault_Macro != "") {
+                array_push($aTGui, $oGui);
                 //Teste si le paramètre est une source
                 if ($oGui->bIsSource)
-                    $aSourceFiles[] = $oGui->sDefault_Macro;
+                    $aSourceFiles[$oGui->sDefault_Macro] = $this->aParametre[$oGui->sDefault_Macro];
                 else if ($oGui->bIsDest)
-                    $aDestinationFiles = $oGui->sDefault_Macro;
+                    $aDestinationFiles[] = $oGui->sDefault_Macro;
             }
         }
+        // Sauve la liste des fichiers de destination.
+        $this->aDestinationFiles = $aDestinationFiles;
         // Liste des paramètres publiés.
-        $aWkParams = explode('|', $aOrder['wk_params']);
-        $aPublishedParams = array();
-        foreach($aWkParams as $sWkParam) {
-            $aWkParam = explode('=', $sWkParam);
-            $aPublishedParams[$aWkParam[0]] = $aWkParam[1];
-        }
-        // Création d'un dépot pour l'utilisateur si inexistant.
-        $sRepository = $aUser["login"];
-        $oFmeServer->createRepository($sRepository, $aUser["name"]);
+        $aFmeParameters = $this->getFmeParameters($oGtfFmwParser);
+        // Ajout des paramètres GTF_ s'ils sont associés à un paramètre publié du traitement.
+        $aFmeParameters = array_merge($aFmeParameters, $this->getGtfParameters($oGtfFmwParser));
+        // Création d'un identifiant pour l'instance de GTF (si inexistant).
+        if (empty($this->aProperties["gtf_instance_id"]))
+            $this->aProperties["gtf_instance_id"] = generateGtfInstanceId();
+        // Création d'un dépot pour l'instance de GTF si inexistant.
+        $sRepository = $this->aProperties["gtf_instance_id"];
+        if ($oFmeServer->createRepository($sRepository, '') === false)
+            return false;
         // Création d'un répertoire dans les ressources si inexistant.
         $sResource = 'FME_SHAREDRESOURCE_TEMP';
-        $sPath = 'gtf';
-        $oFmeServer->createResourceConnectionDirectory($sResource, $sPath, $sNewDir);
-        $sPath .= '/' . $sNewDir;
-        // Upload des fichiers sources.
-        foreach($aSourceFiles as $sParamName) {
-            // Si un objet de la classe AmazonS3 est passé, les ressources seront envoyées sur S3 puis téléchargéss dans FME Server.
-            if (empty($oAmazonS3))
-                $oFmeServer->uploadResourceFile($this->aProperties['upload_dir'] . '/' . $aPublishedParams[$sParamName], $sResource, $sPath, true, true);
-            else {
-                // Upload d'un fichier source vers S3.
-                $sBucket = 'dev-gtf-fmecloud';
-                $sKey = $sPath . '/' . $aPublishedParams[$sParamName];
-                $oAmazonS3->uploadFile($sBucket, $sKey, $this->aProperties['upload_dir'] . '/' . $aPublishedParams[$sParamName]);
-                // Upload du fichier S3Downloader.fmw (si inexistant).
-                $oFmeServer->uploadWorkspaceFile('E:\_Docs\GTF moteur serveur\S3Downloader.fmw', $sRepository);
-                // Téléchargement depuis FME Server du fichier envoyé sur S3.
-                $aS3Params = array(
-                    'access_key_id' => $oAmazonS3->sAwsAccessKeyId,
-                    'secret_access_key' => $oAmazonS3->sAwsSecretAccessKey,
-                    'bucket_name' => $sBucket,
-                    'object_key' => $sKey
-                );
-                $oJobResult = $oFmeServer->uploadResourceFileFromS3($aS3Params, $sRepository, $sResource, $sPath);
+        $sPath = $this->aProperties["gtf_instance_id"];
+        if ($oFmeServer->createResourceConnectionDirectory($sResource, $sPath, $this->sResultDirectoryName) === false)
+            return false;
+        $sPath .= '/' . $this->sResultDirectoryName;
+        // Copie locale du fichier .fmw avec la version.
+        $sFmwFilePath = $this->aProperties["workspace_dir"] . "/" . $this->sFmwFileName;
+        $sRepositoryFmwFileName = pathinfo($this->sFmwFileName, PATHINFO_FILENAME) . '_v' . $aWorkspace['version'] . '.' . pathinfo($this->sFmwFileName, PATHINFO_EXTENSION);
+        $sRepositoryFmwFilePath = $this->aProperties["workspace_dir"] . "/" . pathinfo($this->sFmwFileName, PATHINFO_DIRNAME) . "/" . $sRepositoryFmwFileName;
+        if (!file_exists($sRepositoryFmwFilePath)) {
+            copy($sFmwFilePath, $sRepositoryFmwFilePath);
+            // Supprime le fichier de l'ancienne version du projet (GTF + Fme Server).
+            if ($aWorkspace['version'] > 0) {
+                $sRepositoryOldFmwFileName = pathinfo($this->sFmwFileName, PATHINFO_FILENAME) . '_v' . --$aWorkspace['version'] . '.' . pathinfo($this->sFmwFileName, PATHINFO_EXTENSION);
+                unlink($this->aProperties["workspace_dir"] . "/" . pathinfo($this->sFmwFileName, PATHINFO_DIRNAME) . "/" . $sRepositoryOldFmwFileName);
+                //$oFmeServer->serviceRequest('repositories/' . $sRepository . '/items/' . $sRepositoryOldFmwFileName, 'delete');
             }
         }
         // Upload du fichier .fmw.
-        $sFmwFileName = $this->aProperties["workspace_dir"] . "/" .$this->sFmwFileName;
-        $oFmeServer->uploadWorkspaceFile($sFmwFileName, $sRepository, true);
+        if ($oFmeServer->uploadWorkspaceFile($sFmwFilePath, $sRepository, false, $sRepositoryFmwFileName) === false)
+            return false;
+        // Upload des fichiers sources.
+        foreach($aSourceFiles as $sParamName => $sParamValue) {
+            if ($this->uploadFileToResourceConnection($this->aProperties["upload_dir"] . "/" . $sParamValue, $sRepository, $sResource, $sPath) === false)
+                return false;
+            /*
+            // Upload de plusieurs fichiers sources (ex: contenu d'une archive .zip).
+            $aFiles = explode('|', $aFmeParameters[$sParamName]);
+            foreach ($aFiles as $sFilePath) {
+                if ($this->uploadFileToResourceConnection($sFilePath, $sRepository, $sResource, $sPath) === false)
+                    return false;
+            }
+            */
+        }
+        // Upload des ressources complémentaires du projet.
+        $sResourcesDirectory = $this->aProperties["workspace_dir"] . '/' . pathinfo($this->sFmwFileName, PATHINFO_DIRNAME);
+        if (is_dir($sResourcesDirectory)) {
+            foreach (scandir($sResourcesDirectory) as $sFileName) {
+                if (is_file($sResourcesDirectory . '/' . $sFileName) && array_search(pathinfo($sFileName, PATHINFO_EXTENSION), array('fmw', 'bak')) === false) {
+                    if ($oFmeServer->uploadWorkspaceResourceFile($sResourcesDirectory . '/' . $sFileName, $sRepository, $sRepositoryFmwFileName, false) === false)
+                        return false;
+                }
+            }
+        }
         // Paramètres publiés dans les données de la requête.
-        $aJobParams = array(
-            'publishedParameters' => array(),
-            'NMDirectives' => array(
+        $aJobParams = array('publishedParameters' => array());
+        // Traitement asynchrone.
+        if ($bAsync) {
+            $aJobParams['NMDirectives'] = array(
                 'successTopics' => array(
                     'TEST_TOPIC_FRED'
                 ),
@@ -778,38 +791,438 @@ class Traitement {
                     array('name' => 'order_id', 'value' => $this->iDemandeId)
                 )
                 //'subsection' => 'REST_SERVICE'
-            )
-        );
-        foreach ($aPublishedParams as $sParamName => $sParamValue) {
-            if (in_array($sParamName, $aSourceFiles))
-                $aJobParams['publishedParameters'][] = array("name" => $sParamName, "value" => array('$(' . $sResource . ')/' . $sPath . '/' . pathinfo($sParamValue, PATHINFO_BASENAME)));
+            );
+        }
+        // Chemins pour les paramètres publiés qui sont des fichiers.
+        foreach ($aFmeParameters as $sParamName => $sParamValue) {
+            if (array_key_exists($sParamName, $aSourceFiles)) {
+                $aFiles = explode('|', $sParamValue);
+                $aPublishedParametersFiles = array();
+                foreach ($aFiles as $sFilePath)
+                    $aPublishedParametersFiles[] = '$(' . $sResource . ')/' . $sPath . '/' . $sFilePath;
+                $aJobParams['publishedParameters'][] = array("name" => $sParamName, "value" => $aPublishedParametersFiles);
+            }
+            else if (in_array($sParamName, $aDestinationFiles))
+                $aJobParams['publishedParameters'][] = array("name" => $sParamName, "value" => '$(' . $sResource . ')/' . $sPath . '/' . $this->sResultDirectoryName . '.zip/' . pathinfo($sParamValue, PATHINFO_BASENAME));
             else
-                $aJobParams['publishedParameters'][] = array("name" => $sParamName, "value" => '$(' . $sResource . ')/' . $sPath . '/' . $sNewDir . '.zip/' . $sParamValue);
+                $aJobParams['publishedParameters'][] = array("name" => $sParamName, "value" => $sParamValue);
         }
         // Envoi d'une demande sur un traitement.
-        $this->oJobResult = $oFmeServer->submitJob($sRepository, $aWorkspace['fmw_file'], $aJobParams);
-        // Téléchargement du fichier de log du traitement.
+        $this->oJobResult = $oFmeServer->submitJob($sRepository, $sRepositoryFmwFileName, $aJobParams, $bAsync);
+        if ($this->oJobResult === false)
+            return false;
+        // Demande synchrone -> téléchargement des fichiers de log et de résultat du traitement.
+        if ($bAsync) {
+            $this->aJobDestinationFiles = $aDestinationFiles;
+            $this->sJobResource = $sResource;
+            $this->sJobPath = $sPath;
+        }
+        else {
+            $sZipFile = '';
+            if (!empty($this->oJobResult->id))
+                $sZipFile = $this->downloadFmeServerJobResult($this->oJobResult->id, $oFmeServer, $aDestinationFiles, $sResource, $sPath);
+            return $sZipFile;
+        }
+    }
+    
+    /**
+     * Init all the encryption parameters of the user.
+     */
+    function initUserEncryptionParameters() {
+        // Paramètres de cryptage de l'utilisateur.
+        $sSql = 'SELECT "order".user_id, workspace.workspace_id, "user".login, "user".dataencrypt AS user_dataencrypt, workspace.dataencrypt AS workspace_dataencrypt, "user".secretkey FROM [sSchemaGtf].order LEFT JOIN [sSchemaFramework].user ON "order".user_id = "user".user_id LEFT JOIN [sSchemaGtf].workspace ON "order".workspace_id = workspace.workspace_id WHERE order_id = [iDemandeId]';
+        $aParams = array();
+        $aParams['sSchemaFramework'] = array('value' => $this->aProperties["schema_framework"], 'type' => 'schema_name');
+        $aParams['sSchemaGtf'] = array('value' => $this->aProperties["schema_gtf"], 'type' => 'schema_name');
+        $aParams['iDemandeId'] = array('value' => $this->iDemandeId, 'type' => 'number');
+        $oPDOResult = $this->oBd->executeWithParams($sSql, $aParams);
+        if (!$this->oBd->enErreur()) {
+            $aUserEncryptParams = $this->oBd->ligneSuivante($oPDOResult);
+            if ($aUserEncryptParams['user_dataencrypt'] === true || $aUserEncryptParams['workspace_dataencrypt'] === true) {
+                // Le résultat de la demande sera crypté.
+                $this->bDataEncrypt = true;
+                // Clé secrète de l'utilisateur (sinon il faut la générer).
+                if ($aUserEncryptParams['user_dataencrypt'] === true && !empty($aUserEncryptParams['secretkey']))
+                    // Décryptage de la clé secrète (suppression des caractères "NULL").
+                    $this->sSecretKey = str_replace(chr(0), '', des($aUserEncryptParams['login'], hexToString($aUserEncryptParams['secretkey']), 0, 0));
+                else {
+                    // Génération de la clé secrète.
+                    $this->sSecretKey = getUniqRandomId();
+                    // Envoi du mail avec la clé secrète générée.
+                    $aObjects = array();
+                    $aObjects['oOrder'] = new OrderLib($this->oBd, $this->iDemandeId, $this->aProperties, "v_order");
+                    $aObjects['oOrder']->formatOrderEmail();
+                    $aObjects['oOrder']->sSecretKey = $this->sSecretKey;
+                    $oEmail = new Email($this->oBd, -1, $this->aProperties, $aObjects);
+                    if (!empty($oEmail->oEmailTemplate->name))
+                        $oEmail->send();
+                }
+            }
+        }
+        else
+            writeToLog(INFO_USER_ENCRYPT_PARAMETERS . "(SQL : $sSql)", $this->sRobotLogFile);
+    }
+    
+    /**
+     * Upload a file to a resource connection on Fme Server.
+     * @param {string} $sFilePath Path of the file to upload.
+     * @param {string} $sRepository Name of the repository.
+     * @param {string} $sResource Name of a resource connection.
+     * @param {string} $sPath Path, relative to the resource connection.
+     */
+    function uploadFileToResourceConnection($sFilePath, $sRepository, $sResource, $sPath) {
+        // Si un objet de la classe AmazonS3 existe, les ressources seront envoyées sur S3 puis téléchargéss dans FME Server.
+        if (empty($this->oAmazonS3)) {
+            if ($this->oFmeServer->uploadResourceFile($sFilePath, $sResource, $sPath, true, true) === false)
+                return false;
+        }
+        else {
+            // Upload d'un fichier source vers S3.
+            //$sS3Bucket = $this->aProperties['fme_cloud_s3_bucket'];
+            $sS3ObjectKey = $sPath . '/' . pathinfo($sFilePath, PATHINFO_BASENAME);
+            if ($this->oAmazonS3->uploadFile($this->sFmeServerS3Bucket, $sS3ObjectKey, $sFilePath) === false)
+                return false;
+            // Upload du fichier S3Downloader.fmw (si inexistant).
+            if ($this->oFmeServer->uploadWorkspaceFile($this->aProperties['workspace_dir'] . '/S3Downloader.fmw', $sRepository, false) === false)
+                return false;
+            // Téléchargement depuis FME Server du fichier envoyé sur S3.
+            $aS3Params = array(
+                'access_key_id' => $this->oAmazonS3->sAwsAccessKeyId,
+                'secret_access_key' => $this->oAmazonS3->sAwsSecretAccessKey,
+                'bucket_name' => $this->sFmeServerS3Bucket,
+                'object_key' => $sS3ObjectKey
+            );
+            $oJobResult = $this->oFmeServer->uploadResourceFileFromS3($aS3Params, $sRepository, $sResource, $sPath);
+            if ($oJobResult === false)
+                return false;
+        }
+    }
+
+    function setUseExternalDbConnection ($bValue){
+        if(is_bool($bValue)){
+            $this->bUseExternalDbConnection = $bValue;
+        }
+    }
+    
+    /**
+     * get GTF parameters.
+     * @param {object} $oGtfFmwParser All the GUI.
+     * @return array
+     */
+    function getGtfParameters($oGtfFmwParser) {
+        // Ajout des paramètres GTF_ s'ils sont associés à un paramètre publié du traitement.
+        $aGtfParams = array();
+        foreach ($oGtfFmwParser->aGuiObject as $aGui) {
+            switch($aGui->sDefault_Macro) {
+                 case 'GTF_ORDER_ID':
+                    $aGtfParams['GTF_ORDER_ID'] = $this->iDemandeId;
+                    break;
+                 case 'GTF_SHARED_DIR':
+                    $aGtfParams['GTF_SHARED_DIR'] = $this->aProperties["shared_dir"];
+                    break;
+                 case 'GTF_CONNECTION_STRING':
+                    if ($aGui->sType == "PASSWORD") {
+                        $sServer = $this->aProperties["server"];
+                        $iPort = $this->aProperties["port"];
+                        if ($this->bUseExternalDbConnection){
+                            $sServer = $this->aProperties["connectionStringExternalIp"];
+                            $iPort = $this->aProperties["connectionStringExternalPort"];
+                        }
+                        $aGtfParams['GTF_CONNECTION_STRING'] = $sServer . "," . $iPort . "," . $this->aProperties["database"] . "," . $this->aProperties["login_scheduler"] . "," . $this->aProperties["password_scheduler"];
+                    }
+                    else
+                        writeToLog(INFO_GTF_CONNECTION_STRING_TYPE_PASSWORD, $this->sRobotLogFile);
+                    break;
+                 case 'GTF_REST_URL':
+                    $aGtfParams['GTF_REST_URL'] = $this->aProperties["web_server_name"] . "/" . $this->aProperties["services_alias"] . '/';
+                    break;
+                 case 'GTF_USER_RESTRICTION':
+                    // Restriction de l'utilisateur.
+                    $sSql = 'SELECT "user".restriction FROM [sSchemaGtf].order LEFT JOIN [sSchemaFramework].user ON "order".user_id = "user".user_id WHERE order_id = [iDemandeId]';
+                    $aParams = array();
+                    $aParams['sSchemaFramework'] = array('value' => $this->aProperties["schema_framework"], 'type' => 'schema_name');
+                    $aParams['sSchemaGtf'] = array('value' => $this->aProperties["schema_gtf"], 'type' => 'schema_name');
+                    $aParams['iDemandeId'] = array('value' => $this->iDemandeId, 'type' => 'number');
+                    $oPDOResult = $this->oBd->executeWithParams($sSql, $aParams);
+                    if (!$this->oBd->enErreur()) {
+                        $aUserRestriction = $this->oBd->ligneSuivante($oPDOResult);
+                        $aGtfParams['GTF_USER_RESTRICTION'] = $aUserRestriction['restriction'];
+                    }
+                    else
+                        writeToLog(INFO_USER_RESTRICTION . "(SQL : $sSql)", $this->sRobotLogFile);
+                    break;
+            }
+        }
+        return $aGtfParams;
+    }
+    
+    /**
+     * format a GUI occurrence (GtfGui).
+     * @param {object} $oGui GUI occurrence.
+     * @return string
+     */
+    function formatGuiOccurrence($oGui) {
+        $aBaliseToReplace = array('<GTF_EQUAL>', '<GTF_PIPE>');
+        $aReplacedBalise = array('=', '|');
+        $sGTFOutput = str_replace($aBaliseToReplace, $aReplacedBalise, $this->aParametre[$oGui->sDefault_Macro]);
+        switch ($oGui->sType) {
+            case "FLOAT":
+                $sGTFOutput = str_replace(",", ".", $sGTFOutput);
+                if (!$this->isDecode($sGTFOutput))
+                    $sGTFOutput = $this->decoderFME($sGTFOutput);
+                break;
+            case "LOOKUP_CHOICE":
+                if (!$this->isEncode($sGTFOutput))
+                    $sGTFOutput = $this->encoderFME($sGTFOutput);
+                break;
+            case "TEXT_EDIT" :
+            case "TEXT_EDIT_OR_NUM" :
+                if (!$this->isEncode($sGTFOutput)) {
+                    //$sGTFOutput = $this->decoderFME($sGTFOutput);
+                    $sGTFOutput = $this->encoderFME($sGTFOutput);
+                }
+                break;
+            case "CHOICE":
+            case "LOOKUP_LISTBOX":
+                $sGTFOutput = str_replace('"', '""', $sGTFOutput);
+                if (!$this->isDecode($sGTFOutput))
+                    $sGTFOutput = $this->decoderFME($sGTFOutput);
+                break;
+            case "LISTBOX":
+                if ($this->bFmeServer)
+                    $sGTFOutput = explode('<space>', $sGTFOutput);
+                else if (!$this->isDecode($sGTFOutput))
+                    $sGTFOutput = $this->decoderFME($sGTFOutput);
+                break;
+            default :
+                //$sGTFOutput = str_replace('"', '""', $sGTFOutput);
+                if (!$this->isDecode($sGTFOutput))
+                    $sGTFOutput = $this->decoderFME($sGTFOutput);
+                break;
+        }
+        return $sGTFOutput;
+    }
+    
+    /**
+     * Compress all the result files to a zip archive.
+     * @return string
+     */
+    function zipResultFiles() {
+        // Tous les fichiers de résultat dans une archive .zip.
+        $bHasFile = $this->listDir($this->iDemandeId);
+        if ($this->sSourceTemp != "" && $this->aProperties["debug_mode"] == false)
+            clearDir($this->sSourceTemp);
+        if ($bHasFile) {
+            // Paramètres de cryptage de l'utilisateur.
+            $this->initUserEncryptionParameters();
+            //
+            $sIsToZip = $this->CheckResult($this->iDemandeId);
+            $sDestUrl = $this->aProperties["url_export"] . "/gtf/" . $this->sResultDirectoryName;
+            if ($sIsToZip == "") {
+                //Compression en zip des fichiers résultant. Le parametres Array() permet de filtrer les extensions à compresser. Exemples : Array("shp","shx","dbf") ; Array("*")      
+                $sZipFile = $this->zipFile($this->sResultDirectoryPath, $this->sResultDirectoryPath, $sDestUrl, $this->iDemandeId);
+                $sZipFile = str_replace($sDestUrl, $this->sResultDirectoryName, $sZipFile);
+            }
+            else
+                $sZipFile = str_replace($sDestUrl, $this->sResultDirectoryName, $sIsToZip);
+        }
+        else
+            $sZipFile = "";
+        return $sZipFile;
+    }
+    
+    /**
+     * Create a directory for the result files.
+     * @return string
+     */
+    function createResultDirectory() {
+        // Création du répertoire de sortie des données
+        if (!file_exists($this->aProperties["dir_export"] . '/gtf/')){
+            mkdir($this->aProperties["dir_export"] . '/gtf/');
+        }
+        Do {
+            $sResultDirectoryName = getUniqRandomId();
+            $this->sResultDirectoryPath = $this->aProperties["dir_export"] . '/gtf/' . $sResultDirectoryName;
+        }while(file_exists($this->sResultDirectoryPath));
+        // Création d'un répertoire pour le fichier de log FME.
+        mkdir($this->sResultDirectoryPath . '/log', 0777, true);
+        return $sResultDirectoryName;
+    }
+    
+    /**
+     * get GTF parameters.
+     * @param {object} $oGtfFmwParser All the GUI.
+     * @return array
+     */
+    function getFmeParameters($oGtfFmwParser) {
+        $aTGui = array();
+        $aFmeParameters = array();
+        $bUsePattern = false;
+        foreach ($oGtfFmwParser->aGuiObject as $aGui) {
+            if ($aGui->sDefault_Macro != "") {
+                array_push($aTGui, $aGui);
+            }
+            if ($aGui->sDefault_Macro == "GTF_FORCE_PATTERN") {
+                if (strtolower($aGui->sDefaultValue) == "true"){
+                        $bUsePattern = true;
+                }
+            }
+        }
+        foreach ($aTGui as $oGui) {
+            //Teste si le paramètre est une source
+            if ($oGui->bIsSource) {
+                if ($this->aParametre[$oGui->sDefault_Macro] != "" && substr($this->aParametre[$oGui->sDefault_Macro], 0, 7) != "<quote>") {
+                    $this->aParametre[$oGui->sDefault_Macro] = str_replace('//', '/', $this->aParametre[$oGui->sDefault_Macro]);
+                    $sSourceFilePath = $this->aParametre[$oGui->sDefault_Macro];
+                    $sDirSource = $this->unZipSource($this->aParametre[$oGui->sDefault_Macro]);
+                    $aSourceFiles = $this->getSourceParam($oGui, $oGtfFmwParser, $sDirSource, $bUsePattern);
+                    // Test si le fichier source est un .zip.
+                    $bZipSource = false;
+                    if (strtolower(pathinfo($sSourceFilePath, PATHINFO_EXTENSION)) == 'zip') {
+                        $bZipSource = true;
+                        // Si le fichier n'est pas trouvé alors il se trouve dans le répertoire upload.
+                        if (!file_exists($sSourceFilePath))
+                            $sSourceFilePath = $this->aProperties["upload_dir"] . "/" . $sSourceFilePath;
+                    }
+                    // Formatage des fichiers sources.
+                    foreach ($aSourceFiles as $iIndex => $sSourceFile) {
+                        // Si le fichier source est un .zip -> paramètre publié = [chemin de l'archive zip]/[nom du fichier].
+                        if ($bZipSource) {
+                            if ($this->bFmeServer) {
+                                $sSourceFile = str_replace($sDirSource, '', $sSourceFile);
+                                $aSourceFiles[$iIndex] = pathinfo($sSourceFilePath, PATHINFO_BASENAME) . '/' . $sSourceFile;
+                            }
+                            else
+                                $aSourceFiles[$iIndex] = '""' . str_replace($sDirSource, $sSourceFilePath, $sSourceFile) . '""';
+                            // Supprime l'archive décompressée.
+                            clearDir($sDirSource);
+                        }
+                        else if ($this->bFmeServer)
+                            $aSourceFiles[$iIndex] = pathinfo($sSourceFile, PATHINFO_BASENAME);
+                        else
+                            $aSourceFiles[$iIndex] = '""' . $sSourceFile . '""';
+                        // Supprime les doubles slashes.
+                        $aSourceFiles[$iIndex] = str_replace('//', '/', $aSourceFiles[$iIndex]);
+                    }
+                    // Paramètre au format chaine de caractère.
+                    if ($this->bFmeServer)
+                        $this->aParametre[$oGui->sDefault_Macro] = implode('|', $aSourceFiles);
+                    else
+                        $this->aParametre[$oGui->sDefault_Macro] = '"' . implode('<space>', $aSourceFiles) . '"';
+                }
+            }
+            if ($oGui->bIsDest) {
+                $sDest = $this->aParametre[$oGui->sDefault_Macro];
+                $this->updateDestParam($oGui, $oGtfFmwParser, $sDest);
+            }
+
+            if ($this->aParametre[$oGui->sDefault_Macro] != "") {
+
+                if (!$oGui->bIsSource) {
+                    // Protection des guillemets de chaque valeur pour qu'ils soient correctement envoyé à traitement.tcl
+                    // Cette protection s'effectue uniquement pour les paramètre qui ne sont pas sources (un paramètre source est de ce type : """"param1"" ""param2"" ""param3"""" : les guillemets seraient donc protégé et cela fait planter l'exécution)
+                    //$this->aParametre[$oGui->sDefault_Macro] = str_replace('"', '""', $this->aParametre[$oGui->sDefault_Macro]);
+                }
+                $sGTFOutput = $this->formatGuiOccurrence($oGui);
+                $aFmeParameters[$oGui->sDefault_Macro] = $sGTFOutput;
+            }
+        }
+        return $aFmeParameters;
+    }
+    
+    /**
+     * Cryptage d'une archive .zip.
+     * @param {string} $sZipFilePath Path to the zip archive File.
+     * @param {string} $sPassword Password for the zip archive.
+     * @return boolean
+     */
+    function encryptZipArchiveFiles($sZipFilePath, $sPassword) {
+        $zip = new ZipArchive;
+        $res = $zip->open($sZipFilePath);
+        if ($res === true) {
+            for ($i = 0; $i < $zip->numFiles; $i++) {
+                $zip->setEncryptionIndex($i, ZipArchive::EM_AES_256, $sPassword);
+            }
+            $zip->close();
+            return true;
+        }
+        else
+            return false;
+    }
+    
+    /**
+     * Return the path for the log file.
+     * @param {string} $sResultDirectoryPath Path to the result directory.
+     * @return string
+     */
+    function getFmeLogFilePath($sResultDirectoryPath) {
+        return $sResultDirectoryPath . "/log/fme_" . $this->iDemandeId . ".log";
+    }
+    
+    /**
+     * Return the record for a job on Fme Server.
+     * @param {string} $iJobId The id of the job.
+     * @param {object} $oFmeServer FmeServer object.
+     * @return object
+     */
+    function getFmeServerJobRecord($iJobId, $oFmeServer) {
+        return $oFmeServer->serviceRequest('transformations/jobs/id/' . $iJobId, 'get');
+    }
+    
+    /**
+     * Download Result and log files of a job on Fme Server.
+     * @param {number} $iJobId The od of the job.
+     * @param {object} $oFmeServer FmeServer object.
+     * @return object
+     */
+    function downloadFmeServerJobResult($iJobId, $oFmeServer, $aDestinationFiles, $sResource, $sPath) {
         $sZipFile = '';
-        if (!empty($this->oJobResult->id)) {
-            // Sauve l'url de log fme.
-            $this->sLogFme = $sNewDir . "/fme_" . $this->iDemandeId . ".log";
-            $sSql = "UPDATE " . $this->aProperties['schema_gtf'] . ".order SET log_url='" . $this->sLogFme . "' WHERE order_id=" . $this->iDemandeId;
-            $this->oBd->execute($sSql);
-            // Création du répertoire de sortie des données
-             if (!file_exists($this->aProperties["dir_export"] . "/gtf/"))
-                mkdir($this->aProperties["dir_export"] . "/gtf/");
-            $sDestDir = $this->aProperties["dir_export"] . "/gtf/" . $sNewDir;
-            mkdir($sDestDir);
-            // Création de l'URL de téléchargement des données
-            $sDestUrl = $this->aProperties["url_export"] . "/gtf/" . $sNewDir;
-            $oFmeServer->getJobLog($this->oJobResult->id, $sDestDir . "/fme_" . $this->iDemandeId . ".log");
-            // Télécharge les fichiers de résultat.
+        // Téléchargement du fichier de log.
+        if ($oFmeServer->getJobLog($this->oJobResult->id, $this->getFmeLogFilePath($this->sResultDirectoryPath)) === false)
+            return false;
+        // Sauve l'url de log fme.
+        $this->sLogFme = $this->getFmeLogFilePath($this->sResultDirectoryName);
+        $sSql = "UPDATE " . $this->aProperties['schema_gtf'] . ".order SET log_url='" . $this->sLogFme . "' WHERE order_id=" . $this->iDemandeId;
+        $this->oBd->execute($sSql);
+        // Téléchargement des fichiers de résultat (si traitement).
+        if ($this->oJobResult->status == 'SUCCESS') {
+            // Télécharge l'archive .zip contenant tous les fichiers de résultat.
             if (!empty($aDestinationFiles)) {
-                $oFmeServer->downloadResourceFile($sResource, $sPath . '/' . $sNewDir . '.zip', $sDestDir . '/' . $this->iDemandeId . '.zip');
-                $sZipFile = $sNewDir . '/' . $this->iDemandeId . '.zip';
+                if ($oFmeServer->downloadResourceFile($sResource, $sPath . '/' . $this->sResultDirectoryName . '.zip', $this->sResultDirectoryPath . '/' . $this->iDemandeId . '.zip') === false)
+                    return false;
+                $sZipFile = $this->sResultDirectoryName . '/' . $this->iDemandeId . '.zip';
+                // Paramètres de cryptage de l'utilisateur.
+                $this->initUserEncryptionParameters();
+                // Cryptage de l'archive .zip de résultat.
+                if ($this->bDataEncrypt)
+                    $this->encryptZipArchiveFiles($this->sResultDirectoryPath . '/' . $this->iDemandeId . '.zip', $this->sSecretKey);
             }
+            // Log. du résultat
+            if (!empty($this->oJobResult->result))
+                $sStatusMessage = $this->oJobResult->result->statusMessage;
+            else
+                $sStatusMessage = $this->oJobResult->statusMessage;
+            writeToLog(INFO_INFORM . 'FME| ' . $sStatusMessage, $this->sRobotLogFile);
+            writeToLog(INFO_SUCCESSFUL_TREATMENT, $this->sRobotLogFile);
+            /*
+            // Télécharge tous les fichiers de résultat.
+            foreach($aDestinationFiles as $sParamName) {
+                $sFileName = $aFmeParameters[$sParamName];
+                $oFmeServer->downloadResourceFile($sResource, $sPath . '/' . $sFileName, $this->sResultDirectoryPath . '/' . $sFileName);
+            }
+            // Tous les fichiers de résultat dans une archive .zip.
+            $sZipFile = $this->zipResultFiles();
+            */
+            return $sZipFile;
+        }
+        else {
+            if (!empty($this->oJobResult->result))
+                $sStatusMessage = $this->oJobResult->result->statusMessage;
+            else
+                $sStatusMessage = $this->oJobResult->statusMessage;
+            writeToLog(INFO_INFORM . 'FME| ' . $sStatusMessage, $this->sRobotLogFile);
+            return false;
         }
-        return $sZipFile;
     }
 }
 ?>
diff --git a/gtf.engine/gtf.engines/engine.exe b/gtf.engine/gtf.engines/engine.exe
index 299a2bc1ca56950134511a6694772126a6f3c03c..dda7116dacf3dfdb9bbc35f07da7d6a9ac26d98b 100755
GIT binary patch
delta 18297
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

delta 17791
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
CPayCB

diff --git a/gtf.engine/gtf.engines/engine.php b/gtf.engine/gtf.engines/engine.php
index ecd6de0b..e0446897 100755
--- a/gtf.engine/gtf.engines/engine.php
+++ b/gtf.engine/gtf.engines/engine.php
@@ -10,10 +10,7 @@
  */
 $properties["id_gtf_engine"] = $_SERVER['argv'][1]; //Identifiant du moteur calculé à partir de la valeur passée en argument
 $ErrorLicense = $_SERVER['argv'][2]; //Identifiant du moteur calculé à partir de la valeur passée en argument
-// Si "$_SERVER["HTTP_HOST"]" n'est pas renseigné -> php notice.
-if (!isset($_SERVER["HTTP_HOST"]))
-    $_SERVER["HTTP_HOST"] = 'localhost';
-//
+
 require_once ("php_engine_conf.inc");
 require_once ("vmlib/BD.class.inc");
 require_once ("vmlib/logUtil.inc");
@@ -33,7 +30,7 @@ require_once 'string.inc';
 
 require_once 'gtf_lib/FmeCloud.class.inc';
 require_once 'gtf_lib/FmeServer.class.inc';
-require_once 'gtf_lib/AmazonS3.class.inc';
+//require_once 'aws_lib/AmazonS3.class.inc';
 require_once 'gtf_lib/FmeCloudForGtf.class.inc';
 
 
@@ -45,8 +42,7 @@ if ($ErrorLicense == "0") {
     $sDateFin = new DateTime(date("Y-m-d H:i:s"));
 
     //Connexion à la base de données de Données gtf : pas de mot de passe pour le robot
-    $oBd = new BD($properties["login"], '', $properties["database"], $properties["server"], $properties["port"], $properties["sgbd"], $properties["page_encoding"]);
-    //$oBd = new Vm  ('admin', 'admin', $properties["database"], $properties["server"], $properties["port"], $properties["sgbd"], $properties["page_encoding"]);
+    $oBd = new BD($properties['login_scheduler'], $properties['password_scheduler'], $properties["database"], $properties["server"], $properties["port"], $properties["sgbd"], $properties["page_encoding"]);
     if ($oBd->erreurRencontree) {
         writeToLog(INFO_BASE_CONNECTION_ERROR . $properties["database"], $properties["engine_log_file"]);
     } else {
@@ -114,6 +110,7 @@ if ($ErrorLicense == "0") {
         if ($properties["nbr_order_max"] < 1)
             $properties["nbr_order_max"] = 1;
         $aParams['iNnbrOrderMax'] = array('value' => $properties["nbr_order_max"], 'type' => 'number');
+        $aParams['sTimeZone'] = array('value' => str_replace('UTC', '', $properties["server_timezone"]), 'type' => 'string');
 
         $sEnErreur = 2;
         
@@ -122,731 +119,645 @@ if ($ErrorLicense == "0") {
         } else { // On est PAS en heure creuse
             $oPDOResult = $oBd->executeWithParams($aSql[$properties["sgbd"]]["boucle_2"], $aParams);
         }
-        
+        $bAsync = true;
+        $properties['running_jobs_file_path'] = __DIR__ . '/' . 'gtf_engine' . $properties["id_gtf_engine"] . '_jobid.txt';
+        // Suppression des traitements asynchrones sur Fme Server dont les demandes ont été supprimées sur GTF.
+        //removeFmeServerDeletedJobs();
+        // Traitement des demandes.
         while ($aDemande = $oBd->ligneSuivante($oPDOResult)) {
-            //test pour connaitre les nombres de tentatives de chaque demande
-            //if ($aDemande['attempt']>=1){    modif par og 26/04/13
-            if ($properties["max_attempt"] == '') {
-                $properties["max_attempt"] = 2;
-            }
-            if ($aDemande['attempt'] >= $properties["max_attempt"]) {
-                writeToLog(str_replace("[aDemande['order_id']]", $aDemande['order_id'], INFO_TOO_MANY_ORDER_ATTEMPT), $properties["engine_log_file"]);
-                $iStatut = 4;
-
-                /*
-                  //Mise à jour de la demande.
-                  $sDateTraitement = Date('Y-m-d H:i:s');
-                  $sSql = $aSql[$properties["sgbd"]]["update_demande"];
-                  $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
-                  $sSql = str_replace("[iStatut]", $iStatut, $sSql);
-                  $sSql = str_replace("[iNbSec]", 0, $sSql);
-                  $sSql = str_replace("[sMessage]", $sMessage, $sSql);
-                  $sSql = str_replace("[sDateTraitement]", $sDateTraitement, $sSql);
-                  $sSql = str_replace("[sResultat]", $sResultat, $sSql);
-                  $sSql = str_replace("[sLogFme]", $sLogFme, $sSql);
-
-                  $sSql = str_replace("[iOrderId]", $aDemande["order_id"], $sSql);
-                  $oPDOResult2 = $oBd->execute($sSql);
-                  // */
-
-                //Mise à jour de la demande V2
-                // Requete d'update de la demande
-                $aParams = array();
-                $aParams['sSchemaGtf'] = array('value' => $properties['schema_gtf'], 'type' => 'schema_name');
-                $aParams['iStatut'] = array('value' => $iStatut, 'type' => 'number');
-                $aParams['iNbSec'] = array('value' => 0, 'type' => 'number');
-                $aParams['sDateTraitement'] = array('value' => $sDateTraitement, 'type' => 'string');
-                $aParams['sResultat'] = array('value' => $sResultat, 'type' => 'string');
-                $aParams['sLogFme'] = array('value' => $sLogFme, 'type' => 'string');
-                $aParams['iOrderId'] = array('value' => $aDemande["order_id"], 'type' => 'number');
-                $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["update_demande"], $aParams);
-
-                if ($oBd->erreurRencontree) {
-                    writeToLog(INFO_ORDER_UPDATE_ERROR . "(SQL : $sSql)", $properties["engine_log_file"]);
-                } else {
-                    writeToLog(INFO_ORDER_UPDATE, $properties["engine_log_file"]);
-                    // La demande passe en cours
-                    sendWebsocketMessage($properties['websocket_server'], $properties['websocket_port'], $properties['websocket_alias'], array(
-                        'action' => 'event',
-                        'service' => 'GtfEvents',
-                        'data' => array(
-                            'event' => 'order_started',
-                            'order' => array(
-                                'order_id' => $aDemande['order_id'],
-                                'order_status_id' => $aDemande['order_status_id'],
-                                'user_id' => $aDemande['user_id'],
-                                'workspace_id' => $aDemande['workspace_id']
-                            )
-                        )
-                    ));
+            try {
+                //test pour connaitre les nombres de tentatives de chaque demande
+                //if ($aDemande['attempt']>=1){    modif par og 26/04/13
+                if ($properties["max_attempt"] == '') {
+                    $properties["max_attempt"] = 2;
                 }
-                $oPDOResult2 = $oBd->fermeResultat();
-            } else {
+                if ($aDemande['attempt'] >= $properties["max_attempt"] || empty($aDemande['user_id'])) {
+                    if ($aDemande['attempt'] >= $properties["max_attempt"])
+                        writeToLog(str_replace("[aDemande['order_id']]", $aDemande['order_id'], INFO_TOO_MANY_ORDER_ATTEMPT), $properties["engine_log_file"]);
+                    else
+                        writeToLog(str_replace("[aDemande['order_id']]", $aDemande['order_id'], INFO_NO_ASSOCIATED_USER), $properties["engine_log_file"]);
+                    $iStatut = 4;
+                    
+                    //Mise à jour de la demande V2
+                    $sDateTraitement = gmdate('Y-m-d H:i:s');
+                    if (updateOrder($aDemande["order_id"], $iStatut, $sDateTraitement, null, 0)) {
+                        writeToLog(INFO_ORDER_UPDATE, $properties["engine_log_file"]);
+                        // Demande non traitable
+                        sendWebsocketOrderStatusMessage('order_started', $iStatut);
+                    }
+                    //$oPDOResult2 = $oBd->fermeResultat();
+                } else {
 
-                /*
-                  //Vérification des droits de l'utilsateur
-                  $sSql = $aSql[$properties["sgbd"]]["getLogin"];
-                  $sSql = str_replace("[sSchemaFramework]", $properties["schema_framework"], $sSql);
-                  $sSql = str_replace("[iUserId]", $aDemande['user_id'], $sSql);
-                  $oPDOResult2 = $oBd->execute($sSql);
-                  // */
+                    /*
+                      //Vérification des droits de l'utilsateur
+                      $sSql = $aSql[$properties["sgbd"]]["getLogin"];
+                      $sSql = str_replace("[sSchemaFramework]", $properties["schema_framework"], $sSql);
+                      $sSql = str_replace("[iUserId]", $aDemande['user_id'], $sSql);
+                      $oPDOResult2 = $oBd->execute($sSql);
+                      // */
 
-                //Vérification des droits de l'utilsateur
-                // Recuperation des login et droits de l'utilisateur en cour
-                $aParams = array();
-                $aParams['sSchemaFramework'] = array('value' => $properties["schema_framework"], 'type' => 'schema_name');
-                $aParams['iUserId'] = array('value' => $aDemande['user_id'], 'type' => 'number');
-                $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["getLogin"], $aParams);
-
-                $aUser = $oBd->ligneSuivante($oPDOResult2);
-                $sGroupListId = getUserGroupsEngines($aUser["login"], $oBd, $properties["mixed_rights_management"]);
-                // Mise à jour du nombre de tentative dans la base
-                $iTentative = $aDemande['attempt'] + 1;
-                $sTable = $properties["schema_gtf"] . ".order";
-                $sChamp = "attempt";
-                $sWhere = "order_id";
-                $sListDemande = $aDemande['order_id'];
-                $oBd->updateLinkedTable($sTable, $sChamp, $sWhere, $sListDemande, $iTentative);
-
-                // Mise à jour de l'état de la demande de traitement
-                $oBd->updateLinkedTable($sTable, "order_status_id", $sWhere, $sListDemande, 5);
-
-                writeToLog(str_replace("[aDemande['order_id']]", $aDemande['order_id'], INFO_ORDER_PROCESSING), $properties["engine_log_file"]);
-                // OG 27/03/2013 for table job
-                $sBeginExecutionDate = Date('Y-m-d H:i:s');
-                $date = new DateTime();
-                $iTimeStampBegin = $date->getTimestamp(); // Pour calcul de la durée
-                // fin OG 27/03/2013 for job
-                // $sContenuMail = "";
-                $iNbTraitement = $iNbTraitement + 1;
-                $aUserToRefresh[$iNbTraitement] = $aDemande['user_id'];
-                $aUserToRefresh[$iNbTraitement] = $aDemande['user_id'];
-
-                /*
-                  //Vérification si l'utilisateur a les droits pour faire une demande de ce traitement.
-                  $sSql = $aSql[$properties["sgbd"]]["right_user"];
-                  $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
-                  $sSql = str_replace("[sGroupListId]", $sGroupListId, $sSql);
-                  $oPDOResult2 = $oBd->execute($sSql);
-                  // */
-
-                ///*
-                //Vérification si l'utilisateur a les droits pour faire une demande de ce traitement.
-                $aParams = array();
-                $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
-                $aParams['sGroupListId'] = array('value' => str_replace(',', '|', $sGroupListId), 'type' => 'group');
-                $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["right_user"], $aParams);
-                //*/
-
-                if ($oBd->erreurRencontree) {
-                    writeToLog(INFO_REQUEST_ERROR . $sSql, $properties["engine_log_file"]);
-                    writeToLog(INFO_PHP_ERROR, $properties["engine_log_file"]);
-                    $sMessage = "Erreur SQL.";
-                    // $sContenuMail = 'Votre demande de traitement "'.$aDemande['workspace_nom'].'" a échoué. Voici le message d\'erreur renvoyé : <br><font color="#FF0000">'.$sMessage.'</font><br>';
-                    $iStatut = $sEnErreur;
-                } else {
-                    if ($sGroupListId == "0") {
-                        $bAutorisationDemande = true;
+                    //Vérification des droits de l'utilsateur
+                    // Recuperation des login et droits de l'utilisateur en cour
+                    $aParams = array();
+                    $aParams['sSchemaFramework'] = array('value' => $properties["schema_framework"], 'type' => 'schema_name');
+                    $aParams['iUserId'] = array('value' => $aDemande['user_id'], 'type' => 'number');
+                    $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["getLogin"], $aParams);
+
+                    $aUser = $oBd->ligneSuivante($oPDOResult2);
+                    $sGroupListId = getUserGroupsEngines($aUser["login"], $oBd, $properties["mixed_rights_management"]);
+                    // Mise à jour du nombre de tentative dans la base
+                    $iTentative = $aDemande['attempt'] + 1;
+                    updateOrderAttempt($aDemande['order_id'], $iTentative);
+                    // Mise a jour du message
+                    $aParams = array();
+                    $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
+                    $aParams['iOrderId'] = array('value' => $aDemande["order_id"], 'type' => 'number');
+                    $aParams['status'] = array('value' => 2, 'type' => 'number');
+                    $oPDOResult3 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["update_message"], $aParams);
+                    //*/
+                    if ($oBd->erreurRencontree) {
+                        writeToLog(INFO_TEST_REQUEST_ERROR . '(' . $oBd->getBDMessage() . ')', $properties["engine_log_file"]);
+                    }
+                    // Fin - OG 27/03/2013 for table job
+                    $oPDOResult3 = $oBd->fermeResultat();
+                    
+                    // OG 27/03/2013 for table job
+                    $sBeginExecutionDate = Date('Y-m-d H:i:s');
+                    $date = new DateTime();
+                    $iTimeStampBegin = $date->getTimestamp(); // Pour calcul de la durée
+                    // fin OG 27/03/2013 for job
+                    // $sContenuMail = "";
+                    $iNbTraitement = $iNbTraitement + 1;
+                    $aUserToRefresh[$iNbTraitement] = $aDemande['user_id'];
+                    $aUserToRefresh[$iNbTraitement] = $aDemande['user_id'];
+
+                    /*
+                      //Vérification si l'utilisateur a les droits pour faire une demande de ce traitement.
+                      $sSql = $aSql[$properties["sgbd"]]["right_user"];
+                      $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
+                      $sSql = str_replace("[sGroupListId]", $sGroupListId, $sSql);
+                      $oPDOResult2 = $oBd->execute($sSql);
+                      // */
+
+                    ///*
+                    //Vérification si l'utilisateur a les droits pour faire une demande de ce traitement.
+                    $aParams = array();
+                    $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
+                    $aParams['sGroupListId'] = array('value' => str_replace(',', '|', $sGroupListId), 'type' => 'group');
+                    $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["right_user"], $aParams);
+                    //*/
+
+                    if ($oBd->erreurRencontree) {
+                        writeToLog(INFO_REQUEST_ERROR . $sSql, $properties["engine_log_file"]);
+                        writeToLog(INFO_PHP_ERROR, $properties["engine_log_file"]);
+                        $sMessage = "Erreur SQL.";
+                        // $sContenuMail = 'Votre demande de traitement "'.$aDemande['workspace_nom'].'" a échoué. Voici le message d\'erreur renvoyé : <br><font color="#FF0000">'.$sMessage.'</font><br>';
+                        $iStatut = $sEnErreur;
                     } else {
-                        $bAutorisationDemande = false;
-                        while ($aTraitementsAutorise = $oBd->ligneSuivante($oPDOResult2)) {
+                        if ($sGroupListId == "0") {
+                            $bAutorisationDemande = true;
+                        } else {
+                            $bAutorisationDemande = false;
+                            while ($aTraitementsAutorise = $oBd->ligneSuivante($oPDOResult2)) {
 
-                            if ($aTraitementsAutorise['workspace_id'] == $aDemande['workspace_id']) {
-                                $bAutorisationDemande = true;
+                                if ($aTraitementsAutorise['workspace_id'] == $aDemande['workspace_id']) {
+                                    $bAutorisationDemande = true;
+                                }
                             }
                         }
-                    }
-                    if ($bAutorisationDemande == true) {
-                        if (class_exists("Traitement.class.inc") == false) {
-                            include_once ("Traitement.class.inc");
-                        }
+                        if ($bAutorisationDemande == true) {
+                            if (class_exists("Traitement.class.inc") == false) {
+                                include_once ("Traitement.class.inc");
+                            }
 
-                        /*
-                          // recuperer le nom du fichier fmw a traiter
-                          $sSql = $aSql[$properties["sgbd"]]["select_traitement"];
-                          $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
-                          $sSql = str_replace("[iWorkspaceId]", $aDemande['workspace_id'], $sSql);
-                          $oPDOResult3 = $oBd->execute($sSql);
-                          // */
+                            /*
+                              // recuperer le nom du fichier fmw a traiter
+                              $sSql = $aSql[$properties["sgbd"]]["select_traitement"];
+                              $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
+                              $sSql = str_replace("[iWorkspaceId]", $aDemande['workspace_id'], $sSql);
+                              $oPDOResult3 = $oBd->execute($sSql);
+                              // */
 
-                        ///*
-                        // recuperer le nom du fichier fmw a traiter
-                        $aParams = array();
-                        $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
-                        $aParams['iWorkspaceId'] = array('value' => $aDemande['workspace_id'], 'type' => 'number');
-                        $oPDOResult3 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["select_traitement"], $aParams);
-                        //*/
+                            ///*
+                            // recuperer le nom du fichier fmw a traiter
+                            $aParams = array();
+                            $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
+                            $aParams['iWorkspaceId'] = array('value' => $aDemande['workspace_id'], 'type' => 'number');
+                            $oPDOResult3 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["select_traitement"], $aParams);
+                            //*/
 
-                        $aTraitement = $oBd->ligneSuivante($oPDOResult3);
-                        $iEmailTemplateId = $aTraitement['email_template_id'];
-                        $oPDOResult3 = $oBd->fermeResultat();
-                        // $sSql = $aSql[$properties["sgbd"]]["select_transit_dir"];
-                        // $oPDOResult4 = $oBd->execute($sSql);
-                        // $aAction = $oBd->ligneSuivante ($oPDOResult4);
-                        // $properties["transit_dir"] = $aAction["value"];
-                        // $oPDOResult4 = $oBd->fermeResultat();
-                        
-                        //Lancement du traitement correspondant à la demande.
-                        $bValidFmeLicence = false;
-                        switch($aFmeEngine['fme_engine_type_id']) {
-                            // Traitement exécuté par une occurrence de FME Cloud via l'api rest.
-                            case 'fme_cloud_for_gtf':
-                                $oFmeCloudForGtf = new FmeCloudForGtf($aFmeEngine['iam_access_key_id'], $aFmeEngine['iam_secret_access_key'], $aFmeEngine['s3_region'], 'u0jtg81u4c', 'te', $properties['gtf_instance_id']);
-                            break;
-                            // Traitement exécuté par une occurrence de FME Cloud via l'api rest.
-                            case 'fme_cloud':
-                                $oFmeCloud = new FmeCloud($aFmeEngine['server_url'], $aFmeEngine['fme_cloud_api_token']);
-                                // Liste des occurrences de FME Server.
-                                $aFmeServerInstances = $oFmeCloud->serviceRequest('instances');
-                                if (!empty($aFmeServerInstances)) {
-                                    //print_r($aFmeServerInstances);
-                                    $oFmeServerInstance = $aFmeServerInstances[0];
-                                    // Démarrage de l'occurence si elle est en pause.
-                                    if ($oFmeServerInstance->state == 'PAUSED') {
-                                        $oFmeCloud->startInstance($oFmeServerInstance->id);
-                                        // Statut = en cours.
-                                        $iStatut = 1;
-                                    }
-                                    else if ($oFmeServerInstance->state == 'RUNNING') {
-                                        //print_r($oFmeServer->getToken());
-                                        $oFmeServer = new FmeServer($oFmeServerInstance->instance_url, $aFmeEngine['login'], $aFmeEngine['password'], 'day', 1);
-                                        // Statut de la licence FME --> erreur avec FME Cloud .
-                                        //$oLicenseStatus = $oFmeServer->serviceRequest('licensing/license/status');
-                                        //if ($oLicenseStatus->isLicensed === true && $oLicenseStatus->isLicenseExpired === false) {
-                                            $bValidFmeLicence = true;
-                                            //
-                                            $oAmazonS3 = new AmazonS3($aFmeEngine['s3_access_key_id'], $aFmeEngine['s3_secret_access_key'], $aFmeEngine['s3_region']);
-                                            //
-                                            $oTraitement = new Traitement($oBd, $aDemande['order_id'], $properties["engine_log_file"], $aDemande['wk_params'], $properties, $aDemande['workspace_id'] . "/fme/" . $aTraitement['fmw_file']);
-                                            if (!$oTraitement->bErreur) {
-                                                $sResultat = $oTraitement->processFmeServerOrder($oFmeServer, $aDemande, $aTraitement, $aUser, $oAmazonS3);
-                                                //$sDateFin = new DateTime(date("Y-m-d H:i:s"));
-                                                $sLogFme = $oTraitement->sLogFme;
+                            $aTraitement = $oBd->ligneSuivante($oPDOResult3);
+                            $iEmailTemplateId = $aTraitement['email_template_id'];
+                            $oPDOResult3 = $oBd->fermeResultat();
+                            // $sSql = $aSql[$properties["sgbd"]]["select_transit_dir"];
+                            // $oPDOResult4 = $oBd->execute($sSql);
+                            // $aAction = $oBd->ligneSuivante ($oPDOResult4);
+                            // $properties["transit_dir"] = $aAction["value"];
+                            // $oPDOResult4 = $oBd->fermeResultat();
+
+                            //Lancement du traitement correspondant à la demande.
+                            $bValidFmeLicence = false;
+                            switch($aFmeEngine['fme_engine_type_id']) {
+                                // Traitement exécuté par une occurrence de FME Cloud via l'api rest.
+                                case 'fme_cloud_for_gtf':
+                                    $oFmeCloudForGtf = new FmeCloudForGtf($aFmeEngine['iam_access_key_id'], $aFmeEngine['iam_secret_access_key'], $aFmeEngine['s3_region'], 'u0jtg81u4c', 'te', $properties['gtf_instance_id']);
+                                break;
+                                // Traitement exécuté par une occurrence de FME Server sur Fme Cloud.
+                                case 'fme_cloud':
+                                    $oFmeCloud = new FmeCloud($aFmeEngine['server_url'], $aFmeEngine['fme_cloud_api_token']);
+                                    $oFmeCloud->sLogFilePath = $properties["engine_log_file"];
+                                    $sMessage = '';
+                                    // Liste des occurrences de FME Server.
+                                    $aFmeServerInstances = $oFmeCloud->serviceRequest('instances');
+                                    if (!empty($aFmeServerInstances)) {
+                                        foreach($aFmeServerInstances as $oInstance) {
+                                            if ($oInstance->name == $aFmeEngine['fme_server_instance_name'])
+                                                $oFmeServerInstance = $oInstance;
+                                        }
+                                        if (empty($oFmeServerInstance)) {
+                                            // Aucune instace active -> mise à jour de la demande (En erreur).
+                                            writeToLog(INFO_FME_CLOUD_INSTANCE_NOT_FOUND, $properties["engine_log_file"]);
+                                            updateOrder($aDemande["order_id"], 2, gmdate('Y-m-d H:i:s'));
+                                            sendWebsocketOrderStatusMessage('order_finished_or_error', 2);
+                                            // Envoi un mail de résultat.
+                                            sendOrderResultEmail($iEmailTemplateId);
+                                            writeToLog(INFO_END_ORDER_PROCESSING, $properties["engine_log_file"]);
+                                            // Demande suivante.
+                                            continue 2;
+                                        }
+                                        else {
+                                            writeToLog(INFO_FME_CLOUD_INSTANCE_STATUS . $oFmeServerInstance->state, $properties["engine_log_file"]);
+                                            // Démarrage de l'occurence si elle est en pause.
+                                            if ($oFmeServerInstance->state == 'PAUSED') {
+                                                $oFmeCloud->startInstance($oFmeServerInstance->id);
+                                                writeToLog(INFO_LAUNCHING_FME_CLOUD_INSTANCE, $properties["engine_log_file"]);
+                                                // Nombre de tentative = 0 (instance en pause).
+                                                updateOrderAttempt($aDemande["order_id"], 0);
+                                                // Demande suivante.
+                                                continue 2;
                                             }
-                                            // http 200 : $oFmeServer->aLastCurlRequestInfo->http_code
-                                            if ($oTraitement->oJobResult->status == 'SUCCESS') {
-                                                $sMessage = "";
-                                                $iStatut = 3;
-                                                // Fichier de résultat.
-                                                //if ($sResultat != "")
-                                                    //$sLienResultat = $sResultat;
-                                                $sLienLogFme = $sLogFme;
+                                            else if ($oFmeServerInstance->state == 'RUNNING') {
+                                                writeToLog(INFO_FME_CLOUD_INSTANCE_RUNNING, $properties["engine_log_file"]);
+                                                // Etat de la demande -> en cours.
+                                                $oBd->updateLinkedTable($properties["schema_gtf"] . ".order", "order_status_id", "order_id", $aDemande['order_id'], 5);
+                                                sendWebsocketOrderStatusMessage('order_started', 5);
+                                                if (processFmeServerOrder('https://' . $oFmeServerInstance->public_ip, $aFmeEngine['login'], $aFmeEngine['password']) === false)
+                                                    continue 2;
+                                                /*
+                                                // Stockage Amazon S3 qui contiendra les fichiers sources pour le traitement FME.
+                                                $oAmazonS3 = new AmazonS3($aFmeEngine['s3_access_key_id'], $aFmeEngine['s3_secret_access_key'], $aFmeEngine['s3_region']);
+                                                $oAmazonS3->sLogFilePath = $properties["engine_log_file"];
+                                                $oTraitement->sFmeServerS3Bucket = $aFmeEngine['fme_server_s3_bucket'];
+                                                */
+                                                // Mise en pause de l'occurence.
+                                                //$oFmeCloud->pauseInstance($oFmeServerInstance->id);
                                             }
                                             else {
-                                                $sMessage = "";
-                                                $iStatut = $sEnErreur;
+                                                // Nombre de tentative = 0 (instance en cours de démarrage).
+                                                updateOrderAttempt($aDemande["order_id"], 0);
+                                                // Demande suivante.
+                                                continue 2;
                                             }
-                                        //}
-                                        // Mise en pause de l'occurence.
-                                        $oFmeCloud->pauseInstance($oFmeServerInstance->id);
-                                    }
-                                }
-                            break;
-                            // Traitement exécuté par un serveur fme via l'api rest.
-                            case 'fme_server':
-                                $oFmeServer = new FmeServer($aFmeEngine['server_url'], $aFmeEngine['login'], $aFmeEngine['password'], 'day', 1);
-                                // Statut de la licence FME.
-                                $oLicenseStatus = $oFmeServer->serviceRequest('licensing/license/status');
-                                if ($oLicenseStatus->isLicensed === true && $oLicenseStatus->isLicenseExpired === false) {
-                                    $bValidFmeLicence = true;
-                                    $oTraitement = new Traitement($oBd, $aDemande['order_id'], $properties["engine_log_file"], $aDemande['wk_params'], $properties, $aDemande['workspace_id'] . "/fme/" . $aTraitement['fmw_file']);
-                                    if (!$oTraitement->bErreur) {
-                                        $sResultat = $oTraitement->processFmeServerOrder($oFmeServer, $aDemande, $aTraitement, $aUser);
-                                        //$sDateFin = new DateTime(date("Y-m-d H:i:s"));
-                                        $sLogFme = $oTraitement->sLogFme;
-                                    }
-                                    // http 200 : $oFmeServer->aLastCurlRequestInfo->http_code
-                                    if ($oTraitement->oJobResult->status == 'SUCCESS') {
-                                        $sMessage = "";
-                                        $iStatut = 3;
-                                        // Fichier de résultat.
-                                        //if ($sResultat != "")
-                                            //$sLienResultat = $sResultat;
-                                        $sLienLogFme = $sLogFme;
+                                        }
                                     }
                                     else {
-                                        $sMessage = "";
-                                        $iStatut = $sEnErreur;
+                                        // Aucune instace active -> mise à jour de la demande.
+                                        writeToLog(INFO_NO_FME_CLOUD_INSTANCES, $properties["engine_log_file"]);
+                                        updateOrder($aDemande["order_id"], 2, gmdate('Y-m-d H:i:s'));
+                                        sendWebsocketOrderStatusMessage('order_finished_or_error', 2);
+                                        // Envoi un mail de résultat.
+                                        sendOrderResultEmail($iEmailTemplateId);
+                                        writeToLog(INFO_END_ORDER_PROCESSING, $properties["engine_log_file"]);
+                                        // Demande suivante.
+                                        continue 2;
                                     }
-                                }
-                            break;
-                            // Traitement exécuté par un fme local.
-                            case 'desktop':
-                                $aLicence = getFmeLicence($properties['fme_path']);
-                                $bLicenceIsValid = $aLicence['valid'];
-                                $aLicence['valid'] = 1;
-                                if ($aLicence['valid'] == 1) {
-                                    $bValidFmeLicence = true;
-                                    $sDateDebut = new DateTime(date("Y-m-d H:i:s"));
-                                    $oTraitement = new Traitement($oBd, $aDemande['order_id'], $properties["engine_log_file"], $aDemande['wk_params'], $properties, $aDemande['workspace_id'] . "/fme/" . $aTraitement['fmw_file']);
-
-                                    if (!$oTraitement->bErreur) {
-                                        $sResultat = $oTraitement->Process();
-                                        $sDateFin = new DateTime(date("Y-m-d H:i:s"));
-                                        $sLogFme = $oTraitement->sLogFme;
-                                    }
-                                    //Gestion des erreurs.
-
-                                    if ($oTraitement->bFmeCrash)
-                                        $iStatut = 1;
-                                    elseif ($oTraitement->bErreur) {
-                                        if ($aTraitement["failed_action_id"] != "" && $oTraitement->sSource != "") {
-                                            $aSource = explode("/", $oTraitement->sSource);
-                                            $sSourceDirectory = $properties["upload_dir"] . $aSource[0];
-
-                                            if ($aTraitement["failed_action_id"] == 1) {
-                                                clearDir($sSourceDirectory);
-                                                writeToLog(INFO_DELETE_DIRECTORY . $sSourceDirectory . '.', $properties["engine_log_file"]);
-                                            } elseif ($aTraitement["failed_action_id"] == 2) {
-                                                /*
-                                                  $sSql = $aSql[$properties["sgbd"]]["select_user"];
-                                                  $sSql = str_replace("[iUserId]", $aDemande['user_id'], $sSql);
-                                                  $sSql = str_replace("[sSchemaFramework]", $properties["schema_framework"], $sSql);
-                                                  $oPDOResult2 = $oBd->execute($sSql);
-                                                  // */
-                                                ///*
-                                                // Selection de l'utilisateur
-                                                $aParams = array();
-                                                $aParams['iUserId'] = array('value' => $aDemande['user_id'], 'type' => 'number');
-                                                $aParams['sSchemaFramework'] = array('value' => $properties["schema_framework"], 'type' => 'schema_name');
-                                                $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["select_user"], $aParams);
-                                                //*/
-                                                if ($oBd->erreurRencontree) {
-                                                    writeToLog(INFO_GET_USER_INFO_ERROR . $aDemande['user_id'] . ". (SQL = " . $sSql . ")", $properties["engine_log_file"]);
-                                                } else {
-                                                    $aUser = $oBd->ligneSuivante($oPDOResult2);
-
-                                                    $sUser = userToFolder($aUser["name"]);
-                                                    if (file_exists($properties["transit_dir"])) {
-                                                        if (!file_exists($properties["transit_dir"] . "/failed/")) {
-                                                            mkdir($properties["transit_dir"] . "/failed/");
-                                                        }
-                                                        if (!file_exists($properties["transit_dir"] . "/failed/" . $sUser)) {
-                                                            mkdir($properties["transit_dir"] . "/failed/" . $sUser);
-                                                        }
-                                                        if (!file_exists($properties["transit_dir"] . "/failed/" . $sUser . "/" . $aTraitement["workspace_id"])) {
-                                                            mkdir($properties["transit_dir"] . "/failed/" . $sUser . "/" . $aTraitement["workspace_id"]);
-                                                        }
-                                                        rename($sSourceDirectory, $properties["transit_dir"] . "/failed/" . $sUser . "/" . $aTraitement["workspace_id"] . "/" . $aDemande["order_id"]);
-                                                        writeToLog(str_replace('[sSourceDirectory]', $sSourceDirectory, INFO_MOVING_FILE) . $properties["transit_dir"] . "/failed/" . $sUser . "/" . $aTraitement["workspace_id"] . "/" . $aDemande["order_id"] . '.', $properties["engine_log_file"]);
+                                break;
+                                // Traitement exécuté par un serveur fme via l'api rest.
+                                case 'fme_server':
+                                    // Mise à jour de l'état de la demande de traitement (en cours).
+                                    $oBd->updateLinkedTable($properties["schema_gtf"] . ".order", "order_status_id", "order_id", $aDemande['order_id'], 5);
+                                    sendWebsocketOrderStatusMessage('order_started', 5);
+                                    writeToLog(str_replace("[aDemande['order_id']]", $aDemande['order_id'], INFO_ORDER_PROCESSING), $properties["engine_log_file"]);
+                                    // Lancement du traitement.
+                                    if (processFmeServerOrder($aFmeEngine['server_url'], $aFmeEngine['login'], $aFmeEngine['password']) === false)
+                                        continue 2;
+                                break;
+                                // Traitement exécuté par un fme local.
+                                case 'desktop':
+                                    $aLicence = getFmeLicence($properties['fme_path']);
+                                    $bLicenceIsValid = $aLicence['valid'];
+                                    if ($aLicence['valid'] == 1) {
+                                        $bValidFmeLicence = true;
+                                        $sDateDebut = new DateTime(date("Y-m-d H:i:s"));
+                                        $oTraitement = new Traitement($oBd, $aDemande['order_id'], $properties["engine_log_file"], $aDemande['wk_params'], $properties, $aDemande['workspace_id'] . "/fme/" . $aTraitement['fmw_file']);
+                                        if (!$oTraitement->bErreur) {
+                                            $oTraitement->setUseExternalDbConnection($aFmeEngine['useexternaldbconnection']);
+                                            // Mise à jour de l'état de la demande de traitement (en cours).
+                                            $oBd->updateLinkedTable($properties["schema_gtf"] . ".order", "order_status_id", "order_id", $aDemande['order_id'], 5);
+                                            sendWebsocketOrderStatusMessage('order_started', 5);
+                                            writeToLog(str_replace("[aDemande['order_id']]", $aDemande['order_id'], INFO_ORDER_PROCESSING), $properties["engine_log_file"]);
+                                            // Maj du pid dans la base.
+                                            $sPidFilePath = realpath(dirname($_SERVER['SCRIPT_FILENAME'])  . '/pid_' . $properties["id_gtf_engine"] . '.txt');
+                                            if (file_exists($sPidFilePath)) {
+                                                $iPid = file_get_contents($sPidFilePath);
+                                                if (is_numeric($iPid))
+                                                    updateOrderPid($aDemande['order_id'], $iPid);
+                                            }
+                                            // Lancement du traitement.
+                                            $sResultat = $oTraitement->Process();
+                                            $sDateFin = new DateTime(date("Y-m-d H:i:s"));
+                                            $sLogFme = $oTraitement->sLogFme;
+                                        }
+                                        //Gestion des erreurs.
+
+                                        if ($oTraitement->bFmeCrash)
+                                            $iStatut = 1;
+                                        elseif ($oTraitement->bErreur) {
+                                            if ($aTraitement["failed_action_id"] != "" && $oTraitement->sSource != "") {
+                                                $aSource = explode("/", $oTraitement->sSource);
+                                                $sSourceDirectory = $properties["upload_dir"] . $aSource[0];
+
+                                                if ($aTraitement["failed_action_id"] == 1) {
+                                                    clearDir($sSourceDirectory);
+                                                    writeToLog(INFO_DELETE_DIRECTORY . $sSourceDirectory . '.', $properties["engine_log_file"]);
+                                                } elseif ($aTraitement["failed_action_id"] == 2) {
+                                                    /*
+                                                      $sSql = $aSql[$properties["sgbd"]]["select_user"];
+                                                      $sSql = str_replace("[iUserId]", $aDemande['user_id'], $sSql);
+                                                      $sSql = str_replace("[sSchemaFramework]", $properties["schema_framework"], $sSql);
+                                                      $oPDOResult2 = $oBd->execute($sSql);
+                                                      // */
+                                                    ///*
+                                                    // Selection de l'utilisateur
+                                                    $aParams = array();
+                                                    $aParams['iUserId'] = array('value' => $aDemande['user_id'], 'type' => 'number');
+                                                    $aParams['sSchemaFramework'] = array('value' => $properties["schema_framework"], 'type' => 'schema_name');
+                                                    $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["select_user"], $aParams);
+                                                    //*/
+                                                    if ($oBd->erreurRencontree) {
+                                                        writeToLog(INFO_GET_USER_INFO_ERROR . $aDemande['user_id'] . ". (SQL = " . $sSql . ")", $properties["engine_log_file"]);
                                                     } else {
-                                                        writeToLog(str_replace("[properties['transit_dir']]", $properties['transit_dir'], INFO_DIRECTORY_NOT_FOUND_ENGINE), $properties["engine_log_file"]);
-                                                        $iStatut = $sEnErreur;
+                                                        $aUser = $oBd->ligneSuivante($oPDOResult2);
+
+                                                        $sUser = userToFolder($aUser["name"]);
+                                                        if (file_exists($properties["transit_dir"])) {
+                                                            if (!file_exists($properties["transit_dir"] . "/failed/")) {
+                                                                mkdir($properties["transit_dir"] . "/failed/");
+                                                            }
+                                                            if (!file_exists($properties["transit_dir"] . "/failed/" . $sUser)) {
+                                                                mkdir($properties["transit_dir"] . "/failed/" . $sUser);
+                                                            }
+                                                            if (!file_exists($properties["transit_dir"] . "/failed/" . $sUser . "/" . $aTraitement["workspace_id"])) {
+                                                                mkdir($properties["transit_dir"] . "/failed/" . $sUser . "/" . $aTraitement["workspace_id"]);
+                                                            }
+                                                            rename($sSourceDirectory, $properties["transit_dir"] . "/failed/" . $sUser . "/" . $aTraitement["workspace_id"] . "/" . $aDemande["order_id"]);
+                                                            writeToLog(str_replace('[sSourceDirectory]', $sSourceDirectory, INFO_MOVING_FILE) . $properties["transit_dir"] . "/failed/" . $sUser . "/" . $aTraitement["workspace_id"] . "/" . $aDemande["order_id"] . '.', $properties["engine_log_file"]);
+                                                        } else {
+                                                            writeToLog(str_replace("[properties['transit_dir']]", $properties['transit_dir'], INFO_DIRECTORY_NOT_FOUND_ENGINE), $properties["engine_log_file"]);
+                                                            $iStatut = $sEnErreur;
+                                                        }
                                                     }
                                                 }
                                             }
-                                        }
-                                        $sMessage = $oTraitement->sMessageErreur;
-                                        $iStatut = $sEnErreur;
-                                        $sResultat = '';
-                                        // $sContenuMail = 'Votre demande de traitement "'.$aDemande['workspace_nom'].'" a échoué. Voici le message d\'erreur renvoyé : <br><font color="#FF0000">'.$sMessage.'</font><br>';
-                                        // $sContenuMail .= "Contactez l'administrateur pour consulter le fichier de log du robot.<br>";
-                                        $sLienLogFme = $sLogFme;
-                                    } else {
-                                        if ($aTraitement["success_action_id"] != "" && $oTraitement->sSource != "") {
-                                            $aSource = explode("/", $oTraitement->sSource);
-                                            $sSourceDirectory = $properties["upload_dir"] . $aSource[0];
-                                            if ($aTraitement["success_action_id"] == 1) {
-                                                clearDir($sSourceDirectory);
-                                                writeToLog(INFO_DELETE_DIRECTORY . $sSourceDirectory . '.', $properties["engine_log_file"]);
-                                            } elseif ($aTraitement["success_action_id"] == 2) {
+                                            $sMessage = $oTraitement->sMessageErreur;
+                                            $iStatut = $sEnErreur;
+                                            $sResultat = '';
+                                            // $sContenuMail = 'Votre demande de traitement "'.$aDemande['workspace_nom'].'" a échoué. Voici le message d\'erreur renvoyé : <br><font color="#FF0000">'.$sMessage.'</font><br>';
+                                            // $sContenuMail .= "Contactez l'administrateur pour consulter le fichier de log du robot.<br>";
+                                            $sLienLogFme = $sLogFme;
+                                        } else {
+                                            if ($aTraitement["success_action_id"] != "" && $oTraitement->sSource != "") {
+                                                $aSource = explode("/", $oTraitement->sSource);
+                                                $sSourceDirectory = $properties["upload_dir"] . $aSource[0];
+                                                if ($aTraitement["success_action_id"] == 1) {
+                                                    clearDir($sSourceDirectory);
+                                                    writeToLog(INFO_DELETE_DIRECTORY . $sSourceDirectory . '.', $properties["engine_log_file"]);
+                                                } elseif ($aTraitement["success_action_id"] == 2) {
 
-                                                /*
-                                                  $sSql = $aSql[$properties["sgbd"]]["select_user"];
-                                                  $sSql = str_replace("[iUserId]", $aDemande['user_id'], $sSql);
-                                                  $sSql = str_replace("[sSchemaFramework]", $properties["schema_framework"], $sSql);
-                                                  $oPDOResult2 = $oBd->execute($sSql);
-                                                  // */
-                                                ///*
-                                                //Selection de l'utilisateur
-                                                $aParams = array();
-                                                $aParams['iUserId'] = array('value' => $aDemande['user_id'], 'type' => 'number');
-                                                $aParams['sSchemaFramework'] = array('value' => $properties["schema_framework"], 'type' => 'schema_name');
-                                                $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["select_user"], $aParams);
-                                                //*/
-
-                                                if ($oBd->erreurRencontree) {
-                                                    writeToLog(INFO_GET_USER_INFO_ERROR . $aDemande['user_id'] . ". (SQL = " . $sSql . ")", $properties["engine_log_file"]);
-                                                } else {
-                                                    $aUser = $oBd->ligneSuivante($oPDOResult2);
-
-                                                    $sUser = userToFolder($aUser["name"]);
-                                                    if (file_exists($properties["transit_dir"])) {
-                                                        if (!file_exists($properties["transit_dir"] . "/success/")) {
-                                                            mkdir($properties["transit_dir"] . "/success/");
-                                                        }
-                                                        if (!file_exists($properties["transit_dir"] . "/success/" . $sUser)) {
-                                                            mkdir($properties["transit_dir"] . "/success/" . $sUser);
-                                                        }
-                                                        if (!file_exists($properties["transit_dir"] . "/success/" . $sUser . "/" . $aTraitement["workspace_id"])) {
-                                                            mkdir($properties["transit_dir"] . "/success/" . $sUser . "/" . $aTraitement["workspace_id"]);
-                                                        }
-                                                        rename($sSourceDirectory, $properties["transit_dir"] . "/success/" . $sUser . "/" . $aTraitement["workspace_id"] . "/" . $aDemande["order_id"]);
-                                                        writeToLog(str_replace('[sSourceDirectory]', $sSourceDirectory, INFO_MOVING_FILE) . $properties["transit_dir"] . "/success/" . $sUser . "/" . $aTraitement["workspace_id"] . "/" . $aDemande["order_id"] . '.', $properties["engine_log_file"]);
+                                                    /*
+                                                      $sSql = $aSql[$properties["sgbd"]]["select_user"];
+                                                      $sSql = str_replace("[iUserId]", $aDemande['user_id'], $sSql);
+                                                      $sSql = str_replace("[sSchemaFramework]", $properties["schema_framework"], $sSql);
+                                                      $oPDOResult2 = $oBd->execute($sSql);
+                                                      // */
+                                                    ///*
+                                                    //Selection de l'utilisateur
+                                                    $aParams = array();
+                                                    $aParams['iUserId'] = array('value' => $aDemande['user_id'], 'type' => 'number');
+                                                    $aParams['sSchemaFramework'] = array('value' => $properties["schema_framework"], 'type' => 'schema_name');
+                                                    $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["select_user"], $aParams);
+                                                    //*/
+
+                                                    if ($oBd->erreurRencontree) {
+                                                        writeToLog(INFO_GET_USER_INFO_ERROR . $aDemande['user_id'] . ". (SQL = " . $sSql . ")", $properties["engine_log_file"]);
                                                     } else {
-                                                        writeToLog(str_replace("[properties['transit_dir']]", $properties['transit_dir'], INFO_DIRECTORY_NOT_FOUND_ENGINE), $properties["engine_log_file"]);
-                                                        $iStatut = $sEnErreur;
+                                                        $aUser = $oBd->ligneSuivante($oPDOResult2);
+
+                                                        $sUser = userToFolder($aUser["name"]);
+                                                        if (file_exists($properties["transit_dir"])) {
+                                                            if (!file_exists($properties["transit_dir"] . "/success/")) {
+                                                                mkdir($properties["transit_dir"] . "/success/");
+                                                            }
+                                                            if (!file_exists($properties["transit_dir"] . "/success/" . $sUser)) {
+                                                                mkdir($properties["transit_dir"] . "/success/" . $sUser);
+                                                            }
+                                                            if (!file_exists($properties["transit_dir"] . "/success/" . $sUser . "/" . $aTraitement["workspace_id"])) {
+                                                                mkdir($properties["transit_dir"] . "/success/" . $sUser . "/" . $aTraitement["workspace_id"]);
+                                                            }
+                                                            rename($sSourceDirectory, $properties["transit_dir"] . "/success/" . $sUser . "/" . $aTraitement["workspace_id"] . "/" . $aDemande["order_id"]);
+                                                            writeToLog(str_replace('[sSourceDirectory]', $sSourceDirectory, INFO_MOVING_FILE) . $properties["transit_dir"] . "/success/" . $sUser . "/" . $aTraitement["workspace_id"] . "/" . $aDemande["order_id"] . '.', $properties["engine_log_file"]);
+                                                        } else {
+                                                            writeToLog(str_replace("[properties['transit_dir']]", $properties['transit_dir'], INFO_DIRECTORY_NOT_FOUND_ENGINE), $properties["engine_log_file"]);
+                                                            $iStatut = $sEnErreur;
+                                                        }
                                                     }
                                                 }
                                             }
+                                            $sMessage = "";
+                                            $iStatut = 3;
+                                            $sLienLogFme = $sLogFme;
                                         }
-                                        $sMessage = "";
-                                        $iStatut = 3;
-                                        // $sContenuMail = "Votre demande de traitement '".$aDemande['workspace_nom']."' a réussi.<br>";
-                                        if ($sResultat != "") {
-                                            // $sContenuMail .= '<A href="'.$properties["url_export"]."/".$sResultat.'">Télécharger le résultat</A><br>';
-                                            $sLienResultat = $sResultat;
-                                        }
-                                        $sLienLogFme = $sLogFme;
+                                        $bDataEncrypt = $oTraitement->bDataEncrypt;
+                                        unset($oTraitement);
                                     }
-                                    unset($oTraitement);
-                                }
-                            break;
-                        }
-                        // Licence invalide.
-                        if (!$bValidFmeLicence) {
-                            $iTentative = $iTentative - 1;
-                            $sTable = $properties["schema_gtf"] . ".order";
-                            $sChamp = "attempt";
-                            $sWhere = "order_id";
-                            $sListDemande = $aDemande['order_id'];
-                            $oBd->updateLinkedTable($sTable, $sChamp, $sWhere, $sListDemande, $iTentative);
-                            writeToLog(INFO_INVALID_FME_LICENCE_FILE, $properties["engine_log_file"]);
+                                break;
+                            }
+                            // Licence invalide.
+                            if (!$bValidFmeLicence) {
+                                $iTentative = $iTentative - 1;
+                                updateOrderAttempt($aDemande['order_id'], $iTentative);
+                                writeToLog(INFO_INVALID_FME_LICENCE_FILE, $properties["engine_log_file"]);
+                                writeToLog(INFO_CONTACT_ADMINISTRATOR, $properties["engine_log_file"]);
+                                $sMessage = "Invalid FME licence file. ";
+                                // $sContenuMail = 'Votre demande de traitement "'.$aDemande['workspace_nom'].'" a échoué. Voici le message d\'erreur renvoyé : <br><font color="#FF0000">'.$sMessage.'</font><br>';
+                                $iStatut = 1;
+                                $sLienLogFme = 'Non disponible';
+                            }
+
+                        } else {
+                            writeToLog(INFO_NO_USER_GRANT . $aDemande['workspace_nom'] . ' n\'a pas été défini.', $properties["engine_log_file"]);
                             writeToLog(INFO_CONTACT_ADMINISTRATOR, $properties["engine_log_file"]);
-                            $sMessage = "Invalid FME licence file. ";
+                            $sMessage = "Vous n''avez pas les droits nécessaires pour réaliser ce traitement.";
                             // $sContenuMail = 'Votre demande de traitement "'.$aDemande['workspace_nom'].'" a échoué. Voici le message d\'erreur renvoyé : <br><font color="#FF0000">'.$sMessage.'</font><br>';
-                            $iStatut = 1;
-                            $sLienLogFme = 'Non disponible';
-                        }
-                        
-                    } else {
-                        writeToLog(INFO_NO_USER_GRANT . $aDemande['workspace_nom'] . ' n\'a pas été défini.', $properties["engine_log_file"]);
-                        writeToLog(INFO_CONTACT_ADMINISTRATOR, $properties["engine_log_file"]);
-                        $sMessage = "Vous n''avez pas les droits nécessaires pour réaliser ce traitement.";
-                        // $sContenuMail = 'Votre demande de traitement "'.$aDemande['workspace_nom'].'" a échoué. Voici le message d\'erreur renvoyé : <br><font color="#FF0000">'.$sMessage.'</font><br>';
-                        $iStatut = 6;
+                            $iStatut = 6;
 
-                        if (file_exists($sLogFme)) {
-                            $sLienLogFme = $sLogFme;
-                        } else {
-                            $sLienLogFme = 'Non disponible';
+                            if (file_exists($sLogFme)) {
+                                $sLienLogFme = $sLogFme;
+                            } else {
+                                $sLienLogFme = 'Non disponible';
+                            }
                         }
                     }
-                }
-                $oPDOResult2 = $oBd->fermeResultat();
+                    $oPDOResult2 = $oBd->fermeResultat();
 
-                //Mise à jour de la demande.
+                    //Mise à jour de la demande.
 
-                if ($iStatut == 3) {
-                    /*
-                      $sSql = $aSql[$properties["sgbd"]]["update_message"];
-                      $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
-                      $sSql = str_replace("[iOrderId]", $aDemande["order_id"], $sSql);
-                      $oPDOResult2 = $oBd->execute($sSql);
-                      // */
-                    ///*
-                    // Mise a jour du message
-                    $aParams = array();
-                    $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
-                    $aParams['iOrderId'] = array('value' => $aDemande["order_id"], 'type' => 'number');
-                    $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["update_message"], $aParams);
-                    //*/
-                    if ($oBd->erreurRencontree) {
-                        writeToLog(INFO_TEST_REQUEST_ERROR . '(' . $oBd->getBDMessage() . ')', $properties["engine_log_file"]);
+                    if ($iStatut == 3) {
+                        /*
+                          $sSql = $aSql[$properties["sgbd"]]["update_message"];
+                          $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
+                          $sSql = str_replace("[iOrderId]", $aDemande["order_id"], $sSql);
+                          $oPDOResult2 = $oBd->execute($sSql);
+                          // */
+                        ///*
+                        // Mise a jour du message
+                        $aParams = array();
+                        $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
+                        $aParams['iOrderId'] = array('value' => $aDemande["order_id"], 'type' => 'number');
+                        $aParams['status'] = array('value' => 1, 'type' => 'number');
+                        $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["update_message"], $aParams);
+                        //*/
+                        if ($oBd->erreurRencontree) {
+                            writeToLog(INFO_TEST_REQUEST_ERROR . '(' . $oBd->getBDMessage() . ')', $properties["engine_log_file"]);
+                        }
+                        // Fin - OG 27/03/2013 for table job
+                        $oPDOResult2 = $oBd->fermeResultat();
                     }
-                    // Fin - OG 27/03/2013 for table job
-                    $oPDOResult2 = $oBd->fermeResultat();
-                }
-                if ($iStatut == 2 || $iStatut == 4) {
+                    if ($iStatut == 2 || $iStatut == 4) {
 
-                    /*
-                      $sSql = $aSql[$properties["sgbd"]]["delete_message"];
-                      $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
-                      $sSql = str_replace("[iOrderId]", $aDemande["order_id"], $sSql);
-                      $oPDOResult2 = $oBd->execute($sSql);
-                      // */
-                    ///*
-                    
-                    // Mise a jour du message
-                    $aParams = array();
-                    $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
-                    $aParams['iOrderId'] = array('value' => $aDemande["order_id"], 'type' => 'number');
-                    $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["update_message"], $aParams);
-                    //*/
+                        /*
+                          $sSql = $aSql[$properties["sgbd"]]["delete_message"];
+                          $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
+                          $sSql = str_replace("[iOrderId]", $aDemande["order_id"], $sSql);
+                          $oPDOResult2 = $oBd->execute($sSql);
+                          // */
+                        ///*
 
-                    if ($oBd->erreurRencontree) {
-                        writeToLog(INFO_TEST_REQUEST_ERROR . '(' . $oBd->getBDMessage() . ')', $properties["engine_log_file"]);
+                        // Mise a jour du message
+                        $aParams = array();
+                        $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
+                        $aParams['iOrderId'] = array('value' => $aDemande["order_id"], 'type' => 'number');
+                        $aParams['status'] = array('value' => 1, 'type' => 'number');
+                        $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["update_message"], $aParams);
+                        //*/
+
+                        if ($oBd->erreurRencontree) {
+                            writeToLog(INFO_TEST_REQUEST_ERROR . '(' . $oBd->getBDMessage() . ')', $properties["engine_log_file"]);
+                        }
+                        // Fin - OG 27/03/2013 for table job
+                        $oPDOResult2 = $oBd->fermeResultat();
                     }
-                    // Fin - OG 27/03/2013 for table job
-                    $oPDOResult2 = $oBd->fermeResultat();
-                }
-                $sDateTraitement = Date('Y-m-d H:i:s');
-
-                /*
-                $sSql = $aSql[$properties["sgbd"]]["update_demande"];
-                $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
-                if ($iStatut != 1) {
-                    $timeFirst = strtotime(date_format($sDateDebut, 'Y-m-d H:i:s'));
-                    $timeSecond = strtotime(date_format($sDateFin, 'Y-m-d H:i:s'));
-                    $diff = $timeSecond - $timeFirst;
-                    $iNbSec = $diff;
-                } else {
-                    $iNbSec = "NULL";
-                }
-                // OG 27/03/2013 for table job
-                $date = new DateTime();
-                $iTimeStampEnd = $date->getTimestamp();
-                $iDelay = $iTimeStampEnd - $iTimeStampBegin;
-                $sSql = str_replace("[iNbSec]", $iDelay, $sSql);
-                $sSql = str_replace("[$iStatut]", $iStatut, $sSql);
-                /* $sSql = str_replace("[sMessage]", $sMessage, $sSql); *//*
-                $sSql = str_replace("[sDateTraitement]", $sDateTraitement, $sSql);
-                $sSql = str_replace("[sResultat]", utf8_encode($sResultat), $sSql);
-                $sSql = str_replace("[iOrderId]", $aDemande["order_id"], $sSql);
-                if ($sLogFme == "") {
-                    $sSql = str_replace("'[sLogFme]'", "NULL", $sSql);
-                } else {
-                    $sSql = str_replace("[sLogFme]", $sLogFme, $sSql);
-                }
+                    $sDateTraitement = gmdate('Y-m-d H:i:s');
 
-                $oPDOResult2 = $oBd->execute($sSql);
-                //*/
-
-                //*
-                // Mise a jour de la demande
-                  $aParams = array();
-                  $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
-                  if ($iStatut != 1) {
-                      $timeFirst = strtotime(date_format($sDateDebut, 'Y-m-d H:i:s'));
-                      $timeSecond = strtotime(date_format($sDateFin, 'Y-m-d H:i:s'));
-                      $diff = $timeSecond - $timeFirst;
-                      $iNbSec = $diff;
-                  } else
-                    $iNbSec = "NULL";
-                  // OG 27/03/2013 for table job
-                  $date = new DateTime();
-                  $iTimeStampEnd = $date->getTimestamp();
-                  $iDelay = $iTimeStampEnd - $iTimeStampBegin;
-                  $aParams['iNbSec'] = array('value' => $iDelay, 'type' => 'number');
-                  $aParams['iStatut'] = array('value' => $iStatut, 'type' => 'number');
-                  $aParams['sDateTraitement'] = array('value' => $sDateTraitement, 'type' => 'string');
-                  $aParams['sResultat'] = array('value' =>  utf8_encode($sResultat), 'type' => 'string');
-                  $aParams['iOrderId'] = array('value' =>  $aDemande["order_id"], 'type' => 'number');
-                  if ($sLogFme == "") {
-                  $aParams['sLogFme'] = array('value' =>  "NULL", 'type' => 'string');
-                  } else {
-                  $aParams['sLogFme'] = array('value' =>  $sLogFme, 'type' => 'string');
-                  }
-
-                  $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["update_demande"], $aParams);
-                  // */
-
-
-                if ($oBd->erreurRencontree) {
-                    writeToLog(INFO_ORDER_UPDATE_ERROR . '(' . $oBd->getBDMessage() . ')', $properties["engine_log_file"]);
-                } else {
-                    writeToLog(INFO_ORDER_UPDATE, $properties["engine_log_file"]);
-                    // La demande est terminée avec un résultat
-                    sendWebsocketMessage($properties['websocket_server'], $properties['websocket_port'], $properties['websocket_alias'], array(
-                        'action' => 'event',
-                        'service' => 'GtfEvents',
-                        'data' => array(
-                            'event' => 'order_finished_with_result',
-                            'order' => array(
-                                'order_id' => $aDemande['order_id'],
-                                'order_status_id' => $aDemande['order_status_id'],
-                                'user_id' => $aDemande['user_id'],
-                                'workspace_id' => $aDemande['workspace_id']
-                            )
-                        )
-                    ));
-                }
-                if ($iStatut != 1) {
                     /*
-                      $sSql = $aSql[$properties["sgbd"]]["insertJob"];
-                      $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
-                      $sSql = str_replace("[iOrderId]", $aDemande["order_id"], $sSql);
-                      $sSql = str_replace("[iWorkspaceId]", $aDemande["workspace_id"], $sSql);
-                      $sSql = str_replace("[iUserId]", $aDemande['user_id'], $sSql);
-                      $sSql = str_replace("[sBeginExecutionDate]", $sBeginExecutionDate, $sSql);
-                      $sSql = str_replace("[iDelay]", $iDelay, $sSql);
-                      $sSql = str_replace("[iGtfEngineId]", $properties["id_gtf_engine"], $sSql);
-                      $sSql = str_replace("[iStatut]", $iStatut, $sSql);
-                      //writeToLog('|INFORM|PHP|Test requête OG : '.$sSql,$properties["engine_log_file"]);
-                      $oPDOResult2 = $oBd->execute($sSql);
-                      // */
-                    ///*
-                    // Insert de schemaGtf
-                    $aParams = array();
-                    $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
-                    $aParams['iOrderId'] = array('value' => $aDemande["order_id"], 'type' => 'number');
-                    $aParams['iWorkspaceId'] = array('value' => $aDemande["workspace_id"], 'type' => 'number');
-                    $aParams['iUserId'] = array('value' => $aDemande['user_id'], 'type' => 'number');
-                    $aParams['sBeginExecutionDate'] = array('value' => $sBeginExecutionDate, 'type' => 'string');
-                    $aParams['iDelay'] = array('value' => $iDelay, 'type' => 'number');
-                    $aParams['iGtfEngineId'] = array('value' => $properties["id_gtf_engine"], 'type' => 'number');
-                    $aParams['iDelay'] = array('value' => $iDelay, 'type' => 'number');
-                    $aParams['iStatut'] = array('value' => $iStatut, 'type' => 'number');
-                    //writeToLog('|INFORM|PHP|Test requête OG : '.$sSql,$properties["engine_log_file"]);
-                    $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["insertJob"], $aParams);
-                    //*/
-                    if ($oBd->erreurRencontree) {
-                        writeToLog(INFO_TEST_REQUEST_ERROR . '(' . $oBd->getBDMessage() . ')', $properties["engine_log_file"]);
+                    $sSql = $aSql[$properties["sgbd"]]["update_demande"];
+                    $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
+                    if ($iStatut != 1) {
+                        $timeFirst = strtotime(date_format($sDateDebut, 'Y-m-d H:i:s'));
+                        $timeSecond = strtotime(date_format($sDateFin, 'Y-m-d H:i:s'));
+                        $diff = $timeSecond - $timeFirst;
+                        $iNbSec = $diff;
+                    } else {
+                        $iNbSec = "NULL";
+                    }
+                    // OG 27/03/2013 for table job
+                    $date = new DateTime();
+                    $iTimeStampEnd = $date->getTimestamp();
+                    $iDelay = $iTimeStampEnd - $iTimeStampBegin;
+                    $sSql = str_replace("[iNbSec]", $iDelay, $sSql);
+                    $sSql = str_replace("[$iStatut]", $iStatut, $sSql);
+                    /* $sSql = str_replace("[sMessage]", $sMessage, $sSql); *//*
+                    $sSql = str_replace("[sDateTraitement]", $sDateTraitement, $sSql);
+                    $sSql = str_replace("[sResultat]", utf8_encode($sResultat), $sSql);
+                    $sSql = str_replace("[iOrderId]", $aDemande["order_id"], $sSql);
+                    if ($sLogFme == "") {
+                        $sSql = str_replace("'[sLogFme]'", "NULL", $sSql);
+                    } else {
+                        $sSql = str_replace("[sLogFme]", $sLogFme, $sSql);
                     }
-                    // Fin - OG 27/03/2013 for table job
-                    $oPDOResult2 = $oBd->fermeResultat();
-                }
-                // Mise à jour de la demande si resultat est vide
-                if ($sResultat == "") {
 
-                    /*
-                      $sSql = $aSql[$properties["sgbd"]]["update_demande_resultat_null"];
-                      $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
-                      $sSql = str_replace("[iOrderId]", $aDemande["order_id"], $sSql);
-                      $oPDOResult2 = $oBd->execute($sSql);
-                      // */
+                    $oPDOResult2 = $oBd->execute($sSql);
+                    //*/
 
-                    ///*
-                    // Mise a jour de la demande si resultat null
+                    //*
+                    // Mise a jour de la demande
                     $aParams = array();
                     $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
-                    $aParams['iOrderId'] = array('value' => $aDemande["order_id"], 'type' => 'number');
-                    $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["update_demande_resultat_null"], $aParams);
-                    //*/
-
-                    if ($oBd->erreurRencontree) {
-                        writeToLog(INFO_ORDER_UPDATE_ERROR . ' (' . $oBd->getBDMessage() . ')', $properties["engine_log_file"]);
-                    } else {
-                        writeToLog(INFO_INFO_ORDER_UPDATE_NULL, $properties["engine_log_file"]);
-                        // La demande est terminée où en erreur
-                        sendWebsocketMessage($properties['websocket_server'], $properties['websocket_port'], $properties['websocket_alias'], array(
-                            'action' => 'event',
-                            'service' => 'GtfEvents',
-                            'data' => array(
-                                'event' => 'order_finished_or_error',
-                                'order' => array(
-                                    'order_id' => $aDemande['order_id'],
-                                    'order_status_id' => $aDemande['order_status_id'],
-                                    'user_id' => $aDemande['user_id'],
-                                    'workspace_id' => $aDemande['workspace_id']
-                                )
-                            )
-                        ));
+                    if ($iStatut != 1) {
+                        $timeFirst = strtotime(date_format($sDateDebut, 'Y-m-d H:i:s'));
+                        $timeSecond = strtotime(date_format($sDateFin, 'Y-m-d H:i:s'));
+                        $diff = $timeSecond - $timeFirst;
+                        $iNbSec = $diff;
+                    } else
+                        $iNbSec = "NULL";
+                    // OG 27/03/2013 for table job
+                    $date = new DateTime();
+                    $iTimeStampEnd = $date->getTimestamp();
+                    $iDelay = $iTimeStampEnd - $iTimeStampBegin;
+                    if (updateOrder($aDemande["order_id"], $iStatut, $sDateTraitement, $sLogFme, $iDelay, $sResultat)) {
+                        writeToLog(INFO_ORDER_UPDATE, $properties["engine_log_file"]);
+                        // La demande est terminée avec un résultat
+                        sendWebsocketOrderStatusMessage('order_finished_with_result', $aDemande['order_status_id']);
                     }
-                    $oPDOResult2 = $oBd->fermeResultat();
-                }
-
-                // Notification par e-mail.
-                $bMailToSend = false;
-                switch (strtoupper(trim($aDemande['email_option_id']))) {
-                    case 1:
-                        $bMailToSend = True;
-                        break;
-                    case 2:
-                        $bMailToSend = False;
-                        break;
-                    case 3:
-                        if ($iStatut == $sEnErreur) {
-                            $bMailToSend = True;
-                        }
-                        break;
-                    case 4:
-                        if ($iStatut != $sEnErreur) {
-                            $bMailToSend = True;
+                    if ($iStatut != 1) {
+                        /*
+                          $sSql = $aSql[$properties["sgbd"]]["insertJob"];
+                          $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
+                          $sSql = str_replace("[iOrderId]", $aDemande["order_id"], $sSql);
+                          $sSql = str_replace("[iWorkspaceId]", $aDemande["workspace_id"], $sSql);
+                          $sSql = str_replace("[iUserId]", $aDemande['user_id'], $sSql);
+                          $sSql = str_replace("[sBeginExecutionDate]", $sBeginExecutionDate, $sSql);
+                          $sSql = str_replace("[iDelay]", $iDelay, $sSql);
+                          $sSql = str_replace("[iGtfEngineId]", $properties["id_gtf_engine"], $sSql);
+                          $sSql = str_replace("[iStatut]", $iStatut, $sSql);
+                          //writeToLog('|INFORM|PHP|Test requête OG : '.$sSql,$properties["engine_log_file"]);
+                          $oPDOResult2 = $oBd->execute($sSql);
+                          // */
+                        ///*
+                        // Insert de schemaGtf
+                        $aParams = array();
+                        $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
+                        $aParams['iOrderId'] = array('value' => $aDemande["order_id"], 'type' => 'number');
+                        $aParams['iWorkspaceId'] = array('value' => $aDemande["workspace_id"], 'type' => 'number');
+                        $aParams['iUserId'] = array('value' => $aDemande['user_id'], 'type' => 'number');
+                        $aParams['sBeginExecutionDate'] = array('value' => $sBeginExecutionDate, 'type' => 'string');
+                        $aParams['iDelay'] = array('value' => $iDelay, 'type' => 'number');
+                        $aParams['iGtfEngineId'] = array('value' => $properties["id_gtf_engine"], 'type' => 'number');
+                        $aParams['iDelay'] = array('value' => $iDelay, 'type' => 'number');
+                        $aParams['iStatut'] = array('value' => $iStatut, 'type' => 'number');
+                        //writeToLog('|INFORM|PHP|Test requête OG : '.$sSql,$properties["engine_log_file"]);
+                        $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["insertJob"], $aParams);
+                        //*/
+                        if ($oBd->erreurRencontree) {
+                            writeToLog(INFO_TEST_REQUEST_ERROR . '(' . $oBd->getBDMessage() . ')', $properties["engine_log_file"]);
                         }
-                        break;
-                    default:
-                        $bMailToSend = True;
-                }
-
-                // Licence invalide.
-                if ($iStatut == 2 && !$bLicenceIsValid) {
-                    // Mise à jour de l'état de la demande de traitement (en attente).
-                    $oBd->updateLinkedTable($properties["schema_gtf"] . ".order", "order_status_id", "order_id", $aDemande['order_id'], 1);
-                    // Licence invalide : 1 mail par jour max.
-                    $sToday = date('d/m/Y');
-                    $sMailLicenceFile = __DIR__ . '\mail_licence.txt';
-                    if (file_exists($sMailLicenceFile))
-                        if (file_get_contents($sMailLicenceFile) == $sToday)
-                            $bMailToSend = false;
-                    file_put_contents($sMailLicenceFile, $sToday);
-                    // Mise à jour du nombre de tentative dans la base.
-                    $oBd->updateLinkedTable($properties["schema_gtf"] . ".order", "attempt", "order_id", $aDemande['order_id'], 0);
-                }
-                
-                // Envoi du mail.
-                if ($bMailToSend == true) {
-                    /*
-                      $sSql = $aSql[$properties["sgbd"]]["select_user"];
-                      $sSql = str_replace("[iUserId]", $aDemande['user_id'], $sSql);
-                      $sSql = str_replace("[sSchemaFramework]", $properties["schema_framework"], $sSql);
-                      $oPDOResult2 = $oBd->execute($sSql);
-                      // */
-                    ///*
-                    
-                    //Mise a jour de la demande si resultat null
-                    $aParams = array();
-                    $aParams['iUserId'] = array('value' => $aDemande['user_id'], 'type' => 'number');
-                    $aParams['sSchemaFramework'] = array('value' => $properties["schema_framework"], 'type' => 'schema_name');
-                    $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["update_demande_resultat_null"], $aParams);
-                    //*/
-                    if ($oBd->erreurRencontree) {
-                        writeToLog(INFO_GET_USER_INFO_ERROR . $aDemande['user_id'] . ". (SQL = " . $sSql . ")", $properties["engine_log_file"]);
-                    } else {
-                        // $aUser = $oBd->ligneSuivante ($oPDOResult2);
-                        // $sContenuMail = "Bonjour ".$aUser["name"].",<br><br><br>".$sContenuMail;
-                        // $sContenuMail .= "<br><br><cite><h6>Cet e-mail a été envoyé par un robot, merci de ne pas répondre.</h6></cite><br>";
-                        //	
-
-                        if (empty($iEmailTemplateId))
-                            $iEmailTemplateId = $properties['default_mail_model'];
+                        // Fin - OG 27/03/2013 for table job
+                        $oPDOResult2 = $oBd->fermeResultat();
+                    }
+                    // Mise à jour de la demande si resultat est vide
+                    if ($sResultat == "") {
 
                         /*
-                          // Nom des moteurs GTF et FME
-                          $sSql = $aSql[$properties["sgbd"]]["get_gtf_engine_name"];
+                          $sSql = $aSql[$properties["sgbd"]]["update_demande_resultat_null"];
                           $sSql = str_replace("[sSchemaGtf]", $properties["schema_gtf"], $sSql);
-                          $sSql = str_replace('[gtf_engine_id]', $aDemande['gtf_engine_id'], $sSql);
+                          $sSql = str_replace("[iOrderId]", $aDemande["order_id"], $sSql);
                           $oPDOResult2 = $oBd->execute($sSql);
                           // */
+
                         ///*
-                        // Nom des moteurs GTF et FME
+                        // Mise a jour de la demande si resultat null
                         $aParams = array();
                         $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
-                        $aParams['gtf_engine_id'] = array('value' => $aDemande['gtf_engine_id'], 'type' => 'number');
-                        $oPDOResult2 = $oBd->executeWithParams($sSql = $aSql[$properties["sgbd"]]["get_gtf_engine_name"], $aParams);
+                        $aParams['iOrderId'] = array('value' => $aDemande["order_id"], 'type' => 'number');
+                        $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["update_demande_resultat_null"], $aParams);
                         //*/
 
+                        if ($oBd->erreurRencontree) {
+                            writeToLog(INFO_ORDER_UPDATE_ERROR . ' (' . $oBd->getBDMessage() . ')', $properties["engine_log_file"]);
+                        } else {
+                            writeToLog(INFO_INFO_ORDER_UPDATE_NULL, $properties["engine_log_file"]);
+                            // La demande est terminée où en erreur
+                            sendWebsocketOrderStatusMessage('order_finished_or_error', $aDemande['order_status_id']);
+                        }
+                        $oPDOResult2 = $oBd->fermeResultat();
+                    }
+
+                    // Notification par e-mail.
+                    $bMailToSend = false;
+                    switch (strtoupper(trim($aDemande['email_option_id']))) {
+                        case 1:
+                            $bMailToSend = True;
+                            break;
+                        case 2:
+                            $bMailToSend = False;
+                            break;
+                        case 3:
+                            if ($iStatut == $sEnErreur) {
+                                $bMailToSend = True;
+                            }
+                            break;
+                        case 4:
+                            if ($iStatut != $sEnErreur) {
+                                $bMailToSend = True;
+                            }
+                            break;
+                        default:
+                            $bMailToSend = True;
+                    }
+
+                    // Licence invalide.
+                    if ($iStatut == 2 && !$bLicenceIsValid) {
+                        // Mise à jour de l'état de la demande de traitement (en attente).
+                        $oBd->updateLinkedTable($properties["schema_gtf"] . ".order", "order_status_id", "order_id", $aDemande['order_id'], 1);
+                        // Licence invalide : 1 mail par jour max.
+                        $sToday = date('d/m/Y');
+                        $sMailLicenceFile = __DIR__ . '\mail_licence.txt';
+                        if (file_exists($sMailLicenceFile))
+                            if (file_get_contents($sMailLicenceFile) == $sToday)
+                                $bMailToSend = false;
+                        file_put_contents($sMailLicenceFile, $sToday);
+                        // Mise à jour du nombre de tentative dans la base.
+                        updateOrderAttempt($aDemande['order_id'], 0);
+                    }
 
+                    // Envoi du mail.
+                    if ($bMailToSend == true) {
+                        /*
+                          $sSql = $aSql[$properties["sgbd"]]["select_user"];
+                          $sSql = str_replace("[iUserId]", $aDemande['user_id'], $sSql);
+                          $sSql = str_replace("[sSchemaFramework]", $properties["schema_framework"], $sSql);
+                          $oPDOResult2 = $oBd->execute($sSql);
+                          // */
+                        ///*
+
+                        //Mise a jour de la demande si resultat null
+                        /*
+                        $aParams = array();
+                        $aParams['iOrderId'] = array('value' => $aDemande['order_id'], 'type' => 'number');
+                        $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
+                        $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["update_demande_resultat_null"], $aParams);
+                        //
                         if ($oBd->erreurRencontree) {
-                            writeToErrorLog(ERROR_0001);
-                        } else
-                            $aRow = $oBd->ligneSuivante($oPDOResult2);
-
-                        // URL de téléchargement du résultat
-                        $sResultUrl = '';
-                        if ($sResultat != "")
-                            $sResultUrl = '<a href="' . $properties["url_export"] . "/gtf/" . $sResultat . '">Télécharger le résultat</a>';
-
-                        // Dates
-                        $sOrderDate = date_format(date_create($aDemande['order_date']), 'd/m/Y H:i:s');
-
-                        // Envoi du mail
-                        $aObjects = array();
-                        if (!empty($sMessage))
-                            $aObjects['error'] = $sMessage;
-                        $aObjects['oOrder'] = new OrderLib($oBd, $aDemande["order_id"], $properties, "v_order");
-                        $aObjects['oOrder']->formatOrderEmail();
-                        $oEmail = new Email($oBd, $iEmailTemplateId, $properties, $aObjects);
-                        if (!empty($oEmail->oEmailTemplate->name))
-                            $oEmail->send();
+                            writeToLog(INFO_GET_USER_INFO_ERROR . $aDemande['user_id'] . ". (SQL = " . $sSql . ")", $properties["engine_log_file"]);
+                        } else {
+                        */
+                            // $aUser = $oBd->ligneSuivante ($oPDOResult2);
+                            // $sContenuMail = "Bonjour ".$aUser["name"].",<br><br><br>".$sContenuMail;
+                            // $sContenuMail .= "<br><br><cite><h6>Cet e-mail a été envoyé par un robot, merci de ne pas répondre.</h6></cite><br>";
+                            //  
+                            // Envoi du mail
+                            sendOrderResultEmail($iEmailTemplateId, $sMessage);
+                        //}
+                        $oPDOResult2 = $oBd->fermeResultat();
+                    } else {
+                        // pas d'envoi de mail
+                        writeToLog(INFO_NO_MAIL_SEND, $properties["engine_log_file"]);
                     }
-                    $oPDOResult2 = $oBd->fermeResultat();
-                } else {
-                    // pas d'envoi de mail
-                    writeToLog(INFO_NO_MAIL_SEND, $properties["engine_log_file"]);
-                }
-            } //fin du if sur les tentatives
-            //fin de while	
+                } //fin du if sur les tentatives
+                //fin de while  
+            }
+            catch (Exception $e) {
+                writeToErrorLog($e->getMessage());
+                // Mise a jour du message
+                $aParams = array();
+                $aParams['sSchemaGtf'] = array('value' => $properties["schema_gtf"], 'type' => 'schema_name');
+                $aParams['iOrderId'] = array('value' => $aDemande["order_id"], 'type' => 'number');
+                $aParams['status'] = array('value' => 1, 'type' => 'number');
+                $oPDOResult2 = $oBd->executeWithParams($aSql[$properties["sgbd"]]["update_message"], $aParams);
+                // Mise a jour de la demande.
+                updateOrder($aDemande["order_id"], 2, gmdate('Y-m-d H:i:s'), null, 0);
+                sendWebsocketOrderStatusMessage('order_finished_or_error', 2);
+            }
         }
         if ($iNbTraitement >= 1) {
             //Crée ou modifie le fichier de maj de l'application pour l'utilisateur.
@@ -893,4 +804,414 @@ function TesteHeureCreuse($sHeureMin, $sHeureMax) {
     }
 }
 
+/**
+ * Mise à jour d'une demande.
+ * @param {number} $iOrderId Id de la demande.
+ * @param {number} $iStatut Statut de la demande.
+ * @param {string} $sExecutionDate Date de la demande.
+ * @param {number} $iNbSec Durée de la demande en secondes.
+ * @param {string} $sResultUrl Url du résultat de la demande.
+ * @param {string} $sLogUrl Url du log de la demande.
+ */
+function updateOrder($iOrderId, $iStatut, $sExecutionDate, $sLogUrl = null, $iNbSec = null, $sResultUrl = null) {
+    // Variables globales.
+    global $oBd, $properties, $aSql;
+    // Requete d'update de la demande.
+    if (empty($sLogUrl))
+        $sLogUrl = null;
+    if (empty($sResultUrl))
+        $sResultUrl = null;
+    $aParams = array();
+    $aParams['sSchemaGtf'] = array('value' => $properties['schema_gtf'], 'type' => 'schema_name');
+    $aParams['iOrderId'] = array('value' => $iOrderId, 'type' => 'number');
+    $aParams['iStatut'] = array('value' => $iStatut, 'type' => 'number');
+    $aParams['sDateTraitement'] = array('value' => $sExecutionDate, 'type' => 'string');
+    $aParams['iNbSec'] = array('value' => $iNbSec, 'type' => 'number');
+    $aParams['sResultat'] = array('value' => $sResultUrl, 'type' => 'string');
+    $aParams['sLogFme'] = array('value' => $sLogUrl, 'type' => 'string');
+    $oBd->executeWithParams($aSql[$properties["sgbd"]]["update_demande"], $aParams);
+    if ($oBd->erreurRencontree) {
+        writeToLog(INFO_ORDER_UPDATE_ERROR . '(' . $oBd->getBDMessage() . ')', $properties["engine_log_file"]);
+        return false;
+    }
+    else
+        return true;
+}
+
+/**
+ * Envoi un mail de résultat du traitement FME.
+ * @param {number} $iEmailTemplateId Id du template de mail.
+ * @param {string} $sMessage Message.
+ */
+function sendOrderResultEmail($iEmailTemplateId, $sMessage = '') {
+    // Variables globales.
+    global $oBd, $properties, $aDemande, $oTraitement;
+    if (!empty($oTraitement))
+        $oTraitement = $oTraitement;
+    // Envoi du mail
+    $aObjects = array();
+    if (!empty($sMessage))
+        $aObjects['error'] = $sMessage;
+    $aObjects['oOrder'] = new OrderLib($oBd, $aDemande["order_id"], $properties, "v_order");
+    $aObjects['oOrder']->formatOrderEmail();
+    if (!empty($oTraitement))
+        $aObjects['oOrder']->aFields['bDataEncrypt'] = $oTraitement->bDataEncrypt;
+    $aObjects['oOrder']->aFields['sApplicationUrl'] = $properties['web_server_name'] . '/' . $properties['application_name'];
+    if (empty($iEmailTemplateId))
+        $iEmailTemplateId = $properties['default_mail_model'];
+    $oEmail = new Email($oBd, $iEmailTemplateId, $properties, $aObjects);
+    if (!empty($oEmail->oEmailTemplate->name))
+        $oEmail->send();
+}
+
+/**
+ * Mise à jour du nombre de tentatives de la demande.
+ * @param {number} $iOrderId Id de la demande.
+ * @param {number} $iAttempt Nombre de tentatives.
+ */
+function updateOrderAttempt($iOrderId, $iAttempt) {
+    // Variables globales.
+    global $oBd, $properties;
+    // Mise à jour du nombre de tentatives de la demande.
+    $oBd->updateLinkedTable($properties["schema_gtf"] . ".order", "attempt", "order_id", $iOrderId, $iAttempt);
+}
+
+/**
+ * Envoi un message au websocket contenant le statut de la demande.
+ * @param {string} $sEvent Nom de l'évènement.
+ * @param {number} $iStatut Statut de la demande.
+ */
+function sendWebsocketOrderStatusMessage($sEvent, $iStatut) {
+    // Variables globales.
+    global $properties, $aDemande;
+    // Envoi du message.
+    sendWebsocketMessage($properties['websocket_server'], $properties['websocket_port'], $properties['websocket_alias'], array(
+        'action' => 'event',
+        'service' => 'GtfEvents',
+        'data' => array(
+            'event' => $sEvent,
+            'order' => array(
+                'order_id' => $aDemande['order_id'],
+                'order_status_id' => $iStatut,
+                'user_id' => $aDemande['user_id'],
+                'workspace_id' => $aDemande['workspace_id']
+            )
+        )
+    ));
+}
+
+/**
+ * Ajoute un traitement asynchrone en cours d'exécution.
+ * @param {object} $oTraitement Objet de la classe Traitement.
+ * @param {string} $sServerUrl Url to Fme Server.
+ * @param {string} $sLogin User login.
+ * @param {string} $sPassword User password.
+ */
+function addFmeServerRunningJob($oTraitement, $sServerUrl, $sLogin, $sPassword) {
+    // Variables globales.
+    global $properties, $aDemande, $aFmeEngine;
+    // Liste des demandes asynchrones en cours.
+    $aRunningJobs = getFmeServerRunningJobs();
+    // Paramètres de la demande asynchrone à ajouter.
+    $aRunningJob = array(
+        'order_id' => $aDemande['order_id'],
+        'fme_engine_type_id' => $aFmeEngine['fme_engine_type_id'],
+        'job_id' => $oTraitement->oJobResult->id,
+        'result_directory_name' => $oTraitement->sResultDirectoryName,
+        'result_directory_path' => $oTraitement->sResultDirectoryPath,
+        'destination_files' => $oTraitement->aJobDestinationFiles,
+        'resource' => $oTraitement->sJobResource,
+        'path' => $oTraitement->sJobPath,
+        'fme_server_url' => $sServerUrl,
+        'login' => $sLogin,
+        'password' => $sPassword
+    );
+    $aRunningJobs[] = $aRunningJob;
+    // Sauve la liste.
+    file_put_contents($properties['running_jobs_file_path'], serialize($aRunningJobs));
+    // Mise à jour du job id.
+    updateOrderPid($aDemande['order_id'], $oTraitement->oJobResult->id);
+}
+
+/**
+ * Retourne la liste des traitements asynchrones en cours d'exécution.
+ * return array
+ */
+function getFmeServerRunningJobs() {
+    // Variables globales.
+    global $properties;
+    // Retourne la liste des demandes asynchrones en cours ou un tableau vide.
+    if (file_exists($properties['running_jobs_file_path']))
+        return unserialize(file_get_contents($properties['running_jobs_file_path']));
+    else
+        return array();
+}
+
+/**
+ * Vérification de la présence d'un traitement dans la liste des traitements asynchrones en cours d'exécution.
+ * @param {number} $iOrderId Id de la demande en cours.
+ * @param {array} $aRunningJobs Tableau contenant la liste des traitements asynchrones en cours d'exécution.
+ * return boolean
+ */
+function isFmeServerJobRunning($iOrderId, $aRunningJobs) {
+    foreach ($aRunningJobs as $aRunningJob) {
+        if ($aRunningJob['order_id'] == $iOrderId)
+            return true;
+    }
+    return false;
+}
+
+/**
+ * Retourne les infos d'un traitement asynchrones en cours d'exécution.
+ * @param {number} $iOrderId I de la demande en cours.
+ * @param {array} $aRunningJobs Tableau contenant la liste des traitements asynchrones en cours d'exécution.
+ * return array
+ */
+function getFmeServerRunningJob($iOrderId, $aRunningJobs) {
+    foreach ($aRunningJobs as $aRunningJob) {
+        if ($aRunningJob['order_id'] == $iOrderId)
+            return $aRunningJob;
+    }
+    return false;
+}
+
+/**
+ * Supprime un traitement asynchrone en cours d'exécution.
+ * @param {number} $iOrderId Id de la demande en cours.
+ */
+function removeFmeServerRunningJob($iOrderId, $oFmeServer = null) {
+    // Variables globales.
+    global $properties;
+    // Liste des demandes asynchrones en cours.
+    $iJobIndex = null;
+    $aRunningJobs = getFmeServerRunningJobs();
+    foreach ($aRunningJobs as $iIndex => $aRunningJob) {
+        if ($aRunningJob['order_id'] == $iOrderId) {
+            $iJobIndex = $iIndex;
+            break;
+        }
+    }
+    // Sauve la liste.
+    if ($iJobIndex !== null) {
+        // Sauve la liste des demandes asynchrones en cours.
+        $aRunningJob = array_splice($aRunningJobs, $iJobIndex, 1)[0];
+        if (empty($aRunningJobs))
+            unlink($properties['running_jobs_file_path']);
+        else
+            file_put_contents($properties['running_jobs_file_path'], serialize($aRunningJobs));
+        // Supprime le job id.
+        //updateOrderPid($iOrderId);
+        // Ecriture dans les logs.
+        writeToLog(INFO_FME_SERVER_ASYNCHRONOUS_JOB_REMOVED_FROM_LIST . " (demande $iOrderId).", $properties["engine_log_file"]);
+        // Supprime le traitement sur Fme Server.
+        if (is_object($oFmeServer)) {
+            if (!empty($aRunningJob['job_id']))
+                $oFmeServer->deleteJob($aRunningJob['job_id']);
+            // Supprime le répertoire des ressources de la demande sur Fme Server.
+            if (!empty($aRunningJob['resource']) && !empty($aRunningJob['path']))
+                $oFmeServer->serviceRequest('resources/connections/' . $aRunningJob['resource'] . '/filesys/' . $aRunningJob['path'], 'delete');
+        }
+    }
+}
+
+/**
+ * Traitement d'une demande sur Fme Server.
+ * @param {string} $sServerUrl Url to Fme Server.
+ * @param {string} $sLogin User login.
+ * @param {string} $sPassword User password.
+ * return boolean
+ */
+function processFmeServerOrder($sServerUrl, $sLogin, $sPassword) {
+    // Variables globales utilisées.
+    global $oFmeServer, $properties, $oBd, $aFmeEngine, $aDemande, $aTraitement, $aUser, $iEmailTemplateId, $bAsync, $sEnErreur, $iTentative, $sDateDebut, $sDateFin;
+    // Variables globales modifiées.
+    global $oTraitement, $sMessage, $bValidFmeLicence, $sResultat, $sLogFme, $iStatut, $sLienLogFme;
+    // Paramètres de connexion vers Fme Server pour la demande (si elle est dans la liste des traitements asynchrones en cours).
+    $aRunningJobs = getFmeServerRunningJobs();
+    $aRunningJob = getFmeServerRunningJob($aDemande['order_id'], $aRunningJobs);
+    if ($aRunningJob !== false) {
+        $sServerUrl = $aRunningJob['fme_server_url'];
+        $sLogin = $aRunningJob['login'];
+        $sPassword = $aRunningJob['password'];
+    }
+    // 
+    $oFmeServer = new FmeServer($sServerUrl, $sLogin, $sPassword, 'day', 1);
+    $oFmeServer->sLogFilePath = $properties["engine_log_file"];
+    $sMessage = '';
+    // Statut de la licence Fme Server (pas pour Fme Cloud).
+    $oLicenseStatus = '';
+    if ($aFmeEngine['fme_engine_type_id'] == 'fme_server')
+        $oLicenseStatus = $oFmeServer->serviceRequest('licensing/license/status');
+    if ($oLicenseStatus === false)
+        return false;
+    else if ($aFmeEngine['fme_engine_type_id'] == 'fme_cloud' || (!empty($oLicenseStatus) && $oLicenseStatus->isLicensed === true && $oLicenseStatus->isLicenseExpired === false)) {
+        $bValidFmeLicence = true;
+        $oTraitement = new Traitement($oBd, $aDemande['order_id'], $properties["engine_log_file"], $aDemande['wk_params'], $properties, $aDemande['workspace_id'] . "/fme/" . $aTraitement['fmw_file']);
+        $oTraitement->bFmeServer = true;
+        // Demande suivante si le traitement est déja en cours d'exécution.
+        if ($aRunningJob !== false) {
+            // Chemin et nom du répertoire de résultat déja crée.
+            $oTraitement->sResultDirectoryName = $aRunningJob['result_directory_name'];
+            $oTraitement->sResultDirectoryPath = $aRunningJob['result_directory_path'];
+            // Vérification du statut de la demande.
+            $oJobRecord = $oTraitement->getFmeServerJobRecord($aRunningJob['job_id'], $oFmeServer);
+            // Si le job id n'existe pas : 2 essais puis suppression de la demande dans la liste des traitements asynchrones en cours -> non traitable.
+            if ($oFmeServer->aLastCurlRequestInfo['http_code'] == 404) {
+                if ($iTentative >= $properties["max_attempt"])
+                    removeFmeServerRunningJob($aDemande['order_id']);
+            }
+            if ($oJobRecord === false) {
+                return false;
+            }
+            $oTraitement->oJobResult = $oJobRecord;
+            $aRunningStatus = array('SUBMITTED', 'QUEUED', 'DELAYED', 'PAUSED', 'IN_PROCESS', 'PULLED');
+            $aErrorStatus = array('DELETED', 'ABORTED', 'FME_FAILURE', 'JOB_FAILURE');
+            writeToLog(INFO_FME_SERVER_JOB_STATUS . $oJobRecord->status, $properties["engine_log_file"]);
+            // En cours de traitement.
+            if (in_array($oJobRecord->status, $aRunningStatus)) {
+                writeToLog(INFO_FME_SERVER_ASYNCHRONOUS_JOB_IN_PROGRESS, $properties["engine_log_file"]);
+                // Nombre de tentative = 0 (traitement en cours d'exécution).
+                updateOrderAttempt($aDemande["order_id"], 0);
+                return false;
+            }
+            else {
+                // Supprime la demande dans la liste des traitements asynchrones en cours.
+                removeFmeServerRunningJob($aDemande['order_id']);
+                // Télécharge les fichiers de log (et le résultat si présent).
+                $sResultat = $oTraitement->downloadFmeServerJobResult($aRunningJob['job_id'], $oFmeServer, $aRunningJob['destination_files'], $aRunningJob['resource'], $aRunningJob['path']);
+                $oDateDebut = date_create($oJobRecord->timeStarted);
+                $oDateFin = date_create($oJobRecord->timeFinished);
+                // Terminé en erreur.
+                if (in_array($oJobRecord->status, $aErrorStatus) || $sResultat === false) {
+                    updateOrder($aDemande["order_id"], 2, $oJobRecord->timeStarted, $oTraitement->sLogFme, date_diff($oDateDebut, $oDateFin)->format('%s'));
+                    sendWebsocketOrderStatusMessage('order_finished_or_error', 2);
+                    // Envoi d'un mail de résultat.
+                    sendOrderResultEmail($iEmailTemplateId);
+                    // Ecriture dans les log.
+                    writeToLog(INFO_TREATMENT_FAILURE, $oTraitement->sRobotLogFile);
+                    // Demande suivante.
+                    return false;
+                }
+                else if ($oJobRecord->status == 'SUCCESS') {
+                    $iStatut = 3;
+                    $sLogFme = $oTraitement->sLogFme;
+                }
+            }
+        }
+        else {
+            $oTraitement->setUseExternalDbConnection($aFmeEngine['useexternaldbconnection']);
+            $sResultat = $oTraitement->submitFmeServerJob($oFmeServer, $aDemande, $aTraitement, $aUser, null, $bAsync);
+            if ($bAsync) {
+                $iStatut = 5;
+                addFmeServerRunningJob($oTraitement, $sServerUrl, $sLogin, $sPassword);
+                writeToLog(INFO_FME_SERVER_JOB_ID . $oTraitement->oJobResult->id, $properties["engine_log_file"]);
+                // Nombre de tentative = 0 (traitement en cours d'exécution).
+                updateOrderAttempt($aDemande["order_id"], 0);
+                // Demande suivante.
+                return false;
+            }
+            else {
+                // Erreur retournée par FME Server.
+                if ($sResultat === false) {
+                    updateOrder($aDemande["order_id"], 2, gmdate('Y-m-d H:i:s'), $oTraitement->sLogFme);
+                    sendWebsocketOrderStatusMessage('order_finished_or_error', 2);
+                    writeToLog(INFO_TREATMENT_FAILURE, $oTraitement->sRobotLogFile);
+                    // Envoi d'un mail de résultat.
+                    sendOrderResultEmail($iEmailTemplateId);
+                    // Demande suivante.
+                    return false;
+                }
+                //$sDateFin = new DateTime(date("Y-m-d H:i:s"));
+                $sLogFme = $oTraitement->sLogFme;
+            }
+        }
+        // http 200 : $oFmeServer->aLastCurlRequestInfo['http_code']
+        $sDateDebut = $oJobRecord->timeStarted;
+        $sDateFin = $oJobRecord->timeFinished;
+        if ($oTraitement->oJobResult->status == 'SUCCESS') {
+            $iStatut = 3;
+            $sLienLogFme = $sLogFme;
+        }
+        else
+            $iStatut = $sEnErreur;
+    }
+    else {
+        // Erreur dans la vérification du statut de la licence FME ou expiration.
+        if ($oLicenseStatus->isLicenseExpired)
+            $ErrorMessage = INFO_FME_SERVER_EXPIRED_LICENCE;
+        else
+            $ErrorMessage = INFO_LICENCE_STATUS_VERIFICATION_ERROR;
+        writeToLog($ErrorMessage, $properties["engine_log_file"]);
+        writeToLog(INFO_CONTACT_ADMINISTRATOR, $properties["engine_log_file"]);
+        updateOrder($aDemande["order_id"], 2, gmdate('Y-m-d H:i:s'));
+        sendWebsocketOrderStatusMessage('order_finished_or_error', 2);
+        // Envoi d'un mail de résultat.
+        if ($oLicenseStatus->isLicenseExpired === true)
+            $sMessage = 'Invalid FME licence file';
+        sendOrderResultEmail($iEmailTemplateId, $sMessage);
+        // Demande suivante.
+        return false;
+    }
+}
+
+/**
+ * Mise à jour du processus ou job id d'une demande.
+ * @param {number} $iOrderId Id de la demande.
+ * @param {number} $iPid Id du processus (ou job id) de la demande.
+ */
+function updateOrderPid($iOrderId, $iPid = null) {
+    // Variables globales.
+    global $oBd, $properties, $aSql;
+    // Requete d'update de la demande.
+    $aParams = array();
+    $aParams['sSchemaGtf'] = array('value' => $properties['schema_gtf'], 'type' => 'schema_name');
+    $aParams['iOrderId'] = array('value' => $iOrderId, 'type' => 'number');
+    $aParams['iPid'] = array('value' => $iPid, 'type' => 'number');
+    $oBd->executeWithParams($aSql[$properties['sgbd']]['update_order_pid'], $aParams);
+    if ($oBd->erreurRencontree)
+        writeToLog(INFO_ORDER_PID_UPDATE_ERROR . "(SQL : {$aSql[$properties['sgbd']]['update_order_pid']})", $properties['engine_log_file']);
+}
+
+/**
+ * Supprime tous les traitements sur Fme Server dont la demande a été supprimée dans GTF.
+ */
+/*
+function removeFmeServerDeletedJobs() {
+    // Variables globales.
+    global $properties, $oBd, $aSql;
+    // Requete d'update de la demande.
+    $aParams = array();
+    $aParams['sSchemaGtf'] = array('value' => $properties['schema_gtf'], 'type' => 'schema_name');
+    $oPDOResult = $oBd->executeWithParams($aSql[$properties['sgbd']]['getRunningOrders'], $aParams);
+    if ($oBd->erreurRencontree)
+        writeToLog(INFO_RUNNING_JOBS_ERROR . "(SQL : {$aSql[$properties['sgbd']]['getRunningOrders']})", $properties['engine_log_file']);
+    else {
+        $aOrders = array();
+        while ($aOrder = $oBd->ligneSuivante($oPDOResult))
+            $aOrders[] = $aOrder['order_id'];
+        // Liste des demandes asynchrones en cours.
+        $aRunningJobs = getFmeServerRunningJobs();
+        foreach ($aRunningJobs as $iIndex => $aRunningJob) {
+           if (!in_array($aRunningJob['order_id'], $aOrders)) {
+                $oFmeServer = null;
+                // Supprime le traitement sur Fme Server.
+                if (!empty($aRunningJob['job_id'])) {
+                    $oFmeServer = new FmeServer($aRunningJob['fme_server_url'], $aRunningJob['login'], $aRunningJob['password'], 'day', 1);
+                    $oFmeServer->sLogFilePath = $properties["engine_log_file"];
+                    // Statut de la licence Fme Server (pas pour Fme Cloud).
+                    if ($aRunningJob['fme_engine_type_id'] == 'fme_server') {
+                        $oLicenseStatus = $oFmeServer->serviceRequest('licensing/license/status');
+                        if ($oLicenseStatus === false)
+                            $oFmeServer = null;
+                        else if (is_object($oLicenseStatus) && ($oLicenseStatus->isLicensed === false || $oLicenseStatus->isLicenseExpired === true))
+                            $oFmeServer = null;
+                    }
+                }
+                // Supprime le traitement sur Fme Server.
+                removeFmeServerRunningJob($aRunningJob['order_id'], $oFmeServer);
+            }
+        }
+    }
+}
+*/
 ?>
diff --git a/gtf.engine/gtf.engines/engine.sql.inc b/gtf.engine/gtf.engines/engine.sql.inc
index 9238c05f..24039bdf 100755
--- a/gtf.engine/gtf.engines/engine.sql.inc
+++ b/gtf.engine/gtf.engines/engine.sql.inc
@@ -1,7 +1,7 @@
 <?php
 //Requête pour engine.php pgsql
-$aSql['pgsql']['boucle_1']='SELECT "order".*, rt_priority.priority_id, rt_priority.label_id as priorite_libelle_id, workspace.name as workspace_nom FROM ([sSchemaGtf]."order" LEFT JOIN [sSchemaGtf].rt_priority ON "order".priority_id = rt_priority.priority_id) LEFT JOIN [sSchemaGtf].workspace ON "order".workspace_id=workspace.workspace_id WHERE (order_status_id = 1 or order_status_id = 5) AND "order".period_id IS NULL AND "order".deleted IS not TRUE AND "order".gtf_engine_id=[iIdGtfEngine] AND "order".priority_id >= [iPriorityId] ORDER BY "order".priority_id ASC, "order".order_id ASC LIMIT [iNnbrOrderMax]';
-$aSql['pgsql']['boucle_2']='SELECT "order".*, rt_priority.priority_id, rt_priority.label_id as priorite_libelle_id, workspace.name as workspace_nom FROM ([sSchemaGtf]."order" LEFT JOIN [sSchemaGtf].rt_priority ON "order".priority_id = rt_priority.priority_id) LEFT JOIN [sSchemaGtf].workspace ON "order".workspace_id=workspace.workspace_id WHERE (order_status_id = 1 or order_status_id = 5) AND "order".period_id IS NULL AND "order".deleted IS not TRUE AND "order".gtf_engine_id=[iIdGtfEngine] AND "order".priority_id >  [iPriorityId] ORDER BY "order".priority_id ASC, "order".order_id ASC LIMIT [iNnbrOrderMax]';
+$aSql['pgsql']['boucle_1']='SELECT "order".*, rt_priority.priority_id, rt_priority.label_id as priorite_libelle_id, workspace.name as workspace_nom FROM ([sSchemaGtf]."order" LEFT JOIN [sSchemaGtf].rt_priority ON "order".priority_id = rt_priority.priority_id) LEFT JOIN [sSchemaGtf].workspace ON "order".workspace_id=workspace.workspace_id WHERE (order_status_id = 1 or order_status_id = 5) AND "order".period_id IS NULL AND "order".deleted IS not TRUE AND "order".gtf_engine_id=[iIdGtfEngine] AND "order".priority_id >= [iPriorityId] AND (minexecdate IS NULL or minexecdate AT TIME ZONE [sTimeZone] <=now() AT TIME ZONE [sTimeZone]) ORDER BY "order".priority_id ASC, "order".order_id ASC LIMIT [iNnbrOrderMax]';
+$aSql['pgsql']['boucle_2']='SELECT "order".*, rt_priority.priority_id, rt_priority.label_id as priorite_libelle_id, workspace.name as workspace_nom FROM ([sSchemaGtf]."order" LEFT JOIN [sSchemaGtf].rt_priority ON "order".priority_id = rt_priority.priority_id) LEFT JOIN [sSchemaGtf].workspace ON "order".workspace_id=workspace.workspace_id WHERE (order_status_id = 1 or order_status_id = 5) AND "order".period_id IS NULL AND "order".deleted IS not TRUE AND "order".gtf_engine_id=[iIdGtfEngine] AND "order".priority_id >  [iPriorityId] AND (minexecdate IS NULL or minexecdate AT TIME ZONE [sTimeZone] <=now() AT TIME ZONE [sTimeZone]) ORDER BY "order".priority_id ASC, "order".order_id ASC LIMIT [iNnbrOrderMax]';
 $aSql['pgsql']['right_user']='SELECT workspace."workspace_id" FROM [sSchemaGtf].workspace RIGHT JOIN [sSchemaGtf].workspace_group ON workspace.workspace_id = workspace_group.workspace_id  GROUP BY workspace."workspace_id", workspace_group."group_id" HAVING workspace_group."group_id" IN ([sGroupListId]) ORDER BY workspace."workspace_id" ASC';
 $aSql['pgsql']['update_demande']="UPDATE [sSchemaGtf].order SET length_sec = [iNbSec], order_status_id=[iStatut], execution_date=[sDateTraitement], result_url=[sResultat], log_url=[sLogFme] WHERE order_id=[iOrderId]";
 $aSql['pgsql']['update_demande_resultat_null']="UPDATE [sSchemaGtf].order SET result_url=NULL WHERE order_id=[iOrderId]";
@@ -9,10 +9,12 @@ $aSql['pgsql']['select_user']='SELECT * FROM [sSchemaFramework].user WHERE "user
 $aSql['pgsql']['select_traitement']='SELECT * FROM [sSchemaGtf].workspace WHERE workspace_id=[iWorkspaceId]';
 //$aSql['pgsql']['select_transit_dir']='SELECT value FROM [sSchemaGtf].property WHERE property=\'$properties["transit_dir"]\'';
 $aSql['pgsql']['select_fme_path']='select local_path as fme_path from [sSchemaGtf].gtf_engine, [sSchemaGtf].fme_engine where fme_engine.fme_engine_id = gtf_engine.fme_engine_id AND gtf_engine.gtf_engine_id = [gtf_engine_id]';
-$aSql['pgsql']['update_message']="UPDATE [sSchemaGtf].message SET status=1 WHERE order_id=[iOrderId]";
+$aSql['pgsql']['update_message']="UPDATE [sSchemaGtf].message SET status=[status] WHERE order_id=[iOrderId]";
 $aSql['pgsql']['delete_message']="DELETE FROM [sSchemaGtf].message where order_id=[iOrderId]";
 $aSql['pgsql']['get_gtf_engine_name'] = 'SELECT gtf_engine.name AS gtf_engine_name,fme_engine.name AS fme_engine_name FROM [sSchemaGtf].gtf_engine,[sSchemaGtf].fme_engine WHERE gtf_engine.fme_engine_id=fme_engine.fme_engine_id AND gtf_engine_id=[gtf_engine_id]';
 $aSql['pgsql']["getLogin"] = 'SELECT "login" from [sSchemaFramework]."user" where user_id = [iUserId]';
 $aSql['pgsql']["insertJob"] = 'INSERT INTO [sSchemaGtf].job(order_id, workspace_id, "user_id", execution_date, length_sec, engine_id, order_status_id) VALUES ([iOrderId], [iWorkspaceId], [iUserId], [sBeginExecutionDate] , [iDelay], [iGtfEngineId], [iStatut])';
 $aSql['pgsql']["getFmeEngine"] = 'SELECT * from [sSchemaGtf].fme_engine WHERE fme_engine_id = (SELECT fme_engine_id FROM [sSchemaGtf].gtf_engine WHERE gtf_engine_id = [gtf_engine_id])';
+$aSql['pgsql']['update_order_pid']="UPDATE [sSchemaGtf].order SET pid=[iPid] WHERE order_id=[iOrderId]";
+$aSql['pgsql']['getRunningOrders'] = 'SELECT order_id FROM [sSchemaGtf]."order" WHERE order_status_id IN (1, 5)';
 ?>
diff --git a/gtf.engine/gtf.engines/lang_engines/fr-lang.inc b/gtf.engine/gtf.engines/lang_engines/fr-lang.inc
index 7d5d5046..7b0356cd 100755
--- a/gtf.engine/gtf.engines/lang_engines/fr-lang.inc
+++ b/gtf.engine/gtf.engines/lang_engines/fr-lang.inc
@@ -1,8 +1,8 @@
 <?php
 
 //Error Licence
-define('E001', "Demandes non trait�es : Fichier de licence invalide");
-define('E002', "Demandes non trait�es : Fichier de licence expir�");
-define('E003', "Demandes non trait�es : Num�ro du moteur GTF sup�rieur au nombre de moteurs disponibles");
+define('E001', "Demandes non traitées : Fichier de licence invalide");
+define('E002', "Demandes non traitées : Fichier de licence expiré");
+define('E003', "Demandes non traitées : Numéro du moteur GTF supérieur au nombre de moteurs disponibles");
 
 ?>
\ No newline at end of file
diff --git a/gtf.engine/gtf.engines/licenses/license.txt b/gtf.engine/gtf.engines/licenses/license.txt
deleted file mode 100755
index 3c36fb54..00000000
--- a/gtf.engine/gtf.engines/licenses/license.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-#GTF  License file
-Product: GTF
-License number: Sgtf-0001
-Expiry date: Permanent
-Engines: 5
-Owner: Veremes
-Key: 295C919B 5A83DA4D 23CC819F 68CB7E3A A41BB54F 
\ No newline at end of file
diff --git a/gtf.engine/gtf.engines/php_engine_conf.inc b/gtf.engine/gtf.engines/php_engine_conf.inc
index f43c4cc8..6985372b 100755
--- a/gtf.engine/gtf.engines/php_engine_conf.inc
+++ b/gtf.engine/gtf.engines/php_engine_conf.inc
@@ -1,4 +1,4 @@
 <?php
-set_include_path('C:\svn\gtf_next_version\gtf.engines;C:\svn\vitis_next_version\vas\rest\conf;C:\svn\vitis_next_version\vas\rest\class');
-ini_set ('error_log', 'C:/svn/gtf_next_version/gtf.engines/php/log/php_errors.log');
+set_include_path(dirname($_SERVER["PHP_SELF"]). PATH_SEPARATOR .dirname($_SERVER["PHP_SELF"]).'/../vas/rest/conf'. PATH_SEPARATOR .dirname($_SERVER["PHP_SELF"]).'/../vas/rest/class');
+ini_set ('error_log', dirname($_SERVER["PHP_SELF"]).'/php/log/php.log');
 ?>
\ No newline at end of file
diff --git a/gtf.engine/gtf.engines/string.inc b/gtf.engine/gtf.engines/string.inc
index 26ffca30..6a6a266f 100755
--- a/gtf.engine/gtf.engines/string.inc
+++ b/gtf.engine/gtf.engines/string.inc
@@ -39,6 +39,10 @@
 	define('INFO_GTF_HOME', '|INFORM|PHP| GTF_HOME=');
 	define('INFO_FME_PATH', '|INFORM|PHP| FME_PATH=');
 	define('INFO_TREATMENT_COMMAND_LINE', '|INFORM|PHP| Ligne de commande exécutant le traitement : ');
+	define('INFO_NO_USE_PATTERN', '|INFORM|PHP| Utilisation des noms de fichier, sans utilisation des motifs');
+	define('INFO_USE_PATTERN', '|INFORM|PHP|  Utilisation des motifs ');
+	define('INFO_USER_RESTRICTION', '|ERROR|PHP| Impossible de récupérer la paramètre "restriction" de l\'utilisateur.');
+	define('INFO_GTF_CONNECTION_STRING_TYPE_PASSWORD', '|WARNING|PHP| Le paramètre "GTF_CONNECTION_STRING" doit-être de type "PASSWORD".');
 	
 // engine.php
 	define('INFO_BASE_CONNECTION', '|INFORM|PHP| Connexion à la base de données ');
@@ -54,4 +58,20 @@
 	define('INFO_TEST_REQUEST_ERROR', '|ERROR|PHP|Requête test en erreur. ');
 	define('INFO_INFO_ORDER_UPDATE_NULL', '|INFORM|PHP| Mise à jour de la demande (resultat null).');
 	define('INFO_NO_MAIL_SEND', "|INFORM|PHP| Aucun mail n'a été envoyé ");
+	define('INFO_NO_ASSOCIATED_USER', "|INFORM|PHP| La demande [aDemande['order_id']] n'a pas été traitée car aucun utilisateur est associé.");
+	define('INFO_USER_ENCRYPT_PARAMETERS', '|ERROR|PHP| Impossible de récupérer les paramètres de cryptage de l\'utilisateur et du projet.');
+	define('INFO_NO_FME_CLOUD_INSTANCES', '|ERROR|PHP| Aucune instance FME Server sur FME Cloud n\'est active.');
+	define('INFO_LICENCE_STATUS_VERIFICATION_ERROR', '|ERROR|PHP| Erreur dans la vérification du statut de la licence FME.');
+	define('INFO_FME_CLOUD_INSTANCE_NOT_FOUND', '|ERROR|PHP| L\'instance FME Server spécifiée sur FME Cloud n\'existe pas.');
+	define('INFO_FME_SERVER_JOB_IN_PROGRESS', '|INFORM|PHP| La demande est en cours de traitement par Fme Server.');
+	define('INFO_FME_SERVER_JOB_STATUS', '|INFORM|PHP| Statut de la demande asynchrone sur Fme Server : ');
+	define('INFO_FME_SERVER_JOB_ID', '|INFORM|PHP| Job id pour la demande asynchrone sur Fme Server : ');
+	define('INFO_FME_SERVER_ASYNCHRONOUS_JOB_IN_PROGRESS', '|INFORM|PHP| La demande asynchrone est en cours de traitement par Fme Server.');
+	define('INFO_LAUNCHING_FME_CLOUD_INSTANCE', '|INFORM|PHP| L\'instance FME Server sur FME Cloud est en cours de démarrage.');
+	define('INFO_FME_CLOUD_INSTANCE_STATUS', '|INFORM|PHP| Statut de l\'instance FME Server sur FME Cloud : ');
+	define('INFO_FME_CLOUD_INSTANCE_RUNNING', '|INFORM|PHP| L\'instance FME Server sur FME Cloud est opérationnelle');
+	define('INFO_FME_SERVER_EXPIRED_LICENCE', '|INFORM|PHP| La licence de Fme Server a expiré.');
+	define('INFO_ORDER_PID_UPDATE_ERROR', '|ERROR|PHP| Impossible de mettre à jour le pid de la demande. ');
+	define('INFO_FME_SERVER_ASYNCHRONOUS_JOB_REMOVED_FROM_LIST', '|INFORM|PHP| Le traitement a été retirée de la liste des traitements asynchrones en cours');
+	define('INFO_RUNNING_JOBS_ERROR', '|ERROR|PHP| Impossible de récupérer la liste des demandes en attente et en cours.');
 ?>
\ No newline at end of file
diff --git a/gtf.engine/gtf.engines/subscription.php b/gtf.engine/gtf.engines/subscription.php
index 68d50061..a6caaae0 100755
--- a/gtf.engine/gtf.engines/subscription.php
+++ b/gtf.engine/gtf.engines/subscription.php
@@ -41,7 +41,7 @@ require_once 'string.inc';
   }
  */
 //Pas besoin de mot de passe pour le robot
-$oBd = new Vm($properties["login"], '', $properties["database"], $properties["server"], $properties["port"], $properties["sgbd"], $properties["page_encoding"]);
+$oBd = new Vm($properties["login_scheduler"], $properties['password_scheduler'], $properties["database"], $properties["server"], $properties["port"], $properties["sgbd"], $properties["page_encoding"]);
 if ($oBd->erreurRencontree) {
     writeToLog(INFO_BASE_CONNECTION_ERROR . $properties["database"], $properties["subscription_log_file"]);
 } else {
@@ -199,7 +199,7 @@ if ($oBd->erreurRencontree) {
                         //deplacement vers le dossier upload en fonction du type
                         $bCopie = false;
                         $bIsFile = false;
-                        $sUnique = UniqFileName();
+                        $sUnique = getUniqRandomId();
                         if (is_dir($sFolder . '/' . $Entry)) {
                             $bIsFile = false;
                             $bCopie = rename($sFolder . "/" . $Entry, $properties["upload_dir"] . "/" . $sUnique);
-- 
GitLab