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 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;

View File

@ -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 à larborescence cible
*/
echo "<pre>";
// 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':

View File

@ -15,11 +15,18 @@
'help' => 'Consulter l\'aide en ligne'
]); ?>
</div>
<div class="col3 offset7">
<div class="col1 offset8">
<?php echo template::button('configModulesStore', [
'href' => helper::baseUrl() . 'plugin/store',
'ico' => 'shopping-basket',
'value' => 'Catalogue en ligne'
'value' => template::ico('shopping-basket'),
'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>

View File

@ -6,12 +6,6 @@
'value' => template::ico('left')
]); ?>
</div>
<div class="col2 offset9">
<?php echo template::button('configStoreUpload', [
'href' => helper::baseUrl() . 'plugin/upload',
'value' => 'Installer'
]); ?>
</div>
</div>
<?php if($module::$storeList): ?>
<?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