. */ /* */ /*************************************************************************************/ /** * 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 * @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); } } } } } } ?>