dolibarr 23.0.3
context.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2023-2024 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
4 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
5 * Copyright (C) 2025 Schaffhauser sébastien <sebastien@webmaster67.fr>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
26require_once __DIR__ . '/controller.class.php';
27require_once __DIR__ . '/webPortalTheme.class.php';
28
33{
39 private static $_instance = null;
40
44 public $db;
45
49 public $title;
50
54 public $desc;
55
59 public $meta_title;
60
64 public $meta_desc;
65
70 public $appliName;
71
75 public $controller;
76
80 public $controller_found = false;
81
85 private $controllers = array();
86
90 public $controllerInstance;
91
96 public $error;
97
101 public $errors = array();
102
106 public $action;
107
111 public $tplDir;
112
116 public $tplPath;
117
121 public $topMenu;
122
126 public $rootUrl;
127
131 public $cdnUrl;
132
136 public $menu_active = array();
137
141 public $eventMessages = array();
142
146 public $tokenKey = 'token';
147
152 public $object;
153
157 public $logged_user = null;
158
162 public $logged_thirdparty = null;
163
167 public $logged_member = null;
168
172 public $logged_partnership = null;
173
177 public $theme;
178
179
185 private function __construct()
186 {
187 global $db;
188
189 $this->db = $db;
190
191 $this->tplDir = __DIR__ . '/../';
192
193 $this->getControllerUrl();
194
195 $this->topMenu = new stdClass();
196
197 $this->tplPath = realpath(__DIR__ . '/../../public/webportal/tpl');
198
199 $this->controller = GETPOST('controller', 'aZ09'); // for security, limited to 'aZ09'
200 $this->action = GETPOST('action', 'aZ09');// for security, limited to 'aZ09'
201
202 if (empty($this->controller)) {
203 $this->controller = 'default';
204 }
205
206 $this->appliName = getDolGlobalString('WEBPORTAL_TITLE', getDolGlobalString('MAIN_INFO_SOCIETE_NOM'));
207
208 //$this->generateNewToken();
209
210 $this->initController(false);
211
212 // Init of base URL. Must be the public URL.
213 $this->rootUrl = self::getRootConfigUrl();
214
215 // Init of CDN URL. Must be the public URL.
216 // BECAUSE IN SOME CASES IT COULD BE IMPORTANT TO HIDE PUBLIC URL BUT YOU CAN SET A CDN URL IN HIDDEN CONF
217 $this->cdnUrl = getDolGlobalString('WEBPORTAL_CDN_URL', dol_buildpath('/public/includes/', 3));
218 $this->cdnUrl = rtrim(trim($this->cdnUrl), '/');
219
220 $this->theme = new WebPortalTheme(false);
221 }
222
228 public static function getInstance()
229 {
230 if (is_null(self::$_instance)) {
231 self::$_instance = new Context();
232 }
233
234 return self::$_instance;
235 }
236
243 public function initController($init_theme = true)
244 {
245 global $hookmanager;
246
247 $defaultControllersPath = __DIR__ . '/../controllers/';
248
249 // define controllers definition
250 $this->addControllerDefinition('login', $defaultControllersPath . 'login.controller.class.php', 'LoginController');
251 $this->addControllerDefinition('default', $defaultControllersPath . 'default.controller.class.php', 'DefaultController');
252 $this->addControllerDefinition('document', $defaultControllersPath . 'document.controller.class.php', 'DocumentController');
253 $this->addControllerDefinition('propallist', $defaultControllersPath . 'propallist.controller.class.php', 'PropalListController');
254 $this->addControllerDefinition('orderlist', $defaultControllersPath . 'orderlist.controller.class.php', 'OrderListController');
255 $this->addControllerDefinition('invoicelist', $defaultControllersPath . 'invoicelist.controller.class.php', 'InvoiceListController');
256 $this->addControllerDefinition('membercard', $defaultControllersPath . 'membercard.controller.class.php', 'MemberCardController');
257 $this->addControllerDefinition('partnershipcard', $defaultControllersPath . 'partnershipcard.controller.class.php', 'PartnershipCardController');
258 //** below the addition of DocumentListController adding files by third party attached documents
259 $this->addControllerDefinition('documentlist', $defaultControllersPath . 'documentlist.controller.class.php', 'DocumentListController');
260 //** Below is the addition to the menu of the DocumentUtileController.class.php controller in order to share via the GED (documents) "Documentscomptes"
261 $this->addControllerDefinition('documentutile', $defaultControllersPath . 'documentutile.controller.class.php', 'DocumentUtileController');
262 $this->addControllerDefinition('viewimage', $defaultControllersPath . 'viewimage.controller.class.php', 'ViewImageController');
263
264 // Hooks for init controller
265 $hookmanager->initHooks(array('webportaldao'));
266 $parameters = array();
267 $reshook = $hookmanager->executeHooks('initController', $parameters, $this);
268
269 // search for controller
270 $this->controllerInstance = new Controller();
271 if (isset($this->controllers[$this->controller]) && file_exists($this->controllers[$this->controller]->path)) {
272 require_once $this->controllers[$this->controller]->path;
273
274 if (class_exists($this->controllers[$this->controller]->class)) {
275 $this->controllerInstance = new $this->controllers[$this->controller]->class();
276 $this->setControllerFound();
277 }
278 }
279
280 if ($init_theme) {
281 $this->theme->init();
282 }
283 }
284
293 public function addControllerDefinition($controller, $path, $className)
294 {
295 $fileName = basename($path);
296 $needle = '.controller.class.php';
297 $length = strlen($needle);
298 $isControllerFile = $length > 0 ? substr($fileName, -$length) === $needle : true;
299 if (!$isControllerFile) {
300 $this->setError('Error: controller definition ' . $fileName);
301 return false;
302 }
303
304 $this->controllers[$controller] = new stdClass();
305 $this->controllers[$controller]->path = $path;
306 $this->controllers[$controller]->class = $className;
307
308 return true;
309 }
310
316 public function setControllerFound()
317 {
318 $this->controller_found = true;
319 }
320
326 public static function getRootConfigUrl()
327 {
328 // Init of base URL
329 if (getDolGlobalString('WEBPORTAL_ROOT_URL')) {
330 $rootUrl = getDolGlobalString('WEBPORTAL_ROOT_URL');
331 if (substr($rootUrl, -1) !== '/') {
332 $rootUrl .= '/';
333 }
334 } else {
335 $rootUrl = dol_buildpath('/public/webportal/', 3); // Return the public URL for external access
336 }
337
338 return $rootUrl;
339 }
340
350 public function getRootUrl($controller = '', $moreParams = '', $addToken = true)
351 {
352 return self::getControllerUrl($controller, $moreParams, $addToken);
353 }
354
363 public function getControllerUrl($controller = '', $moreParams = '', $addToken = true)
364 {
365 // TODO : addToken parameter on auto to detect (create or edit) action and add token on url
366 $url = $this->rootUrl;
367
368 if (empty($controller)) {
369 // because can be called without params to get only rootUrl
370 return $url;
371 }
372
373 $Tparams = array();
374
375 $Tparams['controller'] = $controller;
376
377 if (!empty($addToken)) {
378 $Tparams[$this->tokenKey] = $this->newToken();
379 }
380
381 return self::getPublicControllerUrl($controller, $moreParams, $Tparams);
382 }
383
394 public static function getPublicControllerUrl($controller = '', $moreParams = '', $Tparams = array())
395 {
396 $url = self::getRootConfigUrl();
397
398 if (empty($controller)) {
399 // because can be called without params to get only rootUrl
400 return $url;
401 }
402
403 $Tparams['controller'] = $controller;
404
405 // if $moreParams is an array
406 if (!empty($moreParams) && is_array($moreParams)) {
407 if (isset($moreParams['controller'])) {
408 unset($moreParams['controller']);
409 }
410 if (!empty($moreParams)) {
411 foreach ($moreParams as $paramKey => $paramVal) {
412 $Tparams[$paramKey] = $paramVal;
413 }
414 }
415 }
416
417 if (!empty($Tparams)) {
418 $TCompiledAttr = array();
419 foreach ($Tparams as $key => $value) {
420 $TCompiledAttr[] = $key . '=' . $value;
421 }
422 $url .= '?' . implode("&", $TCompiledAttr);
423 }
424
425 // if $moreParams is a string
426 if (!empty($moreParams) && !is_array($moreParams)) {
427 if (empty($Tparams)) {
428 if ($moreParams[0] !== '?') {
429 $url .= '?';
430 }
431 if ($moreParams[0] === '&') {
432 $moreParams = substr($moreParams, 1);
433 }
434 }
435 $url .= $moreParams;
436 }
437
438 return $url;
439 }
440
448 public static function urlOrigin($withRequestUri = true, $use_forwarded_host = false)
449 {
450 $s = $_SERVER;
451
452 $ssl = (!empty($s['HTTPS']) && $s['HTTPS'] == 'on');
453 $sp = strtolower($s['SERVER_PROTOCOL']);
454 $protocol = substr($sp, 0, strpos($sp, '/')) . (($ssl) ? 's' : '');
455 $port = $s['SERVER_PORT'];
456 $port = ((!$ssl && $port == '80') || ($ssl && $port == '443')) ? '' : ':' . $port;
457 $host = ($use_forwarded_host && isset($s['HTTP_X_FORWARDED_HOST'])) ? $s['HTTP_X_FORWARDED_HOST'] : (isset($s['HTTP_HOST']) ? $s['HTTP_HOST'] : null);
458 $host = isset($host) ? $host : $s['SERVER_NAME'] . $port;
459
460 $url = $protocol . '://' . $host;
461
462 if ($withRequestUri) {
463 $url .= $s['REQUEST_URI'];
464 }
465
466 return $url;
467 }
468
474 public function userIsLog()
475 {
476 global $hookmanager;
477
478 // Hooks for security access
479 $hookmanager->initHooks(array('webportaldao'));
480 $parameters = array();
481 $reshook = $hookmanager->executeHooks('userIsLog', $parameters, $this);
482 if ($reshook > 0) {
483 return !empty($hookmanager->resArray['userIsLog']);
484 }
485
486 if (!empty($_SESSION["webportal_logged_thirdparty_account_id"])) {
487 return true;
488 } elseif (!empty($_SESSION["webportal_logged_member_account_id"])) {
489 return true;
490 } else {
491 return false;
492 }
493 }
494
501 public function menuIsActive($menuName)
502 {
503 return in_array($menuName, $this->menu_active);
504 }
505
512 public function setError($errors)
513 {
514 if (!is_array($errors)) {
515 $errors = array($errors);
516 }
517 if (!isset($_SESSION['webportal_errors'])) {
518 $_SESSION['webportal_errors'] = array();
519 }
520 foreach ($errors as $msg) {
521 if (!in_array($msg, $_SESSION['webportal_errors'])) {
522 $_SESSION['webportal_errors'][] = $msg;
523 }
524 }
525 }
526
532 public function getErrors()
533 {
534 if (!empty($_SESSION['webportal_errors'])) {
535 $this->errors = array_values($_SESSION['webportal_errors']);
536 return count($this->errors);
537 }
538
539 return 0;
540 }
541
547 public function clearErrors()
548 {
549 unset($_SESSION['webportal_errors']);
550 $this->errors = array();
551 }
552
561 public function setEventMessage($mesgs, $style = 'mesgs')
562 {
563 $TAcceptedStyle = array('mesgs', 'warnings', 'errors');
564
565 if (!in_array($style, $TAcceptedStyle)) {
566 $style = 'mesgs';
567 }
568
569 if (!is_array($mesgs)) {
570 $mesgs = array($mesgs);
571 }
572 if (!isset($_SESSION['webportal_events'])) {
573 $_SESSION['webportal_events'] = array(
574 'mesgs' => array(), 'warnings' => array(), 'errors' => array()
575 );
576 }
577
578 foreach ($mesgs as $msg) {
579 if (!in_array($msg, $_SESSION['webportal_events'][$style])) {
580 $_SESSION['webportal_events'][$style][] = $msg;
581 }
582 }
583 }
584
594 public function setEventMessages($mesg, $mesgs, $style = 'mesgs')
595 {
596 if (empty($mesg) && empty($mesgs)) {
597 dol_syslog(__METHOD__ . ' Try to add a message in stack, but value to add is empty message', LOG_WARNING);
598 } else {
599 if (!in_array((string) $style, array('mesgs', 'warnings', 'errors'))) {
600 dol_print_error(null, 'Bad parameter style=' . $style . ' for setEventMessages');
601 }
602 if (empty($mesgs)) {
603 $this->setEventMessage($mesg, $style);
604 } else {
605 if (!empty($mesg) && !in_array($mesg, $mesgs)) {
606 $this->setEventMessage($mesg, $style); // Add message string if not already into array
607 }
608 $this->setEventMessage($mesgs, $style);
609 }
610 }
611 }
612
618 public function loadEventMessages()
619 {
620 if (!empty($_SESSION['webportal_events'])) {
621 $this->eventMessages = $_SESSION['webportal_events'];
622 return 1;
623 }
624
625 return 0;
626 }
627
633 public function clearEventMessages()
634 {
635 unset($_SESSION['webportal_events']);
636 $this->eventMessages = array();
637 }
638
646 public function newToken()
647 {
648 return newToken();
649 }
650
656 protected function generateNewToken()
657 {
658 $currentToken = $this->newToken();
659 // Creation of a token against CSRF vulnerabilities
660 if (!defined('NOTOKENRENEWAL') || empty($currentToken)) {
661 // Rolling token at each call ($_SESSION['token'] contains token of previous page)
662 if (isset($_SESSION['newtoken'])) {
663 $_SESSION['token'] = $_SESSION['newtoken'];
664 }
665
666 // Save what will be next token. Into forms, we will add param $context->newToken();
667 $token = dol_hash(uniqid((string) mt_rand(), true)); // Generate
668 $_SESSION['newtoken'] = $token;
669
670 return $token;
671 } else {
672 return $this->newToken();
673 }
674 }
675
681 public function getUrlToken()
682 {
683 $token = $this->newToken();
684 if ($token) {
685 return '&' . $this->tokenKey . '=' . $this->newToken();
686 }
687
688 return null;
689 }
690
696 public function getFormToken()
697 {
698 $token = $this->newToken();
699 if ($token) {
700 return '<input type="hidden" name="' . $this->tokenKey . '" value="' . $this->newToken() . '" />';
701 }
702
703 return null;
704 }
705
713 public function getThirdPartyAccountFromLogin($login, $pass)
714 {
715 $id = 0;
716
717 $sql = "SELECT sa.rowid as id, sa.pass_crypted";
718 $sql .= " FROM " . $this->db->prefix() . "societe_account as sa";
719 $sql .= " WHERE sa.login = '" . $this->db->escape($login) . "'";
720 //$sql .= " AND BINARY sa.pass_crypted = '" . $this->db->escape($pass) . "'"; // case sensitive
721 $sql .= " AND sa.site = 'dolibarr_portal'";
722 $sql .= " AND sa.status = 1";
723 $sql .= " AND sa.entity IN (" . getEntity('societe') . ")";
724
725 dol_syslog(__METHOD__ . ' Try to find the third-party account id for login"' . $login . '" and site="dolibarr_portal"', LOG_DEBUG);
726 $result = $this->db->query($sql);
727 if ($result) {
728 if ($this->db->num_rows($result) == 1) {
729 $passok = false;
730 $obj = $this->db->fetch_object($result);
731 if ($obj) {
732 $passcrypted = $obj->pass_crypted;
733
734 // Check crypted password according to crypt algorithm
735 if ($passcrypted && dol_verifyHash($pass, $passcrypted, '0')) {
736 $passok = true;
737 }
738
739 // Password ok ?
740 if ($passok) {
741 $id = $obj->id;
742 } else {
743 dol_syslog(__METHOD__ .' Authentication KO bad password for ' . $login . ', cryptType=auto', LOG_NOTICE);
744 sleep(1); // Brut force protection. Must be same delay when login is not valid
745 return -3;
746 }
747 }
748 } else {
749 dol_syslog(__METHOD__ . ' Many third-party account found for login"' . $login . '" and site="dolibarr_portal"', LOG_ERR);
750 return -2;
751 }
752 } else {
753 $this->error = $this->db->lasterror();
754 return -1;
755 }
756
757 return $id;
758 }
759
767 public function getMemberAccountFromLogin($login, $pass)
768 {
769 $id = 0;
770
771 $sql = "SELECT a.rowid as id, a.pass_crypted";
772 $sql .= " FROM " . $this->db->prefix() . "adherent as a";
773 $sql .= " WHERE a.login = '" . $this->db->escape($login) . "'";
774 $sql .= " AND a.statut = 1";
775 $sql .= " AND a.entity IN (" . getEntity('member') . ")";
776
777 dol_syslog(__METHOD__ . ' Try to find the member account id for login"' . $login . '"', LOG_DEBUG);
778 $result = $this->db->query($sql);
779 if ($result) {
780 if ($this->db->num_rows($result) == 1) {
781 $passok = false;
782 $obj = $this->db->fetch_object($result);
783 if ($obj) {
784 $passcrypted = $obj->pass_crypted;
785
786 // Check crypted password according to crypt algorithm
787 if ($passcrypted && dol_verifyHash($pass, $passcrypted, '0')) {
788 $passok = true;
789 }
790
791 // Password ok ?
792 if ($passok) {
793 $id = $obj->id;
794 } else {
795 dol_syslog(__METHOD__ .' Authentication KO bad password for ' . $login . ', cryptType=auto', LOG_NOTICE);
796 sleep(1); // Brut force protection. Must be same delay when login is not valid
797 return -3;
798 }
799 }
800 } else {
801 dol_syslog(__METHOD__ . ' Many member account found for login"' . $login . '"', LOG_ERR);
802 return -2;
803 }
804 } else {
805 $this->error = $this->db->lasterror();
806 return -1;
807 }
808
809 return $id;
810 }
811}
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
Class Context.
static urlOrigin($withRequestUri=true, $use_forwarded_host=false)
Url origin.
generateNewToken()
Generate new token.
menuIsActive($menuName)
Is menu enabled ?
getErrors()
Get errors.
static getInstance()
Singleton method to create one instance of this object.
$object
Current object of page.
clearEventMessages()
Clear event messages.
getFormToken()
Get token input for form.
newToken()
Return the value of token currently saved into session with name 'newToken'.
setError($errors)
Set errors.
userIsLog()
Check if user is logged.
getUrlToken()
Get token url.
addControllerDefinition($controller, $path, $className)
Add controller definition.
getRootUrl($controller='', $moreParams='', $addToken=true)
Get root url.
static getPublicControllerUrl($controller='', $moreParams='', $Tparams=array())
Generate public controller URL Used for external link (like email or web page) so remove token and co...
setEventMessages($mesg, $mesgs, $style='mesgs')
Set event messages in dol_events session object.
getThirdPartyAccountFromLogin($login, $pass)
Try to find the third-party account id from.
setControllerFound()
Set controller found.
getControllerUrl($controller='', $moreParams='', $addToken=true)
Get controller url according to context.
static getRootConfigUrl()
Get WebPortal root url.
initController($init_theme=true)
Init controller.
$appliName
The application name.
setEventMessage($mesgs, $style='mesgs')
Set event messages in dol_events session object.
__construct()
Constructor.
loadEventMessages()
Load event messages.
clearErrors()
Clear errors.
getMemberAccountFromLogin($login, $pass)
Try to find the member account id from.
Class to manage pages.
Class WebPortalTheme.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_hash($chain, $type='0', $nosalt=0, $mode=0)
Returns a hash (non reversible encryption) of a string.
dol_verifyHash($chain, $hash, $type='0')
Compute a hash and compare it to the given one For backward compatibility reasons,...