File: /home/assibfaf/assignmentghostwriter.com/prox-classes/Module/Module.php
<?php
/**
* @package Proxim
* @author Davison Pro <davis@davisonpro.dev | https://davisonpro.dev>
* @copyright 2019 Proxim
* @version 1.5.0
* @since File available since Release 1.0.0
*/
namespace Proxim\Module;
use Db;
use Exception;
use Proxim\Application;
use Proxim\Cache\Cache;
use Proxim\Configuration;
use Proxim\Hook;
use Proxim\Order\Meta;
use Proxim\Tools;
use Proxim\Validate;
abstract class Module implements ModuleInterface
{
/** @var int Module ID */
public $id = null;
/** @var float Version */
public $version;
public $database_version;
/** @var string Unique name */
public $name;
/** @var string Human name */
public $displayName;
/** @var string A little description of the module */
public $description;
/** @var string author of the module */
public $author;
/** @var string URI author of the module */
public $author_uri = '';
/** @var string icon */
public $icon;
/** @var bool Status */
public $active = false;
/**
* @since 1.5.0.1
*
* @var string Registered Version in database
*/
public $registered_version;
/** @var array Array cache filled with modules informations */
public static $modules_cache;
/** @var array names of the controllers */
public $controllers = array();
/** @var string Module web path (eg. '/proxim/content/modules/modulename/') */
protected $_path = null;
/**
* @since 1.5.0.1
*
* @var string Module local path (eg. '/home/proxim/content/modules/modulename/')
*/
protected $local_path = null;
/** @var string Main table used for modules installed */
protected $table = 'module';
/** @var string Identifier of the main table */
protected $identifier = 'module_id';
/** @var array Array cache filled with modules instances */
public static $_INSTANCE = array();
/** @var Application */
public $application;
/** @var Smarty_Data */
public $smarty;
const CACHE_FILE_MODULES_LIST = '/content/xml/modules_list.xml';
/**
* Constructor.
*
* @param string $name Module unique name
* @param Application $application
*/
public function __construct($name = null, Application $application = null)
{
if (isset($this->prox_versions_compliancy) && !isset($this->prox_versions_compliancy['min'])) {
$this->prox_versions_compliancy['min'] = '1.0.0';
}
if (isset($this->prox_versions_compliancy) && !isset($this->prox_versions_compliancy['max'])) {
$this->prox_versions_compliancy['max'] = Application::VERSION;
}
if (strlen($this->prox_versions_compliancy['min']) == 3) {
$this->prox_versions_compliancy['min'] .= '.0.0';
}
if (strlen($this->prox_versions_compliancy['min']) == 5) {
$this->prox_versions_compliancy['min'] .= '.0';
}
if (strlen($this->prox_versions_compliancy['max']) == 5) {
$this->prox_versions_compliancy['max'] .= '.999';
}
if (strlen($this->prox_versions_compliancy['max']) == 3) {
$this->prox_versions_compliancy['max'] .= '.999.999';
}
// Load context and smarty
$this->application = $application ? $application : Application::getInstance();
if (is_object($this->application->container->smarty)) {
$this->smarty = $this->application->container->smarty;
}
// If the module has no name we gave him its id as name
if ($this->name === null) {
$this->name = $this->id;
}
// If the module has the name we load the corresponding data from the cache
if ($this->name != null) {
// If cache is not generated, we generate it
if (self::$modules_cache == null && !is_array(self::$modules_cache)) {
self::$modules_cache = array();
// Join clause is done to check if the module is activated in current shop context
$result = Db::getInstance()->executeS('
SELECT m.`module_id`, m.`name`, m.`active`
FROM ' . Db::prefix('module') . ' m
');
foreach ($result as $row) {
self::$modules_cache[$row['name']] = $row;
self::$modules_cache[$row['name']]['active'] = (bool) $row['active'];
}
}
// We load configuration from the cache
if (isset(self::$modules_cache[$this->name])) {
if (isset(self::$modules_cache[$this->name]['module_id'])) {
$this->id = self::$modules_cache[$this->name]['module_id'];
}
foreach (self::$modules_cache[$this->name] as $key => $value) {
if (array_key_exists($key, $this)) {
$this->{$key} = $value;
}
}
$this->_path = PROX_DIR_ROOT . 'modules/' . $this->name . '/';
}
$this->local_path = PROX_DIR_MODULE . $this->name . '/';
}
}
/**
* Return an instance of the specified module.
*
* @param string $module_name Module name
*
* @return Module
*/
public static function getInstanceByName($module_name)
{
if (!Validate::isModuleName($module_name)) {
return false;
}
if (!isset(self::$_INSTANCE[$module_name])) {
if (!Tools::file_exists_no_cache(PROX_DIR_MODULE . $module_name . '/' . $module_name . '.php')) {
return false;
}
return Module::coreLoadModule($module_name);
}
return self::$_INSTANCE[$module_name];
}
/**
* Get ID module by name.
*
* @param string $name
*
* @return int Module ID
*/
public static function getModuleIdByName($name)
{
$cache_id = 'Module::getModuleIdByName_' . pSQL($name);
if (!Cache::isStored($cache_id)) {
$result = (int) Db::getInstance()->getValue('SELECT `module_id` FROM ' . Db::prefix('module') . ' WHERE `name` = "' . pSQL($name) . '"');
Cache::store($cache_id, $result);
return $result;
}
return Cache::retrieve($cache_id);
}
protected static function coreLoadModule($module_name)
{
include_once PROX_DIR_MODULE . $module_name . '/' . $module_name . '.php';
$r = false;
if (class_exists($module_name, false)) {
$r = self::$_INSTANCE[$module_name] = Application::getInstance()->{$module_name} = new $module_name();
}
return $r;
}
/**
* Check if the module is available for the current user.
*/
public function checkAccess()
{
return true;
}
/**
* @param string $module_name
*
* @return bool
*
* @deprecated since 1.7
*/
public static function isInstalled($module_name)
{
if (!Cache::isStored('Module::isInstalled' . $module_name)) {
$module_id = Module::getModuleIdByName($module_name);
Cache::store('Module::isInstalled' . $module_name, (bool) $module_id);
return (bool) $module_id;
}
return Cache::retrieve('Module::isInstalled' . $module_name);
}
public static function isEnabled($module_name)
{
if (!Cache::isStored('Module::isEnabled' . $module_name)) {
$active = false;
$module_id = Module::getModuleIdByName($module_name);
if (Db::getInstance()->getValue('SELECT `module_id` FROM ' . Db::prefix('module') . ' WHERE `module_id` = ' . (int) $module_id . ' AND `active` = 1')) {
$active = true;
}
Cache::store('Module::isEnabled' . $module_name, (bool) $active);
return (bool) $active;
}
return Cache::retrieve('Module::isEnabled' . $module_name);
}
/**
* Install module's controllers using public property $controllers.
*
* @return bool
*/
protected function installControllers()
{
foreach ($this->controllers as $controller) {
$page = 'module-' . $this->name . '-' . $controller;
// $result = Db::getInstance()->getValue(
// 'SELECT * FROM ' . Db::prefix('meta') . ' WHERE page="' . pSQL($page) . '"
// ');
// if ((int) $result > 0) {
// continue;
// }
// $meta = new Meta();
// $meta->page = $page;
// $meta->configurable = 1;
// $meta->save();
}
return true;
}
/**
* Connect module to a hook.
*
* @param string $hook_name Hook name
*
* @return bool result
*/
public function registerHook($hook_name)
{
return Hook::registerHook($this, $hook_name);
}
/**
* Unregister module from hook.
*
* @param mixed $id_hook Hook id (can be a hook name since 1.5.0)
*
* @return bool result
*/
public function unregisterHook($hook_id)
{
return Hook::unregisterHook($this, $hook_id);
}
/**
* Insert module into datable.
*/
public function install()
{
Hook::exec('actionModuleInstallBefore', array('object' => $this));
// Check module name validation
if (!Validate::isModuleName($this->name)) {
throw new Exception('Unable to install the module (Module name is not valid).');
}
// Check if module is installed
$result = $this->isInstalled($this->name);
if ($result) {
throw new Exception('This module has already been installed.');
}
if (!$this->installControllers()) {
throw new Exception('Could not install module controllers.');
}
// Install module and retrieve the installation id
$result = Db::getInstance()->insert(
$this->table,
array('name' => $this->name, 'active' => 1, 'version' => $this->version)
);
if (!$result) {
throw new Exception('Technical error: Proxim could not install this module.');
}
$this->id = Db::getInstance()->Insert_ID();
Cache::clean('Module::isInstalled' . $this->name);
Hook::exec('actionModuleInstallAfter', array('object' => $this));
return true;
}
/**
* Delete module from datable.
*
* @return bool result
*/
public function uninstall()
{
// Check module installation id validation
if (!Validate::isUnsignedId($this->id)) {
throw new Exception('The module is not installed.');
}
// Retrieve hooks used by the module
$sql = 'SELECT DISTINCT(`hook_id`) FROM ' . Db::prefix('hook_module') . ' WHERE `module_id` = ' . (int) $this->id;
$result = Db::getInstance()->executeS($sql);
foreach ($result as $row) {
$this->unregisterHook((int) $row['hook_id']);
}
// Uninstall the module
if (Db::getInstance()->execute('DELETE FROM ' . Db::prefix('module') . ' WHERE `module_id` = ' . (int) $this->id)) {
Cache::clean('Module::isInstalled' . $this->name);
Cache::clean('Module::getModuleIdByName_' . pSQL($this->name));
return true;
}
return false;
}
public static function configXmlStringFormat($string)
{
return Tools::htmlentitiesDecodeUTF8($string);
}
/**
* Use this method to return the result of a smarty template when assign data only locally with $this->smarty->assign().
*
* @param string $templatePath relative path the template file, from the module root dir
*
* @return mixed
*/
public function fetch($templatePath)
{
$template = $this->application->smarty->createTemplate(
$templatePath,
$this->smarty
);
return $template->fetch();
}
protected static function useTooMuchMemory()
{
$memory_limit = Tools::getMemoryLimit();
if (function_exists('memory_get_usage') && $memory_limit != '-1') {
$current_memory = memory_get_usage(true);
$memory_threshold = (int) max($memory_limit * 0.15, Tools::isX86_64arch() ? 4194304 : 2097152);
$memory_left = $memory_limit - $current_memory;
if ($memory_left <= $memory_threshold) {
return true;
}
}
return false;
}
/**
* Return modules directory list.
*
* @return array Modules Directory List
*/
public static function getModulesDirOnDisk()
{
$module_list = array();
$modules = scandir(PROX_DIR_MODULE, SCANDIR_SORT_NONE);
foreach ($modules as $name) {
if (is_file(PROX_DIR_MODULE . $name)) {
continue;
} elseif (is_dir(PROX_DIR_MODULE . $name . DIRECTORY_SEPARATOR) && Tools::file_exists_cache(PROX_DIR_MODULE . $name . '/' . $name . '.php')) {
if (!Validate::isModuleName($name)) {
throw new Exception(sprintf('Module %s is not a valid module name', $name));
}
$module_list[] = $name;
}
}
return $module_list;
}
/**
* Return available modules.
*
* @return array Modules
*/
public static function getModulesOnDisk()
{
$app = Application::getInstance();;
// Init var
$module_list = array();
$module_name_list = array();
$modules_name_to_cursor = array();
// Get modules directory list and memory limit
$modules_dir = Module::getModulesDirOnDisk();
$modules_installed = array();
$result = Db::getInstance()->executeS('
SELECT m.name, m.version
FROM ' . Db::prefix('module') . ' m'
);
foreach ($result as $row) {
$modules_installed[$row['name']] = $row;
}
foreach ($modules_dir as $module) {
$module_errors = array();
if (Module::useTooMuchMemory()) {
$module_errors[] = 'All modules cannot be loaded due to memory limit restrictions, please increase your memory_limit value on your server configuration';
break;
}
// Check if config.xml module file exists and if it's not outdated
$config_file = PROX_DIR_MODULE . $module . '/config.xml';
$xml_exist = (file_exists($config_file));
// If config.xml exists
if ($xml_exist) {
// Load config.xml
libxml_use_internal_errors(true);
$xml_module = @simplexml_load_file($config_file);
if (!$xml_module) {
$module_errors[] = sprintf(
'%s could not be loaded.',
array($config_file)
);
break;
}
foreach (libxml_get_errors() as $error) {
$module_errors[] = '[' . $module . '] Error found in config file: ' . htmlentities($error->message);
}
libxml_clear_errors();
// If no errors in Xml, no need instand and no need new config.xml file, we load only translations
if (!count($module_errors) && (int) $xml_module->need_instance == 0) {
$item = new \stdClass();
$item->id = 0;
$item->warning = '';
foreach ($xml_module as $k => $v) {
$item->$k = (string) $v;
}
$item->displayName = stripslashes(Module::configXmlStringFormat($xml_module->displayName));
$item->description = stripslashes(Module::configXmlStringFormat($xml_module->description));
$item->author = stripslashes(Module::configXmlStringFormat($xml_module->author));
$item->author_uri = (isset($xml_module->author_uri) && $xml_module->author_uri) ? stripslashes($xml_module->author_uri) : false;
$item->logo = 'questionmark.png';
if (@filemtime(PROX_DIR_MODULE . $module . DIRECTORY_SEPARATOR . 'logo.gif')) {
$item->logo = $app->modules_uri . '/' . $module . '/logo.gif';
}
if (@filemtime(PROX_DIR_MODULE . $module . DIRECTORY_SEPARATOR . 'logo.png')) {
$item->logo = $app->modules_uri . '/' . $module . '/logo.png';
}
if (isset($xml_module->confirmUninstall)) {
$item->confirmUninstall = html_entity_decode(Module::configXmlStringFormat($xml_module->confirmUninstall));
}
$item->active = 0;
$item->onclick_option = false;
$module_list[$item->name . '_disk'] = $item;
$module_name_list[] = '\'' . pSQL($item->name) . '\'';
$modules_name_to_cursor[Tools::strtolower((string) ($item->name))] = $item;
}
}
}
// Get modules information from database
if (!empty($module_name_list)) {
$results = Db::getInstance()->executeS('
SELECT m.module_id, m.name, m.active
FROM ' . Db::prefix('module') . ' m
WHERE LOWER(m.name) IN (' . Tools::strtolower(implode(',', $module_name_list)) . ')
');
foreach ($results as $result) {
if (isset($modules_name_to_cursor[Tools::strtolower($result['name'])])) {
$module_cursor = $modules_name_to_cursor[Tools::strtolower($result['name'])];
$module_cursor->id = (int) $result['module_id'];
$module_cursor->active = (bool) $result['active'];
}
}
}
foreach ($module_list as $key => &$module) {
if (isset($modules_installed[$module->name])) {
$module->database_version = $modules_installed[$module->name]['version'];
$module->installed = true;
} else {
$module->database_version = 0;
$module->installed = false;
}
}
usort($module_list, function ($a, $b) {
return strnatcasecmp($a->displayName, $b->displayName);
});
return $module_list;
}
}