File: /home/assibfaf/dashboard.tutorsclub.us/prox-includes/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\FileSystem;
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;
/** @var bool Free */
public $free = false;
/** @var float price */
public $price = 0;
/**
* @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;
protected $_url_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();
public static $purchase_link = "https://addons.craftyworks.co";
/** @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 = (int) 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->_url_path = $this->application->base_uri . '/content/modules/' . $this->name . '/';
$this->_path = PROX_DIR_ROOT . 'content/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
*
*/
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);
}
/**
* 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.');
}
// 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();
if(!is_dir(PROX_DIR_MODULE)) {
@mkdir(PROX_DIR_MODULE, FileSystem::DEFAULT_MODE_FOLDER);
}
$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->not_on_disk = 0;
$item->configure = isset($xml_module->configure) ? 1 : 0;
if(isset($xml_module->price)) {
$item->price = (float) stripslashes($xml_module->price);
$item->buylink = self::$purchase_link . "?module=" . $item->name . "&domain=" . $app->request->getHost();
}
if (@filemtime(PROX_DIR_MODULE . $module . DIRECTORY_SEPARATOR . 'logo.png')) {
$item->logo = $app->modules_uri . '/' . $module . '/logo.png';
} elseif( @filemtime(PROX_DIR_MODULE . $module . DIRECTORY_SEPARATOR . 'logo.jpg')) {
$item->logo = $app->modules_uri . '/' . $module . '/logo.jpg';
} else {
$item->logo = stripslashes(Module::configXmlStringFormat($xml_module->logo));
}
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'];
}
}
}
$files_list = array(
array('type' => 'addonsNative', 'file' => PROX_DIR_ROOT . self::CACHE_FILE_MODULES_LIST),
);
foreach ($files_list as $f) {
if (file_exists($f['file'])) {
$file = $f['file'];
$content = Tools::file_get_contents($file);
$xml = @simplexml_load_string($content, null, LIBXML_NOCDATA);
if ($xml && isset($xml->module)) {
foreach ($xml->module as $modaddons) {
$flag_found = 0;
foreach ($module_list as $k => &$m) {
if (Tools::strtolower($m->name) == Tools::strtolower($modaddons->name) && !isset($m->available_on_addons)) {
$flag_found = 1;
if ($m->version != $modaddons->version && version_compare($m->version, $modaddons->version) === -1) {
$module_list[$k]->version_addons = $modaddons->version;
}
}
}
if ($flag_found == 0) {
$item = new \stdClass();
$item->id = 0;
$item->name = strip_tags((string) $modaddons->name);
$item->displayName = strip_tags((string) $modaddons->displayName);
$item->description = stripslashes(strip_tags((string) $modaddons->description));
$item->author = strip_tags((string) $modaddons->author);
if (@filemtime(PROX_DIR_MODULE . $modaddons->name . DIRECTORY_SEPARATOR . 'logo.png')) {
$item->logo = $app->modules_uri . '/' . $modaddons->name . '/logo.png';
} elseif (@filemtime(PROX_DIR_MODULE . $modaddons->name . DIRECTORY_SEPARATOR . 'logo.jpg')) {
$item->logo = $app->modules_uri . '/' . $modaddons->name . '/logo.jpg';
} else {
$item->logo = strip_tags((string) $modaddons->logo);
}
$item->need_instance = 0;
$item->configure = isset($modaddons->configure) ? 1 : 0;
$item->not_on_disk = 1;
$item->active = 0;
$item->url = isset($modaddons->url) ? $modaddons->url : null;
if(isset($modaddons->price)) {
$item->price = (float) stripslashes($modaddons->price);
$item->buylink = self::$purchase_link . "?module=" . $modaddons->name . "&domain=" . $app->request->getHost();
}
$module_list[$item->name . '_feed'] = $item;
if (isset($module_list[$modaddons->name . '_disk'])) {
$item->not_on_disk = 0;
$module_list[$modaddons->name . '_disk']->not_on_disk = 0;
}
}
}
}
}
}
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;
}
}