diff --git a/core/core.php b/core/core.php index 58bfcc8f..e184e4a0 100644 --- a/core/core.php +++ b/core/core.php @@ -35,6 +35,7 @@ class common { const DATA_DIR = 'site/data/'; const FILE_DIR = 'site/file/'; const TEMP_DIR = 'site/tmp/'; + const MODULE_DIR = 'module/'; // Miniatures de la galerie const THUMBS_SEPARATOR = 'mini_'; @@ -180,7 +181,7 @@ class common { ]; public static $fontsWebSafe = [ - 'arial' => [ + 'arial' => [ 'name' => 'Arial', 'font-family' => 'Arial, Helvetica, sans-serif', 'resource' => 'websafe' @@ -1137,30 +1138,52 @@ class common { * @param string $dst dossier destination * @return bool */ - public function copyDir($src, $dst) { - // Ouvrir le dossier source - $dir = opendir($src); - // Créer le dossier de destination - if (!is_dir($dst)) - $success = mkdir($dst, 0755, true); - else - $success = true; + function copyDir( string $sourceDirectory, string $destinationDirectory, string $childFolder = '') { - // Boucler dans le dossier source en l'absence d'échec de lecture écriture - while( $success - AND $file = readdir($dir) ) { - if (( $file != '.' ) && ( $file != '..' )) { - if ( is_dir($src . '/' . $file) ){ - // Appel récursif des sous-dossiers - $success = $success OR $this->copyDir($src . '/' . $file, $dst . '/' . $file); + $success = true; + $directory = opendir($sourceDirectory); + + if (is_dir($destinationDirectory) === false) { + mkdir($destinationDirectory); + } + + if ($childFolder !== '') { + if (is_dir("$destinationDirectory/$childFolder") === false) { + mkdir("$destinationDirectory/$childFolder"); + } + + while (($file = readdir($directory)) !== false) { + if ($file === '.' || $file === '..') { + continue; } - else { - $success = $success OR copy($src . '/' . $file, $dst . '/' . $file); + + if (is_dir("$sourceDirectory/$file") === true) { + $success = $success && $this->copyDir("$sourceDirectory/$file", "$destinationDirectory/$childFolder/$file"); + } else { + $success = $success && copy("$sourceDirectory/$file", "$destinationDirectory/$childFolder/$file"); } } + + closedir($directory); + + return; } - closedir($dir); - return $success; + + while (($file = readdir($directory)) !== false) { + if ($file === '.' || $file === '..') { + continue; + } + + if (is_dir("$sourceDirectory/$file") === true) { + $success = $success && $this->copyDir("$sourceDirectory/$file", "$destinationDirectory/$file"); + } + else { + $success = $success && copy("$sourceDirectory/$file", "$destinationDirectory/$file"); + } + } + + closedir($directory); + return($success); } @@ -2160,9 +2183,9 @@ class common { elseif( $moduleId AND in_array($moduleId, self::$coreModuleIds) === false - AND file_exists('module/' . $moduleId . '/vendor/' . $vendorName . '/inc.json') + AND file_exists(self::MODULE_DIR . $moduleId . '/vendor/' . $vendorName . '/inc.json') ) { - $vendorPath = 'module/' . $moduleId . '/vendor/' . $vendorName . '/'; + $vendorPath = self::MODULE_DIR . $moduleId . '/vendor/' . $vendorName . '/'; } // Sinon continue else { @@ -2660,8 +2683,8 @@ class core extends common { require 'core/module/' . $classPath; } // Module - elseif(is_readable('module/' . $classPath)) { - require 'module/' . $classPath; + elseif(is_readable(self::MODULE_DIR . $classPath)) { + require self::MODULE_DIR . $classPath; } // Librairie elseif(is_readable('core/vendor/' . $classPath)) { @@ -2810,7 +2833,7 @@ class core extends common { 'title' => $title, 'content' => $this->getPage($this->getUrl(0), self::$i18n) . // Concatène avec les paramètres avancés. - $this->getData(['page', $this->getUrl(0), 'css']) . + $this->getData(['page', $this->getUrl(0), 'css']) . $this->getData(['page', $this->getUrl(0), 'js']), 'metaDescription' => $this->getData(['page', $this->getUrl(0), 'metaDescription']), 'metaTitle' => $this->getData(['page', $this->getUrl(0), 'metaTitle']), @@ -2945,7 +2968,7 @@ class core extends common { // Chemin en fonction d'un module du coeur ou d'un module $modulePath = in_array($moduleId, self::$coreModuleIds) ? 'core/' : ''; // CSS - $stylePath = $modulePath . 'module/' . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.css'; + $stylePath = $modulePath . self::MODULE_DIR . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.css'; if(file_exists($stylePath)) { $this->addOutput([ 'style' => file_get_contents($stylePath) @@ -2958,7 +2981,7 @@ class core extends common { } // JS - $scriptPath = $modulePath . 'module/' . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.js.php'; + $scriptPath = $modulePath . self::MODULE_DIR . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.js.php'; if(file_exists($scriptPath)) { ob_start(); include $scriptPath; @@ -2967,7 +2990,7 @@ class core extends common { ]); } // Vue - $viewPath = $modulePath . 'module/' . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.php'; + $viewPath = $modulePath . self::MODULE_DIR . $moduleId . '/view/' . $output['view'] . '/' . $output['view'] . '.php'; if(file_exists($viewPath)) { ob_start(); include $viewPath; diff --git a/core/module/plugin/plugin.php b/core/module/plugin/plugin.php index 553acb81..510a9f6b 100644 --- a/core/module/plugin/plugin.php +++ b/core/module/plugin/plugin.php @@ -31,7 +31,7 @@ class plugin extends common { // URL des modules const BASEURL_STORE = 'https://store.zwiicms.fr/'; - const MODULE_STORE = '?modules/'; + const MODULE_STORE = 'modules-pour-zwii-v12/'; // Gestion des modules public static $modulesData = []; @@ -100,14 +100,9 @@ class plugin extends common { */ private function install($moduleFileName, $checkValid){ - /** - * Initialisation des variables - */ - //$tempFolder = uniqid() . '/'; - $tempFolder = 'truc/'; - $notification = ''; - // Numéro de version du module déjà installé - $versionInstalled = ''; + // Dossier temporaire + $tempFolder = uniqid() . '/'; + //$tempFolder = 'truc/'; /** * Désarchivage @@ -115,123 +110,143 @@ class plugin extends common { $zip = new ZipArchive(); if ($zip->open($moduleFileName) === TRUE) { - /** - * Création du dossier temporaire - */ + + //Création du dossier temporaire et extraction if (!is_dir (self::TEMP_DIR . $tempFolder) ) { mkdir (self::TEMP_DIR . $tempFolder, 0755); } - $zip->extractTo(self::TEMP_DIR . $tempFolder ); - // Lecture du descripteur de ressource - $modulePath = self::TEMP_DIR . $tempFolder . 'module'; - if (file_exists(self::TEMP_DIR . $tempFolder . 'desc.json') - ) { - $res = json_decode(file_get_contents(self::TEMP_DIR . $tempFolder . 'desc.json'), true); - } else { - return([ - 'success' => false, - 'notification'=> 'Cette archive est invalide' - ]); - } + /** - * Structure lue - * $res ['name'] = id du module, correspond à la classe - * $res ['realname'] = Nom complet du module - * $res ['version'] = version du module - * $res ['dirs'] @array + * Lecture du descripteur de ressource + * $module ['name'] = id du module, correspond à la classe + * $module ['realname'] = Nom complet du module + * $module ['version'] = version du module + * $module ['dirs'] @array * 'dossier' => 'destination', * 'download" => 'module/download' - * - * Attention le dossier source est celui dans l'archive, la destination correspond à l’arborescence cible */ - echo "
"; - // Affectation - $moduleName = $res ['name']; - $modulePath = $res ['name'] . '/'; - $moduleFile = $res ['name'] . '.php' ; + + if (file_exists(self::TEMP_DIR . $tempFolder . 'desc.json') + ) { + $module = json_decode(file_get_contents(self::TEMP_DIR . $tempFolder . 'desc.json'), true); + } else { + // Message de retour + $this->removeDir(self::TEMP_DIR . $tempFolder); + $zip->close(); + return([ + 'success' => false, + 'notification'=> 'Archive invalide, le descripteur est absent.' + ]); + } /** * Validation des informations du descripteur */ - if ( !is_dir ( self::TEMP_DIR . $tempFolder . $modulePath) || - !is_file (self::TEMP_DIR . $tempFolder . $modulePath . $moduleFile) - ) { + foreach ($module['dirs'] as $src => $dest) { + // Vérification de la présence des dossier décrits + if ( !is_dir (self::TEMP_DIR . $tempFolder . $src )) { + // Message de retour + $this->removeDir(self::TEMP_DIR . $tempFolder); + $zip->close(); return([ 'success' => false, - 'notification'=> 'Cette archive est invalide' + 'notification'=> 'Archive invalide, les dossiers ne correspondent pas au descripteur.' ]); + } + // Interdire l'écriture dans le dossier core + if ( strstr($dest, 'core') !== false ) { + // Message de retour + $this->removeDir(self::TEMP_DIR . $tempFolder); + $zip->close(); + return([ + 'success' => false, + 'notification'=> 'Archive invalide, l\'écriture dans le dossier core est interdite' + ]); + } } + /** - * Le module est-il installé ? Lire le numéro de version + * Validation de la présence du fichier de base du module */ - if (is_file( 'module/' . $modulePath . $moduleFile) ) { + if ( !file_exists(self::TEMP_DIR . $tempFolder . $module['name'] . '/' . $module['name'] . '.php')) { + // Message de retour + $this->removeDir(self::TEMP_DIR . $tempFolder); + $zip->close(); + return([ + 'success' => false, + 'notification'=> 'Cette archive est invalide, le fichier de classe est absent.' + ]); + } + + + /** + * Le module est-il déjà installé ? + * Si oui lire le numéro de version et le stocker dans $versionInstalled + */ + if (is_file( self::MODULE_DIR . $module['name'] . '/' . $module['name'] . '.php') ) { $c = helper::getModules(); - if (array_key_exists($moduleName, $c)) { - $versionInstalled = $c[$moduleName]['version']; + if (array_key_exists($module['name'], $c)) { + $versionInstalled = $c[$module['name']]['version']; } } - // Si version actuelle >= version indiquée dans UPDATE la mise à jour est validée - $infoModules = helper::getModules(); - if( $infoModules[$moduleName]['update'] >= $update ) $valUpdate = true; - // Module déjà installé ? - $moduleInstal = false; - foreach($infoModules as $key=>$value ){ - if($moduleName === $key){ - $moduleInstal = true; - } - } - - // Validation de la maj si autorisation du concepteur du module ET - // ( Version plus récente OU Check de forçage ) - $valNewVersion = floatval($version); - $valInstalVersion = floatval( $infoModules[$moduleName]['version'] ); - $newVersion = false; - if( $valNewVersion > $valInstalVersion ) $newVersion = true; - $validMaj = $valUpdate && ( $newVersion || $checkValid); - - // Nouvelle installation ou mise à jour du module - if( ! $moduleInstal || $validMaj ){ - // Copie récursive des dossiers - $this->copyDir( self::TEMP_DIR . $tempFolder, './' ); - $success = true; - if( ! $moduleInstal ){ - $notification = 'Module '.$moduleName.' installé'; - } - else{ - $notification = 'Module '.$moduleName.' mis à jour'; - } - } - else{ - $success = false; - if( $valNewVersion == $valInstalVersion){ - $notification = ' Version détectée '.$version.' = à celle installée '.$infoModules[$moduleName]['version']; - } - else{ - $notification = ' Version détectée '.$version.' < à celle installée '.$infoModules[$moduleName]['version']; - } - if( $valUpdate === false){ - if( $infoModules[$moduleName]['update'] === $update ){ - $notification = ' Mise à jour par ce procédé interdite par le concepteur du module'; - } - else{ - $notification = ' Mise à jour par ce procédé interdite, votre version est trop ancienne'; - } - } + // Le module est installé, contrôle de la version + $installOk = false; + if ( isset($versionInstalled) === false ) { + $installOk = true; + } elseif ( version_compare($module['version'], $versionInstalled) >= 0 ) { + $installOk = true; + } else { + if (version_compare($module['version'], $versionInstalled) === -1 ) { + // Contrôle du forçage + if ($this->getInput('configModulesCheck', helper::FILTER_BOOLEAN) === true) { + $installOk = true; + } else { + // Message de retour + $this->removeDir(self::TEMP_DIR . $tempFolder); + $zip->close(); + return([ + 'success' => false, + 'notification'=> 'La version installée est plus récente, la mise à jour peut être forcée en cochant l\'option.' + ]); } } - // Supprimer le dossier temporaire même si le module est invalide - $this->removeDir(self::TEMP_DIR . $tempFolder); - $zip->close(); + } + + // Installation ou mise à jour du module valides + if ($installOk) { + // Copie récursive des dossiers + foreach ($module['dirs'] as $src => $dest) { + if (!is_dir (self::TEMP_DIR . $tempFolder . $src)) { + mkdir(self::TEMP_DIR . $tempFolder . $src); + } + $success = $this->copyDir( self::TEMP_DIR . $tempFolder . $src, $dest ); + } + // Message de retour + $t = isset($versionInstalled) ? ' actualisé' : 'installé'; + $this->removeDir(self::TEMP_DIR . $tempFolder); + $zip->close(); + return(['success' => $success, + 'notification'=> $success ? 'Le module '.$module['name'].' a été ' . $t + : 'Erreur inconnue, le module n\'est pas installé' + ]); + } else { + return([ + 'success' => false, + 'notification'=> 'Une erreur inconnue s\est produite !' + ]); + // Supprimer le dossier temporaire + $this->removeDir(self::TEMP_DIR . $tempFolder); + $zip->close(); + } } else { - // erreur à l'ouverture - $success = false; - $notification = 'Impossible d\'ouvrir l\'archive'; + // Message de retour + return(['success' => $success, + 'notification'=> 'Impossible d\'ouvrir l\'archive' + ]); } - return(['success' => $success, - 'notification'=> $notification - ]); + } /*** @@ -294,21 +309,19 @@ class plugin extends common { // Sauver les données du fichiers file_put_contents(self::FILE_DIR . 'source/modules/' . $moduleFile, $moduleData); - /** - * $if( $moduleFile !== ''){ - * $success = [ - * 'success' => false, - * 'notification'=> '' - * ]; - * $state = $this->install(self::FILE_DIR.'source/modules/'.$moduleFile, false); - *} - */ + // Installation directe + if ( file_exists(self::FILE_DIR . 'source/modules/' . $moduleFile) ) { + $r = $this->install(self::FILE_DIR . 'source/modules/' . $moduleFile, false); + } else { + $r['notification'] = 'Un problème est survenu, le module n\'est pas installé'; + $r['success'] = false; + } + // Valeurs en sortie $this->addOutput([ 'redirect' => helper::baseUrl() . 'plugin/store', - 'notification' => $moduleFile . ' téléchargé dans le dossier modules du gestionnaire de fichiers', - 'state' => true + 'notification' => $r['notification'], + 'state' => $r['success'] ]); - } // Valeurs en sortie $this->addOutput([ @@ -548,7 +561,7 @@ class plugin extends common { //Nom de l'archive $fileName = $this->getUrl(3) . '.zip'; - $this->makeZip ($tmpFolder . '/' . $fileName, 'module/' . $this->getUrl(3)); + $this->makeZip ($tmpFolder . '/' . $fileName, self::MODULE_DIR . $this->getUrl(3)); switch ($this->getUrl(2)) { case 'filemanager': diff --git a/core/module/plugin/view/index/index.php b/core/module/plugin/view/index/index.php index 30939f06..0c33f68d 100644 --- a/core/module/plugin/view/index/index.php +++ b/core/module/plugin/view/index/index.php @@ -15,11 +15,18 @@ 'help' => 'Consulter l\'aide en ligne' ]); ?> -+diff --git a/core/module/plugin/view/store/store.php b/core/module/plugin/view/store/store.php index 8134b91c..f06bf536 100644 --- a/core/module/plugin/view/store/store.php +++ b/core/module/plugin/view/store/store.php @@ -6,12 +6,6 @@ 'value' => template::ico('left') ]); ?> -helper::baseUrl() . 'plugin/store', - 'ico' => 'shopping-basket', - 'value' => 'Catalogue en ligne' + 'value' => template::ico('shopping-basket'), + 'help' => 'Installer depuis le catalogue en ligne' + ]); ?> +++ helper::baseUrl() . 'plugin/upload', + 'value' => template::ico('file-archive'), + 'help' => 'Installer depuis une archive' ]); ?>- helper::baseUrl() . 'plugin/upload', - 'value' => 'Installer' - ]); ?> -diff --git a/module/version/version.php b/module/version/version.php new file mode 100644 index 00000000..284675e6 --- /dev/null +++ b/module/version/version.php @@ -0,0 +1,36 @@ + * + * @copyright Copyright (C) 2018-2020, Frédéric Tempez + * @link http://zwiicms.com/ + */ + +class version extends common { + + const VERSION = '1.0'; + const REALNAME = 'Version'; + const DELETE = true; + const UPDATE = '0.0'; + const DATADIRECTORY = ''; // Contenu localisé inclus par défaut (page.json et module.json) + + public static $actions = [ + 'index'=> self::GROUP_VISITOR + + ]; + + /** + * Retourne le numéro de version + */ + + public function index() { + exit( common::ZWII_VERSION); + } + +} diff --git a/module/version/view/index/index.php b/module/version/view/index/index.php new file mode 100644 index 00000000..2263730f --- /dev/null +++ b/module/version/view/index/index.php @@ -0,0 +1 @@ +