722 lines
17 KiB
PHP
722 lines
17 KiB
PHP
<?php
|
|
/* Copyright (C) 2023-2024 Laurent Destailleur <eldy@users.sourceforge.net>
|
|
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
|
|
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
|
|
*
|
|
* 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, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/**
|
|
* \file htdocs/webportal/class/context.class.php
|
|
* \ingroup webportal
|
|
* \brief File of context class for WebPortal
|
|
*/
|
|
|
|
require_once __DIR__ . '/controller.class.php';
|
|
require_once __DIR__ . '/webPortalTheme.class.php';
|
|
|
|
/**
|
|
* Class Context
|
|
*/
|
|
class Context
|
|
{
|
|
/**
|
|
* @var Context Singleton
|
|
* @access private
|
|
* @static
|
|
*/
|
|
private static $_instance = null;
|
|
|
|
/**
|
|
* @var DoliDb $db Database handler
|
|
*/
|
|
public $db;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
public $title;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
public $desc;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
public $meta_title;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
public $meta_desc;
|
|
|
|
/**
|
|
* The application name
|
|
* @var string $appliName
|
|
*/
|
|
public $appliName;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
public $controller;
|
|
|
|
/**
|
|
* @var boolean
|
|
*/
|
|
public $controller_found = false;
|
|
|
|
/**
|
|
* @var stdClass[]
|
|
*/
|
|
private $controllers = array();
|
|
|
|
/**
|
|
* @var Controller $controllerInstance
|
|
*/
|
|
public $controllerInstance;
|
|
|
|
/**
|
|
* for internal error msg
|
|
* @var string error
|
|
*/
|
|
public $error;
|
|
|
|
/**
|
|
* @var array errors
|
|
*/
|
|
public $errors = array();
|
|
|
|
/**
|
|
* @var string Action
|
|
*/
|
|
public $action;
|
|
|
|
public $tplDir;
|
|
public $tplPath;
|
|
public $topMenu;
|
|
|
|
public $rootUrl;
|
|
|
|
public $menu_active = array();
|
|
|
|
public $eventMessages = array();
|
|
|
|
public $tokenKey = 'token';
|
|
|
|
/**
|
|
* Current object of page
|
|
* @var object $object
|
|
*/
|
|
public $object;
|
|
|
|
/**
|
|
* @var CommonObject Logged user
|
|
*/
|
|
public $logged_user = null;
|
|
|
|
/**
|
|
* @var CommonObject Logged third-party
|
|
*/
|
|
public $logged_thirdparty = null;
|
|
|
|
/**
|
|
* @var CommonObject Logged member
|
|
*/
|
|
public $logged_member = null;
|
|
|
|
/**
|
|
* @var CommonObject Logged partnership
|
|
*/
|
|
public $logged_partnership = null;
|
|
|
|
|
|
/**
|
|
* @var WebPortalTheme Theme data
|
|
*/
|
|
public $theme;
|
|
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @return void
|
|
*/
|
|
private function __construct()
|
|
{
|
|
global $conf, $db;
|
|
|
|
$this->db = $db;
|
|
|
|
$this->tplDir = __DIR__ . '/../';
|
|
|
|
$this->getControllerUrl();
|
|
|
|
$this->topMenu = new stdClass();
|
|
|
|
$this->tplPath = realpath(__DIR__ . '/../../public/webportal/tpl');
|
|
|
|
$this->controller = GETPOST('controller', 'aZ09'); // for security, limited to 'aZ09'
|
|
$this->action = GETPOST('action', 'aZ09');// for security, limited to 'aZ09'
|
|
|
|
if (empty($this->controller)) {
|
|
$this->controller = 'default';
|
|
}
|
|
|
|
$this->appliName = getDolGlobalString('WEBPORTAL_TITLE', getDolGlobalString('MAIN_INFO_SOCIETE_NOM'));
|
|
|
|
//$this->generateNewToken();
|
|
|
|
$this->initController();
|
|
|
|
// Init de l'url de base
|
|
$this->rootUrl = self::getRootConfigUrl();
|
|
|
|
|
|
$this->theme = new WebPortalTheme();
|
|
}
|
|
|
|
/**
|
|
* Singleton method to create one instance of this object
|
|
*
|
|
* @return Context Instance
|
|
*/
|
|
public static function getInstance()
|
|
{
|
|
if (is_null(self::$_instance)) {
|
|
self::$_instance = new Context();
|
|
}
|
|
|
|
return self::$_instance;
|
|
}
|
|
|
|
/**
|
|
* Init controller
|
|
*
|
|
* @return void
|
|
*/
|
|
public function initController()
|
|
{
|
|
global $db;
|
|
|
|
$defaultControllersPath = __DIR__ . '/../controllers/';
|
|
|
|
// define controllers definition
|
|
$this->addControllerDefinition('login', $defaultControllersPath . 'login.controller.class.php', 'LoginController');
|
|
$this->addControllerDefinition('default', $defaultControllersPath . 'default.controller.class.php', 'DefaultController');
|
|
$this->addControllerDefinition('document', $defaultControllersPath . 'document.controller.class.php', 'DocumentController');
|
|
$this->addControllerDefinition('propallist', $defaultControllersPath . 'propallist.controller.class.php', 'PropalListController');
|
|
$this->addControllerDefinition('orderlist', $defaultControllersPath . 'orderlist.controller.class.php', 'OrderListController');
|
|
$this->addControllerDefinition('invoicelist', $defaultControllersPath . 'invoicelist.controller.class.php', 'InvoiceListController');
|
|
$this->addControllerDefinition('membercard', $defaultControllersPath . 'membercard.controller.class.php', 'MemberCardController');
|
|
$this->addControllerDefinition('partnershipcard', $defaultControllersPath . 'partnershipcard.controller.class.php', 'PartnershipCardController');
|
|
|
|
// call triggers
|
|
//include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
|
|
//$interface=new Interfaces($db);
|
|
//$interface->run_triggers('WebPortalInitController', $this, $logged_user, $langs, $conf);
|
|
|
|
// search for controller
|
|
$this->controllerInstance = new Controller();
|
|
if (isset($this->controllers[$this->controller]) && file_exists($this->controllers[$this->controller]->path)) {
|
|
require_once $this->controllers[$this->controller]->path;
|
|
|
|
if (class_exists($this->controllers[$this->controller]->class)) {
|
|
$this->controllerInstance = new $this->controllers[$this->controller]->class();
|
|
$this->setControllerFound();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add controller definition
|
|
*
|
|
* @param string $controller Name
|
|
* @param string $path Path
|
|
* @param string $className Class name
|
|
* @return bool
|
|
*/
|
|
public function addControllerDefinition($controller, $path, $className)
|
|
{
|
|
$fileName = basename($path);
|
|
$needle = '.controller.class.php';
|
|
$length = strlen($needle);
|
|
$isControllerFile = $length > 0 ? substr($fileName, -$length) === $needle : true;
|
|
if (!$isControllerFile) {
|
|
$this->setError('Error: controller definition ' . $fileName);
|
|
return false;
|
|
}
|
|
|
|
$this->controllers[$controller] = new stdClass();
|
|
$this->controllers[$controller]->path = $path;
|
|
$this->controllers[$controller]->class = $className;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Set controller found
|
|
*
|
|
* @return void
|
|
*/
|
|
public function setControllerFound()
|
|
{
|
|
$this->controller_found = true;
|
|
}
|
|
|
|
/**
|
|
* Get WebPortal root url
|
|
*
|
|
* @return string Web Portal root url
|
|
*/
|
|
public static function getRootConfigUrl()
|
|
{
|
|
global $conf;
|
|
|
|
// Init de l'url de base
|
|
if (getDolGlobalString('WEBPORTAL_ROOT_URL')) {
|
|
$rootUrl = getDolGlobalString('WEBPORTAL_ROOT_URL');
|
|
if (substr($rootUrl, -1) !== '/') {
|
|
$rootUrl .= '/';
|
|
}
|
|
} else {
|
|
$rootUrl = dol_buildpath('/public/webportal/', 2);
|
|
}
|
|
|
|
return $rootUrl;
|
|
}
|
|
|
|
/**
|
|
* Get root url
|
|
*
|
|
* @param string $controller Controller name
|
|
* @param string|array $moreParams More parameters
|
|
* @param bool $addToken Add token hash only if $controller is set
|
|
* @return string
|
|
* @deprecated see getControllerUrl()
|
|
*/
|
|
public function getRootUrl($controller = '', $moreParams = '', $addToken = true)
|
|
{
|
|
return self::getControllerUrl($controller, $moreParams, $addToken);
|
|
}
|
|
|
|
/**
|
|
* Get controller url according to context
|
|
*
|
|
* @param string $controller Controller name
|
|
* @param string|array $moreParams More parameters
|
|
* @param bool $addToken Add token hash only if controller is set
|
|
* @return string
|
|
*/
|
|
public function getControllerUrl($controller = '', $moreParams = '', $addToken = true)
|
|
{
|
|
// TODO : addToken parameter on auto to detect (create or edit) action and add token on url
|
|
$url = $this->rootUrl;
|
|
|
|
if (empty($controller)) {
|
|
// because can be called without params to get only rootUrl
|
|
return $url;
|
|
}
|
|
|
|
$Tparams = array();
|
|
|
|
$Tparams['controller'] = $controller;
|
|
|
|
if (!empty($addToken)) {
|
|
$Tparams[$this->tokenKey] = $this->newToken();
|
|
}
|
|
|
|
return self::getPublicControllerUrl($controller, $moreParams, $Tparams);
|
|
}
|
|
|
|
/**
|
|
* Generate public controller URL
|
|
* Used for external link (like email or web page)
|
|
* so remove token and contextual behavior associate with current user
|
|
*
|
|
* @param string $controller Controller
|
|
* @param string|array $moreParams More parameters
|
|
* @param array $Tparams Parameters
|
|
* @return string
|
|
*/
|
|
public static function getPublicControllerUrl($controller = '', $moreParams = '', $Tparams = array())
|
|
{
|
|
$url = self::getRootConfigUrl();
|
|
|
|
if (empty($controller)) {
|
|
// because can be called without params to get only rootUrl
|
|
return $url;
|
|
}
|
|
|
|
$Tparams['controller'] = $controller;
|
|
|
|
// if $moreParams is an array
|
|
if (!empty($moreParams) && is_array($moreParams)) {
|
|
if (isset($moreParams['controller'])) {
|
|
unset($moreParams['controller']);
|
|
}
|
|
if (!empty($moreParams)) {
|
|
foreach ($moreParams as $paramKey => $paramVal) {
|
|
$Tparams[$paramKey] = $paramVal;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!empty($Tparams)) {
|
|
$TCompiledAttr = array();
|
|
foreach ($Tparams as $key => $value) {
|
|
$TCompiledAttr[] = $key . '=' . $value;
|
|
}
|
|
$url .= '?' . implode("&", $TCompiledAttr);
|
|
}
|
|
|
|
// if $moreParams is a string
|
|
if (!empty($moreParams) && !is_array($moreParams)) {
|
|
if (empty($Tparams)) {
|
|
if ($moreParams[0] !== '?') {
|
|
$url .= '?';
|
|
}
|
|
if ($moreParams[0] === '&') {
|
|
$moreParams = substr($moreParams, 1);
|
|
}
|
|
}
|
|
$url .= $moreParams;
|
|
}
|
|
|
|
return $url;
|
|
}
|
|
|
|
/**
|
|
* Url origin
|
|
*
|
|
* @param bool $withRequestUri With request URI
|
|
* @param bool $use_forwarded_host Use formatted host
|
|
* @return string
|
|
*/
|
|
public static function urlOrigin($withRequestUri = true, $use_forwarded_host = false)
|
|
{
|
|
$s = $_SERVER;
|
|
|
|
$ssl = (!empty($s['HTTPS']) && $s['HTTPS'] == 'on');
|
|
$sp = strtolower($s['SERVER_PROTOCOL']);
|
|
$protocol = substr($sp, 0, strpos($sp, '/')) . (($ssl) ? 's' : '');
|
|
$port = $s['SERVER_PORT'];
|
|
$port = ((!$ssl && $port == '80') || ($ssl && $port == '443')) ? '' : ':' . $port;
|
|
$host = ($use_forwarded_host && isset($s['HTTP_X_FORWARDED_HOST'])) ? $s['HTTP_X_FORWARDED_HOST'] : (isset($s['HTTP_HOST']) ? $s['HTTP_HOST'] : null);
|
|
$host = isset($host) ? $host : $s['SERVER_NAME'] . $port;
|
|
|
|
$url = $protocol . '://' . $host;
|
|
|
|
if ($withRequestUri) {
|
|
$url .= $s['REQUEST_URI'];
|
|
}
|
|
|
|
return $url;
|
|
}
|
|
|
|
/**
|
|
* Check if user is logged
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function userIsLog()
|
|
{
|
|
if (!empty($_SESSION["webportal_logged_thirdparty_account_id"])) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Is menu enabled ?
|
|
*
|
|
* @param string $menuName Menu name
|
|
* @return bool
|
|
*/
|
|
public function menuIsActive($menuName)
|
|
{
|
|
return in_array($menuName, $this->menu_active);
|
|
}
|
|
|
|
/**
|
|
* Set errors
|
|
*
|
|
* @param array $errors Errors
|
|
* @return void
|
|
*/
|
|
public function setError($errors)
|
|
{
|
|
if (!is_array($errors)) {
|
|
$errors = array($errors);
|
|
}
|
|
if (!isset($_SESSION['webportal_errors'])) {
|
|
$_SESSION['webportal_errors'] = array();
|
|
}
|
|
foreach ($errors as $msg) {
|
|
if (!in_array($msg, $_SESSION['webportal_errors'])) {
|
|
$_SESSION['webportal_errors'][] = $msg;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get errors
|
|
*
|
|
* @return int
|
|
*/
|
|
public function getErrors()
|
|
{
|
|
if (!empty($_SESSION['webportal_errors'])) {
|
|
$this->errors = array_values($_SESSION['webportal_errors']);
|
|
return count($this->errors);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Clear errors
|
|
*
|
|
* @return void
|
|
*/
|
|
public function clearErrors()
|
|
{
|
|
unset($_SESSION['webportal_errors']);
|
|
$this->errors = array();
|
|
}
|
|
|
|
/**
|
|
* Set event messages in dol_events session object. Will be output by calling dol_htmloutput_events.
|
|
* Note: Calling dol_htmloutput_events is done into pages by standard llxFooter() function.
|
|
*
|
|
* @param string|string[] $mesgs Message string or array
|
|
* @param string $style Which style to use ('mesgs' by default, 'warnings', 'errors')
|
|
* @return void
|
|
*/
|
|
public function setEventMessage($mesgs, $style = 'mesgs')
|
|
{
|
|
$TAcceptedStyle = array('mesgs', 'warnings', 'errors');
|
|
|
|
if (!in_array($style, $TAcceptedStyle)) {
|
|
$style = 'mesgs';
|
|
}
|
|
|
|
if (!is_array($mesgs)) {
|
|
$mesgs = array($mesgs);
|
|
}
|
|
if (!isset($_SESSION['webportal_events'])) {
|
|
$_SESSION['webportal_events'] = array(
|
|
'mesgs' => array(), 'warnings' => array(), 'errors' => array()
|
|
);
|
|
}
|
|
|
|
foreach ($mesgs as $msg) {
|
|
if (!in_array($msg, $_SESSION['webportal_events'][$style])) {
|
|
$_SESSION['webportal_events'][$style][] = $msg;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set event messages in dol_events session object. Will be output by calling dol_htmloutput_events.
|
|
* Note: Calling dol_htmloutput_events is done into pages by standard llxFooter() function.
|
|
*
|
|
* @param string $mesg Message string
|
|
* @param array|null $mesgs Message array
|
|
* @param string $style Which style to use ('mesgs' by default, 'warnings', 'errors')
|
|
* @return void
|
|
*/
|
|
public function setEventMessages($mesg, $mesgs, $style = 'mesgs')
|
|
{
|
|
if (empty($mesg) && empty($mesgs)) {
|
|
dol_syslog(__METHOD__ . ' Try to add a message in stack, but value to add is empty message', LOG_WARNING);
|
|
} else {
|
|
if (!in_array((string) $style, array('mesgs', 'warnings', 'errors'))) {
|
|
dol_print_error(null, 'Bad parameter style=' . $style . ' for setEventMessages');
|
|
}
|
|
if (empty($mesgs)) {
|
|
$this->setEventMessage($mesg, $style);
|
|
} else {
|
|
if (!empty($mesg) && !in_array($mesg, $mesgs)) {
|
|
$this->setEventMessage($mesg, $style); // Add message string if not already into array
|
|
}
|
|
$this->setEventMessage($mesgs, $style);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load event messages
|
|
*
|
|
* @return int
|
|
*/
|
|
public function loadEventMessages()
|
|
{
|
|
if (!empty($_SESSION['webportal_events'])) {
|
|
$this->eventMessages = $_SESSION['webportal_events'];
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Clear event messages
|
|
*
|
|
* @return void
|
|
*/
|
|
public function clearEventMessages()
|
|
{
|
|
unset($_SESSION['webportal_events']);
|
|
$this->eventMessages = array();
|
|
}
|
|
|
|
/**
|
|
* Return the value of token currently saved into session with name 'newToken'.
|
|
* This token must be sent by any POST as it will be used by next page for comparison with value in session.
|
|
* This token depends on controller
|
|
*
|
|
* @return string
|
|
*/
|
|
public function newToken()
|
|
{
|
|
return newToken();
|
|
}
|
|
|
|
/**
|
|
* Generate new token.
|
|
* @deprecated see main
|
|
* @return string
|
|
*/
|
|
protected function generateNewToken()
|
|
{
|
|
$currentToken = $this->newToken();
|
|
// Creation of a token against CSRF vulnerabilities
|
|
if (!defined('NOTOKENRENEWAL') || empty($currentToken)) {
|
|
// Rolling token at each call ($_SESSION['token'] contains token of previous page)
|
|
if (isset($_SESSION['newtoken'])) {
|
|
$_SESSION['token'] = $_SESSION['newtoken'];
|
|
}
|
|
|
|
// Save what will be next token. Into forms, we will add param $context->newToken();
|
|
$token = dol_hash(uniqid((string) mt_rand(), true)); // Generate
|
|
$_SESSION['newtoken'] = $token;
|
|
|
|
return $token;
|
|
} else {
|
|
return $this->newToken();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get token url
|
|
*
|
|
* @return string|null
|
|
*/
|
|
public function getUrlToken()
|
|
{
|
|
$token = $this->newToken();
|
|
if ($token) {
|
|
return '&' . $this->tokenKey . '=' . $this->newToken();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Get token input for form
|
|
*
|
|
* @return string|null
|
|
*/
|
|
public function getFormToken()
|
|
{
|
|
$token = $this->newToken();
|
|
if ($token) {
|
|
return '<input type="hidden" name="' . $this->tokenKey . '" value="' . $this->newToken() . '" />';
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Try to find the third-party account id from
|
|
*
|
|
* @param string $login Login
|
|
* @param string $pass Password
|
|
* @return int Third-party account id || <0 if error
|
|
*/
|
|
public function getThirdPartyAccountFromLogin($login, $pass)
|
|
{
|
|
$id = 0;
|
|
|
|
$sql = "SELECT sa.rowid as id, sa.pass_crypted";
|
|
$sql .= " FROM " . $this->db->prefix() . "societe_account as sa";
|
|
$sql .= " WHERE BINARY sa.login = '" . $this->db->escape($login) . "'"; // case sensitive
|
|
//$sql .= " AND BINARY sa.pass_crypted = '" . $this->db->escape($pass) . "'"; // case sensitive
|
|
$sql .= " AND sa.site = 'dolibarr_portal'";
|
|
$sql .= " AND sa.status = 1";
|
|
$sql .= " AND sa.entity IN (" . getEntity('societe') . ")";
|
|
|
|
dol_syslog(__METHOD__ . ' Try to find the third-party account id for login"' . $login . '" and site="dolibarr_portal"', LOG_DEBUG);
|
|
$result = $this->db->query($sql);
|
|
if ($result) {
|
|
if ($this->db->num_rows($result) == 1) {
|
|
$passok = false;
|
|
$obj = $this->db->fetch_object($result);
|
|
if ($obj) {
|
|
$passcrypted = $obj->pass_crypted;
|
|
|
|
// Check crypted password
|
|
$cryptType = '';
|
|
if (getDolGlobalString('DATABASE_PWD_ENCRYPTED')) {
|
|
$cryptType = getDolGlobalString('DATABASE_PWD_ENCRYPTED');
|
|
}
|
|
|
|
// By default, we use default setup for encryption rule
|
|
if (!in_array($cryptType, array('auto'))) {
|
|
$cryptType = 'auto';
|
|
}
|
|
|
|
// Check crypted password according to crypt algorithm
|
|
if ($cryptType == 'auto') {
|
|
if ($passcrypted && dol_verifyHash($pass, $passcrypted, '0')) {
|
|
$passok = true;
|
|
}
|
|
}
|
|
|
|
// Password ok ?
|
|
if ($passok) {
|
|
$id = $obj->id;
|
|
} else {
|
|
dol_syslog(__METHOD__ .' Authentication KO bad password for ' . $login . ', cryptType=' . $cryptType, LOG_NOTICE);
|
|
sleep(1); // Brut force protection. Must be same delay when login is not valid
|
|
return -3;
|
|
}
|
|
}
|
|
} else {
|
|
dol_syslog(__METHOD__ . ' Many third-party account found for login"' . $login . '" and site="dolibarr_portal"', LOG_ERR);
|
|
return -2;
|
|
}
|
|
} else {
|
|
$this->error = $this->db->lasterror();
|
|
return -1;
|
|
}
|
|
|
|
return $id;
|
|
}
|
|
}
|