This repository has been archived on 2023-12-05. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
ae75/www/backoffice/actions/ActionsAdminModules.class.php
2020-11-02 15:46:52 +01:00

474 lines
14 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : thelia@openstudio.fr */
/* web : http://www.openstudio.fr */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/*    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
/**
* Administration des modulesGestion des modules depuis l'administration
*
* Ce singleton permet de gérer la manipulation des modules depuis l'admin Thelia.
*
* @author Franck Allimant <franck@cqfdev.fr>
* @version $Id$
*/
require_once(__DIR__ . '/../../lib/pclzip.lib.php');
class ActionsAdminModules extends ActionsModules {
private static $instance = false;
private function __construct() {
parent::__construct();
}
/**
* Cette classe est un singleton
* @return ActionsAdminModules une instance de ActionsAdminModules
*/
public static function instance() {
if (self::$instance === false) self::$instance = new ActionsAdminModules();
return self::$instance;
}
/**
* @method string Retourne le titre du module, en fonction du contenu du fichier XML
* @param Modules le module concerné
* @return string le titre du module
*/
public function lire_titre_module($modules) {
try {
$this->lire_descripteur_xml($modules);
if ($modules->xml->descriptif->titre != "") return $modules->xml->descriptif->titre;
} catch (Exception $e) {}
return $modules->nom;
}
/**
* @method bool determiner si le fichier xxx_adminyyy existe sur un module
* @param string le nom complet du fichier
* @throws TheliaException::MODULE_FICHIER_ADMIN_NON_TROUVE si le fichier n'existe pas
*/
public function trouver_fichier_admin($nom_module, $type_fichier_admin = false) {
$suffixe = '_admin';
if ($type_fichier_admin !== false) $suffixe .= "_$type_fichier_admin";
$path = $this->lire_chemin_module($nom_module) . "/${nom_module}${suffixe}.php";
if (file_exists($path))
return $path;
else
throw new TheliaException(trad("Fichier admin %s non trouvé", 'admin', $path), TheliaException::MODULE_FICHIER_ADMIN_NON_TROUVE);
}
/**
* @method bool determiner si un module comporte un include dans le B.O.
* @param string le nom du module
* @return true si le module est present dans l'admin, false sinon.
* @throws TheliaException::MODULE_FICHIER_ADMIN_NON_TROUVE si le fichier n'existe pas
*/
public function est_administrable($nom_module) {
$suffixe = '_admin';
$dir = $this->lire_chemin_module($nom_module);
$est_admin = false;
if ($dh = @opendir($dir)) {
while ($entry = readdir($dh)) {
if (strstr($entry, '_admin') !== FALSE) {
$est_admin = true;
break;
}
}
@closedir($dh);
}
return $est_admin;
}
/**
* @method void inclure dans une page admin un fichier spécifique des modules
* @param string le nom complet du fichier
*/
public function inclure_module_admin($type_fichier_admin = false) {
$liste = $this->lister(false, true);
foreach($liste as $module) {
if ($module->est_autorise()) {
try {
$path = $this->trouver_fichier_admin($module->nom, $type_fichier_admin);
include_once($path);
} catch (Exception $e) {}
}
}
}
/**
*
* Cherches les fichiers de langues définit dans les plugins activés. Le fichier de langue doit être dans le répertoire lang_admin du plugin
*
* @param int $lang
*/
public function inclure_lang_admin($lang)
{
$liste = $this->lister(false, true);
foreach($liste as $module) {
try {
$path = $this->lire_chemin_module($module->nom) . "/lang/".$lang.'.php';
if(file_exists($path))
{
include_once($path);
}
}
catch (Exception $ex) {}
}
}
/**
* @method Modules Charger un module depuis la BD
* @param string $nom_module: le nom du module
* @return un objet Modules chargé
* @throws MODULE_ECHEC_CHARGEMENT si le module ne peut pas être chargé.
*/
public function charger($nom_module) {
$modules = new Modules();
if ($modules->charger($nom_module)) return $modules;
throw new TheliaException(trad("Ne peut charger le module %s depuis la BD: ", 'admin', $nom_module), TheliaException::MODULE_ECHEC_CHARGEMENT);
}
/**
* @method Modules Activer un module
* @param string $nom_module: le nom du module
* @return un objet Modules chargé
* @throws MODULE_INCOMPATIBLE si le module est incompatibel avec la version courante de Thelia
* @throws MODULE_PREREQUIS_NON_VERIFIES si les prérequis du modules ne sont pas vérifiés.
*/
public function activer($nom_module) {
$modules = $this->charger($nom_module);
$instance = $this->instancier($nom_module);
if ($this->est_activable($modules))
{
if ($instance->prerequis()) {
$instance->init();
$modules->actif = 1;
$modules->maj();
return $modules;
} else {
throw new TheliaException(trad("Les prérequis du module %s ne sont pas vérifiés", 'admin', $nom_module), TheliaException::MODULE_PREREQUIS_NON_VERIFIES);
}
}
else {
throw new TheliaException(trad("Module %s incompatible avec votre version de Thelia", 'admin', $nom_module), TheliaException::MODULE_INCOMPATIBLE);
}
}
/**
* @method Modules Désactiver un module
* @param string $nom_module: le nom du module
* @return un objet Modules chargé
*/
public function desactiver($nom_module) {
$modules = $this->charger($nom_module);
// On essaye d'invoquer destroy()
try {
$instance = $this->instancier($nom_module);
$instance->destroy();
} catch (Exception $e) {
}
$modules->actif = 0;
$modules->maj();
return $modules;
}
/**
* @method void Supprime un module, après avoir invoqué la méthiode destroy
* @param string $nom_module: le nom du module
*/
public function supprimer($nom_module) {
// Tenter de désactiver le module, sans tenir compte des erreurs
try {
$modules = $this->desactiver($nom_module);
// Supprimer le module de la BD
$modules->delete();
// Supprimer aussi la description
$modules->query("delete from " . Modulesdesc::TABLE . " where plugin='$nom_module'");
} catch (Exception $e) {
// Ignorer l'erreur
}
// Par mesure de précaution
$nom_module = basename($nom_module);
if ($nom_module != '')
{
// Supprimer le répertoire des modules
$this->delTree($this->lire_chemin_module($nom_module));
// En cas d'échec de la suppression
try {
$this->lire_chemin_module($nom_module);
$existe_toujours = true;
} catch (Exception $e) {
// Le repertoire n'existe plus !
$existe_toujours = false;
}
if ($existe_toujours)
throw new TheliaException(trad("Echec de la suppression du répertoire du module %s", 'admin', $nom_module) , TheliaException::MODULE_ERR_SUPPRESSION_REPERTOIRE);
}
}
/**
* @method void Upload et décompresse un plugin au format zip
* @throws MODULE_ECHEC_UPLOAD si le module n'a pas pu être chargé décompressé
* @throws MODULE_INVALIDE si le fichier à installer ne contient pas un module Thelia
* @throws MODULE_ECHEC_INSTALL si l'installation échoue (problème de zip, de copie, etc.)
*/
public function installer($uploadedfile, $fichier_zip) {
require_once(__DIR__ . '/../../lib/pclzip.lib.php');
if ($uploadedfile != '')
{
$path_zip = "$this->plugins_base_dir/$fichier_zip";
if (@copy($uploadedfile, $path_zip)) {
$archive = new PclZip($path_zip);
$resul = $archive->extract(PCLZIP_OPT_PATH, $this->plugins_base_dir);
@unlink($path_zip);
if ($resul == 0) {
throw new TheliaException(trad("Echec à l'installation du module %s. Erreur ZIP: %s", 'admin', $nom_module, $archive->errorInfo(true)), TheliaException::MODULE_ECHEC_INSTALL);
}
// Vérifier qu'on peut instancier le plugin. Retrouver tout d'abord le repertoire du plugin
$tmp = preg_split ("/[\/\\\:]/", $resul[0]['stored_filename']);
$module_name = $tmp[0];
try {
$this->instancier($module_name);
$this->conversion_utf8($this->lire_chemin_module($module_name));
} catch (Exception $ex) {
// Supprimer le répertoire
if ($module_name != '') $this->delTree($this->plugins_base_dir . "/$module_name");
throw new TheliaException(trad("Le fichier %s ne semble pas contenir un module Thelia", 'admin', $fichier_zip), TheliaException::MODULE_INVALIDE);
}
} else {
throw new TheliaException(trad("Echec à la copie du fichier %s vers %s", 'admin', $uploadedfile, $path_zip), TheliaException::MODULE_ECHEC_INSTALL);
}
}
}
/**
* @method void Mise a jour des modules en BD en fonction du contenu du repertoire des modules
*/
public function mettre_a_jour() {
if ($dh = opendir($this->plugins_base_dir)) {
while ($file = readdir($dh)) {
if ($file == '.' || $file == '..') continue;
try {
// Tenter d'instancier le plugin
$instance = $this->instancier($file);
$modules = new Modules();
if ($instance instanceof PluginsPaiements)
$modules->type = Modules::PAIEMENT;
else if ($instance instanceof PluginsTransports)
$modules->type = Modules::TRANSPORT;
else if ($instance instanceof FiltreBase)
$modules->type = Modules::FILTRE;
else if ($instance instanceof PluginsClassiques)
$modules->type = Modules::CLASSIQUE;
else
continue; // On ignore
// Vérifier si le module existe en BD, et l'ajouter s'il n'y est pas
if (! $modules->charger($file)) {
$modules->nom = $file;
$modules->actif = 0;
$modules->add();
// On en profite pour le convertir en UTF-8 au passage si nécessaire.
$this->conversion_utf8($this->lire_chemin_module($modules->nom));
// Lire le descripteur, et mettre à jour la description du module en base
$this->lire_descripteur_xml($modules);
foreach($modules->xml->descriptif as $desc) {
$codelang = $desc->attributes()->lang;
$lang = new Lang();
if ($lang->charger_code($codelang)) {
$this->mise_a_jour_description(
$modules->nom,
$lang->id,
$desc->titre,
$desc->chapo,
$desc->description,
0 // Devise ?
);
}
}
}
} catch (Exception $ex) {
// On ne peut pas instancier -> ignorer
}
}
@closedir($dh);
}
// Vérifier que les plugins en base existent toujours sur disque
$modules = new Modules();
$result = $modules->query('select nom from '.Modules::TABLE);
while ($result && $row = $modules->fetch_object($result)) {
try {
$this->lire_chemin_module($row->nom);
} catch (Exception $ex) {
// Le plugin n'existe plus sur disque -> le retirer de la BD
if ($modules->charger($row->nom)) {
$modules->delete();
// Supprimer aussi la description
$modules->query("delete from " . Modulesdesc::TABLE . " where plugin='$modules->nom'");
}
}
}
CacheBase::getCache()->reset_cache();
}
/**
* @method void Suppression récursive du contenu d'un répertoire
* @todo FIXME: A déplacer vers une classe outils ?
*/
private function delTree($dir) {
if (is_dir($dir)) {
if ($dh = opendir($dir)) {
while ($file = readdir($dh)) {
if ($file == '.' || $file == '..') continue;
$this->delTree("$dir/$file");
}
@closedir($dh);
@rmdir($dir);
}
} else {
@unlink($dir);
}
}
/**
* @method void convertir récursivement en UTF-8 les fichiers d'un plugin uploadé
* @param string $path le chemin d'accès au fichier
*/
private function conversion_utf8($path)
{
if (is_dir($path)) {
if ($dh = opendir($path)) {
while ($file = readdir($dh)) {
if ($file == '.' || $file == '..') continue;
$this->conversion_utf8("$path/$file");
}
@closedir($dh);
}
} else {
// Uniquement les .php, .xml et .txt
$ext = strtolower(substr($path, -4));
if ( ($ext == '.php' || $ext == '.txt' || $ext == '.xml') && $str = file_get_contents($path)) {
$is_utf8 = mb_detect_encoding($str, 'UTF-8', true);
if (! $is_utf8) {
if ($fh = @fopen($path, "w")) {
$str = str_ireplace("iso-8859-1", "utf-8", $str);
fwrite($fh, utf8_encode($str));
@fclose($fh);
}
}
}
}
}
}
?>