/', '', $out);
- $out = preg_replace('/<\/div>$/', '', $out);
+ // Remove the trick added to solve pb with text in utf8 and text without parent tag
+ $out = preg_replace('/^'.preg_quote('', '/').'/', '', $out);
+ $out = preg_replace('/^'.preg_quote('<', '/').'[^<>]+'.preg_quote('>
', '/').'$/', '', trim($out));
+ // $out = preg_replace('/^<\?xml encoding="UTF-8">
/', '', $out);
+ // $out = preg_replace('/<\/div>$/', '', $out);
+ // var_dump('rrrrrrrrrrrrrrrrrrrrrrrrrrrrr'.$out);
} catch (Exception $e) {
// If error, invalid HTML string with no way to clean it
//print $e->getMessage();
@@ -10316,7 +10333,7 @@ function verifCond($strToEvaluate, $onlysimplestring = '1')
/**
* Replace eval function to add more security.
- * This function is called by verifCond() or trans() and transnoentitiesnoconv().
+ * This function is called by verifCond() for example.
*
* @param string $s String to evaluate
* @param int<0,1> $returnvalue 0=No return (deprecated, used to execute eval($a=something)). 1=Value of eval is returned (used to eval($something)).
@@ -10449,18 +10466,33 @@ function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1'
$forbiddenphpstrings = array('$$', '$_', '}[');
$forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
+ // We list all forbidden function as keywords we don't want to see (we don't mind it if is "kewyord(" or just "keyword", we don't want "keyword" at all)
+ // We must exclude all functions that allow to execute another function. This includes all function that has a parameter with type "callable" to avoid things
+ // like we can do with array_map and its callable parameter: dol_eval('json_encode(array_map(implode("",["ex","ec"]), ["id"]))', 1, 1, '0')
$forbiddenphpfunctions = array();
// @phpcs:ignore
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64"."_"."decode", "rawurl"."decode", "url"."decode", "str"."_rot13", "hex"."2bin")); // name of forbidden functions are split to avoid false positive
- $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
+
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("override_function", "session_id", "session_create_id", "session_regenerate_id"));
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
- $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func"));
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func", "call_user_func_array"));
+
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("array_all", "array_any", "array_diff_ukey", "array_filter", "array_find", "array_find_key", "array_map", "array_reduce", "array_intersect_uassoc", "array_intersect_ukey", "array_walk", "array_walk_recursive"));
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("usort", "uasort", "uksort", "preg_replace_callback", "preg_replace_callback_array", "header_register_callback"));
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("set_error_handler", "set_exception_handler", "libxml_set_external_entity_loader", "register_shutdown_function", "register_tick_function", "unregister_tick_function"));
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("spl_autoload_register", "spl_autoload_unregister", "iterator_apply", "session_set_save_handler"));
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("forward_static_call", "forward_static_call_array", "register_postsend_function"));
+
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("ob_start"));
+
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("exec", "passthru", "shell_exec", "system", "proc_open", "popen"));
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
- $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace")); // function with eval capabilities
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace", "mb_ereg_replace_callback")); // function with eval capabilities
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("readline_completion_function", "readline_callback_handler_install"));
$forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_compress_dir", "dol_decode", "dol_delete_file", "dol_delete_dir", "dol_delete_dir_recursive", "dol_copy", "archiveOrBackupFile")); // more dolibarr functions
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
+ $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include"));
$forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
diff --git a/htdocs/install/upgrade.php b/htdocs/install/upgrade.php
index e323fb88b62..f5f7d9ac9bd 100644
--- a/htdocs/install/upgrade.php
+++ b/htdocs/install/upgrade.php
@@ -39,6 +39,11 @@
define('ALLOWED_IF_UPGRADE_UNLOCK_FOUND', 1);
include_once 'inc.php';
+
+/**
+ * @var string $conffile
+ */
+
if (!file_exists($conffile)) {
print 'Error: Dolibarr config file was not found. This may means that Dolibarr is not installed yet. Please call the page "/install/index.php" instead of "/install/upgrade.php").';
}
@@ -47,6 +52,11 @@ require_once $dolibarr_main_document_root.'/core/lib/admin.lib.php';
global $langs;
+/**
+ * @var Conf $conf
+ * @var Translate $langs
+ */
+
$grant_query = '';
$step = 2;
$ok = 0;
diff --git a/htdocs/install/upgrade2.php b/htdocs/install/upgrade2.php
index 52f00eaec8a..c2c555252b2 100644
--- a/htdocs/install/upgrade2.php
+++ b/htdocs/install/upgrade2.php
@@ -42,6 +42,11 @@
define('ALLOWED_IF_UPGRADE_UNLOCK_FOUND', 1);
include_once 'inc.php';
+
+/**
+ * @var string $conffile
+ */
+
if (!file_exists($conffile)) {
print 'Error: Dolibarr config file was not found. This may means that Dolibarr is not installed yet. Please call the page "/install/index.php" instead of "/install/upgrade.php").';
}
@@ -58,13 +63,17 @@ require_once $dolibarr_main_document_root.'/core/lib/files.lib.php';
global $langs;
+/**
+ * @var Conf $conf
+ * @var Translate $langs
+ */
+
$grant_query = '';
$step = 2;
$error = 0;
-// Cette page peut etre longue. On augmente le delai autorise.
-// Ne fonctionne que si on est pas en safe_mode.
+// This page can be long. We increase the allowed delay, but this does not work when we are in safe_mode.
$err = error_reporting();
error_reporting(0);
if (getDolGlobalString('MAIN_OVERRIDE_TIME_LIMIT')) {
@@ -226,8 +235,11 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$db->begin();
foreach ($listofentities as $entity) {
+ dol_syslog("Process upgrade2 for entity ".$entity);
+
// Set $conf context for entity
$conf->setEntityValues($db, $entity);
+
// Reset forced setup after the setValues
if (defined('SYSLOG_FILE')) {
$conf->global->SYSLOG_FILE = constant('SYSLOG_FILE');
@@ -250,10 +262,11 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$versiontoarray = explode('.', $versionto);
$versionranarray = explode('.', DOL_VERSION);
-
$afterversionarray = explode('.', '2.0.0');
$beforeversionarray = explode('.', '2.7.9');
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
// Script pour V2 -> V2.1
migrate_paiements($db, $langs, $conf);
@@ -317,6 +330,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$beforeversionarray = explode('.', '2.8.9');
//print $versionto.' '.versioncompare($versiontoarray,$afterversionarray).' '.versioncompare($versiontoarray,$beforeversionarray);
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
migrate_price_facture($db, $langs, $conf); // Code of this function works for 2.8+ because need a field tva_tx
migrate_relationship_tables($db, $langs, $conf, 'co_exp', 'fk_commande', 'commande', 'fk_expedition', 'shipping');
@@ -342,6 +357,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$afterversionarray = explode('.', '2.8.9');
$beforeversionarray = explode('.', '2.9.9');
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
migrate_element_time($db, $langs, $conf);
migrate_customerorder_shipping($db, $langs, $conf);
@@ -362,6 +379,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$afterversionarray = explode('.', '3.0.9');
$beforeversionarray = explode('.', '3.1.9');
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
migrate_rename_directories($db, $langs, $conf, '/rss', '/externalrss');
migrate_actioncomm_element($db, $langs, $conf);
@@ -371,6 +390,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$afterversionarray = explode('.', '3.1.9');
$beforeversionarray = explode('.', '3.2.9');
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
migrate_price_contrat($db, $langs, $conf);
migrate_mode_reglement($db, $langs, $conf);
@@ -382,6 +403,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$afterversionarray = explode('.', '3.2.9');
$beforeversionarray = explode('.', '3.3.9');
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
migrate_categorie_association($db, $langs, $conf);
}
@@ -392,6 +415,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$afterversionarray = explode('.', '3.6.9'); // target is after this
$beforeversionarray = explode('.', '3.7.9'); // target is before this
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
migrate_event_assignement($db, $langs, $conf);
}
@@ -406,6 +431,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$afterversionarray = explode('.', '3.9.9');
$beforeversionarray = explode('.', '4.0.9');
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
migrate_rename_directories($db, $langs, $conf, '/fckeditor', '/medias');
}
@@ -413,6 +440,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$afterversionarray = explode('.', '4.0.9');
$beforeversionarray = explode('.', '5.0.9');
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
// Migrate to add entity value into llx_societe_remise
migrate_remise_entity($db, $langs, $conf);
@@ -429,6 +458,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
// Only if the transverse mode is not used
if (empty($multicompany_transverse_mode)) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
// Migrate to add entity value into llx_user_rights
migrate_user_rights_entity($db, $langs, $conf);
@@ -442,6 +473,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$afterversionarray = explode('.', '6.0.9');
$beforeversionarray = explode('.', '7.0.9');
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
// Migrate contact association
migrate_event_assignement_contact($db, $langs, $conf);
@@ -452,6 +485,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$afterversionarray = explode('.', '7.0.9');
$beforeversionarray = explode('.', '8.0.9');
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
migrate_rename_directories($db, $langs, $conf, '/contracts', '/contract');
}
@@ -466,6 +501,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$afterversionarray = explode('.', '10.0.9');
$beforeversionarray = explode('.', '11.0.9');
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
migrate_users_socialnetworks();
migrate_members_socialnetworks();
migrate_contacts_socialnetworks();
@@ -476,6 +513,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$afterversionarray = explode('.', '13.0.9');
$beforeversionarray = explode('.', '14.0.9');
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
migrate_export_import_profiles('export');
migrate_export_import_profiles('import');
}
@@ -484,6 +523,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$afterversionarray = explode('.', '15.0.9');
$beforeversionarray = explode('.', '16.0.9');
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
migrate_user_photospath();
migrate_user_photospath2();
}
@@ -492,6 +533,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$afterversionarray = explode('.', '16.0.9');
$beforeversionarray = explode('.', '17.0.9');
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
migrate_contractdet_rank();
}
@@ -499,6 +542,8 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
$afterversionarray = explode('.', '17.0.9');
$beforeversionarray = explode('.', '18.0.9');
if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
+ dol_syslog("Run migrate_... versionto is between ".json_encode($afterversionarray)." and ".json_encode($beforeversionarray));
+
migrate_contractdet_rank();
}
@@ -519,9 +564,10 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
}
}
-
// Code executed only if migration is LAST ONE. Must always be done.
if (versioncompare($versiontoarray, $versionranarray) >= 0 || versioncompare($versiontoarray, $versionranarray) <= -3) {
+ dol_syslog("Run migrate_... if migration is LAST ONE");
+
// Reload modules (this must be always done and only into last targeted version, because code to reload module may need table structure of last version)
$listofmodule = array(
'MAIN_MODULE_ACCOUNTING' => 'newboxdefonly',
@@ -566,6 +612,7 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ
if ($result < 0) {
$error++;
}
+
// Reload menus (this must be always and only into last targeted version)
$result = migrate_reload_menu($db, $langs, $conf);
if ($result < 0) {
diff --git a/test/phpunit/.gitignore b/test/phpunit/.gitignore
new file mode 100644
index 00000000000..647a82afb84
--- /dev/null
+++ b/test/phpunit/.gitignore
@@ -0,0 +1 @@
+/DemoTest.php
diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php
index f9483236c54..73da0e2fd4f 100644
--- a/test/phpunit/SecurityTest.php
+++ b/test/phpunit/SecurityTest.php
@@ -545,8 +545,8 @@ class SecurityTest extends CommonClassTest
print __METHOD__." result for param0=".$result."\n";
$this->assertEquals($resultexpected, $result, 'Test on param0');
- $result = GETPOST("param15b", 'restricthtml'); // param15b =
![]()
src=>0xbeefed that is a dangerous string
- print __METHOD__." result for param15b=".$result."\n";
+ $result=GETPOST("param15", 'restricthtml'); // param15 =
![]()
src=>0xbeefed that is a dangerous string
+ print __METHOD__." result for param15=".$result."\n";
//$this->assertEquals('InvalidHTMLStringCantBeCleaned', $result, 'Test 15b'); // With some PHP and libxml version, we got this result when parsing invalid HTML, but ...
//$this->assertEquals('
![]()
src=>0xbeefed', $result, 'Test 15b'); // ... on other PHP and libxml versions, we got a HTML that has been cleaned
@@ -798,7 +798,9 @@ class SecurityTest extends CommonClassTest
{
$stringtotest = 'eée';
$decodedstring = dol_string_onlythesehtmlattributes($stringtotest);
- $this->assertEquals('eée', $decodedstring, 'Function did not sanitize correctly with test 1');
+
+ //$this->assertEquals('eée', $decodedstring, 'Function did not sanitize correctly with test 1');
+ $this->assertEquals('eée', $decodedstring, 'Function did not sanitize correctly with test 1');
$stringtotest = '
';
$decodedstring = dol_string_onlythesehtmlattributes($stringtotest);
@@ -1071,6 +1073,22 @@ class SecurityTest extends CommonClassTest
print "result6 = ".$result."\n";
$this->assertStringContainsString('Bad string syntax to evaluate', $result);
+ $result = dol_eval('json_encode(array_map(implode("",["ex","ec"]), ["id"]))', 1, 1, '1'); // result of dol_eval may be an object Closure
+ print "result4a = ".json_encode($result)."\n";
+ $this->assertStringContainsString('Bad string syntax to evaluate', json_encode($result), 'The string was not detected as evil, it should due to the [ char and method "2"');
+
+ $result = dol_eval('json_encode(array_map(implode("",["ex","ec"]), ["id"]))', 1, 1, '2'); // result of dol_eval may be an object Closure
+ print "result4b = ".json_encode($result)."\n";
+ $this->assertStringContainsString('Bad string syntax to evaluate', json_encode($result), 'The string was not detected as evil, it should due to the use of array_map');
+
+ $result = dol_eval('json_encode(array_map(implode("",array("ex","ec"), array("id")))', 1, 1, '1'); // result of dol_eval may be an object Closure
+ print "result4c = ".json_encode($result)."\n";
+ $this->assertStringContainsString('Bad string syntax to evaluate', json_encode($result), 'The string was not detected as evil, it should due to the use of array_map');
+
+ $result = dol_eval('$a=function() { }; $a', 1, 1, '0'); // result of dol_eval may be an object Closure
+ print "result5 = ".json_encode($result)."\n";
+ $this->assertStringContainsString('Bad string syntax to evaluate', json_encode($result), 'The string was not detected as evil');
+
$result = (string) dol_eval('$a=exec("ls");', 1, 1);
print "result7 = ".$result."\n";
$this->assertStringContainsString('Bad string syntax to evaluate', $result);