diff --git a/core/module/config/config.php b/core/module/config/config.php index 85f34738..5036f1de 100755 --- a/core/module/config/config.php +++ b/core/module/config/config.php @@ -29,9 +29,14 @@ class config extends common { 'logReset' => self::GROUP_ADMIN, 'logDownload'=> self::GROUP_ADMIN, 'blacklistReset' => self::GROUP_ADMIN, - 'blacklistDownload' => self::GROUP_ADMIN + 'blacklistDownload' => self::GROUP_ADMIN, + 'modules' => self::GROUP_ADMIN, + 'moduleDelete' => self::GROUP_ADMIN ]; + + public static $modInstal = []; + public static $str; public static $timezones = [ 'Pacific/Midway' => '(GMT-11:00) Midway Island', @@ -579,9 +584,10 @@ class config extends common { // Générer robots.txt et sitemap $this->generateFiles(); // Valeurs en sortie + $notification = $notification . 'Modifications enregistrées'; $this->addOutput([ 'redirect' => helper::baseUrl() . $this->getUrl(), - 'notification' => 'Modifications enregistrées', + 'notification' => $notification, 'state' => $success ]); } @@ -591,7 +597,216 @@ class config extends common { 'view' => 'advanced' ]); } - + + /* + * Installation de modules à partir d'un zip normalisé + * Affichage des modules installés + */ + public function modules() { + + // Préparation du tableau des modules installés + // Liste des modules installés (répertoire de module/) + if ($dh = opendir( 'module/' )) { + $i=0; + while (($dirmodule = readdir($dh)) !== false) { + if( $dirmodule !== '.' && $dirmodule !== '..'){ + self::$modInstal[$i][0] = $dirmodule; + self::$modInstal[$i][1] = page::$moduleNames[$dirmodule]; + // Lecture de la version pour les modules officiels et distribués + $blogversion = blog::BLOG_VERSION; + $formversion = form::FORM_VERSION; + $galleryversion = gallery::GALLERY_VERSION; + $newsversion = news::NEWS_VERSION; + $redirectionversion = redirection::REDIRECTION_VERSION; + $searchversion = search::SEARCH_VERSION; + self::$str = $dirmodule.'version'; + self::$modInstal[$i][2] = '?'; + if( ${self::$str} !== null){ + self::$modInstal[$i][2] = ${self::$str}; + } + // Lecture de la version pour les modules non distribués + elseif($this->getData(['module', '_gestion_modules_' , $dirmodule, 'version' ]) !== null){ + self::$modInstal[$i][2] = $this->getData(['module', '_gestion_modules_' , $dirmodule, 'version' ]); + } + self::$modInstal[$i][3] = 'non'; + self::$modInstal[$i][4] = ''; + self::$modInstal[$i][5] = ''; + $i++; + } + } + closedir($dh); + } + // Module utilisé ? + $nb = count(self::$modInstal); + for ($i = 0; $i < $nb; $i++) { + foreach( $this->getData(['page']) as $keyPage=>$valuePage){ + if( $valuePage['moduleId'] === self::$modInstal[$i][0]){ + self::$modInstal[$i][3] = 'oui'; + if(self::$modInstal[$i][4] !==''){ + self::$modInstal[$i][4] = self::$modInstal[$i][4].'
'.$valuePage['title']; + } + else{ + self::$modInstal[$i][4] = $valuePage['title']; + } + } + } + $modulesDistrib = array('blog', 'form', 'gallery', 'news', 'redirection', 'search'); + if( self::$modInstal[$i][4] =='' && array_search( self::$modInstal[$i][0], $modulesDistrib ) === false + && $this->getData(['module', '_gestion_modules_', self::$modInstal[$i][0], 'delete' ]) === true){ + self::$modInstal[$i][5] = template::button('moduleDelete' . self::$modInstal[$i][0], [ + 'class' => 'moduleDelete buttonRed', + 'href' => helper::baseUrl() . $this->getUrl(0) . '/moduleDelete/' . self::$modInstal[$i][0] . '/' . $_SESSION['csrf'], + 'value' => template::ico('cancel') + ]); + + } + } + + // Retour du formulaire ? + if($this->isPost()) { + // Installation d'un module + $success = true; + $checkValidMaj = $this->getInput('configModulesCheck', helper::FILTER_BOOLEAN); + $zipFilename = $this->getInput('configModulesInstallation', helper::FILTER_STRING_SHORT); + if( $zipFilename !== ''){ + $tempFolder = uniqid(); + $zip = new ZipArchive(); + if ($zip->open(self::FILE_DIR.'source/'.$zipFilename) === TRUE) { + $notification = 'Archive ouverte'; + mkdir (self::TEMP_DIR . $tempFolder); + $zip->extractTo(self::TEMP_DIR . $tempFolder ); + // Archive de module ? + $success = false; + $notification = 'Ce n\'est pas l\'archive d\'un module !'; + $moduleDir = self::TEMP_DIR . $tempFolder . '/module'; + $moduleName = ''; + if ( is_dir( $moduleDir )) { + // Lire le nom du module + if ($dh = opendir( $moduleDir )) { + while (($file = readdir($dh)) !== false) { + $moduleName = $file; + } + closedir($dh); + } + // Module normalisé ? + if( is_file( $moduleDir.'/'.$moduleName.'/'.$moduleName.'.php' ) AND is_file( $moduleDir.'/'.$moduleName.'/view/index/index.php' ) ){ + + // Lecture de info.json et mémorisation des 3 paramètres version, update et delete + $version = '?'; + $update = '?'; + $delete = false; + if( is_file( $moduleDir.'/'.$moduleName.'/info/info.json' )){ + $json = file_get_contents( $moduleDir.'/'.$moduleName.'/info/info.json' ); + $param = json_decode( $json, true); + if( $param['module'] === $moduleName && is_bool($param['update']) && is_bool($param['update'])){ + $version = $param['version']; + $update = $param['update']; + $delete = $param['delete']; + } + } + $this->setData(['module','_gestion_modules_',$moduleName, 'version', $version]); + $this->setData(['module','_gestion_modules_',$moduleName, 'update', $update]); + $this->setData(['module','_gestion_modules_',$moduleName, 'delete', $delete]); + + // Module déjà installé ? + $moduleInstal = false; + foreach( self::$modInstal as $key=>$value){ + if($moduleName === $value[0]){ + if( $value[3] !== 'non'){ + $notification = 'Module déjà installé et utilisé page '.$value[4]; + } + else{ + $notification = 'Module déjà installé et non utilisé'; + } + $moduleInstal = true; + } + } + $validMaj = $checkValidMaj; + if(is_bool($update)){ + $validMaj = $checkValidMaj && $update; + } + + // Nouvelle installation ou mise à jour du module avec validation du concepteur et validation de l'utilisateur + if( ! $moduleInstal || ( $moduleInstal && $validMaj )){ + // Copie récursive des dossiers + $this -> custom_copy( self::TEMP_DIR . $tempFolder, './' ); + $success = true; + if( ! $moduleInstal ){ + $notification = 'Module '.$moduleName.' installé'; + } + else{ + $notification = 'Module '.$moduleName.' mis à jour'; + } + } + else{ + $success = false; + $notification = ' Vous devez cocher la case "Valider la mise à jour d\'un module déjà installé"'; + if( $update === false){ + $notification = ' Mise à jour par ce procédé interdite par le concepteur du module'; + } + } + } + } + // Supprimer le dossier temporaire même si le module est invalide + $this->removeDir(self::TEMP_DIR . $tempFolder); + $zip->close(); + } else { + // erreur à l'ouverture + $success = false; + $notification = 'Impossible d\'ouvrir l\'archive'; + } + } + + $this->addOutput([ + 'redirect' => helper::baseUrl() . $this->getUrl(), + 'notification' => $notification, + 'state' => $success + ]); + } + // Valeurs en sortie + $this->addOutput([ + 'title' => 'Gestion des modules', + 'view' => 'modules' + ]); + } + + /* + * + * Effacement d'un module installé et non utilisé + */ + public function moduleDelete() { + + // Jeton incorrect + if ($this->getUrl(3) !== $_SESSION['csrf']) { + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . 'config/modules', + 'state' => false, + 'notification' => 'Action non autorisée' + ]); + } + else{ + // suppression de la clef version du module + $this->deleteData(['module', '_gestion_modules_', $this->getUrl(2)]); + // Suppression des dossiers + if( $this->delete_directory('./module/'.$this->getUrl(2)) === true){ + $success = true; + $notification = 'Module '.$this->getUrl(2) .' effacé du dossier /module/, il peut rester des données dans d\'autres dossiers'; + } + else{ + $success = false; + $notification = 'La suppression a échouée'; + } + // Valeurs en sortie + $this->addOutput([ + 'redirect' => helper::baseUrl() . 'config/modules', + 'notification' => $notification, + 'state' => $success + ]); + } + } + + public function script() { // Soumission du formulaire if($this->isPost()) { @@ -812,5 +1027,65 @@ class config extends common { } return $newArray; } + + + /* + * Copie récursive de dossiers + * + */ + private function custom_copy($src, $dst) { + // open the source directory + $dir = opendir($src); + // Make the destination directory if not exist + @mkdir($dst); + // Loop through the files in source directory + while( $file = readdir($dir) ) { + if (( $file != '.' ) && ( $file != '..' )) { + if ( is_dir($src . '/' . $file) ){ + // Recursively calling custom copy function + // for sub directory + $this -> custom_copy($src . '/' . $file, $dst . '/' . $file); + } + else { + copy($src . '/' . $file, $dst . '/' . $file); + } + } + } + closedir($dir); + } + + /* + * + * Suppression d'un dossier et de ses sous-dossiers + */ + private function delete_directory($directory, $empty = false) { + if(substr($directory,-1) == "/") { + $directory = substr($directory,0,-1); + } + if(!file_exists($directory) || !is_dir($directory)) { + return false; + } elseif(!is_readable($directory)) { + return false; + } else { + $directoryHandle = opendir($directory); + while ($contents = readdir($directoryHandle)) { + if($contents != '.' && $contents != '..') { + $path = $directory . "/" . $contents; + if(is_dir($path)) { + $this->delete_directory($path); + } else { + unlink($path); + } + } + } + closedir($directoryHandle); + if($empty == false) { + if(!rmdir($directory)) { + return false; + } + } + return true; + } + } } diff --git a/core/module/config/view/advanced/advanced.php b/core/module/config/view/advanced/advanced.php index 06718e43..0d11fe06 100644 --- a/core/module/config/view/advanced/advanced.php +++ b/core/module/config/view/advanced/advanced.php @@ -504,4 +504,5 @@ + diff --git a/core/module/config/view/index/index.php b/core/module/config/view/index/index.php index 42b8b8ae..0985a251 100755 --- a/core/module/config/view/index/index.php +++ b/core/module/config/view/index/index.php @@ -8,7 +8,14 @@ 'value' => 'Accueil' ]); ?> -
+
+ helper::baseUrl() . 'config/modules', + 'value' => 'Modules', + 'ico' => 'download', + ]); ?> +
+
helper::baseUrl() . 'config/advanced', 'value' => 'Avancée', diff --git a/core/module/config/view/modules/modules.css b/core/module/config/view/modules/modules.css new file mode 100644 index 00000000..805e9150 --- /dev/null +++ b/core/module/config/view/modules/modules.css @@ -0,0 +1,18 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + + +/** NE PAS EFFACER +* admin.css +*/ \ No newline at end of file diff --git a/core/module/config/view/modules/modules.js.php b/core/module/config/view/modules/modules.js.php new file mode 100644 index 00000000..222b85a1 --- /dev/null +++ b/core/module/config/view/modules/modules.js.php @@ -0,0 +1,21 @@ +/** + * This file is part of Zwii. + * + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @license GNU General Public License, version 3 + * @link http://zwiicms.fr/ + */ + +/** + * Confirmation de suppression + */ +$(".moduleDelete").on("click", function() { + var _this = $(this); + return core.confirm("Êtes-vous sûr de vouloir supprimer, effacer ce module ?", function() { + $(location).attr("href", _this.attr("href")); + }); +}); \ No newline at end of file diff --git a/core/module/config/view/modules/modules.php b/core/module/config/view/modules/modules.php new file mode 100644 index 00000000..9ffe9b65 --- /dev/null +++ b/core/module/config/view/modules/modules.php @@ -0,0 +1,48 @@ + +
+
+ 'buttonGrey', + 'href' => helper::baseUrl() . 'config', + 'ico' => 'left', + 'value' => 'Retour' + ]); ?> +
+
+ 'Valider', + 'ico' => 'check' + ]); ?> +
+
+
+
+
+

Installer un module

+
+
+ 'Archive ZIP :', + 'type' => 2 + ]); ?> +
+
+
+
+ false, + 'help' => 'Vérifier sur le forum que ce module supporte la mise à jour par réinstallation des fichiers.', + ]); ?> +
+
+
+
+
+ + + + + + + + \ No newline at end of file