diff --git a/ChangeLog b/ChangeLog index 25688ef0ccb..3207490752d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,9 @@ The following changes may create regressions for some external modules, but were * The signature for all ->delete() method has been modified to match the modulebuilder template (so first paramis now always $user), except the delete for thirdparty (still accept the id of thirdparty to delete as first parameter). Will probably be modified into another version. * Route for API /thirdparties/gateways has been renamed into /thirdparties/accounts +* The $userdoneid in actioncomm class is deprecated. Please use $userownerid instead. +* The field fk_user_done in actioncomm table is deprecated. Please use fk_user_action instead. +* The AGENDA_ENABLE_DONEBY hidden option is deprecated. ***** ChangeLog for 19.0.1 compared to 19.0.0 ***** diff --git a/SECURITY.md b/SECURITY.md index 0cc37b96ce6..02a015756cf 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -104,3 +104,5 @@ Scope is the web application (backoffice) and the APIs. * SSL/TLS best practices * Invalid or missing SPF (Sender Policy Framework) records (Incomplete or missing SPF/DKIM/DMARC) * Physical or social engineering attempts or issues that require physical access to a victim’s computer/device +* Vulnerabilities of type XSS exploited by using javascript into a website page (with permission to edit website pages) or by using php code into a website page + using the permission to edit php code are not qualified, except if this allow to get higher privileges (being able to set javascript or php code is the expected behaviour). diff --git a/dev/tools/codespell/codespell-ignore.txt b/dev/tools/codespell/codespell-ignore.txt index c71e990a467..0c84807010b 100644 --- a/dev/tools/codespell/codespell-ignore.txt +++ b/dev/tools/codespell/codespell-ignore.txt @@ -57,3 +57,4 @@ dur fonction espace methode +datee diff --git a/dev/tools/phan/config.php b/dev/tools/phan/config.php index 4771e953a36..0f97494f6f5 100644 --- a/dev/tools/phan/config.php +++ b/dev/tools/phan/config.php @@ -453,7 +453,7 @@ return [ 'PhanTypeInvalidDimOffset', // 'PhanPluginNoCommentOnProtectedProperty', // 'PhanPluginDescriptionlessCommentOnPublicMethod', - 'PhanPluginUnknownClosureParamType', + // 'PhanPluginUnknownClosureParamType', 'PhanPluginUnknownClosureReturnType', // 'PhanPluginNoCommentOnProtectedMethod', // 'PhanTypeArraySuspicious', @@ -527,7 +527,7 @@ return [ 'PhanTypeMismatchBitwiseBinaryOperands', 'PhanTypeMismatchDimEmpty', 'PhanTypeSuspiciousEcho', - 'PhanNoopBinaryOperator', + // 'PhanNoopBinaryOperator', // 'PhanTypeInvalidBitwiseBinaryOperator', // 'PhanPluginDescriptionlessCommentOnFunction', 'PhanPluginPHPDocInWrongComment', @@ -549,7 +549,7 @@ return [ // 'PhanSyntaxReturnValueInVoid', // 'PhanTypeInstantiateTraitStaticOrSelf', // 'PhanUndeclaredInvokeInCallable', - 'PhanNoopProperty', + // 'PhanNoopProperty', 'PhanNoopVariable', // 'PhanPluginPrintfUnusedArgument', // 'PhanSyntaxReturnExpectedValue', diff --git a/dev/tools/phan/config_extended.php b/dev/tools/phan/config_extended.php index b9e92619b06..91b2894cd26 100644 --- a/dev/tools/phan/config_extended.php +++ b/dev/tools/phan/config_extended.php @@ -368,6 +368,7 @@ return [ 'PhanPluginDuplicateConditionalTernaryDuplication', // 2750+ occurrences 'PhanPluginDuplicateConditionalNullCoalescing', // Not essential - 990+ occurrences 'PhanPluginRedundantAssignmentInGlobalScope', // Not essential, a lot of false warning + 'PhanPluginDuplicateCatchStatementBody', // Requires PHP7.1 - 50+ occurrences ], // You can put relative paths to internal stubs in this config option. // Phan will continue using its detailed type annotations, diff --git a/htdocs/accountancy/admin/accountmodel.php b/htdocs/accountancy/admin/accountmodel.php index dbe02a3ff02..e14477b9158 100644 --- a/htdocs/accountancy/admin/accountmodel.php +++ b/htdocs/accountancy/admin/accountmodel.php @@ -191,10 +191,10 @@ if (GETPOST('actionadd', 'alpha') || GETPOST('actionmodify', 'alpha')) { // Si verif ok et action add, on ajoute la ligne if ($ok && GETPOST('actionadd', 'alpha')) { + $newid = 0; if ($tabrowid[$id]) { // Get free id for insert - $newid = 0; - $sql = "SELECT MAX(".$db->sanitize($tabrowid[$id]).") newid FROM ".$db->sanitize($tabname[$id]); + $sql = "SELECT MAX(".$db->sanitize($tabrowid[$id]).") as newid FROM ".$db->sanitize($tabname[$id]); $result = $db->query($sql); if ($result) { $obj = $db->fetch_object($result); diff --git a/htdocs/adherents/ldap.php b/htdocs/adherents/ldap.php index edfa8adbb2f..f94cc476321 100644 --- a/htdocs/adherents/ldap.php +++ b/htdocs/adherents/ldap.php @@ -120,12 +120,13 @@ print '
'; print ''; // Login -print ''; +print ''; // If there is a link to the unencrypted password, we show the value in database here so we can compare because it is shown nowhere else +// This is for very old situation. Password are now encrypted and $object->pass is empty. if (getDolGlobalString('LDAP_MEMBER_FIELD_PASSWORD')) { print ''; - print ''; + print ''; print "\n"; } diff --git a/htdocs/admin/fckeditor.php b/htdocs/admin/fckeditor.php index 5dc257a55d2..d11c3adf4ca 100644 --- a/htdocs/admin/fckeditor.php +++ b/htdocs/admin/fckeditor.php @@ -3,6 +3,7 @@ * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2012-2013 Juanjo Menent * Copyright (C) 2019 Christophe Battarel + * Copyright (C) 2024 Frédéric France * * 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 @@ -31,7 +32,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/doleditor.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; // Load translation files required by the page -$langs->loadLangs(array('admin', 'fckeditor')); +$langs->loadLangs(array('admin', 'fckeditor', 'errors')); $action = GETPOST('action', 'aZ09'); // Possible modes are: @@ -221,12 +222,12 @@ if (empty($conf->use_javascript_ajax)) { if ($mode != 'Full_inline') { $uselocalbrowser = true; $readonly = ($mode == 'dolibarr_readonly' ? 1 : 0); - $editor = new DolEditor('formtestfield', isset($conf->global->FCKEDITOR_TEST) ? $conf->global->FCKEDITOR_TEST : 'Test', '', 200, $mode, 'In', true, $uselocalbrowser, 1, 120, 8, $readonly); + $editor = new DolEditor('formtestfield', getDolGlobalString('FCKEDITOR_TEST', 'Test'), '', 200, $mode, 'In', true, $uselocalbrowser, 1, 120, 8, $readonly); $editor->Create(); } else { // CKEditor inline enabled with the contenteditable="true" print '
'; - print $conf->global->FCKEDITOR_TEST; + print getDolGlobalString('FCKEDITOR_TEST'); print '
'; } print $form->buttonsSaveCancel("Save", '', null, 0, 'reposition'); diff --git a/htdocs/admin/system/modules.php b/htdocs/admin/system/modules.php index da70b1fbbec..89912dd030e 100644 --- a/htdocs/admin/system/modules.php +++ b/htdocs/admin/system/modules.php @@ -2,6 +2,7 @@ /* Copyright (C) 2005-2009 Laurent Destailleur * Copyright (C) 2007 Rodolphe Quiedeville * Copyright (C) 2010-2012 Regis Houssin + * Copyright (C) 2024 MDW * * 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 @@ -308,21 +309,37 @@ print ''; // sort list if ($sortfield == "name" && $sortorder == "asc") { - usort($moduleList, function (stdClass $a, stdClass $b) { - return strcasecmp($a->name, $b->name); - }); + usort( + $moduleList, + /** @return bool */ + function (stdClass $a, stdClass $b) { + return strcasecmp($a->name, $b->name); + } + ); } elseif ($sortfield == "name" && $sortorder == "desc") { - usort($moduleList, function (stdClass $a, stdClass $b) { - return strcasecmp($b->name, $a->name); - }); + usort( + $moduleList, + /** @return bool */ + static function (stdClass $a, stdClass $b) { + return strcasecmp($b->name, $a->name); + } + ); } elseif ($sortfield == "version" && $sortorder == "asc") { - usort($moduleList, function (stdClass $a, stdClass $b) { - return strcasecmp($a->version, $b->version); - }); + usort( + $moduleList, + /** @return bool */ + static function (stdClass $a, stdClass $b) { + return strcasecmp($a->version, $b->version); + } + ); } elseif ($sortfield == "version" && $sortorder == "desc") { - usort($moduleList, function (stdClass $a, stdClass $b) { - return strcasecmp($b->version, $a->version); - }); + usort( + $moduleList, + /** @return bool */ + static function (stdClass $a, stdClass $b) { + return strcasecmp($b->version, $a->version); + } + ); } elseif ($sortfield == "id" && $sortorder == "asc") { usort($moduleList, "compareIdAsc"); } elseif ($sortfield == "id" && $sortorder == "desc") { diff --git a/htdocs/admin/workflow.php b/htdocs/admin/workflow.php index e06954b0422..2e28dc8a6f9 100644 --- a/htdocs/admin/workflow.php +++ b/htdocs/admin/workflow.php @@ -3,6 +3,7 @@ * Copyright (C) 2004 Eric Seigne * Copyright (C) 2005-2021 Laurent Destailleur * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2024 MDW * * 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 @@ -60,96 +61,96 @@ clearstatcache(); $workflowcodes = array( // Automatic creation - 'WORKFLOW_PROPAL_AUTOCREATE_ORDER'=>array( - 'family'=>'create', - 'position'=>10, - 'enabled'=>(isModEnabled("propal") && isModEnabled('order')), - 'picto'=>'order' + 'WORKFLOW_PROPAL_AUTOCREATE_ORDER' => array( + 'family' => 'create', + 'position' => 10, + 'enabled' => (isModEnabled("propal") && isModEnabled('order')), + 'picto' => 'order' ), - 'WORKFLOW_ORDER_AUTOCREATE_INVOICE'=>array( - 'family'=>'create', - 'position'=>20, - 'enabled'=>(isModEnabled('order') && isModEnabled('invoice')), - 'picto'=>'bill' + 'WORKFLOW_ORDER_AUTOCREATE_INVOICE' => array( + 'family' => 'create', + 'position' => 20, + 'enabled' => (isModEnabled('order') && isModEnabled('invoice')), + 'picto' => 'bill' ), 'WORKFLOW_TICKET_CREATE_INTERVENTION' => array( - 'family'=>'create', - 'position'=>25, - 'enabled'=>(isModEnabled('ticket') && isModEnabled('intervention')), - 'picto'=>'ticket' + 'family' => 'create', + 'position' => 25, + 'enabled' => (isModEnabled('ticket') && isModEnabled('intervention')), + 'picto' => 'ticket' ), - 'separator1'=>array('family'=>'separator', 'position'=>25, 'title'=>'', 'enabled'=>((isModEnabled("propal") && isModEnabled('order')) || (isModEnabled('order') && isModEnabled('invoice')) || (isModEnabled('ticket') && isModEnabled('intervention')))), + 'separator1' => array('family' => 'separator', 'position' => 25, 'title' => '', 'enabled' => ((isModEnabled("propal") && isModEnabled('order')) || (isModEnabled('order') && isModEnabled('invoice')) || (isModEnabled('ticket') && isModEnabled('intervention')))), // Automatic classification of proposal - 'WORKFLOW_ORDER_CLASSIFY_BILLED_PROPAL'=>array( - 'family'=>'classify_proposal', - 'position'=>30, - 'enabled'=>(isModEnabled("propal") && isModEnabled('order')), - 'picto'=>'propal', - 'warning'=>'' + 'WORKFLOW_ORDER_CLASSIFY_BILLED_PROPAL' => array( + 'family' => 'classify_proposal', + 'position' => 30, + 'enabled' => (isModEnabled("propal") && isModEnabled('order')), + 'picto' => 'propal', + 'warning' => '' ), - 'WORKFLOW_INVOICE_CLASSIFY_BILLED_PROPAL'=>array( - 'family'=>'classify_proposal', - 'position'=>31, - 'enabled'=>(isModEnabled("propal") && isModEnabled('invoice')), - 'picto'=>'propal', - 'warning'=>'' + 'WORKFLOW_INVOICE_CLASSIFY_BILLED_PROPAL' => array( + 'family' => 'classify_proposal', + 'position' => 31, + 'enabled' => (isModEnabled("propal") && isModEnabled('invoice')), + 'picto' => 'propal', + 'warning' => '' ), // Automatic classification of order - 'WORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING'=>array( // when shipping validated - 'family'=>'classify_order', - 'position'=>40, - 'enabled'=>(isModEnabled("shipping") && isModEnabled('order')), - 'picto'=>'order' + 'WORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING' => array( // when shipping validated + 'family' => 'classify_order', + 'position' => 40, + 'enabled' => (isModEnabled("shipping") && isModEnabled('order')), + 'picto' => 'order' ), - 'WORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING_CLOSED'=>array( // when shipping closed - 'family'=>'classify_order', - 'position'=>41, - 'enabled'=>(isModEnabled("shipping") && isModEnabled('order')), - 'picto'=>'order' + 'WORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING_CLOSED' => array( // when shipping closed + 'family' => 'classify_order', + 'position' => 41, + 'enabled' => (isModEnabled("shipping") && isModEnabled('order')), + 'picto' => 'order' ), - 'WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_ORDER'=>array( - 'family'=>'classify_order', - 'position'=>42, - 'enabled'=>(isModEnabled('invoice') && isModEnabled('order')), - 'picto'=>'order', - 'warning'=>'' + 'WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_ORDER' => array( + 'family' => 'classify_order', + 'position' => 42, + 'enabled' => (isModEnabled('invoice') && isModEnabled('order')), + 'picto' => 'order', + 'warning' => '' ), // For this option, if module invoice is disabled, it does not exists, so "Classify billed" for order must be done manually from order card. // Automatic classification supplier proposal - 'WORKFLOW_ORDER_CLASSIFY_BILLED_SUPPLIER_PROPOSAL'=>array( - 'family'=>'classify_supplier_proposal', - 'position'=>60, - 'enabled'=>(isModEnabled('supplier_proposal') && (isModEnabled("supplier_order") || isModEnabled("supplier_invoice"))), - 'picto'=>'supplier_proposal', - 'warning'=>'' + 'WORKFLOW_ORDER_CLASSIFY_BILLED_SUPPLIER_PROPOSAL' => array( + 'family' => 'classify_supplier_proposal', + 'position' => 60, + 'enabled' => (isModEnabled('supplier_proposal') && (isModEnabled("supplier_order") || isModEnabled("supplier_invoice"))), + 'picto' => 'supplier_proposal', + 'warning' => '' ), // Automatic classification supplier order - 'WORKFLOW_ORDER_CLASSIFY_RECEIVED_RECEPTION'=>array( - 'family'=>'classify_supplier_order', - 'position'=>63, - 'enabled'=>(getDolGlobalString('MAIN_FEATURES_LEVEL') && isModEnabled("reception") && isModEnabled('supplier_order')), - 'picto'=>'supplier_order', - 'warning'=>'' + 'WORKFLOW_ORDER_CLASSIFY_RECEIVED_RECEPTION' => array( + 'family' => 'classify_supplier_order', + 'position' => 63, + 'enabled' => (getDolGlobalString('MAIN_FEATURES_LEVEL') && isModEnabled("reception") && isModEnabled('supplier_order')), + 'picto' => 'supplier_order', + 'warning' => '' ), - 'WORKFLOW_ORDER_CLASSIFY_RECEIVED_RECEPTION_CLOSED'=>array( - 'family'=>'classify_supplier_order', - 'position'=>64, - 'enabled'=>(getDolGlobalString('MAIN_FEATURES_LEVEL') && isModEnabled("reception") && isModEnabled('supplier_order')), - 'picto'=>'supplier_order', - 'warning'=>'' + 'WORKFLOW_ORDER_CLASSIFY_RECEIVED_RECEPTION_CLOSED' => array( + 'family' => 'classify_supplier_order', + 'position' => 64, + 'enabled' => (getDolGlobalString('MAIN_FEATURES_LEVEL') && isModEnabled("reception") && isModEnabled('supplier_order')), + 'picto' => 'supplier_order', + 'warning' => '' ), - 'WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_SUPPLIER_ORDER'=>array( - 'family'=>'classify_supplier_order', - 'position'=>65, - 'enabled'=>(isModEnabled("supplier_order") || isModEnabled("supplier_invoice")), - 'picto'=>'supplier_order', - 'warning'=>'' + 'WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_SUPPLIER_ORDER' => array( + 'family' => 'classify_supplier_order', + 'position' => 65, + 'enabled' => (isModEnabled("supplier_order") || isModEnabled("supplier_invoice")), + 'picto' => 'supplier_order', + 'warning' => '' ), // Automatic classification shipping @@ -188,7 +189,7 @@ $workflowcodes = array( ), - 'separator2'=>array('family'=>'separator', 'position'=>400, 'enabled' => (isModEnabled('ticket') && isModEnabled('contract'))), + 'separator2' => array('family' => 'separator', 'position' => 400, 'enabled' => (isModEnabled('ticket') && isModEnabled('contract'))), // Automatic link ticket -> contract 'WORKFLOW_TICKET_LINK_CONTRACT' => array( @@ -212,9 +213,16 @@ if (!empty($conf->modules_parts['workflow']) && is_array($conf->modules_parts['w } // remove not available workflows (based on activated modules and global defined keys) -$workflowcodes = array_filter($workflowcodes, function ($var) { - return $var['enabled']; -}); +$workflowcodes = array_filter( + $workflowcodes, + /** + * @param array{enabled:int<0,1>} $var + * @return int<0,1> + */ + static function ($var) { + return $var['enabled']; + } +); diff --git a/htdocs/ai/admin/custom_prompt.php b/htdocs/ai/admin/custom_prompt.php index 7790c822249..8974e25a66c 100644 --- a/htdocs/ai/admin/custom_prompt.php +++ b/htdocs/ai/admin/custom_prompt.php @@ -255,7 +255,7 @@ if ($action == 'edit') { $out .= 'pre-Prompt'; $out .= ''; $out .= '
'; $out .= ''; $out .= ''; @@ -263,7 +263,7 @@ if ($action == 'edit') { $out .= 'Post-prompt'; $out .= ''; $out .= ''; $out .= ''; $out .= ''; @@ -307,7 +307,7 @@ if ($action == 'edit' || $action == 'create') { $out .= 'pre-Prompt'; $out .= ''; $out .= ''; $out .= ''; $out .= ''; @@ -315,8 +315,9 @@ if ($action == 'edit' || $action == 'create') { $out .= 'Post-prompt'; $out .= ''; $out .= ''; $out .= ''; $out .= ''; diff --git a/htdocs/api/class/api_access.class.php b/htdocs/api/class/api_access.class.php index 82a60bc5116..8e4bdb0db9f 100644 --- a/htdocs/api/class/api_access.class.php +++ b/htdocs/api/class/api_access.class.php @@ -2,6 +2,7 @@ /* Copyright (C) 2015 Jean-François Ferry * Copyright (C) 2016 Laurent Destailleur * Copyright (C) 2023 Ferran Marcet + * Copyright (C) 2024 MDW * * 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 @@ -19,11 +20,16 @@ // Create the autoloader for Luracast require_once DOL_DOCUMENT_ROOT.'/includes/restler/framework/Luracast/Restler/AutoLoader.php'; -call_user_func(function () { - $loader = Luracast\Restler\AutoLoader::instance(); - spl_autoload_register($loader); - return $loader; -}); +call_user_func( + /** + * @return Luracast\Restler\AutoLoader + */ + static function () { + $loader = Luracast\Restler\AutoLoader::instance(); + spl_autoload_register($loader); + return $loader; + } +); require_once DOL_DOCUMENT_ROOT.'/includes/restler/framework/Luracast/Restler/iAuthenticate.php'; require_once DOL_DOCUMENT_ROOT.'/includes/restler/framework/Luracast/Restler/iUseAuthentication.php'; diff --git a/htdocs/api/index.php b/htdocs/api/index.php index d55fe8d38d5..4b3385fe5ee 100644 --- a/htdocs/api/index.php +++ b/htdocs/api/index.php @@ -3,6 +3,7 @@ * Copyright (C) 2016 Laurent Destailleur * Copyright (C) 2017 Regis Houssin * Copyright (C) 2021 Alexis LAURIER + * Copyright (C) 2024 MDW * * 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 @@ -91,11 +92,16 @@ if (!$res) { require_once DOL_DOCUMENT_ROOT.'/includes/restler/framework/Luracast/Restler/AutoLoader.php'; -call_user_func(function () { - $loader = Luracast\Restler\AutoLoader::instance(); - spl_autoload_register($loader); - return $loader; -}); +call_user_func( + /** + * @return Luracast\Restler\AutoLoader + */ + static function () { + $loader = Luracast\Restler\AutoLoader::instance(); + spl_autoload_register($loader); + return $loader; + } +); require_once DOL_DOCUMENT_ROOT.'/api/class/api.class.php'; require_once DOL_DOCUMENT_ROOT.'/api/class/api_access.class.php'; diff --git a/htdocs/categories/viewcat.php b/htdocs/categories/viewcat.php index efcd10ddbb9..a277b9b03c8 100644 --- a/htdocs/categories/viewcat.php +++ b/htdocs/categories/viewcat.php @@ -102,7 +102,7 @@ if ($confirm == 'no') { } } -$parameters = array(); +$parameters = array('type' => $type, 'id' => $id, 'label' => $label); $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks // Remove element from category if ($id > 0 && $removeelem > 0 && $action == 'unlink') { @@ -1355,6 +1355,10 @@ if ($type == Categorie::TYPE_TICKET) { } } +// Note that $action and $object may have been modified by some hooks +$parameters = array('type' => $type, 'id' => $id, 'label' => $label); +$reshook = $hookmanager->executeHooks('addMoreCategoriesList', $parameters, $object, $action); + // End of page llxFooter(); $db->close(); diff --git a/htdocs/comm/action/card.php b/htdocs/comm/action/card.php index f5d96eec190..1e27f3d54f8 100644 --- a/htdocs/comm/action/card.php +++ b/htdocs/comm/action/card.php @@ -426,12 +426,6 @@ if (empty($reshook) && $action == 'add') { } } - if (!$error && getDolGlobalString('AGENDA_ENABLE_DONEBY')) { - if (GETPOST("doneby") > 0) { - $object->userdoneid = GETPOSTINT("doneby"); - } - } - $object->note_private = trim(GETPOST("note", "restricthtml")); if (GETPOSTISSET("contactid")) { @@ -877,12 +871,6 @@ if (empty($reshook) && $action == 'update') { $object->transparency = $transparency; // We set transparency on event (even if we can also store it on each user, standard says this property is for event) // TODO store also transparency on owner user - if (getDolGlobalString('AGENDA_ENABLE_DONEBY')) { - if (GETPOST("doneby")) { - $object->userdoneid = GETPOSTINT("doneby"); - } - } - // Check parameters if (GETPOSTISSET('actioncode') && !GETPOST('actioncode', 'aZ09')) { // actioncode is '0' $error++; @@ -1230,16 +1218,6 @@ if ($action == 'create') { setdatefields(); }); - $("#selectcomplete").change(function() { - console.log("we change the complete status - set the doneby"); - if ($("#selectcomplete").val() == 100) { - if ($("#doneby").val() <= 0) $("#doneby").val(\''.((int) $user->id).'\'); - } - if ($("#selectcomplete").val() == 0) { - $("#doneby").val(-1); - } - }); - $("#actioncode").change(function() { if ($("#actioncode").val() == \'AC_RDV\') $("#dateend").addClass("fieldrequired"); else $("#dateend").removeClass("fieldrequired"); @@ -1444,13 +1422,6 @@ if ($action == 'create') { print ''; print ''; - // Done by - if (getDolGlobalString('AGENDA_ENABLE_DONEBY')) { - print ''; - } - // Location if (!getDolGlobalString('AGENDA_DISABLE_LOCATION')) { print ''; @@ -1995,13 +1966,6 @@ if ($id > 0) { }*/ print ''; - // Realised by - if (getDolGlobalString('AGENDA_ENABLE_DONEBY')) { - print ''; - } - // Location if (!getDolGlobalString('AGENDA_DISABLE_LOCATION')) { print ''; @@ -2427,17 +2391,6 @@ if ($id > 0) { */ print ' '; - // Done by - if (getDolGlobalString('AGENDA_ENABLE_DONEBY')) { - print ''; - } - // Categories if (isModEnabled('category')) { print '
'.$langs->trans("Login").' / '.$langs->trans("Id").''.$object->login.' 
'.$langs->trans("Login").' / '.$langs->trans("Id").''.dol_escape_htmltag($object->login).' 
'.$langs->trans("LDAPFieldPasswordNotCrypted").''.$object->pass.''.dol_escape_htmltag($object->pass).'
'; - $out .= ''; + $out .= ''; $out .= '
'; - $out .= ''; + $out .= ''; $out .= '
'; - $out .= ''; + $out .= ''; $out .= '
'; - $out .= ''; + $out .= ''; $out .= '
'; + $out .= '
'.$langs->trans("ActionDoneBy").''; - print $form->select_dolusers(GETPOSTISSET("doneby") ? GETPOSTINT("doneby") : (!empty($object->userdoneid) && $percent == 100 ? $object->userdoneid : 0), 'doneby', 1); - print '
'.$langs->trans("Location").'
'.$langs->trans("ActionDoneBy").''; - print $form->select_dolusers($object->userdoneid > 0 ? $object->userdoneid : -1, 'doneby', 1); - print '
'.$langs->trans("Location").'
'.$langs->trans("ActionDoneBy").''; - if ($object->userdoneid > 0) { - $tmpuser = new User($db); - $tmpuser->fetch($object->userdoneid); - print $tmpuser->getNomUrl(1); - } - print '
'.$langs->trans("Categories").''; diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php index 704f14baeb8..db8eadee618 100644 --- a/htdocs/comm/action/class/actioncomm.class.php +++ b/htdocs/comm/action/class/actioncomm.class.php @@ -6,7 +6,8 @@ * Copyright (C) 2015 Marcos García * Copyright (C) 2018 Nicolas ZABOURI * Copyright (C) 2018-2024 Frédéric France - * Copyright (C) 2024 MDW + * Copyright (C) 2024 MDW + * Copyright (C) 2024 William Mead * * 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 @@ -240,11 +241,6 @@ class ActionComm extends CommonObject */ public $userownerid; - /** - * @var int Id of user that has done the event. Used only if AGENDA_ENABLE_DONEBY is set. - */ - public $userdoneid; - /** * @var int[] Array of contact ids */ @@ -493,7 +489,6 @@ class ActionComm extends CommonObject } $userownerid = $this->userownerid; - $userdoneid = $this->userdoneid; // Be sure assigned user is defined as an array of array('id'=>,'mandatory'=>,...). if (empty($this->userassigned) || count($this->userassigned) == 0 || !is_array($this->userassigned)) { @@ -543,7 +538,6 @@ class ActionComm extends CommonObject $sql .= "fk_contact,"; $sql .= "fk_user_author,"; $sql .= "fk_user_action,"; - $sql .= "fk_user_done,"; $sql .= "label,percent,priority,fulldayevent,location,"; $sql .= "transparency,"; $sql .= "fk_element,"; @@ -582,7 +576,6 @@ class ActionComm extends CommonObject $sql .= ((isset($this->contact_id) && $this->contact_id > 0) ? ((int) $this->contact_id) : "null").", "; // deprecated, use ->socpeopleassigned $sql .= (isset($user->id) && $user->id > 0 ? $user->id : "null").", "; $sql .= ($userownerid > 0 ? $userownerid : "null").", "; - $sql .= ($userdoneid > 0 ? $userdoneid : "null").", "; $sql .= "'".$this->db->escape($this->label)."', "; $sql .= "'".$this->db->escape($this->percentage)."', "; $sql .= "'".$this->db->escape($this->priority)."', "; @@ -811,7 +804,7 @@ class ActionComm extends CommonObject $sql .= " a.fk_soc,"; $sql .= " a.fk_project,"; $sql .= " a.fk_user_author, a.fk_user_mod,"; - $sql .= " a.fk_user_action, a.fk_user_done,"; + $sql .= " a.fk_user_action,"; $sql .= " a.fk_contact, a.percent as percentage,"; $sql .= " a.fk_element as elementid, a.elementtype,"; $sql .= " a.priority, a.fulldayevent, a.location, a.transparency,"; @@ -1161,16 +1154,9 @@ class ActionComm extends CommonObject $this->fk_project = 0; } - // Check parameters - if ($this->percentage == 0 && $this->userdoneid > 0) { - $this->error = "ErrorCantSaveADoneUserWithZeroPercentage"; - return -1; - } - $socid = (($this->socid > 0) ? $this->socid : 0); $contactid = (($this->contact_id > 0) ? $this->contact_id : 0); $userownerid = ($this->userownerid ? $this->userownerid : 0); - $userdoneid = ($this->userdoneid ? $this->userdoneid : 0); // If a type_id is set, we must also have the type_code set if ($this->type_id > 0) { @@ -1208,7 +1194,6 @@ class ActionComm extends CommonObject $sql .= ", transparency = '".$this->db->escape($this->transparency)."'"; $sql .= ", fk_user_mod = ".((int) $user->id); $sql .= ", fk_user_action = ".($userownerid > 0 ? ((int) $userownerid) : "null"); - $sql .= ", fk_user_done = ".($userdoneid > 0 ? ((int) $userdoneid) : "null"); if (!empty($this->fk_element)) { $sql .= ", fk_element=".($this->fk_element ? ((int) $this->fk_element) : "null"); } @@ -1431,7 +1416,7 @@ class ActionComm extends CommonObject } $sql .= " AND a.entity IN (".getEntity('agenda').")"; if (!$user->hasRight('agenda', 'allactions', 'read')) { - $sql .= " AND (a.fk_user_author = ".((int) $user->id)." OR a.fk_user_action = ".((int) $user->id)." OR a.fk_user_done = ".((int) $user->id); + $sql .= " AND (a.fk_user_author = ".((int) $user->id)." OR a.fk_user_action = ".((int) $user->id); $sql .= " OR ar.fk_element = ".((int) $user->id); $sql .= ")"; } @@ -2003,7 +1988,6 @@ class ActionComm extends CommonObject $buildfile = true; $login = ''; $logina = ''; - $logind = ''; $logint = ''; $eventorganization = ''; @@ -2354,9 +2338,6 @@ class ActionComm extends CommonObject if ($logint) { $more = $langs->transnoentities("ActionsToDoBy").' '.$logint; } - if ($logind) { - $more = $langs->transnoentities("ActionsDoneBy").' '.$logind; - } if ($eventorganization) { $langs->load("eventorganization"); $title = $langs->transnoentities("OrganizedEvent").(empty($eventarray[0]['label']) ? '' : ' '.$eventarray[0]['label']); diff --git a/htdocs/compta/cashcontrol/cashcontrol_card.php b/htdocs/compta/cashcontrol/cashcontrol_card.php index fe4d5a15f77..74cce92938d 100644 --- a/htdocs/compta/cashcontrol/cashcontrol_card.php +++ b/htdocs/compta/cashcontrol/cashcontrol_card.php @@ -6,6 +6,7 @@ * Copyright (C) 2015 Jean-François Ferry * Copyright (C) 2016 Marcos García * Copyright (C) 2018 Andreu Bisquerra + * Copyright (C) 2024 MDW * * 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 @@ -68,7 +69,7 @@ if ($contextpage == 'takepos') { $_GET['optioncss'] = 'print'; } -$arrayofpaymentmode = array('cash'=>'Cash', 'cheque'=>'Cheque', 'card'=>'CreditCard'); +$arrayofpaymentmode = array('cash' => 'Cash', 'cheque' => 'Cheque', 'card' => 'CreditCard'); $arrayofposavailable = array(); if (isModEnabled('cashdesk')) { @@ -180,7 +181,7 @@ if ($action == "start") { $db->commit(); $action = "view"; } else { - $db->rollback; + $db->rollback(); $action = "view"; } } diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index b80ce304f94..251442a9b72 100644 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -5,8 +5,9 @@ * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2015 Marcos García * Copyright (C) 2016-2023 Charlene Benke - * Copyright (C) 2018-2023 Frédéric France + * Copyright (C) 2018-2024 Frédéric France * Copyright (C) 2020 Josep Lluís Amador + * Copyright (C) 2024 MDW * * 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 @@ -232,6 +233,9 @@ abstract class CommonDocGenerator ); // Retrieve extrafields if (is_array($user->array_options) && count($user->array_options)) { + if (empty($extrafields->attributes[$user->table_element])) { + $extrafields->fetch_name_optionals_label($user->table_element); + } $array_user = $this->fill_substitutionarray_with_extrafields($user, $array_user, $extrafields, 'myuser', $outputlangs); } return $array_user; @@ -1488,9 +1492,17 @@ abstract class CommonDocGenerator if (!empty($fields)) { // Sort extrafields by rank - uasort($fields, function ($a, $b) { - return ($a->rank > $b->rank) ? 1 : -1; - }); + uasort( + $fields, + /** + * @param stdClass $a + * @param stdClass $b + * @return int<-1,1> + */ + static function ($a, $b) { + return ($a->rank > $b->rank) ? 1 : -1; + } + ); // define some HTML content with style $html .= !empty($params['style']) ? '' : ''; diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 960d9ee7eec..5b18aee94af 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -857,14 +857,14 @@ function dol_copy($srcfile, $destfile, $newmask = '0', $overwriteifexists = 1, $ /** * Copy a dir to another dir. This include recursive subdirectories. * - * @param string $srcfile Source file (a directory) - * @param string $destfile Destination file (a directory) - * @param string $newmask Mask for new file ('0' by default means getDolGlobalString('MAIN_UMASK')). Example: '0666' - * @param int $overwriteifexists Overwrite file if exists (1 by default) + * @param string $srcfile Source file (a directory) + * @param string $destfile Destination file (a directory) + * @param string $newmask Mask for new file ('0' by default means getDolGlobalString('MAIN_UMASK')). Example: '0666' + * @param int $overwriteifexists Overwrite file if exists (1 by default) * @param array $arrayreplacement Array to use to replace filenames with another one during the copy (works only on file names, not on directory names). - * @param int $excludesubdir 0=Do not exclude subdirectories, 1=Exclude subdirectories, 2=Exclude subdirectories if name is not a 2 chars (used for country codes subdirectories). - * @param string[] $excludefileext Exclude some file extensions - * @return int Return integer <0 if error, 0 if nothing done (all files already exists and overwriteifexists=0), >0 if OK + * @param int $excludesubdir 0=Do not exclude subdirectories, 1=Exclude subdirectories, 2=Exclude subdirectories if name is not a 2 chars (used for country codes subdirectories). + * @param string[] $excludefileext Exclude some file extensions + * @return int Return integer <0 if error, 0 if nothing done (all files already exists and overwriteifexists=0), >0 if OK * @see dol_copy() */ function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement = null, $excludesubdir = 0, $excludefileext = null) @@ -878,6 +878,7 @@ function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayrep } $destexists = dol_is_dir($destfile); + //if (! $overwriteifexists && $destexists) return 0; // The overwriteifexists is for files only, so propagated to dol_copy only. if (!$destexists) { @@ -888,7 +889,13 @@ function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayrep $dirmaskdec = octdec(getDolGlobalString('MAIN_UMASK')); } $dirmaskdec |= octdec('0200'); // Set w bit required to be able to create content for recursive subdirs files - dol_mkdir($destfile, '', decoct($dirmaskdec)); + + $result = dol_mkdir($destfile, '', decoct($dirmaskdec)); + + if (!dol_is_dir($destfile)) { + // The output directory does not exists and we failed to create it. So we stop here. + return -1; + } } $ossrcfile = dol_osencode($srcfile); diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index bcc2e9864e9..68256ee7774 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -4618,7 +4618,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $srco if (empty($srconly) && in_array($pictowithouttext, array( '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected', 'accountancy', 'accounting_account', 'account', 'accountline', 'action', 'add', 'address', 'ai', 'angle-double-down', 'angle-double-up', 'asset', - 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bookmark', 'bom', 'briefcase-medical', 'bug', 'building', + 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bom', 'bookcal', 'bookmark', 'briefcase-medical', 'bug', 'building', 'card', 'calendarlist', 'calendar', 'calendarmonth', 'calendarweek', 'calendarday', 'calendarperuser', 'calendarpertype', 'cash-register', 'category', 'chart', 'check', 'clock', 'clone', 'close_title', 'code', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cross', 'cubes', 'check-circle', 'check-square', 'currency', 'multicurrency', @@ -4666,6 +4666,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $srco 'asset' => 'money-check-alt', 'autofill' => 'fill', 'bank_account' => 'university', 'bill' => 'file-invoice-dollar', 'billa' => 'file-excel', 'billr' => 'file-invoice-dollar', 'billd' => 'file-medical', + 'bookcal' => 'calendar-check', 'supplier_invoice' => 'file-invoice-dollar', 'supplier_invoicea' => 'file-excel', 'supplier_invoicer' => 'file-invoice-dollar', 'supplier_invoiced' => 'file-medical', 'bom' => 'shapes', 'card' => 'address-card', 'chart' => 'chart-line', 'company' => 'building', 'contact' => 'address-book', 'contract' => 'suitcase', 'collab' => 'people-arrows', 'conversation' => 'comments', 'country' => 'globe-americas', 'cron' => 'business-time', 'cross' => 'times', @@ -4764,6 +4765,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $srco 'action' => 'infobox-action', 'account' => 'infobox-bank_account', 'accounting_account' => 'infobox-bank_account', 'accountline' => 'infobox-bank_account', 'accountancy' => 'infobox-bank_account', 'asset' => 'infobox-bank_account', 'bank_account' => 'infobox-bank_account', 'bill' => 'infobox-commande', 'billa' => 'infobox-commande', 'billr' => 'infobox-commande', 'billd' => 'infobox-commande', + 'bookcal' => 'infobox-action', 'margin' => 'infobox-bank_account', 'conferenceorbooth' => 'infobox-project', 'cash-register' => 'infobox-bank_account', 'contract' => 'infobox-contrat', 'check' => 'font-status4', 'collab' => 'infobox-action', 'conversation' => 'infobox-contrat', 'donation' => 'infobox-commande', 'dolly' => 'infobox-commande', 'dollyrevert' => 'flip infobox-order_supplier', @@ -7424,7 +7426,7 @@ function dol_mkdir($dir, $dataroot = '', $newmask = '') } $dirmaskdec |= octdec('0111'); // Set x bit required for directories if (!@mkdir($ccdir_osencoded, $dirmaskdec)) { - // Si le is_dir a renvoye une fausse info, alors on passe ici. + // If the is_dir has returned a false information, we arrive here dol_syslog("functions.lib::dol_mkdir: Fails to create directory '".$ccdir."' or directory already exists.", LOG_WARNING); $nberr++; } else { @@ -7927,9 +7929,17 @@ function dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox = 0, $check = ' // We replace chars from a/A to z/Z encoded with numeric HTML entities with the real char so we won't loose the chars at the next step (preg_replace). // No need to use a loop here, this step is not to sanitize (this is done at next step, this is to try to save chars, even if they are // using a non coventionnel way to be encoded, to not have them sanitized just after) - $out = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) { - return realCharForNumericEntities($m); - }, $out); + $out = preg_replace_callback( + '/&#(x?[0-9][0-9a-f]+;?)/i', + /** + * @param string $m + * @return string + */ + static function ($m) { + return realCharForNumericEntities($m); + }, + $out + ); // Now we remove all remaining HTML entities starting with a number. We don't want such entities. @@ -9726,14 +9736,14 @@ function dol_osencode($str) * Return an id or code from a code or id. * Store also Code-Id into a cache to speed up next request on same key. * - * @param DoliDB $db Database handler - * @param string $key Code or Id to get Id or Code - * @param string $tablename Table name without prefix - * @param string $fieldkey Field to search the key into - * @param string $fieldid Field to get - * @param int $entityfilter Filter by entity - * @param string $filters Filters to add. WARNING: string must be escaped for SQL and not coming from user input. - * @return int<-1,max> ID of code if OK, 0 if key empty, -1 if KO + * @param DoliDB $db Database handler + * @param string $key Code or Id to get Id or Code + * @param string $tablename Table name without prefix + * @param string $fieldkey Field to search the key into + * @param string $fieldid Field to get + * @param int $entityfilter Filter by entity + * @param string $filters Filters to add. WARNING: string must be escaped for SQL and not coming from user input. + * @return int<-1,max>|string ID of code if OK, 0 if key empty, -1 if KO * @see $langs->getLabelFromKey */ function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = 'id', $entityfilter = 0, $filters = '') diff --git a/htdocs/core/lib/modulebuilder.lib.php b/htdocs/core/lib/modulebuilder.lib.php index 68e8b982cce..30b199a735f 100644 --- a/htdocs/core/lib/modulebuilder.lib.php +++ b/htdocs/core/lib/modulebuilder.lib.php @@ -1,5 +1,6 @@ + * Copyright (C) 2024 MDW * * 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 @@ -839,7 +840,8 @@ function deletePropsAndPermsFromDoc($file, $objectname) /** - * Search a string and return all lines needed from file + * Search a string and return all lines needed from file. Does not include line $start nor $end + * * @param string $file file for searching * @param string $start start line if exist * @param string $end end line if exist @@ -953,106 +955,136 @@ function writePermsInAsciiDoc($file, $destfile) /** * Add Object in ModuleApi File - * @param string $file path of file - * @param array $objects array of objects in the module - * @param string $modulename name of module - * @return int 1 if OK, -1 if KO + * + * @param string $srcfile Source file to use as example + * @param string $file Path of modified file + * @param array $objects Array of objects in the module + * @param string $modulename Name of module + * @return int Return 1 if OK, -1 if KO */ -function addObjectsToApiFile($file, $objects, $modulename) +function addObjectsToApiFile($srcfile, $file, $objects, $modulename) { + global $langs, $user; + if (!file_exists($file)) { return -1; } - $content = file($file); - $includeClass = "dol_include_once('/mymodule/class/myobject.class.php');"; - $props = "public \$myobject;"; - $varcomented = "@var MyObject \$myobject {@type MyObject}"; - $constructObj = "\$this->myobject = new MyObject(\$this->db);"; + + $now = dol_now(); + $content = file($file); // $content is an array + + $includeClass = "dol_include_once\(\'\/\w+\/class\/\w+\.class\.php\'\);"; + $props = 'public\s+\$\w+;'; + $varcommented = '@var\s+\w+\s+\$\w+\s+{@type\s+\w+}'; + $constructObj = '\$this->\w+\s+=\s+new\s+\w+\(\$this->db\);'; // add properties and declare them in constructor foreach ($content as $lineNumber => &$lineContent) { - if (strpos($lineContent, $varcomented) !== false) { + if (preg_match('/'.$varcommented.'/', $lineContent)) { $lineContent = ''; - foreach ($objects as $object) { - $lineContent .= "\t * @var ".$object." \$".strtolower($object)." {@type ".$object."}". PHP_EOL; + foreach ($objects as $objectname) { + $lineContent .= "\t * @var ".$objectname." \$".strtolower($objectname)." {@type ".$objectname."}". PHP_EOL; } //var_dump($lineContent);exit; - } - if (strpos($lineContent, $props) !== false) { + } elseif (preg_match('/'.$props.'/', $lineContent)) { $lineContent = ''; - foreach ($objects as $object) { - $lineContent .= "\tpublic \$".strtolower($object).";". PHP_EOL; + foreach ($objects as $objectname) { + $lineContent .= "\tpublic \$".strtolower($objectname).";". PHP_EOL; } - } - if (strpos($lineContent, $constructObj) !== false) { + } elseif (preg_match('/'.$constructObj.'/', $lineContent)) { $lineContent = ''; - foreach ($objects as $object) { - $lineContent .= "\t\t\$this->".strtolower($object)." = new ".$object."(\$this->db);". PHP_EOL; + foreach ($objects as $objectname) { + $lineContent .= "\t\t\$this->".strtolower($objectname)." = new ".$objectname."(\$this->db);". PHP_EOL; } - } - if (strpos($lineContent, $includeClass) !== false) { + } elseif (preg_match('/'.$includeClass.'/', $lineContent)) { $lineContent = ''; - foreach ($objects as $object) { - $lineContent .= "dol_include_once('/".strtolower($modulename)."/class/".strtolower($object).".class.php');". PHP_EOL; + foreach ($objects as $objectname) { + $lineContent .= "dol_include_once('/".strtolower($modulename)."/class/".strtolower($objectname).".class.php');". PHP_EOL; } } } + $allContent = implode("", $content); file_put_contents($file, $allContent); - //add methods for each object - $allContent = getFromFile($file, '/*begin methods CRUD*/', '/*end methods CRUD*/'); - foreach ($objects as $object) { - $contentReplaced = str_replace(["myobject","MyObject"], [strtolower($object),$object], $allContent); - dolReplaceInFile($file, array('/*end methods CRUD*/' => '/*CRUD FOR '.strtoupper($object).'*/'."\n".$contentReplaced."\n\t".'/*END CRUD FOR '.strtoupper($object).'*/'."\n\t".'/*end methods CRUD*/')); + // Add methods for each object + $allContent = getFromFile($srcfile, '/* BEGIN MODULEBUILDER API MYOBJECT */', '/* END MODULEBUILDER API MYOBJECT */'); + foreach ($objects as $objectname) { + $arrayreplacement = array( + 'mymodule' => strtolower($modulename), + 'MyModule' => $modulename, + 'MYMODULE' => strtoupper($modulename), + 'My module' => $modulename, + 'my module' => $modulename, + 'Mon module' => $modulename, + 'mon module' => $modulename, + 'htdocs/modulebuilder/template' => strtolower($modulename), + 'myobject' => strtolower($objectname), + 'MyObject' => $objectname, + 'MYOBJECT' => strtoupper($objectname), + '---Put here your own copyright and developer email---' => dol_print_date($now, '%Y').' '.$user->getFullName($langs).($user->email ? ' <'.$user->email.'>' : '') + ); + $contentReplaced = make_substitutions($allContent, $arrayreplacement, null); + //$contentReplaced = str_replace(["myobject","MyObject"], [strtolower($object),$object], $allContent); + + dolReplaceInFile($file, array( + '/* BEGIN MODULEBUILDER API MYOBJECT */' => '/* BEGIN MODULEBUILDER API '.strtoupper($objectname).' */'.$contentReplaced."\t".'/* END MODULEBUILDER API '.strtoupper($objectname).' */'."\n\n\n\t".'/* BEGIN MODULEBUILDER API MYOBJECT */' + )); } - dolReplaceInFile($file, array($allContent => '','MyModule' => ucfirst($modulename))); + + // Remove the block $allContent found in src file + // TODO Replace with a replacement of all text including into /* BEGIN MODULEBUILDER API MYOBJECT */ and /* END MODULEBUILDER API MYOBJECT */ + dolReplaceInFile($file, array($allContent => '')); + return 1; } /** - * Remove Object variables and methods from API_Module File - * @param string $file file api module - * @param string $objectname name of object want to remove - * @param string $modulename name of module - * @return int 1 if OK, -1 if KO + * Remove Object variables and methods from API_Module File + * + * @param string $file File api module + * @param array $objects Array of objects in the module + * @param string $objectname Name of object want to remove + * @return int 1 if OK, -1 if KO */ -function removeObjectFromApiFile($file, $objectname, $modulename) +function removeObjectFromApiFile($file, $objects, $objectname) { - $begin = '/*CRUD FOR '.strtoupper($objectname).'*/'; - $end = '/*END CRUD FOR '.strtoupper($objectname).'*/'; - $includeClass = "dol_include_once('/".strtolower($modulename)."/class/".strtolower($objectname).".class.php');"; - $varcomentedDel = "\t * @var ".$objectname." \$".strtolower($objectname)." {@type ".$objectname."}"; - $propsDel = "\tpublic \$".strtolower($objectname).";"; - $constructObjDel = "\t\t\$this->".strtolower($objectname)." = new ".$objectname."(\$this->db);"; - if (!file_exists($file)) { return -1; } - $content = file($file); - // for delete property and the initialization from the construct + + $content = file($file); // $content is an array + + $includeClass = "dol_include_once\(\'\/\w+\/class\/".strtolower($objectname)."\.class\.php\'\);"; + $props = 'public\s+\$'.strtolower($objectname); + $varcommented = '@var\s+\w+\s+\$'.strtolower($objectname).'\s+{@type\s+\w+}'; + $constructObj = '\$this->'.strtolower($objectname).'\s+=\s+new\s+\w+\(\$this->db\);'; + + // add properties and declare them in constructor foreach ($content as $lineNumber => &$lineContent) { - if (strpos($lineContent, $includeClass) !== false) { + if (preg_match('/'.$varcommented.'/i', $lineContent)) { $lineContent = ''; - } - if (strpos($lineContent, $varcomentedDel) !== false) { + } elseif (preg_match('/'.$props.'/i', $lineContent)) { $lineContent = ''; - } - if (strpos($lineContent, $propsDel) !== false) { + } elseif (preg_match('/'.$constructObj.'/i', $lineContent)) { $lineContent = ''; - } - if (strpos($lineContent, $constructObjDel) !== false) { + } elseif (preg_match('/'.$includeClass.'/i', $lineContent)) { $lineContent = ''; } } + $allContent = implode("", $content); file_put_contents($file, $allContent); + // for delete methods of object + $begin = '/* BEGIN MODULEBUILDER API '.strtoupper($objectname).' */'; + $end = '/* END MODULEBUILDER API '.strtoupper($objectname).' */'; $allContent = getFromFile($file, $begin, $end); $check = dolReplaceInFile($file, array($allContent => '')); if ($check) { dolReplaceInFile($file, array($begin => '', $end => '')); } + return 1; } @@ -1179,9 +1211,16 @@ function updateDictionaryInFile($module, $file, $dicts) $dicData .= "\t\t\t'$key'=>"; if ($key === 'tabcond') { - $conditions = array_map(function ($val) use ($module) { - return ($val === true || $val === false) ? "isModEnabled('$module')" : $val; - }, $value); + $conditions = array_map( + /** + * @param bool|int|string $val + * @return string|int + */ + function ($val) use ($module) { + return is_bool($val) ? "isModEnabled('$module')" : $val; + }, + $value + ); $dicData .= "array(" . implode(",", $conditions) . ")"; } elseif ($key === 'tabhelp') { $helpItems = array(); @@ -1191,9 +1230,19 @@ function updateDictionaryInFile($module, $file, $dicts) $dicData .= "array(" . implode(",", $helpItems) . ")"; } else { if (is_array($value)) { - $dicData .= "array(" . implode(",", array_map(function ($val) { - return "'$val'"; - }, $value)) . ")"; + $dicData .= "array(" . implode( + ",", + array_map( + /** + * @param string $val + * @return string + */ + static function ($val) { + return "'$val'"; + }, + $value + ) + ) . ")"; } else { $dicData .= "'$value'"; } diff --git a/htdocs/core/lib/project.lib.php b/htdocs/core/lib/project.lib.php index ab142a50675..12974209afe 100644 --- a/htdocs/core/lib/project.lib.php +++ b/htdocs/core/lib/project.lib.php @@ -934,7 +934,7 @@ function projectLinesa(&$inc, $parent, &$lines, &$level, $var, $showproject, &$t // Extra fields $extrafieldsobjectkey = $taskstatic->table_element; $extrafieldsobjectprefix = 'efpt.'; - $obj = $lines[$i]->obj; + $obj = $lines[$i]; include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; // Fields from hook $parameters = array('arrayfields' => $arrayfields, 'obj' => $lines[$i]); diff --git a/htdocs/core/lib/website2.lib.php b/htdocs/core/lib/website2.lib.php index 752216aa230..9691b94642a 100644 --- a/htdocs/core/lib/website2.lib.php +++ b/htdocs/core/lib/website2.lib.php @@ -671,7 +671,7 @@ function showWebsiteTemplates(Website $website) */ function checkPHPCode($phpfullcodestringold, $phpfullcodestring) { - global $conf, $langs, $user; + global $langs, $user; $error = 0; @@ -680,9 +680,9 @@ function checkPHPCode($phpfullcodestringold, $phpfullcodestring) } // First check forbidden commands - $forbiddenphpcommands = array(); + $forbiddenphpcommands = array("override_function", "session_id", "session_create_id", "session_regenerate_id"); if (!getDolGlobalString('WEBSITE_PHP_ALLOW_EXEC')) { // If option is not on, we disallow functions to execute commands - $forbiddenphpcommands = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen", "eval", "dol_eval", "executeCLI"); + $forbiddenphpcommands = array_merge($forbiddenphpcommands, array("exec", "passthru", "shell_exec", "system", "proc_open", "popen", "eval", "dol_eval", "executeCLI")); } if (!getDolGlobalString('WEBSITE_PHP_ALLOW_WRITE')) { // If option is not on, we disallow functions to write files $forbiddenphpcommands = array_merge($forbiddenphpcommands, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "unlink", "mkdir", "rmdir", "symlink", "touch", "umask")); diff --git a/htdocs/core/modules/DolibarrModules.class.php b/htdocs/core/modules/DolibarrModules.class.php index 15fbe56aa32..04081ba6a02 100644 --- a/htdocs/core/modules/DolibarrModules.class.php +++ b/htdocs/core/modules/DolibarrModules.class.php @@ -453,7 +453,7 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it $err += $this->insert_tabs(); } - // Insert activation of module's parts + // Insert activation of module's parts. Copy website templates into doctemplates. if (!$err) { $err += $this->insert_module_parts(); } @@ -2310,6 +2310,15 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it $this->errors[] = ($errormsg ? $errormsg : $langs->trans('ErrorFailToCreateZip', $dest)); } } + + // Copy also the preview website_xxx.jpg file + $docs = dol_dir_list($srcroot, 'files', 0, 'website_.*\.jpg$'); + foreach ($docs as $cursorfile) { + $src = $srcroot.'/'.$cursorfile['name']; + $dest = DOL_DATA_ROOT.'/doctemplates/websites/'.$cursorfile['name']; + + dol_copy($src, $dest); + } } $entity = $conf->entity; // Reset the current entity diff --git a/htdocs/core/modules/fichinter/mod_arctic.php b/htdocs/core/modules/fichinter/mod_arctic.php index e8f79c9c084..33fce191c0e 100644 --- a/htdocs/core/modules/fichinter/mod_arctic.php +++ b/htdocs/core/modules/fichinter/mod_arctic.php @@ -121,11 +121,11 @@ class mod_arctic extends ModeleNumRefFicheinter /** * Return next free value * - * @param Societe $objsoc Object thirdparty - * @param Fichinter $object Object we need next value for - * @return string|0 Value if OK, 0 if KO + * @param Societe|string $objsoc Object thirdparty + * @param Fichinter|string $object Object we need next value for + * @return string|0 Value if OK, 0 if KO */ - public function getNextValue($objsoc = 0, $object = '') + public function getNextValue($objsoc = '', $object = '') { global $db, $conf; @@ -138,8 +138,11 @@ class mod_arctic extends ModeleNumRefFicheinter $this->error = 'NotConfigured'; return 0; } - - $numFinal = get_next_value($db, $mask, 'fichinter', 'ref', '', $objsoc, $object->datec); + $datec = ''; + if (!empty($object->datec)) { + $datec = $object->datec; + } + $numFinal = get_next_value($db, $mask, 'fichinter', 'ref', '', $objsoc, $datec); return $numFinal; } diff --git a/htdocs/core/modules/fichinter/mod_pacific.php b/htdocs/core/modules/fichinter/mod_pacific.php index f05a1ec320f..0f780ee2bb6 100644 --- a/htdocs/core/modules/fichinter/mod_pacific.php +++ b/htdocs/core/modules/fichinter/mod_pacific.php @@ -121,11 +121,11 @@ class mod_pacific extends ModeleNumRefFicheinter /** * Return next free value * - * @param Societe $objsoc Object thirdparty - * @param Fichinter $object Object we need next value for - * @return string Value if KO, <0 if KO + * @param Societe|string $objsoc Object thirdparty + * @param Fichinter|string $object Object we need next value for + * @return string Value if KO, <0 if KO */ - public function getNextValue($objsoc = 0, $object = '') + public function getNextValue($objsoc = '', $object = '') { global $db, $conf; @@ -147,7 +147,10 @@ class mod_pacific extends ModeleNumRefFicheinter } //$date=time(); - $date = $object->datec; + $date = ''; + if (!empty($object->datec)) { + $date = $object->datec; + } $yymm = dol_print_date($date, "%y%m"); if ($max >= (pow(10, 4) - 1)) { diff --git a/htdocs/core/modules/modAi.class.php b/htdocs/core/modules/modAi.class.php index 3194a93ed5a..3c47eb376d3 100644 --- a/htdocs/core/modules/modAi.class.php +++ b/htdocs/core/modules/modAi.class.php @@ -69,7 +69,7 @@ class modAi extends DolibarrModules $this->descriptionlong = "AiDescriptionLong"; // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z' - $this->version = 'development'; + $this->version = 'experimental'; // Key used in llx_const table to save module status enabled/disabled (where BOOKCAL is value of property name of module in uppercase) $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); @@ -78,7 +78,7 @@ class modAi extends DolibarrModules // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue' // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module' // To use a supported fa-xxx css style of font awesome, use this->picto='xxx' - $this->picto = 'fa-microchip'; + $this->picto = 'fa-magic'; // Define some features supported by module (triggers, login, substitutions, menus, css, etc...) $this->module_parts = array( diff --git a/htdocs/core/modules/modBookCal.class.php b/htdocs/core/modules/modBookCal.class.php index a778ac8ffc7..0b2ce6c2c77 100644 --- a/htdocs/core/modules/modBookCal.class.php +++ b/htdocs/core/modules/modBookCal.class.php @@ -78,7 +78,7 @@ class modBookCal extends DolibarrModules // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue' // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module' // To use a supported fa-xxx css style of font awesome, use this->picto='xxx' - $this->picto = 'fa-calendar-check'; + $this->picto = 'bookcal'; // Define some features supported by module (triggers, login, substitutions, menus, css, etc...) $this->module_parts = array( diff --git a/htdocs/core/modules/mrp/doc/pdf_vinci.modules.php b/htdocs/core/modules/mrp/doc/pdf_vinci.modules.php index cc5bc784df0..81e910d4e19 100644 --- a/htdocs/core/modules/mrp/doc/pdf_vinci.modules.php +++ b/htdocs/core/modules/mrp/doc/pdf_vinci.modules.php @@ -5,7 +5,7 @@ * Copyright (C) 2010-2014 Juanjo Menent * Copyright (C) 2015 Marcos García * Copyright (C) 2017 Ferran Marcet - * Copyright (C) 2018-2023 Frédéric France + * Copyright (C) 2018-2024 Frédéric France * * 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 @@ -124,13 +124,13 @@ class pdf_vinci extends ModelePDFMo /** * Function to build pdf onto disk * - * @param CommandeFournisseur $object Id of object to generate - * @param Translate $outputlangs Lang output object - * @param string $srctemplatepath Full path of source filename for generator using a template file - * @param int $hidedetails Do not show line details - * @param int $hidedesc Do not show desc - * @param int $hideref Do not show ref - * @return int 1=OK, 0=KO + * @param Mo $object Id of object to generate + * @param Translate $outputlangs Lang output object + * @param string $srctemplatepath Full path of source filename for generator using a template file + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return int 1=OK, 0=KO */ public function write_file($object, $outputlangs = null, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0) { @@ -235,10 +235,10 @@ class pdf_vinci extends ModelePDFMo $pdf->SetDrawColor(128, 128, 128); $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref)); - $pdf->SetSubject($outputlangs->transnoentities("Mo")); + $pdf->SetSubject($outputlangs->transnoentities("ManufacturingOrder")); $pdf->SetCreator("Dolibarr ".DOL_VERSION); $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs))); - $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("Mo")." ".$outputlangs->convToOutputCharset($object->thirdparty->name)); + $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("ManufacturingOrder")." ".$outputlangs->convToOutputCharset($object->thirdparty->name)); if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) { $pdf->SetCompression(false); } @@ -657,7 +657,7 @@ class pdf_vinci extends ModelePDFMo * Show payments table * * @param TCPDF $pdf Object PDF - * @param CommandeFournisseur $object Object order + * @param Mo $object Object order * @param int $posy Position y in PDF * @param Translate $outputlangs Object langs for output * @return int Return integer <0 if KO, >0 if OK @@ -674,7 +674,7 @@ class pdf_vinci extends ModelePDFMo * Show miscellaneous information (payment mode, payment term, ...) * * @param TCPDF $pdf Object PDF - * @param CommandeFournisseur $object Object to show + * @param Mo $object Object to show * @param int $posy Y * @param Translate $outputlangs Langs object * @return integer @@ -1016,7 +1016,7 @@ class pdf_vinci extends ModelePDFMo * Show top header of page. * * @param TCPDF $pdf Object PDF - * @param CommandeFournisseur $object Object to show + * @param Mo $object Object to show * @param int $showaddress 0=no, 1=yes * @param Translate $outputlangs Object lang for output * @return float|int Return topshift value @@ -1031,7 +1031,7 @@ class pdf_vinci extends ModelePDFMo } // Load translation files required by the page - $outputlangs->loadLangs(array("main", "orders", "companies", "bills", "sendings")); + $outputlangs->loadLangs(array("main", "orders", "companies", "bills", "sendings", "mrp")); $default_font_size = pdf_getPDFFontSize($outputlangs); @@ -1074,7 +1074,7 @@ class pdf_vinci extends ModelePDFMo $pdf->SetFont('', 'B', $default_font_size + 3); $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $title = $outputlangs->transnoentities("Mo")." ".$outputlangs->convToOutputCharset($object->ref); + $title = $outputlangs->transnoentities("ManufacturingOrder")." ".$outputlangs->convToOutputCharset($object->ref); $pdf->MultiCell(100, 3, $title, '', 'R'); $posy += 1; @@ -1311,7 +1311,7 @@ class pdf_vinci extends ModelePDFMo * Show footer of page. Need this->emetteur object * * @param TCPDF $pdf PDF - * @param CommandeFournisseur $object Object to show + * @param Mo $object Object to show * @param Translate $outputlangs Object lang for output * @param int $hidefreetext 1=Hide free text * @return int Return height of bottom margin including footer text @@ -1323,15 +1323,14 @@ class pdf_vinci extends ModelePDFMo } - /** * Define Array Column Field * - * @param object $object common object + * @param Mo $object common object * @param Translate $outputlangs langs - * @param int $hidedetails Do not show line details - * @param int $hidedesc Do not show desc - * @param int $hideref Do not show ref + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref * @return void */ public function defineColumnField($object, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0) @@ -1422,7 +1421,7 @@ class pdf_vinci extends ModelePDFMo 'status' => true, 'width' => 25, // in mm 'title' => array( - 'textkey' => 'Size' + 'textkey' => 'Dimensions' ), 'border-left' => true, // add left line separator ); diff --git a/htdocs/core/modules/product/mod_codeproduct_elephant.php b/htdocs/core/modules/product/mod_codeproduct_elephant.php index 644808826d5..397312fbb5f 100644 --- a/htdocs/core/modules/product/mod_codeproduct_elephant.php +++ b/htdocs/core/modules/product/mod_codeproduct_elephant.php @@ -118,12 +118,12 @@ class mod_codeproduct_elephant extends ModeleProductCode /** * Return an example of result returned by getNextValue * - * @param Translate $langs Object langs - * @param Product $objproduct Object product - * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) - * @return string Return string example + * @param Translate $langs Object langs + * @param Product|string $objproduct Object product + * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) + * @return string Return string example */ - public function getExample($langs, $objproduct = null, $type = -1) + public function getExample($langs, $objproduct = '', $type = -1) { $exampleproduct = $exampleservice = ''; diff --git a/htdocs/core/modules/product/mod_codeproduct_leopard.php b/htdocs/core/modules/product/mod_codeproduct_leopard.php index 126527a55bf..d8ae7f91676 100644 --- a/htdocs/core/modules/product/mod_codeproduct_leopard.php +++ b/htdocs/core/modules/product/mod_codeproduct_leopard.php @@ -85,11 +85,11 @@ class mod_codeproduct_leopard extends ModeleProductCode /** * Return an example of result returned by getNextValue * - * @param Product $objproduct Object product - * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) - * @return string Return next value + * @param Product|string $objproduct Object product + * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) + * @return string Return next value */ - public function getNextValue($objproduct = null, $type = -1) + public function getNextValue($objproduct = '', $type = -1) { return ''; } diff --git a/htdocs/core/modules/product/modules_product.class.php b/htdocs/core/modules/product/modules_product.class.php index 893dc9dc2dc..cfe79891429 100644 --- a/htdocs/core/modules/product/modules_product.class.php +++ b/htdocs/core/modules/product/modules_product.class.php @@ -64,11 +64,11 @@ abstract class ModeleProductCode extends CommonNumRefGenerator /** * Return next value available * - * @param Product $objproduct Object product - * @param int $type Type - * @return string Value + * @param Product|string $objproduct Object product + * @param int $type Type + * @return string Value */ - public function getNextValue($objproduct = 0, $type = -1) + public function getNextValue($objproduct = '', $type = -1) { global $langs; return $langs->trans("Function_getNextValue_InModuleNotWorking"); diff --git a/htdocs/core/modules/project/mod_project_simple.php b/htdocs/core/modules/project/mod_project_simple.php index a153b3a590d..1ef51d36c95 100644 --- a/htdocs/core/modules/project/mod_project_simple.php +++ b/htdocs/core/modules/project/mod_project_simple.php @@ -165,19 +165,4 @@ class mod_project_simple extends ModeleNumRefProjects dol_syslog("mod_project_simple::getNextValue return ".$this->prefix.$yymm."-".$num); return $this->prefix.$yymm."-".$num; } - - - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return next reference not yet used as a reference - * - * @param Societe $objsoc Object third party - * @param Project $project Object project - * @return string|-1 Next not used reference, -1 if KO - */ - public function project_get_num($objsoc = 0, $project = '') - { - // phpcs:enable - return $this->getNextValue($objsoc, $project); - } } diff --git a/htdocs/core/modules/project/task/mod_task_simple.php b/htdocs/core/modules/project/task/mod_task_simple.php index 0eea8129ca3..e75fd1b5e8a 100644 --- a/htdocs/core/modules/project/task/mod_task_simple.php +++ b/htdocs/core/modules/project/task/mod_task_simple.php @@ -1,6 +1,7 @@ * Copyright (C) 2010 Laurent Destailleur + * Copyright (C) 2024 Frédéric France * * 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 @@ -122,9 +123,9 @@ class mod_task_simple extends ModeleNumRefTask /** * Return next value * - * @param Societe $objsoc Object third party - * @param Task $object Object Task - * @return string|-1 Value if OK, -1 if KO + * @param Societe|string $objsoc Object third party + * @param Task|string $object Object Task + * @return string|-1 Value if OK, -1 if KO */ public function getNextValue($objsoc, $object) { @@ -161,18 +162,4 @@ class mod_task_simple extends ModeleNumRefTask dol_syslog("mod_task_simple::getNextValue return ".$this->prefix.$yymm."-".$num); return $this->prefix.$yymm."-".$num; } - - - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return next reference not yet used as a reference - * - * @param Societe $objsoc Object third party - * @param Task $object Object task - * @return string|-1 Next not used reference, -1 if KO - */ - public function task_get_num($objsoc = 0, $object = '') - { - return $this->getNextValue($objsoc, $object); - } } diff --git a/htdocs/core/modules/project/task/mod_task_universal.php b/htdocs/core/modules/project/task/mod_task_universal.php index 95c7d392ed0..52b7b9b18d9 100644 --- a/htdocs/core/modules/project/task/mod_task_universal.php +++ b/htdocs/core/modules/project/task/mod_task_universal.php @@ -1,5 +1,6 @@ + * Copyright (C) 2024 Frédéric France * * 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 @@ -119,11 +120,11 @@ class mod_task_universal extends ModeleNumRefTask /** * Return next value * - * @param Societe $objsoc Object third party - * @param Task $object Object task - * @return string|0 Value if OK, 0 if KO + * @param Societe|string $objsoc Object third party + * @param Task|string $object Object task + * @return string|0 Value if OK, 0 if KO */ - public function getNextValue($objsoc, $object) + public function getNextValue($objsoc = '', $object = '') { global $db, $conf; @@ -141,19 +142,4 @@ class mod_task_universal extends ModeleNumRefTask return $numFinal; } - - - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return next reference not yet used as a reference - * - * @param Societe $objsoc Object third party - * @param Task $object Object task - * @return string|0 Next not used reference, 0 if KO - */ - public function project_get_num($objsoc = 0, $object = '') - { - // phpcs:enable - return $this->getNextValue($objsoc, $object); - } } diff --git a/htdocs/core/modules/societe/doc/doc_generic_odt.modules.php b/htdocs/core/modules/societe/doc/doc_generic_odt.modules.php index 2022fd03dd8..efacbd6b196 100644 --- a/htdocs/core/modules/societe/doc/doc_generic_odt.modules.php +++ b/htdocs/core/modules/societe/doc/doc_generic_odt.modules.php @@ -259,6 +259,7 @@ class doc_generic_odt extends ModeleThirdPartyDoc } $file = $dir . '/' . $filename; $object->builddoc_filename = $filename; // For triggers + $object->context['builddoc_filename'] = $filename; // For triggers //print "newfileformat=".$newfileformat; //print "newdir=".$dir; //print "newfile=".$newfile; diff --git a/htdocs/core/modules/societe/mod_codeclient_elephant.php b/htdocs/core/modules/societe/mod_codeclient_elephant.php index f83ec00dc77..6e1d61e165d 100644 --- a/htdocs/core/modules/societe/mod_codeclient_elephant.php +++ b/htdocs/core/modules/societe/mod_codeclient_elephant.php @@ -124,14 +124,13 @@ class mod_codeclient_elephant extends ModeleThirdPartyCode /** * Return an example of result returned by getNextValue * - * @param Translate $langs Object langs - * @param Societe $objsoc Object thirdparty - * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) - * @return string Return string example + * @param Translate $langs Object langs + * @param Societe|string $objsoc Object thirdparty + * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) + * @return string Return string example */ - public function getExample($langs, $objsoc = 0, $type = -1) + public function getExample($langs, $objsoc = '', $type = -1) { - $error = 0; $examplecust = ''; $examplesup = ''; $errmsg = array( @@ -150,12 +149,10 @@ class mod_codeclient_elephant extends ModeleThirdPartyCode if (!$examplecust && ($cssforerror == 'error' || $this->error != 'NotConfigured')) { $langs->load("errors"); $examplecust = ''.$langs->trans('ErrorBadMask').''; - $error = 1; } if (in_array($examplecust, $errmsg)) { $langs->load("errors"); $examplecust = ''.$langs->trans($examplecust).''; - $error = 1; } } if ($type != 0) { @@ -163,12 +160,10 @@ class mod_codeclient_elephant extends ModeleThirdPartyCode if (!$examplesup && ($cssforerror == 'error' || $this->error != 'NotConfigured')) { $langs->load("errors"); $examplesup = ''.$langs->trans('ErrorBadMask').''; - $error = 1; } if (in_array($examplesup, $errmsg)) { $langs->load("errors"); $examplesup = ''.$langs->trans($examplesup).''; - $error = 1; } } @@ -184,23 +179,23 @@ class mod_codeclient_elephant extends ModeleThirdPartyCode /** * Return next value * - * @param Societe $objsoc Object third party - * @param int $type Client ou fournisseur (0:customer, 1:supplier) - * @return string|-1 Value if OK, '' if module not configured, -1 if KO + * @param Societe|string $objsoc Object third party + * @param int $type Client ou fournisseur (0:customer, 1:supplier) + * @return string|-1 Value if OK, '' if module not configured, -1 if KO */ - public function getNextValue($objsoc = 0, $type = -1) + public function getNextValue($objsoc = '', $type = -1) { - global $db, $conf; + global $db; require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; // Get Mask value $mask = ''; if ($type == 0) { - $mask = !getDolGlobalString('COMPANY_ELEPHANT_MASK_CUSTOMER') ? '' : $conf->global->COMPANY_ELEPHANT_MASK_CUSTOMER; + $mask = getDolGlobalString('COMPANY_ELEPHANT_MASK_CUSTOMER'); } if ($type == 1) { - $mask = !getDolGlobalString('COMPANY_ELEPHANT_MASK_SUPPLIER') ? '' : $conf->global->COMPANY_ELEPHANT_MASK_SUPPLIER; + $mask = getDolGlobalString('COMPANY_ELEPHANT_MASK_SUPPLIER'); } if (!$mask) { $this->error = 'NotConfigured'; diff --git a/htdocs/core/modules/societe/mod_codeclient_leopard.php b/htdocs/core/modules/societe/mod_codeclient_leopard.php index 98343987765..1f592057adb 100644 --- a/htdocs/core/modules/societe/mod_codeclient_leopard.php +++ b/htdocs/core/modules/societe/mod_codeclient_leopard.php @@ -77,12 +77,12 @@ class mod_codeclient_leopard extends ModeleThirdPartyCode /** * Return an example of result returned by getNextValue * - * @param Translate $langs Object langs - * @param Societe $objsoc Object thirdparty - * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) - * @return string Return string example + * @param Translate $langs Object langs + * @param Societe|string $objsoc Object thirdparty + * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) + * @return string Return string example */ - public function getExample($langs, $objsoc = 0, $type = -1) + public function getExample($langs, $objsoc = '', $type = -1) { return ''; } @@ -90,11 +90,11 @@ class mod_codeclient_leopard extends ModeleThirdPartyCode /** * Return an example of result returned by getNextValue * - * @param Societe $objsoc Object thirdparty - * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) - * @return string Return next value + * @param Societe|string $objsoc Object thirdparty + * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) + * @return string Return next value */ - public function getNextValue($objsoc = 0, $type = -1) + public function getNextValue($objsoc = '', $type = -1) { return ''; } diff --git a/htdocs/core/modules/societe/mod_codeclient_monkey.php b/htdocs/core/modules/societe/mod_codeclient_monkey.php index 9019ff44d29..e46b5dc3f7a 100644 --- a/htdocs/core/modules/societe/mod_codeclient_monkey.php +++ b/htdocs/core/modules/societe/mod_codeclient_monkey.php @@ -76,12 +76,12 @@ class mod_codeclient_monkey extends ModeleThirdPartyCode /** * Return an example of result returned by getNextValue * - * @param Translate $langs Object langs - * @param Societe $objsoc Object thirdparty - * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) - * @return string Return string example + * @param Translate $langs Object langs + * @param Societe|string $objsoc Object thirdparty + * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) + * @return string Return string example */ - public function getExample($langs, $objsoc = 0, $type = -1) + public function getExample($langs, $objsoc = '', $type = -1) { return $this->prefixcustomer.'0901-00001
'.$this->prefixsupplier.'0901-00001'; } @@ -90,11 +90,11 @@ class mod_codeclient_monkey extends ModeleThirdPartyCode /** * Return next value * - * @param Societe $objsoc Object third party - * @param int $type Client ou fournisseur (1:client, 2:fournisseur) - * @return string|-1 Value if OK, '' if module not configured, -1 if KO + * @param Societe|string $objsoc Object third party + * @param int $type Client ou fournisseur (1:client, 2:fournisseur) + * @return string|-1 Value if OK, '' if module not configured, -1 if KO */ - public function getNextValue($objsoc = 0, $type = -1) + public function getNextValue($objsoc = '', $type = -1) { global $db; diff --git a/htdocs/core/modules/societe/mod_codecompta_aquarium.php b/htdocs/core/modules/societe/mod_codecompta_aquarium.php index 264ee51741b..64b65be81e5 100644 --- a/htdocs/core/modules/societe/mod_codecompta_aquarium.php +++ b/htdocs/core/modules/societe/mod_codecompta_aquarium.php @@ -130,12 +130,12 @@ class mod_codecompta_aquarium extends ModeleAccountancyCode /** * Return an example of result returned by getNextValue * - * @param Translate $langs Object langs - * @param Societe $objsoc Object thirdparty - * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) - * @return string Return string example + * @param Translate $langs Object langs + * @param Societe|string $objsoc Object thirdparty + * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) + * @return string Return string example */ - public function getExample($langs, $objsoc = 0, $type = -1) + public function getExample($langs, $objsoc = '', $type = -1) { $s = ''; $s .= $this->prefixcustomeraccountancycode.'CUSTCODE'; diff --git a/htdocs/core/modules/societe/mod_codecompta_digitaria.php b/htdocs/core/modules/societe/mod_codecompta_digitaria.php index fc9feb6b25f..d536c5e7dd6 100644 --- a/htdocs/core/modules/societe/mod_codecompta_digitaria.php +++ b/htdocs/core/modules/societe/mod_codecompta_digitaria.php @@ -2,7 +2,8 @@ /* Copyright (C) 2004 Rodolphe Quiedeville * Copyright (C) 2010 Laurent Destailleur * Copyright (C) 2019 Alexandre Spangaro - * Copyright (C) 2019 Frédéric France + * Copyright (C) 2019-2024 Frédéric France + * Copyright (C) 2024 MDW * * 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 @@ -160,12 +161,12 @@ class mod_codecompta_digitaria extends ModeleAccountancyCode /** * Return an example of result returned by getNextValue * - * @param Translate $langs Object langs - * @param Societe $objsoc Object thirdparty - * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) - * @return string Example + * @param Translate $langs Object langs + * @param Societe|string $objsoc Object thirdparty + * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) + * @return string Example */ - public function getExample($langs, $objsoc = 0, $type = -1) + public function getExample($langs, $objsoc = '', $type = -1) { global $conf, $mysoc; @@ -188,7 +189,7 @@ class mod_codecompta_digitaria extends ModeleAccountancyCode * * @param DoliDB $db Database handler * @param Societe $societe Third party object - * @param int $type 'customer' or 'supplier' + * @param string $type 'customer' or 'supplier' * @return int >=0 if OK, <0 if KO */ public function get_code($db, $societe, $type = '') @@ -260,9 +261,7 @@ class mod_codecompta_digitaria extends ModeleAccountancyCode $i++; } - } else { - $disponibility == 0; - } + } // else { $disponibility = 0; /* Already set */ } } if ($disponibility == 0) { @@ -277,7 +276,7 @@ class mod_codecompta_digitaria extends ModeleAccountancyCode * * @param DoliDB $db Database handler * @param string $code Code of third party - * @param int $type 'customer' or 'supplier' + * @param string $type 'customer' or 'supplier' * @return int >=0 if OK, <0 if KO */ public function checkIfAccountancyCodeIsAlreadyUsed($db, $code, $type = '') diff --git a/htdocs/core/modules/societe/mod_codecompta_panicum.php b/htdocs/core/modules/societe/mod_codecompta_panicum.php index 1cec3d33dad..9dd740313f9 100644 --- a/htdocs/core/modules/societe/mod_codecompta_panicum.php +++ b/htdocs/core/modules/societe/mod_codecompta_panicum.php @@ -1,6 +1,7 @@ * Copyright (C) 2010 Laurent Destailleur + * Copyright (C) 2024 Frédéric France * * 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 @@ -71,12 +72,12 @@ class mod_codecompta_panicum extends ModeleAccountancyCode /** * Return an example of result returned by getNextValue * - * @param Translate $langs Object langs - * @param Societe $objsoc Object thirdparty - * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) - * @return string Example + * @param Translate $langs Object langs + * @param Societe|string $objsoc Object thirdparty + * @param int $type Type of third party (1:customer, 2:supplier, -1:autodetect) + * @return string Example */ - public function getExample($langs, $objsoc = 0, $type = -1) + public function getExample($langs, $objsoc = '', $type = -1) { return ''; } @@ -87,7 +88,7 @@ class mod_codecompta_panicum extends ModeleAccountancyCode * * @param DoliDB $db Database handler * @param Societe $societe Third party object - * @param int $type 'customer' or 'supplier' + * @param string $type 'customer' or 'supplier' * @return int >=0 if OK, <0 if KO */ public function get_code($db, $societe, $type = '') diff --git a/htdocs/core/modules/societe/modules_societe.class.php b/htdocs/core/modules/societe/modules_societe.class.php index dff42b63e86..8cc1ddd8082 100644 --- a/htdocs/core/modules/societe/modules_societe.class.php +++ b/htdocs/core/modules/societe/modules_societe.class.php @@ -72,11 +72,11 @@ abstract class ModeleThirdPartyCode extends CommonNumRefGenerator /** * Return next value available * - * @param Societe $objsoc Object thirdparty - * @param int $type Type - * @return string Value + * @param Societe|string $objsoc Object thirdparty + * @param int $type Type + * @return string Value */ - public function getNextValue($objsoc = 0, $type = -1) + public function getNextValue($objsoc = '', $type = -1) { global $langs; return $langs->trans("Function_getNextValue_InModuleNotWorking"); @@ -254,7 +254,7 @@ abstract class ModeleAccountancyCode extends CommonNumRefGenerator * * @param DoliDB $db Database handler * @param Societe $societe Third party object - * @param int $type 'customer' or 'supplier' + * @param string $type 'customer' or 'supplier' * @return int >=0 if OK, <0 if KO */ public function get_code($db, $societe, $type = '') diff --git a/htdocs/core/modules/supplier_invoice/doc/doc_generic_supplier_invoice_odt.modules.php b/htdocs/core/modules/supplier_invoice/doc/doc_generic_supplier_invoice_odt.modules.php index d149b5ff576..e03a9fcb835 100644 --- a/htdocs/core/modules/supplier_invoice/doc/doc_generic_supplier_invoice_odt.modules.php +++ b/htdocs/core/modules/supplier_invoice/doc/doc_generic_supplier_invoice_odt.modules.php @@ -4,7 +4,7 @@ * Copyright (C) 2014 Marcos García * Copyright (C) 2016 Charlie Benke * Copyright (C) 2018-2019 Philippe Grand - * Copyright (C) 2018-2019 Frédéric France + * Copyright (C) 2018-2024 Frédéric France * Copyright (C) 2019 Tim Otte * * This program is free software; you can redistribute it and/or modify @@ -123,7 +123,7 @@ class doc_generic_supplier_invoice_odt extends ModelePDFSuppliersInvoices // List of directories area $texte .= '
'; $texttitle = $langs->trans("ListOfDirectories"); - $listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim($conf->global->SUPPLIER_INVOICE_ADDON_PDF_ODT_PATH))); + $listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim(getDolGlobalString('SUPPLIER_INVOICE_ADDON_PDF_ODT_PATH')))); $listoffiles = array(); diff --git a/htdocs/core/modules/supplier_order/doc/doc_generic_supplier_order_odt.modules.php b/htdocs/core/modules/supplier_order/doc/doc_generic_supplier_order_odt.modules.php index a0963e88c04..049683aa1f5 100644 --- a/htdocs/core/modules/supplier_order/doc/doc_generic_supplier_order_odt.modules.php +++ b/htdocs/core/modules/supplier_order/doc/doc_generic_supplier_order_odt.modules.php @@ -4,7 +4,7 @@ * Copyright (C) 2014 Marcos García * Copyright (C) 2016 Charlie Benke * Copyright (C) 2018-2019 Philippe Grand - * Copyright (C) 2018-2019 Frédéric France + * Copyright (C) 2018-2024 Frédéric France * Copyright (C) 2019 Tim Otte * * This program is free software; you can redistribute it and/or modify @@ -123,7 +123,7 @@ class doc_generic_supplier_order_odt extends ModelePDFSuppliersOrders // List of directories area $texte .= '
'; $texttitle = $langs->trans("ListOfDirectories"); - $listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim($conf->global->SUPPLIER_ORDER_ADDON_PDF_ODT_PATH))); + $listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim(getDolGlobalString('SUPPLIER_ORDER_ADDON_PDF_ODT_PATH')))); $listoffiles = array(); foreach ($listofdir as $key => $tmpdir) { $tmpdir = trim($tmpdir); diff --git a/htdocs/core/modules/supplier_order/mod_commande_fournisseur_muguet.php b/htdocs/core/modules/supplier_order/mod_commande_fournisseur_muguet.php index 740dbfbfd17..cd6d9f78d0e 100644 --- a/htdocs/core/modules/supplier_order/mod_commande_fournisseur_muguet.php +++ b/htdocs/core/modules/supplier_order/mod_commande_fournisseur_muguet.php @@ -131,11 +131,11 @@ class mod_commande_fournisseur_muguet extends ModeleNumRefSuppliersOrders /** * Return next value * - * @param Societe $objsoc Object third party + * @param Societe|string $objsoc Object third party * @param CommandeFournisseur $object Object * @return string Value if OK, 0 if KO */ - public function getNextValue($objsoc = 0, $object = '') + public function getNextValue($objsoc = '', $object = '') { global $db, $conf; diff --git a/htdocs/core/modules/supplier_order/mod_commande_fournisseur_orchidee.php b/htdocs/core/modules/supplier_order/mod_commande_fournisseur_orchidee.php index db138369a53..03f948de1c1 100644 --- a/htdocs/core/modules/supplier_order/mod_commande_fournisseur_orchidee.php +++ b/htdocs/core/modules/supplier_order/mod_commande_fournisseur_orchidee.php @@ -122,11 +122,11 @@ class mod_commande_fournisseur_orchidee extends ModeleNumRefSuppliersOrders /** * Return next value * - * @param Societe $objsoc Object third party + * @param Societe|string $objsoc Object third party * @param CommandeFournisseur $object Object * @return string|0 Value if OK, 0 if KO */ - public function getNextValue($objsoc = 0, $object = '') + public function getNextValue($objsoc = '', $object = '') { global $db, $conf; diff --git a/htdocs/core/tpl/login.tpl.php b/htdocs/core/tpl/login.tpl.php index b2072e48eed..eb0c48e27c3 100644 --- a/htdocs/core/tpl/login.tpl.php +++ b/htdocs/core/tpl/login.tpl.php @@ -204,7 +204,7 @@ if ($disablenofollow) { } ?> -" name="username" class="flat input-icon-user minwidth150" value="" tabindex="1" autofocus="autofocus" /> +" name="username" class="flat input-icon-user minwidth150" value="" tabindex="1" autofocus="autofocus" autocapitalize="off" autocomplete="on" spellcheck="false" autocorrect="off" /> diff --git a/htdocs/core/tpl/passwordforgotten.tpl.php b/htdocs/core/tpl/passwordforgotten.tpl.php index 7a190498efe..188e3099f6c 100644 --- a/htdocs/core/tpl/passwordforgotten.tpl.php +++ b/htdocs/core/tpl/passwordforgotten.tpl.php @@ -150,7 +150,7 @@ if (!empty($disablenofollow)) {
-" id="username" name="username" class="flat input-icon-user minwidth150" value="" tabindex="1" /> +" id="username" name="username" class="flat input-icon-user minwidth150" value="" tabindex="1" autocapitalize="off" autocomplete="on" spellcheck="false" autocorrect="off" />
diff --git a/htdocs/core/website.inc.php b/htdocs/core/website.inc.php index 9a340050d22..4708d12e929 100644 --- a/htdocs/core/website.inc.php +++ b/htdocs/core/website.inc.php @@ -263,3 +263,22 @@ if (!defined('USEDOLIBARREDITOR') && empty($website->status)) { print '


'.$weblangs->trans("SorryWebsiteIsCurrentlyOffLine").'
'; exit; } + + +// Get session info and obfuscate session cookie and other variables +$prefix = dol_getprefix(''); +$sessionname = 'DOLSESSID_'.$prefix; +//$savsessionid = $_COOKIE[$sessionname]; + +$_COOKIE[$sessionname] = 'obfuscatedcookie'; +unset($conf->file->instance_unique_id); + +unset($dolibarr_main_instance_unique_id); +unset($dolibarr_main_db_host); +unset($dolibarr_main_db_port); +unset($dolibarr_main_db_name); +unset($dolibarr_main_db_user); +unset($dolibarr_main_db_pass); +unset($$dolibarr_main_db_type); +unset($dolibarr_main_document_root); +unset($dolibarr_main_document_root_alt); diff --git a/htdocs/dav/fileserver.php b/htdocs/dav/fileserver.php index f4fad036d8d..ad1b7cb1290 100644 --- a/htdocs/dav/fileserver.php +++ b/htdocs/dav/fileserver.php @@ -1,6 +1,7 @@ * Copyright (C) 2019 Regis Houssin + * Copyright (C) 2024 MDW * * 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 @@ -92,69 +93,76 @@ $tmpDir = $conf->dav->multidir_output[$entity]; // We need root dir, not a dir t // Authentication callback function -$authBackend = new \Sabre\DAV\Auth\Backend\BasicCallBack(function ($username, $password) { - global $user, $conf; - global $dolibarr_main_authentication, $dolibarr_auto_user; +$authBackend = new \Sabre\DAV\Auth\Backend\BasicCallBack( + /** + * @param string $username Username to validate as a login + * @param string $password Password to validate for $username + * @return true True if login ok, false if not + */ + static function ($username, $password) { + global $user, $conf; + global $dolibarr_main_authentication, $dolibarr_auto_user; - if (empty($user->login)) { - dol_syslog("Failed to authenticate to DAV, login is not provided", LOG_WARNING); - return false; - } - if ($user->socid > 0) { - dol_syslog("Failed to authenticate to DAV, user is an external user", LOG_WARNING); - return false; - } - if ($user->login != $username) { - dol_syslog("Failed to authenticate to DAV, login does not match the login of loaded user", LOG_WARNING); - return false; - } - - // Authentication mode - if (empty($dolibarr_main_authentication)) { - $dolibarr_main_authentication = 'dolibarr'; - } - - // Authentication mode: forceuser - if ($dolibarr_main_authentication == 'forceuser') { - if (empty($dolibarr_auto_user)) { - $dolibarr_auto_user = 'auto'; - } - if ($dolibarr_auto_user != $username) { - dol_syslog("Warning: your instance is set to use the automatic forced login '".$dolibarr_auto_user."' that is not the requested login. DAV usage is forbidden in this mode."); + if (empty($user->login)) { + dol_syslog("Failed to authenticate to DAV, login is not provided", LOG_WARNING); return false; } + if ($user->socid > 0) { + dol_syslog("Failed to authenticate to DAV, user is an external user", LOG_WARNING); + return false; + } + if ($user->login != $username) { + dol_syslog("Failed to authenticate to DAV, login does not match the login of loaded user", LOG_WARNING); + return false; + } + + // Authentication mode + if (empty($dolibarr_main_authentication)) { + $dolibarr_main_authentication = 'dolibarr'; + } + + // Authentication mode: forceuser + if ($dolibarr_main_authentication == 'forceuser') { + if (empty($dolibarr_auto_user)) { + $dolibarr_auto_user = 'auto'; + } + if ($dolibarr_auto_user != $username) { + dol_syslog("Warning: your instance is set to use the automatic forced login '".$dolibarr_auto_user."' that is not the requested login. DAV usage is forbidden in this mode."); + return false; + } + } + + $authmode = explode(',', $dolibarr_main_authentication); + $entity = (GETPOSTINT('entity') ? GETPOSTINT('entity') : (!empty($conf->entity) ? $conf->entity : 1)); + + if (checkLoginPassEntity($username, $password, $entity, $authmode, 'dav') != $username) { + return false; + } + + // Check if user status is enabled + if ($user->statut != $user::STATUS_ENABLED) { + // Status is disabled + dol_syslog("The user has been disabled."); + return false; + } + + // Check if session was unvalidated by a password change + if (($user->flagdelsessionsbefore && !empty($_SESSION["dol_logindate"]) && $user->flagdelsessionsbefore > $_SESSION["dol_logindate"])) { + // Session is no more valid + dol_syslog("The user has a date for session invalidation = ".$user->flagdelsessionsbefore." and a session date = ".$_SESSION["dol_logindate"].". We must invalidate its sessions."); + return false; + } + + // Check date validity + if ($user->isNotIntoValidityDateRange()) { + // User validity dates are no more valid + dol_syslog("The user login has a validity between [".$user->datestartvalidity." and ".$user->dateendvalidity."], current date is ".dol_now()); + return false; + } + + return true; } - - $authmode = explode(',', $dolibarr_main_authentication); - $entity = (GETPOSTINT('entity') ? GETPOSTINT('entity') : (!empty($conf->entity) ? $conf->entity : 1)); - - if (checkLoginPassEntity($username, $password, $entity, $authmode, 'dav') != $username) { - return false; - } - - // Check if user status is enabled - if ($user->statut != $user::STATUS_ENABLED) { - // Status is disabled - dol_syslog("The user has been disabled."); - return false; - } - - // Check if session was unvalidated by a password change - if (($user->flagdelsessionsbefore && !empty($_SESSION["dol_logindate"]) && $user->flagdelsessionsbefore > $_SESSION["dol_logindate"])) { - // Session is no more valid - dol_syslog("The user has a date for session invalidation = ".$user->flagdelsessionsbefore." and a session date = ".$_SESSION["dol_logindate"].". We must invalidate its sessions."); - return false; - } - - // Check date validity - if ($user->isNotIntoValidityDateRange()) { - // User validity dates are no more valid - dol_syslog("The user login has a validity between [".$user->datestartvalidity." and ".$user->dateendvalidity."], current date is ".dol_now()); - return false; - } - - return true; -}); +); $authBackend->setRealm(constant('DOL_APPLICATION_TITLE').' - WebDAV'); @@ -211,7 +219,7 @@ if (isset($baseUri)) { if ((!getDolGlobalString('DAV_ALLOW_PUBLIC_DIR') || !preg_match('/'.preg_quote(DOL_URL_ROOT.'/dav/fileserver.php/public', '/').'/', $_SERVER["PHP_SELF"])) && !preg_match('/^sabreAction=asset&assetName=[a-zA-Z0-9%\-\/]+\.(png|css|woff|ico|ttf)$/', $_SERVER["QUERY_STRING"]) // URL for Sabre browser resources - ) { +) { //var_dump($_SERVER["QUERY_STRING"]);exit; $server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend)); } diff --git a/htdocs/debugbar/class/DataCollector/DolPhpCollector.php b/htdocs/debugbar/class/DataCollector/DolPhpCollector.php index c4ff10dbc61..8adc2a3814d 100644 --- a/htdocs/debugbar/class/DataCollector/DolPhpCollector.php +++ b/htdocs/debugbar/class/DataCollector/DolPhpCollector.php @@ -76,18 +76,26 @@ class PhpCollector extends DataCollector implements Renderable /** * Returns a list of messages ordered by their timestamp. * - * @return array A list of messages ordered by time. + * @return array A list of messages ordered by time. */ public function getMessages() { $messages = $this->messages; - usort($messages, function ($itemA, $itemB) { - if ($itemA['time'] === $itemB['time']) { - return 0; + usort( + $messages, + /** + * @param array{time:int} $itemA Message A information + * @param array{time:int} $itemB Message B information + * @return int<-1,1> -1 if Item A before Item B, 0 if same, 1 if later. + */ + static function ($itemA, $itemB) { + if ($itemA['time'] === $itemB['time']) { + return 0; + } + return $itemA['time'] < $itemB['time'] ? -1 : 1; } - return $itemA['time'] < $itemB['time'] ? -1 : 1; - }); + ); return $messages; } diff --git a/htdocs/debugbar/class/autoloader.php b/htdocs/debugbar/class/autoloader.php index a093315172a..b5e54aa29dd 100644 --- a/htdocs/debugbar/class/autoloader.php +++ b/htdocs/debugbar/class/autoloader.php @@ -1,35 +1,43 @@ + */ /** * Simple autoloader, so we don't need Composer just for this. */ -spl_autoload_register(function ($class) { - if (preg_match('/^DebugBar/', $class)) { - $file = DOL_DOCUMENT_ROOT.'/includes/maximebf/debugbar/src/'.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php'; - //var_dump($class.' - '.file_exists($file).' - '.$file); - if (file_exists($file)) { - require_once $file; - return true; +spl_autoload_register( + /** + * @param string $class Class to load + * @return true If class could be loaded + */ + static function ($class) { + if (preg_match('/^DebugBar/', $class)) { + $file = DOL_DOCUMENT_ROOT.'/includes/maximebf/debugbar/src/'.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php'; + //var_dump($class.' - '.file_exists($file).' - '.$file); + if (file_exists($file)) { + require_once $file; + return true; + } + return false; } - return false; - } - if (preg_match('/^'.preg_quote('Psr\Log', '/').'/', $class)) { - $file = DOL_DOCUMENT_ROOT.'/includes/'.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php'; - //var_dump($class.' - '.file_exists($file).' - '.$file); - if (file_exists($file)) { - require_once $file; - return true; + if (preg_match('/^'.preg_quote('Psr\Log', '/').'/', $class)) { + $file = DOL_DOCUMENT_ROOT.'/includes/'.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php'; + //var_dump($class.' - '.file_exists($file).' - '.$file); + if (file_exists($file)) { + require_once $file; + return true; + } + return false; } - return false; - } - if (preg_match('/^'.preg_quote('Symfony\Component\VarDumper', '/').'/', $class)) { - $class = preg_replace('/'.preg_quote('Symfony\Component\VarDumper', '/').'/', '', $class); - $file = DOL_DOCUMENT_ROOT.'/includes/symfony/var-dumper/'.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php'; - if (file_exists($file)) { - require_once $file; - return true; + if (preg_match('/^'.preg_quote('Symfony\Component\VarDumper', '/').'/', $class)) { + $class = preg_replace('/'.preg_quote('Symfony\Component\VarDumper', '/').'/', '', $class); + $file = DOL_DOCUMENT_ROOT.'/includes/symfony/var-dumper/'.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php'; + if (file_exists($file)) { + require_once $file; + return true; + } + return false; } - return false; + return true; } - return true; -}); +); diff --git a/htdocs/emailcollector/class/emailcollector.class.php b/htdocs/emailcollector/class/emailcollector.class.php index 8efeda93635..b885ba5340b 100644 --- a/htdocs/emailcollector/class/emailcollector.class.php +++ b/htdocs/emailcollector/class/emailcollector.class.php @@ -2385,7 +2385,7 @@ class EmailCollector extends CommonObject $operationslog .= '
We have this data to search thirdparty: id='.$idtouseforthirdparty.', email='.$emailtouseforthirdparty.', name='.$nametouseforthirdparty.', name_alias='.$namealiastouseforthirdparty; $tmpobject = new stdClass(); - $tmpobject->element == 'generic'; + $tmpobject->element = 'generic'; $tmpobject->id = $idtouseforthirdparty; $tmpobject->name = $nametouseforthirdparty; $tmpobject->name_alias = $namealiastouseforthirdparty; diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 6742c84011b..6afc9492235 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -9,7 +9,7 @@ * Copyright (C) 2014-2015 Marcos García * Copyright (C) 2014-2017 Francis Appels * Copyright (C) 2015 Claudio Aschieri - * Copyright (C) 2016-2022 Ferran Marcet + * Copyright (C) 2016-2024 Ferran Marcet * Copyright (C) 2018 Nicolas ZABOURI * Copyright (C) 2018-2024 Frédéric France * Copyright (C) 2020 Lenin Rivas @@ -921,7 +921,7 @@ class Expedition extends CommonObject if (isModEnabled('stock') && !empty($orderline->fk_product)) { $fk_product = $orderline->fk_product; - if (!($entrepot_id > 0) && !getDolGlobalString('STOCK_WAREHOUSE_NOT_REQUIRED_FOR_SHIPMENTS')) { + if (!($entrepot_id > 0) && !getDolGlobalString('STOCK_WAREHOUSE_NOT_REQUIRED_FOR_SHIPMENTS') && !(getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES') && $line->product_type == Product::TYPE_SERVICE)) { $langs->load("errors"); $this->error = $langs->trans("ErrorWarehouseRequiredIntoShipmentLine"); return -1; diff --git a/htdocs/expensereport/class/api_expensereports.class.php b/htdocs/expensereport/class/api_expensereports.class.php index 464ca7edf60..3ccf90c0255 100644 --- a/htdocs/expensereport/class/api_expensereports.class.php +++ b/htdocs/expensereport/class/api_expensereports.class.php @@ -1,7 +1,7 @@ * Copyright (C) 2016 Laurent Destailleur - * Copyright (C) 2020 Frédéric France + * Copyright (C) 2020-2024 Frédéric France * * 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 @@ -107,7 +107,7 @@ class ExpenseReports extends DolibarrApi * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @return array Array of Expense Report objects */ - public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $user_ids = 0, $sqlfilters = '', $properties = '') + public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $user_ids = '', $sqlfilters = '', $properties = '') { if (!DolibarrApiAccess::$user->hasRight('expensereport', 'lire')) { throw new RestException(403); diff --git a/htdocs/expensereport/payment/list.php b/htdocs/expensereport/payment/list.php index 88cd5ecb2d0..bd3ba374d76 100644 --- a/htdocs/expensereport/payment/list.php +++ b/htdocs/expensereport/payment/list.php @@ -517,9 +517,9 @@ while ($i < $imaxinloop) { if ($objp->bid) { $accountstatic->fetch($objp->bid); - $paymentexpensereportstatic->fk_bank = $accountstatic->getNomUrl(1); + $paymentexpensereportstatic->fk_bank = $accountstatic->id; } else { - $paymentexpensereportstatic->fk_bank = null; + $paymentexpensereportstatic->fk_bank = 0; } $userstatic->id = $objp->userid; diff --git a/htdocs/fichinter/card-rec.php b/htdocs/fichinter/card-rec.php index 8e7aad352be..4c71562da9b 100644 --- a/htdocs/fichinter/card-rec.php +++ b/htdocs/fichinter/card-rec.php @@ -10,6 +10,7 @@ * Copyright (C) 2016-2018 Charlie Benke * Copyright (C) 2018-2021 Frédéric France * Copyright (C) 2024 William Mead + * Copyright (C) 2024 MDW * * 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 @@ -730,9 +731,7 @@ if ($action == 'create') { // Show product and description if (isset($object->lines[$i]->product_type)) { $type = $object->lines[$i]->product_type; - } else { - $object->lines[$i]->fk_product_type; - } + } // else { $object->lines[$i]->fk_product_type; } // Try to enhance type detection using date_start and date_end for free lines when type // was not saved. if (!empty($objp->date_start)) { diff --git a/htdocs/filefunc.inc.php b/htdocs/filefunc.inc.php index ff496ac9673..a94af12f92d 100644 --- a/htdocs/filefunc.inc.php +++ b/htdocs/filefunc.inc.php @@ -61,6 +61,66 @@ if (defined('DOL_INC_FOR_VERSION_ERROR')) { return; } + +/** + * Replace session_start() + * + * @return void + */ +function dol_session_start() +{ + session_start(); +} + +/** + * Replace session_regenerate_id() + * + * @return void + */ +function dol_session_regenerate_id() +{ + session_regenerate_id(); +} + +/** + * Destroy and recreate a new session without losing content. + * Not used yet. + * + * @param $sessionname string Session name + * @return void + */ +function dol_session_rotate($sessionname = '') +{ + $oldsessionid = session_id(); + + // Backup the current session + $session_backup = $_SESSION; + + // Set current session to expire in 1 minute + $_SESSION['OBSOLETE'] = true; + $_SESSION['EXPIRES'] = time() + 60; + + // Close the current session + session_write_close(); + + // Set a new session id and start the session + session_name($sessionname); + dol_session_start(); + + // Restore the previous session backup + $_SESSION = $session_backup; + + // Clean up + unset($session_backup); + unset($_SESSION['OBSOLETE']); + unset($_SESSION['EXPIRES']); + + $newsessionid = session_id(); + //var_dump("oldsessionid=".$oldsessionid." - newsessionid=".$newsessionid); +} + + + // Define vars $conffiletoshowshort = "conf.php"; // Define localization of conf file @@ -76,7 +136,7 @@ $conffiletoshow = "htdocs/conf/conf.php"; // --- End of part replaced by Dolibarr packager makepack-dolibarr // Include configuration -$result = @include_once $conffile; // Keep @ because with some error reporting this break the redirect done when file not found +$result = @include_once $conffile; // Keep @ because with some error reporting mode, this breaks the redirect done when file is not found // Disable some not used PHP stream $listofwrappers = stream_get_wrappers(); diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index 5130c4ad2bd..cd90cf86179 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -2313,13 +2313,13 @@ class FactureFournisseur extends CommonInvoice * @param double $txlocaltax2 LocalTax2 Rate * @param double $qty Quantity * @param int $idproduct Id produit - * @param double $price_base_type HT or TTC + * @param string $price_base_type HT or TTC * @param int $info_bits Miscellaneous information of line * @param int $type Type of line (0=product, 1=service) * @param double $remise_percent Percentage discount of the line * @param int $notrigger Disable triggers - * @param integer $date_start Date start of service - * @param integer $date_end Date end of service + * @param int|string $date_start Date start of service + * @param int|string $date_end Date end of service * @param array $array_options extrafields array * @param int|null $fk_unit Code of the unit to use. Null to use the default one * @param double $pu_devise Amount in currency diff --git a/htdocs/hrm/class/job.class.php b/htdocs/hrm/class/job.class.php index c0ec08939d4..34893a805b2 100644 --- a/htdocs/hrm/class/job.class.php +++ b/htdocs/hrm/class/job.class.php @@ -148,7 +148,7 @@ class Job extends CommonObject // public $class_element_line = 'Jobline'; // /** - // * @var array List of child tables. To test if we can delete object. + // * @var string[] List of child tables. To test if we can delete object. // */ protected $childtables = array('hrm_evaluation', 'hrm_job_user'); diff --git a/htdocs/install/inc.php b/htdocs/install/inc.php index 8abfb691119..d896cae320c 100644 --- a/htdocs/install/inc.php +++ b/htdocs/install/inc.php @@ -7,6 +7,7 @@ * Copyright (C) 2016 Raphaël Doursenaud * Copyright (C) 2021 Charlene Benke * Copyright (C) 2023 Alexandre Janniaux + * Copyright (C) 2024 MDW * * 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 @@ -140,24 +141,39 @@ if (php_sapi_name() === "cli" && (float) PHP_VERSION > 7.0) { case 'config': $conffile = $arg; $conffiletoshow = $arg; - break; + break; case 'h': case 'help': usage($argv[0], "Usage:"); - exit(0); + exit(0); } } // Parse the arguments to find the options. - $args_options = array_filter(array_slice($argv, 0, $rest_index), function ($arg) { - return strlen($arg) >= 2 && $arg[0] == '-'; - }); - $parsed_options = array_map(function ($arg) { - if (strlen($arg) > 1) { - return "--" . $arg; + $args_options = array_filter( + array_slice($argv, 0, $rest_index), + /** + * @param string $arg + * @return bool + */ + static function ($arg) { + return strlen($arg) >= 2 && $arg[0] == '-'; } - return "-" . $arg; - }, array_keys($opts)); + ); + $parsed_options = array_map( + /** + * Previx option with '-' for single characters and -- for more than single characters + * @param string $arg + * @return straing + */ + static function ($arg) { + if (strlen($arg) > 1) { + return "--" . $arg; + } + return "-" . $arg; + }, + array_keys($opts) + ); // Find options (dash-prefixed) that were not parsed. $unknown_options = array_diff($args_options, $parsed_options); @@ -301,7 +317,7 @@ if (constant('DOL_DATA_ROOT') === null) { $lockfile = '../../documents/install.lock'; $upgradeunlockfile = '../../documents/upgrade.unlock'; } -$islocked=false; +$islocked = false; if (@file_exists($lockfile) || @file_exists($lockfile2)) { if (!defined('ALLOWED_IF_UPGRADE_UNLOCK_FOUND') || (! @file_exists($upgradeunlockfile) && ! @file_exists($upgradeunlockfile2))) { // If this is a dangerous install page (ALLOWED_IF_UPGRADE_UNLOCK_FOUND not defined) or diff --git a/htdocs/install/mysql/tables/llx_actioncomm.sql b/htdocs/install/mysql/tables/llx_actioncomm.sql index 54eac887362..eccb6f49fe8 100644 --- a/htdocs/install/mysql/tables/llx_actioncomm.sql +++ b/htdocs/install/mysql/tables/llx_actioncomm.sql @@ -17,7 +17,7 @@ -- along with this program. If not, see . -- -- --- Table of events and actions (past and to do). +-- Table of events and actions (past and to do). -- This is also the table to track events on other Dolibarr objects. -- ======================================================================== @@ -31,7 +31,7 @@ create table llx_actioncomm datep2 datetime, -- date end fk_action integer, -- type of action (optional link with id in llx_c_actioncomm or null) - code varchar(50) NULL, -- code of action for automatic action ('AC_OTH_AUTO' for automatic actions, 'AC_EMAILIN_AUTO' for email input, 'AC_xxx' for manual action...) + code varchar(50) NULL, -- code of action for automatic action ('AC_OTH_AUTO' for automatic actions, 'AC_EMAILIN_AUTO' for email input, 'AC_xxx' for manual action...) datec datetime, -- date creation tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- last modification date @@ -43,7 +43,6 @@ create table llx_actioncomm fk_contact integer, fk_parent integer NOT NULL default 0, fk_user_action integer, -- user id of owner of action (note that users assigned to event are stored into table 'actioncomm_resources') - fk_user_done integer, -- user id of user that has made action (deprecated) transparency integer, -- transparency (ical standard). used to say if user assigned to event are busy or not by event. This field may be deprecated if we want to store transparency for each assigned user, moved into table llx_actioncomm_resources. @@ -56,9 +55,9 @@ create table llx_actioncomm label varchar(255) NOT NULL, -- label/title of event or topic of email note mediumtext, -- private note of event or content of email - + calling_duration integer, -- when event is a phone call, duration of phone call - + email_subject varchar(255), -- when event was an email, we store here the subject. content is stored into note. email_msgid varchar(255), -- when event was an email, we store here the msgid email_from varchar(255), -- when event was an email, we store here the from @@ -68,7 +67,7 @@ create table llx_actioncomm email_tobcc varchar(255), -- when event was an email, we store here the email_tobcc errors_to varchar(255), -- when event was an email, we store here the erros_to reply_to varchar(255), -- when event was an email, we store here the reply_to - + recurid varchar(128), -- used to store event id to link each other all the repeating event record. It can be the 'iCalUID' as in RFC5545 (an id similar for all the same serie) recurrule varchar(128), -- contains string with ical format recurring rule like 'FREQ=MONTHLY;INTERVAL=2;BYMONTHDAY=19' or 'FREQ=WEEKLY;BYDAY=MO' recurdateend datetime, -- no more recurring event after this date diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang index fe7cb304610..1fde12f73ff 100644 --- a/htdocs/langs/en_US/errors.lang +++ b/htdocs/langs/en_US/errors.lang @@ -412,3 +412,4 @@ ThisIdNotDefined=Id not defined OperNotDefined=Payment method not defined ErrorThisContactXIsAlreadyDefinedAsThisType=%s is already defined as contact for this type. ErrorThisGroupIsAlreadyDefinedAsThisType=The contacts with this group are already defined as contact for this type. +EmptyMessageNotAllowedError=Empty Message Not Allowed Error diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang index 95042a5cc24..f519e098d01 100644 --- a/htdocs/langs/en_US/main.lang +++ b/htdocs/langs/en_US/main.lang @@ -562,6 +562,7 @@ New=New Discount=Discount Unknown=Unknown General=General +Dimensions=Dimensions Size=Size OriginalSize=Original size RotateImage=Rotate 90° diff --git a/htdocs/langs/en_US/modulebuilder.lang b/htdocs/langs/en_US/modulebuilder.lang index c59c4271710..9ff542d9799 100644 --- a/htdocs/langs/en_US/modulebuilder.lang +++ b/htdocs/langs/en_US/modulebuilder.lang @@ -165,7 +165,7 @@ BadValueForType=Bad value for type %s DefinePropertiesFromExistingTable=Define the fields/properties from an existing table DefinePropertiesFromExistingTableDesc=If a table in the database (for the object to create) already exists, you can use it to define the properties of the object. DefinePropertiesFromExistingTableDesc2=Keep empty if the table does not exist yet. The code generator will use different kinds of fields to build an example of table that you can edit later. -GeneratePermissions=I want to manage permissions on this object +GeneratePermissions=I want to manage permissions on this object GeneratePermissionsHelp=If you check this, some code will be added to manage permissions to read, write and delete record of the objects PermissionDeletedSuccesfuly=Permission has been successfully removed PermissionUpdatedSuccesfuly=Permission has been successfully updated @@ -173,6 +173,7 @@ PermissionAddedSuccesfuly=Permission has been successfully added MenuDeletedSuccessfuly=Menu has been successfully deleted MenuAddedSuccessfuly=Menu has been successfully added MenuUpdatedSuccessfuly=Menu has been successfully updated +AddAPIsForThisObject=Add APIs for this object ApiObjectDeleted=API for object %s has been successfully deleted CRUDRead=Read CRUDCreateWrite=Create or Update @@ -181,8 +182,8 @@ DictionariesCreated=Dictionary %s created successfully DictionaryDeleted=Dictionary %s removed successfully PropertyModuleUpdated=Property %s has been update successfully InfoForApiFile=* When you generate file for the first time then all methods will be created for each object.
* When you click in remove you just remove all methods for the selected object. -SetupFile=Page for module setup +SetupFile=Page for module setup EmailingSelectors=Emails selectors EmailingSelectorDesc=You can generate and edit here the class files to provide new email target selectors for the mass emailing module EmailingSelectorFile=Emails selector file -NoEmailingSelector=No emails selector file \ No newline at end of file +NoEmailingSelector=No emails selector file diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 6fc00d524ac..5dd096ef228 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -101,10 +101,18 @@ function testSqlAndScriptInject($val, $type) $oldval = $val; $val = html_entity_decode($val, ENT_QUOTES | ENT_HTML5); // Decode ':', ''', ' ', '&NewLine', ... // Sometimes we have entities without the ; at end so html_entity_decode does not work but entities is still interpreted by browser. - $val = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) { - // Decode 'n', ... - return realCharForNumericEntities($m); - }, $val); + $val = preg_replace_callback( + '/&#(x?[0-9][0-9a-f]+;?)/i', + /** + * @param string $m + * @return string + */ + static function ($m) { + // Decode 'n', ... + return realCharForNumericEntities($m); + }, + $val + ); // We clean html comments because some hacks try to obfuscate evil strings by inserting HTML comments. Example: onerror=alert(1) $val = preg_replace('//', '', $val); @@ -386,7 +394,7 @@ if (!defined('NOSESSION')) { session_set_cookie_params($sessioncookieparams); } session_name($sessionname); - session_start(); // This call the open and read of session handler + dol_session_start(); // This call the open and read of session handler //exit; // this exist generates a call to write and close } @@ -972,7 +980,7 @@ if (!defined('NOLOGIN')) { session_destroy(); session_set_cookie_params(0, '/', null, (empty($dolibarr_main_force_https) ? false : true), true); // Add tag secure and httponly on session cookie session_name($sessionname); - session_start(); + dol_session_start(); if ($resultFetchUser == 0) { // Load translation files required by page @@ -1059,7 +1067,7 @@ if (!defined('NOLOGIN')) { session_destroy(); session_set_cookie_params(0, '/', null, (empty($dolibarr_main_force_https) ? false : true), true); // Add tag secure and httponly on session cookie session_name($sessionname); - session_start(); + dol_session_start(); if ($resultFetchUser == 0) { $langs->loadLangs(array('main', 'errors')); diff --git a/htdocs/modulebuilder/index.php b/htdocs/modulebuilder/index.php index 1e78c341f06..6eb2db3db15 100644 --- a/htdocs/modulebuilder/index.php +++ b/htdocs/modulebuilder/index.php @@ -467,13 +467,13 @@ if ($dirins && in_array($action, array('initapi', 'initphpunit', 'initpagecontac '---Put here your own copyright and developer email---' => dol_print_date($now, '%Y').' '.$user->getFullName($langs).($user->email ? ' <'.$user->email.'>' : '') ); - if (count($objects) > 1) { - addObjectsToApiFile($destfile, $objects, $modulename); + if ($action == 'initapi') { + if (count($objects) >= 1) { + addObjectsToApiFile($srcfile, $destfile, $objects, $modulename); + } } else { // @phan-suppress-next-line PhanPluginSuspiciousParamPosition dolReplaceInFile($destfile, $arrayreplacement); - // @phan-suppress-next-line PhanPluginSuspiciousParamPosition - dolReplaceInFile($destfile, array('/*begin methods CRUD*/' => '/*begin methods CRUD*/'."\n\t".'/*CRUD FOR '.strtoupper($objectname).'*/', '/*end methods CRUD*/' => '/*END CRUD FOR '.strtoupper($objectname).'*/'."\n\t".'/*end methods CRUD*/')); } if ($varnametoupdate) { @@ -952,20 +952,31 @@ if ($dirins && $action == 'confirm_removefile' && !empty($module)) { $filetodelete = $dirins.'/'.$relativefilename; $dirtodelete = $dirins.'/'.$dirnametodelete; - //check when we want delete api_file + // Get list of existing objects + $objects = dolGetListOfObjectClasses($destdir); + + $keyofobjecttodelete = array_search($objectname, $objects); + if ($keyofobjecttodelete !== false) { + unset($objects[$keyofobjecttodelete]); + } + + // Delete or modify the file if (strpos($relativefilename, 'api') !== false) { $file_api = $destdir.'/class/api_'.strtolower($module).'.class.php'; - $removeFile = removeObjectFromApiFile($file_api, $objectname, $module); - $var = getFromFile($file_api, '/*begin methods CRUD*/', '/*end methods CRUD*/'); - if (str_word_count($var) == 0) { + + $removeFile = removeObjectFromApiFile($file_api, $objects, $objectname); + + if (count($objects) == 0) { $result = dol_delete_file($filetodelete); } + if ($removeFile) { setEventMessages($langs->trans("ApiObjectDeleted"), null); } } else { $result = dol_delete_file($filetodelete); } + if (!$result) { setEventMessages($langs->trans("ErrorFailToDeleteFile", basename($filetodelete)), null, 'errors'); } else { @@ -2387,15 +2398,15 @@ if ($dirins && GETPOST('action') == 'update_right' && GETPOST('modifyright') && if ($label == "Read objects of $module" && $crud != "read") { $crud = "read"; - $label == "Read objects of $module"; + // $label = "Read objects of $module"; } if ($label == "Create/Update objects of $module" && $crud != "write") { $crud = "write"; - $label == "Create/Update objects of $module"; + // $label = "Create/Update objects of $module"; } if ($label == "Delete objects of $module" && $crud != "delete") { $crud = "delete"; - $label == "Delete objects of $module"; + // $label = "Delete objects of $module"; } $permissions = $moduleobj->rights; @@ -4209,7 +4220,7 @@ if ($module == 'initmodule') { print ''.$langs->trans("ApiExplorer").''; } } else { - print ''.img_picto('AddAPIsForThisObject', 'generate', 'class="paddingleft"').''; + print ''.img_picto($langs->trans('AddAPIsForThisObject'), 'generate', 'class="paddingleft"').''; } } else { print ''.img_picto('Generate', 'generate', 'class="paddingleft"').''; diff --git a/htdocs/modulebuilder/template/admin/about.php b/htdocs/modulebuilder/template/admin/about.php index 7ec1d1f30f3..ecacf04f4c1 100644 --- a/htdocs/modulebuilder/template/admin/about.php +++ b/htdocs/modulebuilder/template/admin/about.php @@ -83,7 +83,7 @@ $backtopage = GETPOST('backtopage', 'alpha'); $form = new Form($db); $help_url = ''; -$title = "MyModuleAbout"; +$title = "MyModuleSetup"; llxHeader('', $langs->trans($title), $help_url, '', 0, 0, '', '', '', 'mod-mymodule page-admin_about'); diff --git a/htdocs/mrp/class/mo.class.php b/htdocs/mrp/class/mo.class.php index 2a1c580a03b..0244bfd3866 100644 --- a/htdocs/mrp/class/mo.class.php +++ b/htdocs/mrp/class/mo.class.php @@ -236,7 +236,7 @@ class Mo extends CommonObject public $lines = array(); /** - * @var MoLine MO line + * @var MoLine|null MO line */ public $line = array(); @@ -1859,7 +1859,7 @@ class Mo extends CommonObject * Function used to return all child MOs recursively * * @param int $depth Depth for recursing loop count - * @return Mo[]|int[] array of MOs if OK, -1 if KO + * @return Mo[]|int array of MOs if OK, -1 if KO */ public function getAllMoChilds($depth = 0) { diff --git a/htdocs/multicurrency/class/multicurrency.class.php b/htdocs/multicurrency/class/multicurrency.class.php index 57a6c1ee69a..f2ff645052c 100644 --- a/htdocs/multicurrency/class/multicurrency.class.php +++ b/htdocs/multicurrency/class/multicurrency.class.php @@ -90,7 +90,7 @@ class MultiCurrency extends CommonObject public $fk_user; /** - * @var CurrencyRate The currency rate + * @var CurrencyRate|null The currency rate */ public $rate; diff --git a/htdocs/paybox/lib/paybox.lib.php b/htdocs/paybox/lib/paybox.lib.php index 7138646c8ca..6cc94d4d6f3 100644 --- a/htdocs/paybox/lib/paybox.lib.php +++ b/htdocs/paybox/lib/paybox.lib.php @@ -1,6 +1,7 @@ * Copyright (C) 2005-2007 Regis Houssin + * Copyright (C) 2024 MDW * * 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 @@ -146,8 +147,8 @@ function print_paybox_redirect($PRICE, $CURRENCY, $EMAIL, $urlok, $urlko, $TAG) "&PBX_OUTPUT=".$IBS_OUTPUT. "&PBX_SOURCE=".$PBX_SOURCE. "&PBX_TYPEPAIEMENT=".$PBX_TYPEPAIEMENT; - "&PBX_HASH=".$PBX_HASH; - "&PBX_TIME=".$PBX_TIME; + // "&PBX_HASH=".$PBX_HASH; + // "&PBX_TIME=".$PBX_TIME; $binKey = pack("H*", dol_decode($conf->global->PAYBOX_HMAC_KEY)); diff --git a/htdocs/product/dynamic_price/class/price_global_variable_updater.class.php b/htdocs/product/dynamic_price/class/price_global_variable_updater.class.php index 42030aa290e..c0ec8226e3d 100644 --- a/htdocs/product/dynamic_price/class/price_global_variable_updater.class.php +++ b/htdocs/product/dynamic_price/class/price_global_variable_updater.class.php @@ -456,7 +456,7 @@ class PriceGlobalVariableUpdater $langs->load("errors"); dol_syslog(__METHOD__, LOG_DEBUG); - $this->error = null; + $this->error = ''; $this->checkParameters(); //Try to load the target global variable and abort if fails diff --git a/htdocs/product/stock/class/api_warehouses.class.php b/htdocs/product/stock/class/api_warehouses.class.php index e39ede65299..1af08af0534 100644 --- a/htdocs/product/stock/class/api_warehouses.class.php +++ b/htdocs/product/stock/class/api_warehouses.class.php @@ -222,9 +222,9 @@ class Warehouses extends DolibarrApi if ($this->warehouse->update($id, DolibarrApiAccess::$user)) { return $this->get($id); + } else { + throw new RestException(500, $this->warehouse->error); } - - return false; } /** diff --git a/htdocs/product/stock/class/productlot.class.php b/htdocs/product/stock/class/productlot.class.php index f1941283842..f9787f8e3eb 100644 --- a/htdocs/product/stock/class/productlot.class.php +++ b/htdocs/product/stock/class/productlot.class.php @@ -1220,7 +1220,7 @@ class Productlot extends CommonObject $this->specimen = 1; $this->entity = $conf->entity; - $this->fk_product = null; + $this->fk_product = 0; $this->batch = ''; $this->eatby = $now - 100000; $this->sellby = $now - 100000; diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index 13d4c426bc7..153e1f9c26d 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -2607,7 +2607,7 @@ class Project extends CommonObject $to = ''; $nbMailSend = 0; $error = 0; - $errors_to = 0; + $errors_to = ''; while ($obj = $this->db->fetch_object($resql)) { $to = $obj->email; $numHolidays = num_public_holiday($lastWeekStartTS, $lastWeekEndTS, $mysoc->country_code, 1); diff --git a/htdocs/projet/class/task.class.php b/htdocs/projet/class/task.class.php index 5f97d8c9a3f..754f465e574 100644 --- a/htdocs/projet/class/task.class.php +++ b/htdocs/projet/class/task.class.php @@ -525,7 +525,12 @@ class Task extends CommonObjectLine $project->getLinesArray(null); // this method does not return <= 0 if fails $projectCompleted = array_reduce( $project->lines, - function ($allTasksCompleted, $task) { + /** + * @param bool $allTasksCompleted + * @param Task $task + * @return bool + */ + static function ($allTasksCompleted, $task) { return $allTasksCompleted && $task->progress >= 100; }, 1 diff --git a/htdocs/public/payment/newpayment.php b/htdocs/public/payment/newpayment.php index d57987f4434..feec219703d 100644 --- a/htdocs/public/payment/newpayment.php +++ b/htdocs/public/payment/newpayment.php @@ -1619,7 +1619,7 @@ if ($source == 'member' || $source == 'membersubscription') { // Set the new member type $member->typeid = $newtypeid; - $member->type = dol_getIdFromCode($db, $newtypeid, 'adherent_type', 'rowid', 'libelle'); + $member->type = (string) dol_getIdFromCode($db, $newtypeid, 'adherent_type', 'rowid', 'libelle'); // list member type if (!$action) { diff --git a/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php b/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php index 0d950928653..148e75eee6d 100644 --- a/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php +++ b/htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php @@ -4,7 +4,7 @@ * Copyright (C) 2014 Marcos García * Copyright (C) 2016 Charlie Benke * Copyright (C) 2018-2021 Philippe Grand - * Copyright (C) 2018-2022 Frédéric France + * Copyright (C) 2018-2024 Frédéric France * * 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 @@ -212,7 +212,7 @@ class doc_generic_recruitmentjobposition_odt extends ModelePDFRecruitmentJobPosi /** * Function to build a document on disk using the generic odt module. * - * @param Commande $object Object source to build document + * @param RecruitmentJobPosition $object Object source to build document * @param Translate $outputlangs Lang output object * @param string $srctemplatepath Full path of source filename for generator using a template file * @param int $hidedetails Do not show line details diff --git a/htdocs/recruitment/core/modules/recruitment/doc/pdf_standard_recruitmentjobposition.modules.php b/htdocs/recruitment/core/modules/recruitment/doc/pdf_standard_recruitmentjobposition.modules.php index fd5a1a88d06..11727b809f1 100644 --- a/htdocs/recruitment/core/modules/recruitment/doc/pdf_standard_recruitmentjobposition.modules.php +++ b/htdocs/recruitment/core/modules/recruitment/doc/pdf_standard_recruitmentjobposition.modules.php @@ -8,7 +8,7 @@ * Copyright (C) 2012-2014 Raphaël Doursenaud * Copyright (C) 2015 Marcos García * Copyright (C) 2017 Ferran Marcet - * Copyright (C) 2018-2021 Frédéric France + * Copyright (C) 2018-2024 Frédéric France * * 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 @@ -177,7 +177,7 @@ class pdf_standard_recruitmentjobposition extends ModelePDFRecruitmentJobPositio /** * Function to build pdf onto disk * - * @param Object $object Object to generate + * @param RecruitmentJobPosition $object RecruitmentJobPosition to generate * @param Translate $outputlangs Lang output object * @param string $srctemplatepath Full path of source filename for generator using a template file * @param int $hidedetails Do not show line details @@ -807,7 +807,7 @@ class pdf_standard_recruitmentjobposition extends ModelePDFRecruitmentJobPositio * Show top header of page. * * @param TCPDF $pdf Object PDF - * @param Object $object Object to show + * @param RecruitmentJobPosition $object Object to show * @param int $showaddress 0=no, 1=yes * @param Translate $outputlangs Object lang for output * @param Translate $outputlangsbis Object lang for output bis @@ -1053,7 +1053,7 @@ class pdf_standard_recruitmentjobposition extends ModelePDFRecruitmentJobPositio * Show footer of page. Need this->emetteur object * * @param TCPDF $pdf PDF - * @param Object $object Object to show + * @param RecruitmentJobPosition $object Object to show * @param Translate $outputlangs Object lang for output * @param int $hidefreetext 1=Hide free text * @return int Return height of bottom margin including footer text diff --git a/htdocs/recruitment/core/modules/recruitment/mod_recruitmentcandidature_advanced.php b/htdocs/recruitment/core/modules/recruitment/mod_recruitmentcandidature_advanced.php index 7cc19971cb3..c1258703e6c 100644 --- a/htdocs/recruitment/core/modules/recruitment/mod_recruitmentcandidature_advanced.php +++ b/htdocs/recruitment/core/modules/recruitment/mod_recruitmentcandidature_advanced.php @@ -3,7 +3,7 @@ * Copyright (C) 2004-2007 Laurent Destailleur * Copyright (C) 2005-2009 Regis Houssin * Copyright (C) 2008 Raphael Bertrand (Resultic) - * Copyright (C) 2019 Frédéric France + * Copyright (C) 2019-2024 Frédéric France * * 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 @@ -118,7 +118,7 @@ class mod_recruitmentcandidature_advanced extends ModeleNumRefRecruitmentCandida /** * Return next free value * - * @param Object $object Object we need next value for + * @param RecruitmentCandidature $object Object we need next value for * @return string|0 Next value if OK, 0 if KO */ public function getNextValue($object) @@ -135,7 +135,7 @@ class mod_recruitmentcandidature_advanced extends ModeleNumRefRecruitmentCandida return 0; } - $date = $object->date; + $date = $object->date ?? ''; $numFinal = get_next_value($db, $mask, 'recruitment_recruitmentcandidature', 'ref', '', null, $date); diff --git a/htdocs/recruitment/core/modules/recruitment/mod_recruitmentcandidature_standard.php b/htdocs/recruitment/core/modules/recruitment/mod_recruitmentcandidature_standard.php index dca26f27602..6a7b4d8c510 100644 --- a/htdocs/recruitment/core/modules/recruitment/mod_recruitmentcandidature_standard.php +++ b/htdocs/recruitment/core/modules/recruitment/mod_recruitmentcandidature_standard.php @@ -1,6 +1,7 @@ * Copyright (C) 2005-2009 Regis Houssin + * Copyright (C) 2024 Frédéric France * * 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 @@ -76,7 +77,7 @@ class mod_recruitmentcandidature_standard extends ModeleNumRefRecruitmentCandida * Checks if the numbers already in the database do not * cause conflicts that would prevent this numbering working. * - * @param Object $object Object we need next value for + * @param CommonObject $object Object we need next value for * @return boolean false if conflict, true if ok */ public function canBeActivated($object) @@ -116,8 +117,8 @@ class mod_recruitmentcandidature_standard extends ModeleNumRefRecruitmentCandida /** * Return next free value * - * @param Object $object Object we need next value for - * @return string|-1 Next value if OK, -1 if KO + * @param RecruitmentCandidature $object Object we need next value for + * @return string|-1 Next value if OK, -1 if KO */ public function getNextValue($object) { diff --git a/htdocs/recruitment/core/modules/recruitment/mod_recruitmentjobposition_advanced.php b/htdocs/recruitment/core/modules/recruitment/mod_recruitmentjobposition_advanced.php index 4be33bfd352..868b4b284e0 100644 --- a/htdocs/recruitment/core/modules/recruitment/mod_recruitmentjobposition_advanced.php +++ b/htdocs/recruitment/core/modules/recruitment/mod_recruitmentjobposition_advanced.php @@ -3,7 +3,7 @@ * Copyright (C) 2004-2007 Laurent Destailleur * Copyright (C) 2005-2009 Regis Houssin * Copyright (C) 2008 Raphael Bertrand (Resultic) - * Copyright (C) 2019 Frédéric France + * Copyright (C) 2019-2024 Frédéric France * * 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 @@ -118,8 +118,8 @@ class mod_recruitmentjobposition_advanced extends ModeleNumRefRecruitmentJobPosi /** * Return next free value * - * @param Object $object Object we need next value for - * @return string|0 Next value if OK, 0 if KO + * @param RecruitmentJobPosition $object Object we need next value for + * @return string|0 Next value if OK, 0 if KO */ public function getNextValue($object) { @@ -135,7 +135,7 @@ class mod_recruitmentjobposition_advanced extends ModeleNumRefRecruitmentJobPosi return 0; } - $date = $object->date; + $date = $object->date ?? ''; $numFinal = get_next_value($db, $mask, 'recruitment_recruitmentjobposition', 'ref', '', null, $date); diff --git a/htdocs/recruitment/core/modules/recruitment/mod_recruitmentjobposition_standard.php b/htdocs/recruitment/core/modules/recruitment/mod_recruitmentjobposition_standard.php index 09c69067887..50c2ab775e7 100644 --- a/htdocs/recruitment/core/modules/recruitment/mod_recruitmentjobposition_standard.php +++ b/htdocs/recruitment/core/modules/recruitment/mod_recruitmentjobposition_standard.php @@ -1,6 +1,7 @@ * Copyright (C) 2005-2009 Regis Houssin + * Copyright (C) 2024 Frédéric France * * 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 @@ -76,7 +77,7 @@ class mod_recruitmentjobposition_standard extends ModeleNumRefRecruitmentJobPosi * Checks if the numbers already in the database do not * cause conflicts that would prevent this numbering working. * - * @param Object $object Object we need next value for + * @param CommonObject $object Object we need next value for * @return boolean false if conflict, true if ok */ public function canBeActivated($object) @@ -116,7 +117,7 @@ class mod_recruitmentjobposition_standard extends ModeleNumRefRecruitmentJobPosi /** * Return next free value * - * @param Object $object Object we need next value for + * @param RecruitmentJobPosition $object Object we need next value for * @return string|-1 Next value if OK, -1 if KO */ public function getNextValue($object) diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php index 0d501e63cdc..dfd78b08cd6 100644 --- a/htdocs/societe/class/api_thirdparties.class.php +++ b/htdocs/societe/class/api_thirdparties.class.php @@ -1,10 +1,10 @@ - * Copyright (C) 2018 Pierre Chéné - * Copyright (C) 2019 Cedric Ancelin - * Copyright (C) 2020-2024 Frédéric France - * Copyright (C) 2023 Alexandre Janniaux - * Copyright (C) 2024 MDW +/* Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2018 Pierre Chéné + * Copyright (C) 2019 Cedric Ancelin + * Copyright (C) 2020-2024 Frédéric France + * Copyright (C) 2023 Alexandre Janniaux + * Copyright (C) 2024 MDW * * 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 @@ -49,7 +49,7 @@ class Thirdparties extends DolibarrApi */ public function __construct() { - global $db, $conf; + global $db; $this->db = $db; require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php'; @@ -258,7 +258,7 @@ class Thirdparties extends DolibarrApi continue; } - $this->company->$field = $value; + $this->company->$field = $this->_checkValForAPI($field, $value, $this->company); } if ($this->company->create(DolibarrApiAccess::$user) < 0) { @@ -303,7 +303,7 @@ class Thirdparties extends DolibarrApi continue; } - $this->company->$field = $value; + $this->company->$field = $this->_checkValForAPI($field, $value, $this->company); } if (isModEnabled('mailing') && !empty($this->company->email) && isset($this->company->no_email)) { diff --git a/htdocs/variants/class/ProductCombination.class.php b/htdocs/variants/class/ProductCombination.class.php index 25d69eaeac9..ef23ce4857d 100644 --- a/htdocs/variants/class/ProductCombination.class.php +++ b/htdocs/variants/class/ProductCombination.class.php @@ -2,6 +2,7 @@ /* Copyright (C) 2016 Marcos García * Copyright (C) 2018 Juanjo Menent * Copyright (C) 2022 Open-Dsi + * Copyright (C) 2024 MDW * * 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 @@ -292,13 +293,13 @@ class ProductCombination global $conf; $sql = "SELECT pac.rowid, pac.fk_product_parent, pac.fk_product_child, pac.variation_price, pac.variation_price_percentage, pac.variation_ref_ext, pac.variation_weight"; - $sql.= " FROM ".MAIN_DB_PREFIX."product_attribute_combination AS pac"; + $sql .= " FROM ".MAIN_DB_PREFIX."product_attribute_combination AS pac"; if ($sort_by_ref) { - $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product AS p ON p.rowid = pac.fk_product_child"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product AS p ON p.rowid = pac.fk_product_child"; } - $sql.= " WHERE pac.fk_product_parent = ".((int) $fk_product_parent)." AND pac.entity IN (".getEntity('product').")"; + $sql .= " WHERE pac.fk_product_parent = ".((int) $fk_product_parent)." AND pac.entity IN (".getEntity('product').")"; if ($sort_by_ref) { - $sql.= $this->db->order('p.ref', 'ASC'); + $sql .= $this->db->order('p.ref', 'ASC'); } $query = $this->db->query($sql); @@ -614,7 +615,7 @@ class ProductCombination * Retrieves the combination that matches the given features. * * @param int $prodid Id of parent product - * @param array $features Format: [$attr] => $attr_val + * @param array $features Format: [$attr] => $attr_val * @return false|ProductCombination False if not found */ public function fetchByProductCombination2ValuePairs($prodid, array $features) @@ -626,9 +627,15 @@ class ProductCombination $prodcomb2val = new ProductCombination2ValuePair($this->db); $prodcomb = new ProductCombination($this->db); - $features = array_filter($features, function ($v) { - return !empty($v); - }); + $features = array_filter( + $features, + /** + * @param mixed $v Feature information of a product. + */ + static function ($v) { + return !empty($v); + } + ); foreach ($features as $attr => $attr_val) { $actual_comp[$attr] = $attr_val; @@ -729,7 +736,7 @@ class ProductCombination $this->db->begin(); - $price_impact = array(1=>0); // init level price impact + $price_impact = array(1 => 0); // init level price impact $forced_refvar = trim($forced_refvar); diff --git a/htdocs/website/class/website.class.php b/htdocs/website/class/website.class.php index 47d572654be..2dbc2227f9d 100644 --- a/htdocs/website/class/website.class.php +++ b/htdocs/website/class/website.class.php @@ -1075,15 +1075,16 @@ class Website extends CommonObject $i++; } + $line = '-- File generated by Dolibarr '.DOL_VERSION.' --;'."\n"; + $line .= "\n"; + fwrite($fp, $line); + foreach ($listofpages as $pageid => $objectpageold) { $oldpageid = $objectpageold->id; $allaliases = $objectpageold->pageurl; $allaliases .= ($objectpageold->aliasalt ? ','.$objectpageold->aliasalt : ''); - $line = '-- File generated by Dolibarr '.DOL_VERSION.' -- '.dol_print_date(dol_now('gmt'), 'standard', 'gmt').' UTC --;'."\n"; - $line .= "\n"; - if (!getDolGlobalInt('WEBSITE_EXPORT_KEEP_FILES_OF_PAGES')) { // We don't need to keep the PHP files of pages and aliases (they are regenerated at import) so we remove them. You can ask to keep them in the export // Delete the pageX.tpl.php page dol_delete_file($conf->website->dir_temp.'/'.$website->ref.'/containers/page'.$objectpageold->id.'.tpl.php', 0, 0, 0, null, false, 0); @@ -1098,13 +1099,12 @@ class Website extends CommonObject } // This comment syntax is important, it is parsed by import to get information on page ID and all aliases to regenerate - $line .= '-- Page ID '.$objectpageold->newid.'__+MAX_llx_website_page__ - Aliases '.$allaliases.' --;'; // newid start at 1, 2... + $line = '-- Page ID '.$objectpageold->newid.'__+MAX_llx_website_page__ - Aliases '.$allaliases.' --;'; // newid start at 1, 2... $line .= "\n"; fwrite($fp, $line); // Warning: We must keep llx_ here. It is a generic SQL. $line = 'INSERT INTO llx_website_page(rowid, fk_page, fk_website, pageurl, aliasalt, title, description, lang, image, keywords, status, date_creation, tms, import_key, grabbed_from, type_container, htmlheader, content, author_alias, allowed_in_frames)'; - $line .= " VALUES("; $line .= $objectpageold->newid."__+MAX_llx_website_page__, "; $line .= ($objectpageold->newfk_page ? $this->db->escape($objectpageold->newfk_page)."__+MAX_llx_website_page__" : "null").", "; @@ -1170,7 +1170,7 @@ class Website extends CommonObject fwrite($fp, $line); } - $line .= "\n"; + fwrite($fp, "\n"); } $line = "\n-- For Dolibarr v14+ --;\n"; @@ -1180,6 +1180,7 @@ class Website extends CommonObject fwrite($fp, $line); fclose($fp); + dolChmod($filesql); // Build zip file @@ -1244,7 +1245,8 @@ class Website extends CommonObject $arrayreplacement['__LOGO_MINI_KEY__'] = $this->db->escape($mysoc->logo_mini); $arrayreplacement['__LOGO_KEY__'] = $this->db->escape($mysoc->logo); - // Copy containers + + // Copy containers directory dolCopyDir($conf->website->dir_temp.'/'.$object->ref.'/containers', $conf->website->dir_output.'/'.$object->ref, 0, 1); // Overwrite if exists // Make replacement into css and htmlheader file @@ -1262,8 +1264,17 @@ class Website extends CommonObject $error++; } - dolCopyDir($conf->website->dir_temp.'/'.$object->ref.'/medias/image/websitekey', $conf->website->dir_output.'/'.$object->ref.'/medias/image/'.$object->ref, 0, 1); // Medias can be shared, do not overwrite if exists - dolCopyDir($conf->website->dir_temp.'/'.$object->ref.'/medias/js/websitekey', $conf->website->dir_output.'/'.$object->ref.'/medias/js/'.$object->ref, 0, 1); // Medias can be shared, do not overwrite if exists + $result = dolCopyDir($conf->website->dir_temp.'/'.$object->ref.'/medias/image/websitekey', $conf->website->dir_output.'/'.$object->ref.'/medias/image/'.$object->ref, 0, 1); + if ($result < 0) { + $this->errors[] = 'Failed to copy files into '.$conf->website->dir_output.'/'.$object->ref.'/medias/image/'.$object->ref.'.'; + return -5; + } + + $result = dolCopyDir($conf->website->dir_temp.'/'.$object->ref.'/medias/js/websitekey', $conf->website->dir_output.'/'.$object->ref.'/medias/js/'.$object->ref, 0, 1); + if ($result < 0) { + $this->errors[] = 'Failed to copy files into '.$conf->website->dir_output.'/'.$object->ref.'/medias/js/'.$object->ref.'.'; + return -5; + } $sqlfile = $conf->website->dir_temp."/".$object->ref.'/website_pages.sql'; @@ -1288,7 +1299,7 @@ class Website extends CommonObject $objectpagestatic = new WebsitePage($this->db); - // Make replacement of IDs + // Regenerate the php files for pages $fp = fopen($sqlfile, "r"); if ($fp) { while (!feof($fp)) { @@ -1296,18 +1307,30 @@ class Website extends CommonObject // Warning fgets with second parameter that is null or 0 hang. $buf = fgets($fp, 65000); + $newid = 0; + + // Scan the line if (preg_match('/^-- Page ID (\d+)\s[^\s]+\s(\d+).*Aliases\s(.*)\s--;/i', $buf, $reg)) { + // Example of line: "-- Page ID 179 -> 1__+MAX_llx_website_page__ - Aliases about-us --;" $oldid = $reg[1]; $newid = ($reg[2] + $maxrowid); $aliasesarray = explode(',', $reg[3]); - dol_syslog("Found ID ".$oldid." to replace with ID ".$newid." and shortcut aliases to create: ".$reg[3]); + dol_syslog("In sql source file, we have the page ID ".$oldid." to replace with the new ID ".$newid.", and we must create the shortcut aliases: ".$reg[3]); - dol_move($conf->website->dir_output.'/'.$object->ref.'/page'.$oldid.'.tpl.php', $conf->website->dir_output.'/'.$object->ref.'/page'.$newid.'.tpl.php', 0, 1, 0, 0); + //dol_move($conf->website->dir_output.'/'.$object->ref.'/page'.$oldid.'.tpl.php', $conf->website->dir_output.'/'.$object->ref.'/page'.$newid.'.tpl.php', 0, 1, 0, 0); + } elseif (preg_match('/^-- Page ID (\d+).*Aliases\s(.*)\s--;/i', $buf, $reg)) { + // Example of line: "-- Page ID 1__+MAX_llx_website_page__ - Aliases about-us --;" + $newid = ($reg[1] + $maxrowid); + $aliasesarray = explode(',', $reg[2]); + dol_syslog("In sql source file, we have the page with the new ID ".$newid.", and we must create the shortcut aliases: ".$reg[3]); + } + + if ($newid) { $objectpagestatic->fetch($newid); - // The move is not enough, so we regenerate pageX.tpl.php + // We regenerate the pageX.tpl.php $filetpl = $conf->website->dir_output.'/'.$object->ref.'/page'.$newid.'.tpl.php'; $result = dolSavePageContent($filetpl, $object, $objectpagestatic); if (!$result) { @@ -1346,7 +1369,7 @@ class Website extends CommonObject } } - // Regenerate index page to point to the new index page + // Regenerate the index.php page to point to the new index page $pathofwebsite = $conf->website->dir_output.'/'.$object->ref; dolSaveIndexPage($pathofwebsite, $pathofwebsite.'/index.php', $pathofwebsite.'/page'.$object->fk_default_home.'.tpl.php', $pathofwebsite.'/wrapper.php', $object); @@ -1684,173 +1707,20 @@ class Website extends CommonObject // Export on target sources $resultarray = dol_uncompress($pathtotmpzip, $destdir); + // Remove the file README and LICENSE from the $destdir (already into the containers directory) + dol_delete_file($destdir.'/README.md'); + dol_delete_file($destdir.'/LICENSE'); + + // Remove non required files (will be re-generated during the import) + dol_delete_file($destdir.'/containers/index.php'); + dol_delete_file($destdir.'/containers/master.inc.php'); + if (!empty($resultarray)) { setEventMessages("Error, failed to unzip the export into target dir", null, 'errors'); } else { setEventMessages("Website content written into ".$destdirrel, null, 'mesgs'); } - /* - $sourcedir = $conf->website->dir_output."/".$website->ref; - - // Get array with hash of files (for the last sync) - $fichierEtat = $sourcedir . '/filelist-'.dol_sanitizeFileName($destdir).'.txt'; - $etatPrecedent = $this->checkPreviousState($fichierEtat); - - // Get list of all source files of the website - $arraySourcedir = dol_dir_list($sourcedir); - - // Get list of modified files - $modifications = []; - foreach ($arraySourcedir as $file) { - if (substr($file['name'], -4) === '.old') { - continue; - } - $hashActuel = hash_file('md5', $file['fullname']); - - // Check whether the file is new or has been modified - if (!isset($etatPrecedent[$file['name']]) || $etatPrecedent[$file['name']] !== $hashActuel) { - $modifications[] = $file; - } - - $etatPrecedent[$file['name']] = $hashActuel; // we store he new hash to record it later on disk. - } - - $arraydestdir = dol_dir_list($destdir, "all", 1); - $differences = []; - $names = array_column($arraydestdir, 'name'); - $namesSource = array_column($arraySourcedir, 'name'); - - if (count($modifications) > 1) { - foreach ($modifications as $fichierModifie) { - $nomFichierModifie = $fichierModifie['name']; - if ($nomFichierModifie == basename($fichierEtat)) { - continue; - } - $success = 0; - - //check if it is a new file - if ((!preg_match('/^page\d+\.tpl\.php$/', $nomFichierModifie)) && (!in_array($nomFichierModifie, $names))) { - if (file_exists($fichierModifie['fullname']) && dol_is_dir($destdir.'/containers')) { - $cp = dol_copy($fichierModifie['fullname'], $destdir.'/containers/'.$nomFichierModifie, '0664'); - if ($cp > 0) { - if (file_exists($destdir.'/containers/'.$nomFichierModifie)) { - $tabnumpage = array(); - foreach ($arraydestdir as $fileDest) { - if ($this->extractNumberFromFilename($fileDest['name']) !== -1) { - $tabnumpage[] = $this->extractNumberFromFilename($fileDest['name']); - } - } - $getContentSource = file_get_contents($destdir.'/containers/'.$nomFichierModifie); - $nextpage = max($tabnumpage) + 1; - $chaineModifiee = preg_replace('/page\d+\.tpl\.php/', 'page' . $nextpage . '.tpl.php', $getContentSource); - $write = file_put_contents($destdir.'/containers/'.$nomFichierModifie, $chaineModifiee); - if ($write !== false) { - if (!touch($destdir.'/containers/'."page" . $nextpage . ".tpl.php")) { - setEventMessages("Please check permission to create page" . $nextpage . ".tpl.php in template ".$website->name_template."", null, 'errors'); - } - $filesFound = ''; - foreach ($arraySourcedir as $file) { - if ($file['name'] == $nomFichierModifie) { - $fileContent = file_get_contents($file['fullname']); - $matches = array(); - if (preg_match("/page\d+\.tpl\.php/", $fileContent, $matches)) { - $filesFound = $matches[0]; - break; - } - } - } - foreach ($arraySourcedir as $file) { - if ($file['name'] == $filesFound) { - if (!is_writable($file['fullname'])) { - dolChmod($file['fullname'], '0664'); - } - $diff = $this->showDifferences(file_get_contents($destdir.'/containers/'."page" . $nextpage . ".tpl.php"), file_get_contents($file['fullname']), array($nextpage,$this->extractNumberFromFilename($file['name']))); - if ($diff != -1) { - $replace = $this->replaceLineUsingNum($destdir.'/containers/'."page" . $nextpage . ".tpl.php", $diff); - if ($replace !== false) { - setEventMessages("Copy file page".$nextpage.".tpl.php in template ".$this->name_template." with success", null, 'warnings'); - } - } - } - } - } - } - - $this->saveState($etatPrecedent, $fichierEtat); - setEventMessages("file ".$nomFichierModifie." was created in template ".$website->name_template."", null, 'warnings'); - - header("Location: ".$_SERVER["PHP_SELF"].'?website='.$website->ref); - exit(); - } - } else { - setEventMessages("Error, target dir containers not found", null, 'errors'); - $error = 1; - break; - } - } - - // Find the corresponding file in the destination folder - if (!$error && in_array($nomFichierModifie, $namesSource)) { - foreach ($arraydestdir as $destFile) { - if ($destFile['name'] == $nomFichierModifie) { - $sourceContent = file_get_contents($fichierModifie['fullname']); - $destContent = file_get_contents($destFile['fullname']); - - if ($sourceContent !== $destContent) { - $differences[$nomFichierModifie] = $this->showDifferences($destContent, $sourceContent); - if (count($differences[$nomFichierModifie]) > 0) { - $result = $this->replaceLineUsingNum($destFile['fullname'], $differences[$nomFichierModifie]); - if ($result >= 0) { - setEventMessages("file ".$nomFichierModifie." was modified in template ".$website->name_template."", null, 'warnings'); - } else { - if ($result == -2) { - setEventMessages("No permissions to write into file ".$destdirrel.'/'.$nomFichierModifie." from the current website ".$website->name_template."", null, 'errors'); - - header("Location: ".$_SERVER["PHP_SELF"].'?website='.$website->ref); - exit(); - } - setEventMessages("file ".$nomFichierModifie." was not modified", null, 'errors'); - } - } - } - } - - if (preg_match('/page(\d+)\.tpl\.php/', $nomFichierModifie)) { - $differences[$nomFichierModifie] = $this->compareFichierModifie($sourcedir, $destdir, $fichierModifie); - if (count($differences[$nomFichierModifie]) > 0) { - $result = $this->replaceLineUsingNum($differences[$nomFichierModifie]['file_destination']['fullname'], $differences[$nomFichierModifie]); - if ($result !== false) { - if ($result == -2) { - setEventMessages("No permissions to write into file ".$destdirrel.'/'.$differences[$nomFichierModifie]['file_destination']['name']." from the current website ".$website->name_template."", null, 'errors'); - header("Location: ".$_SERVER["PHP_SELF"].'?website='.$website->ref); - exit(); - } - $success++; - } - } - } - } - } - } - if ($success > 0) { - // Save the state file filelist.txt - $this->saveState($etatPrecedent, $fichierEtat); - setEventMessages("file ".$differences[$nomFichierModifie]['file_destination']['name']." was modified in template ".$website->name_template."", null, 'warnings'); - - header("Location: ".$_SERVER["PHP_SELF"].'?website='.$website->ref); - exit(); - } - } else { - setEventMessages("No file has been modified", null, 'errors'); - } - - // save state file - if (!$error) { - $this->saveState($etatPrecedent, $fichierEtat); - } - */ - header("Location: ".$_SERVER["PHP_SELF"].'?website='.$website->ref); exit(); } @@ -1918,38 +1788,6 @@ class Website extends CommonObject return file_put_contents($pathname, serialize($etat)); } - /** - * create file for save state of all files in folder - * - * @param string $sourcedir path of folder - * @return void - */ - /* - public function initFilesStatus($sourcedir) - { - $fichierEtat = $sourcedir . '/filelist-lastwrite-doctemplates.txt'; - - $etatPrecedent = $this->checkPreviousState($fichierEtat); - - // for first save state when create file - if (empty($etatPrecedent)) { - $arraySourcedir = dol_dir_list($sourcedir, "files"); - $etatFichiers = []; - - foreach ($arraySourcedir as $file) { - // Ignore .old files and the status file itself - if (substr($file['name'], -4) === '.old' || $file['name'] === basename($fichierEtat)) { - continue; - } - - $hashActuel = hash_file('md5', $file['fullname']); - $etatFichiers[$file['name']] = $hashActuel; - } - $this->saveState($etatFichiers, $fichierEtat); - } - } - */ - /** * Compare two files has not same name but same content * @param string $dossierSource filepath of folder source diff --git a/htdocs/website/index.php b/htdocs/website/index.php index 566a1c2feb9..91adc317602 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -1155,7 +1155,17 @@ if ($action == 'addcontainer' && $usercanedit) { $substitutionarray = array(); $substitutionarray['__WEBSITE_CREATE_BY__'] = $user->getFullName($langs); - // Define id of page the new page is translation of + // Define id of the page the new page is translation of + /* + if ($objectpage->lang == $object->lang) { + // If + $pageidfortranslation = (GETPOSTINT('pageidfortranslation') > 0 ? GETPOSTINT('pageidfortranslation') : 0); + if ($pageidfortranslation > 0) { + // We must update the page $pageidfortranslation to set fk_page = $object->id. + // But what if page $pageidfortranslation is already linked to another ? + } + } else { + */ $pageidfortranslation = (GETPOSTINT('pageidfortranslation') > 0 ? GETPOSTINT('pageidfortranslation') : 0); if ($pageidfortranslation > 0) { // Check if the page we are translation of is already a translation of a source page. if yes, we will use source id instead @@ -1166,6 +1176,7 @@ if ($action == 'addcontainer' && $usercanedit) { } } $objectpage->fk_page = $pageidfortranslation; + //} $sample = GETPOST('sample', 'alpha'); if (empty($sample)) { @@ -2406,6 +2417,22 @@ if ($usercanedit && (($action == 'updatesource' || $action == 'updatecontent' || } } +if ($action == 'deletelang' && $usercanedit) { + $sql = "UPDATE ".MAIN_DB_PREFIX."website_page SET fk_page = NULL"; + $sql .= " WHERE rowid = ".GETPOSTINT('deletelangforid'); + //$sql .= " AND fk_page = ".((int) $objectpage->id); + + $resql = $db->query($sql); + if (!$resql) { + setEventMessages($db->lasterror(), null, 'errors'); + } else { + $objectpage->fk_page = null; + } + + $action = 'editmeta'; +} + + // Export site if ($action == 'exportsite' && $user->hasRight('website', 'export')) { $fileofzip = $object->exportWebSite(); @@ -4360,7 +4387,9 @@ if ($action == 'editmeta' || $action == 'createcontainer') { // Edit properties if ($i > 0) { $tmpstring .= '
'; } - $tmpstring .= $tmppage->getNomUrl(1).' ('.$tmppage->lang.')'; + $tmpstring .= $tmppage->getNomUrl(1).' '.picto_from_langcode($tmppage->lang).' '.$tmppage->lang; + // Button unlink + $tmpstring .= ' id).'">'.img_picto($langs->trans("Remove"), 'unlink').''; $translatedby++; $i++; } @@ -4376,17 +4405,27 @@ if ($action == 'editmeta' || $action == 'createcontainer') { // Edit properties dol_print_error($db); } } - if (empty($translatedby) && ($action == 'editmeta' || $action == 'createcontainer' || $objectpage->fk_page > 0)) { + if ((empty($translatedby) || ($objectpage->lang != $object->lang)) && ($action == 'editmeta' || $action == 'createcontainer' || $objectpage->fk_page > 0)) { $sourcepage = new WebsitePage($db); - $result = $sourcepage->fetch($objectpage->fk_page); - if ($result == 0) { - // not found, we can reset value to clean database - } elseif ($result > 0) { + $result = 1; + if ($objectpage->fk_page > 0) { + $result = $sourcepage->fetch($objectpage->fk_page); + if ($result == 0) { + // not found, we can reset value to clean database + // TODO + } + } + if ($result >= 0) { + if ($translatedby) { + print '
'; + } $translationof = $objectpage->fk_page; print ''.$langs->trans('ThisPageIsTranslationOf').' '; - print $formwebsite->selectContainer($website, 'pageidfortranslation', ($translationof ? $translationof : -1), 1, $action, 'minwidth300', array($objectpage->id)); + print $sourcepage->getNomUrl(2).' '.$formwebsite->selectContainer($website, 'pageidfortranslation', ($translationof ? $translationof : -1), 1, $action, 'minwidth300', array($objectpage->id)); if ($translationof > 0 && $sourcepage->lang) { - print $sourcepage->getNomUrl(2).' ('.$sourcepage->lang.')'; + print picto_from_langcode($sourcepage->lang).' '.$sourcepage->lang; + // Button unlink + print ' id).'">'.img_picto($langs->trans("Remove"), 'unlink').''; } } } @@ -5161,6 +5200,12 @@ if ((empty($action) || $action == 'preview' || $action == 'createfromclone' || $ //var_dump($filetpl); $filephp = $filetpl; + + // Get session info and obfuscate session cookie + $savsessionname = session_name(); + $savsessionid = $_COOKIE[$savsessionname]; + $_COOKIE[$savsessionname] = 'obfuscatedcookie'; + ob_start(); try { $res = include $filephp; @@ -5172,6 +5217,9 @@ if ((empty($action) || $action == 'preview' || $action == 'createfromclone' || $ } $newcontent = ob_get_contents(); ob_end_clean(); + + // Restore data + $_COOKIE[$savsessionname] = $savsessionid; } // Change the contenteditable to "true" or "false" when mode Edit Inline is on or off