plugin okay + new copyDir

This commit is contained in:
fredtempez 2022-04-08 09:47:35 +02:00
parent 19aa822c8e
commit b23d9f8c9b
6 changed files with 224 additions and 150 deletions

View File

@ -35,6 +35,7 @@ class common {
const DATA_DIR = 'site/data/'; const DATA_DIR = 'site/data/';
const FILE_DIR = 'site/file/'; const FILE_DIR = 'site/file/';
const TEMP_DIR = 'site/tmp/'; const TEMP_DIR = 'site/tmp/';
const MODULE_DIR = 'module/';
// Miniatures de la galerie // Miniatures de la galerie
const THUMBS_SEPARATOR = 'mini_'; const THUMBS_SEPARATOR = 'mini_';
@ -1137,30 +1138,52 @@ class common {
* @param string $dst dossier destination * @param string $dst dossier destination
* @return bool * @return bool
*/ */
public function copyDir($src, $dst) { function copyDir( string $sourceDirectory, string $destinationDirectory, string $childFolder = '') {
// 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;
// Boucler dans le dossier source en l'absence d'échec de lecture écriture $success = true;
while( $success $directory = opendir($sourceDirectory);
AND $file = readdir($dir) ) {
if (( $file != '.' ) && ( $file != '..' )) { if (is_dir($destinationDirectory) === false) {
if ( is_dir($src . '/' . $file) ){ mkdir($destinationDirectory);
// Appel récursif des sous-dossiers }
$success = $success OR $this->copyDir($src . '/' . $file, $dst . '/' . $file);
if ($childFolder !== '') {
if (is_dir("$destinationDirectory/$childFolder") === false) {
mkdir("$destinationDirectory/$childFolder");
}
while (($file = readdir($directory)) !== false) {
if ($file === '.' || $file === '..') {
continue;
}
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;
}
while (($file = readdir($directory)) !== false) {
if ($file === '.' || $file === '..') {
continue;
}
if (is_dir("$sourceDirectory/$file") === true) {
$success = $success && $this->copyDir("$sourceDirectory/$file", "$destinationDirectory/$file");
} }
else { else {
$success = $success OR copy($src . '/' . $file, $dst . '/' . $file); $success = $success && copy("$sourceDirectory/$file", "$destinationDirectory/$file");
} }
} }
}
closedir($dir); closedir($directory);
return $success; return($success);
} }
@ -2160,9 +2183,9 @@ class common {
elseif( elseif(
$moduleId $moduleId
AND in_array($moduleId, self::$coreModuleIds) === false 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 // Sinon continue
else { else {
@ -2660,8 +2683,8 @@ class core extends common {
require 'core/module/' . $classPath; require 'core/module/' . $classPath;
} }
// Module // Module
elseif(is_readable('module/' . $classPath)) { elseif(is_readable(self::MODULE_DIR . $classPath)) {
require 'module/' . $classPath; require self::MODULE_DIR . $classPath;
} }
// Librairie // Librairie
elseif(is_readable('core/vendor/' . $classPath)) { elseif(is_readable('core/vendor/' . $classPath)) {
@ -2945,7 +2968,7 @@ class core extends common {
// Chemin en fonction d'un module du coeur ou d'un module // Chemin en fonction d'un module du coeur ou d'un module
$modulePath = in_array($moduleId, self::$coreModuleIds) ? 'core/' : ''; $modulePath = in_array($moduleId, self::$coreModuleIds) ? 'core/' : '';
// CSS // 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)) { if(file_exists($stylePath)) {
$this->addOutput([ $this->addOutput([
'style' => file_get_contents($stylePath) 'style' => file_get_contents($stylePath)
@ -2958,7 +2981,7 @@ class core extends common {
} }
// JS // 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)) { if(file_exists($scriptPath)) {
ob_start(); ob_start();
include $scriptPath; include $scriptPath;
@ -2967,7 +2990,7 @@ class core extends common {
]); ]);
} }
// Vue // 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)) { if(file_exists($viewPath)) {
ob_start(); ob_start();
include $viewPath; include $viewPath;

View File

@ -31,7 +31,7 @@ class plugin extends common {
// URL des modules // URL des modules
const BASEURL_STORE = 'https://store.zwiicms.fr/'; const BASEURL_STORE = 'https://store.zwiicms.fr/';
const MODULE_STORE = '?modules/'; const MODULE_STORE = 'modules-pour-zwii-v12/';
// Gestion des modules // Gestion des modules
public static $modulesData = []; public static $modulesData = [];
@ -100,14 +100,9 @@ class plugin extends common {
*/ */
private function install($moduleFileName, $checkValid){ private function install($moduleFileName, $checkValid){
/** // Dossier temporaire
* Initialisation des variables $tempFolder = uniqid() . '/';
*/ //$tempFolder = 'truc/';
//$tempFolder = uniqid() . '/';
$tempFolder = 'truc/';
$notification = '';
// Numéro de version du module déjà installé
$versionInstalled = '';
/** /**
* Désarchivage * Désarchivage
@ -115,124 +110,144 @@ class plugin extends common {
$zip = new ZipArchive(); $zip = new ZipArchive();
if ($zip->open($moduleFileName) === TRUE) { if ($zip->open($moduleFileName) === TRUE) {
/**
* Création du dossier temporaire //Création du dossier temporaire et extraction
*/
if (!is_dir (self::TEMP_DIR . $tempFolder) ) { if (!is_dir (self::TEMP_DIR . $tempFolder) ) {
mkdir (self::TEMP_DIR . $tempFolder, 0755); mkdir (self::TEMP_DIR . $tempFolder, 0755);
} }
$zip->extractTo(self::TEMP_DIR . $tempFolder ); $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 * Lecture du descripteur de ressource
* $res ['name'] = id du module, correspond à la classe * $module ['name'] = id du module, correspond à la classe
* $res ['realname'] = Nom complet du module * $module ['realname'] = Nom complet du module
* $res ['version'] = version du module * $module ['version'] = version du module
* $res ['dirs'] @array * $module ['dirs'] @array
* 'dossier' => 'destination', * 'dossier' => 'destination',
* 'download" => 'module/download' * 'download" => 'module/download'
*
* Attention le dossier source est celui dans l'archive, la destination correspond à larborescence cible
*/ */
echo "<pre>";
// Affectation if (file_exists(self::TEMP_DIR . $tempFolder . 'desc.json')
$moduleName = $res ['name']; ) {
$modulePath = $res ['name'] . '/'; $module = json_decode(file_get_contents(self::TEMP_DIR . $tempFolder . 'desc.json'), true);
$moduleFile = $res ['name'] . '.php' ; } 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 * Validation des informations du descripteur
*/ */
if ( !is_dir ( self::TEMP_DIR . $tempFolder . $modulePath) || foreach ($module['dirs'] as $src => $dest) {
!is_file (self::TEMP_DIR . $tempFolder . $modulePath . $moduleFile) // Vérification de la présence des dossier décrits
) { if ( !is_dir (self::TEMP_DIR . $tempFolder . $src )) {
return([ // Message de retour
'success' => false,
'notification'=> 'Cette archive est invalide'
]);
}
/**
* Le module est-il installé ? Lire le numéro de version
*/
if (is_file( 'module/' . $modulePath . $moduleFile) ) {
$c = helper::getModules();
if (array_key_exists($moduleName, $c)) {
$versionInstalled = $c[$moduleName]['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';
}
}
}
}
// Supprimer le dossier temporaire même si le module est invalide
$this->removeDir(self::TEMP_DIR . $tempFolder); $this->removeDir(self::TEMP_DIR . $tempFolder);
$zip->close(); $zip->close();
} else { return([
// erreur à l'ouverture 'success' => false,
$success = false; 'notification'=> 'Archive invalide, les dossiers ne correspondent pas au descripteur.'
$notification = 'Impossible d\'ouvrir l\'archive';
}
return(['success' => $success,
'notification'=> $notification
]); ]);
} }
// 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'
]);
}
}
/**
* Validation de la présence du fichier de base du module
*/
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($module['name'], $c)) {
$versionInstalled = $c[$module['name']]['version'];
}
}
// 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.'
]);
}
}
}
// 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 {
// Message de retour
return(['success' => $success,
'notification'=> 'Impossible d\'ouvrir l\'archive'
]);
}
}
/*** /***
* Installation d'un module à partir du gestionnaire de fichier * Installation d'un module à partir du gestionnaire de fichier
@ -294,21 +309,19 @@ class plugin extends common {
// Sauver les données du fichiers // Sauver les données du fichiers
file_put_contents(self::FILE_DIR . 'source/modules/' . $moduleFile, $moduleData); file_put_contents(self::FILE_DIR . 'source/modules/' . $moduleFile, $moduleData);
/** // Installation directe
* $if( $moduleFile !== ''){ if ( file_exists(self::FILE_DIR . 'source/modules/' . $moduleFile) ) {
* $success = [ $r = $this->install(self::FILE_DIR . 'source/modules/' . $moduleFile, false);
* 'success' => false, } else {
* 'notification'=> '' $r['notification'] = 'Un problème est survenu, le module n\'est pas installé';
* ]; $r['success'] = false;
* $state = $this->install(self::FILE_DIR.'source/modules/'.$moduleFile, false); }
*} // Valeurs en sortie
*/
$this->addOutput([ $this->addOutput([
'redirect' => helper::baseUrl() . 'plugin/store', 'redirect' => helper::baseUrl() . 'plugin/store',
'notification' => $moduleFile . ' téléchargé dans le dossier modules du gestionnaire de fichiers', 'notification' => $r['notification'],
'state' => true 'state' => $r['success']
]); ]);
} }
// Valeurs en sortie // Valeurs en sortie
$this->addOutput([ $this->addOutput([
@ -548,7 +561,7 @@ class plugin extends common {
//Nom de l'archive //Nom de l'archive
$fileName = $this->getUrl(3) . '.zip'; $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)) { switch ($this->getUrl(2)) {
case 'filemanager': case 'filemanager':

View File

@ -15,11 +15,18 @@
'help' => 'Consulter l\'aide en ligne' 'help' => 'Consulter l\'aide en ligne'
]); ?> ]); ?>
</div> </div>
<div class="col3 offset7"> <div class="col1 offset8">
<?php echo template::button('configModulesStore', [ <?php echo template::button('configModulesStore', [
'href' => helper::baseUrl() . 'plugin/store', 'href' => helper::baseUrl() . 'plugin/store',
'ico' => 'shopping-basket', 'value' => template::ico('shopping-basket'),
'value' => 'Catalogue en ligne' 'help' => 'Installer depuis le catalogue en ligne'
]); ?>
</div>
<div class="col1">
<?php echo template::button('configStoreUpload', [
'href' => helper::baseUrl() . 'plugin/upload',
'value' => template::ico('file-archive'),
'help' => 'Installer depuis une archive'
]); ?> ]); ?>
</div> </div>
</div> </div>

View File

@ -6,12 +6,6 @@
'value' => template::ico('left') 'value' => template::ico('left')
]); ?> ]); ?>
</div> </div>
<div class="col2 offset9">
<?php echo template::button('configStoreUpload', [
'href' => helper::baseUrl() . 'plugin/upload',
'value' => 'Installer'
]); ?>
</div>
</div> </div>
<?php if($module::$storeList): ?> <?php if($module::$storeList): ?>
<?php echo template::table([2, 2, 1, 2, 2, 1], $module::$storeList, ['Catégorie', 'Module', 'Version', 'Date', 'Pages', '']); ?> <?php echo template::table([2, 2, 1, 2, 2, 1], $module::$storeList, ['Catégorie', 'Module', 'Version', 'Date', 'Pages', '']); ?>

View File

@ -0,0 +1,36 @@
<?php
/**
* This file is part of Zwii.
*
* For full copyright and license information, please see the LICENSE
* file that was distributed with this source code.
*
* @license GNU General Public License, version 3
* @author : Frédéric Tempez <frederic.tempez@outlook.com> *
* @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);
}
}

View File

@ -0,0 +1 @@
<?php // Dummy file