Passed
Push — dev ( 3becbd...634f81 )
by Rafael
53:25
created

run_sql()   F

Complexity

Conditions 73
Paths 11701

Size

Total Lines 397
Code Lines 227

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 73
eloc 227
nc 11701
nop 12
dl 0
loc 397
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* Copyright (C) 2008-2011  Laurent Destailleur         <[email protected]>
4
 * Copyright (C) 2005-2016  Regis Houssin               <[email protected]>
5
 * Copyright (C) 2012       J. Fernando Lagrange        <[email protected]>
6
 * Copyright (C) 2015       Raphaël Doursenaud          <[email protected]>
7
 * Copyright (C) 2023       Eric Seigne      		    <[email protected]>
8
 * Copyright (C) 2024		MDW							<[email protected]>
9
 * Copyright (C) 2024       Rafael San José             <[email protected]>
10
 *
11
 * This program is free software; you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation; either version 3 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23
 * or see https://www.gnu.org/
24
 */
25
26
use Dolibarr\Code\Core\Classes\DolEditor;
27
use Dolibarr\Code\Core\Classes\Form;
28
use Dolibarr\Code\Core\Classes\FormMail;
29
use Dolibarr\Core\Base\DolibarrModules;
30
use Dolibarr\Lib\AveryLabels;
31
use Dolibarr\Lib\Version;
32
33
/**
34
 *  \file           htdocs/core/lib/admin.lib.php
35
 *  \brief          Library of admin functions
36
 */
37
38
require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/functions2.lib.php';
39
40
/**
41
 *  Launch a sql file. Function is used by:
42
 *  - Migrate process (dolibarr-xyz-abc.sql)
43
 *  - Loading sql menus (auguria)
44
 *  - Running specific Sql by a module init
45
 *  - Loading sql file of website import package
46
 *  Install process however does not use it.
47
 *  Note that Sql files must have all comments at start of line. Also this function take ';' as the char to detect end of sql request
48
 *
49
 * @param string $sqlfile Full path to sql file
50
 * @param int $silent 1=Do not output anything, 0=Output line for update page
51
 * @param int $entity Entity targeted for multicompany module
52
 * @param int $usesavepoint 1=Run a savepoint before each request and a rollback to savepoint if error (this allow to have some request with errors inside global transactions).
53
 * @param string $handler Handler targeted for menu (replace __HANDLER__ with this value between quotes)
54
 * @param string $okerror Family of errors we accept ('default', 'none')
55
 * @param int $linelengthlimit Limit for length of each line (Use 0 if unknown, may be faster if defined)
56
 * @param int $nocommentremoval Do no try to remove comments (in such a case, we consider that each line is a request, so use also $linelengthlimit=0)
57
 * @param int $offsetforchartofaccount Offset to use to load chart of account table to update sql on the fly to add offset to rowid and account_parent value
58
 * @param int $colspan 2=Add a colspan=2 on td
59
 * @param int $onlysqltoimportwebsite Only sql requests used to import a website template are allowed
60
 * @param string $database Database (replace __DATABASE__ with this value)
61
 * @return     int                                     Return integer <=0 if KO, >0 if OK
62
 */
63
function run_sql($sqlfile, $silent = 1, $entity = 0, $usesavepoint = 1, $handler = '', $okerror = 'default', $linelengthlimit = 32768, $nocommentremoval = 0, $offsetforchartofaccount = 0, $colspan = 0, $onlysqltoimportwebsite = 0, $database = '')
64
{
65
    global $db, $conf, $langs, $user;
66
67
    dol_syslog("Admin.lib::run_sql run sql file " . $sqlfile . " silent=" . $silent . " entity=" . $entity . " usesavepoint=" . $usesavepoint . " handler=" . $handler . " okerror=" . $okerror, LOG_DEBUG);
68
69
    if (!is_numeric($linelengthlimit)) {
70
        dol_syslog("Admin.lib::run_sql param linelengthlimit is not a numeric", LOG_ERR);
71
        return -1;
72
    }
73
74
    $ok = 0;
75
    $error = 0;
76
    $i = 0;
77
    $buffer = '';
78
    $arraysql = array();
79
80
    // Get version of database
81
    $versionarray = $db->getVersionArray();
82
83
    $fp = fopen($sqlfile, "r");
84
    if ($fp) {
85
        while (!feof($fp)) {
86
            // Warning fgets with second parameter that is null or 0 hang.
87
            if ($linelengthlimit > 0) {
88
                $buf = fgets($fp, $linelengthlimit);
89
            } else {
90
                $buf = fgets($fp);
91
            }
92
93
            // Test if request must be ran only for particular database or version (if yes, we must remove the -- comment)
94
            $reg = array();
95
            if (preg_match('/^--\sV(MYSQL|PGSQL)([^\s]*)/i', $buf, $reg)) {
96
                $qualified = 1;
97
98
                // restrict on database type
99
                if (!empty($reg[1])) {
100
                    if (!preg_match('/' . preg_quote($reg[1]) . '/i', $db->type)) {
101
                        $qualified = 0;
102
                    }
103
                }
104
105
                // restrict on version
106
                if ($qualified) {
107
                    if (!empty($reg[2])) {
108
                        if (is_numeric($reg[2])) {  // This is a version
109
                            $versionrequest = explode('.', $reg[2]);
110
                            //var_dump($versionrequest);
111
                            //var_dump($versionarray);
112
                            if (!count($versionrequest) || !count($versionarray) || Version::compare($versionrequest, $versionarray) > 0) {
113
                                $qualified = 0;
114
                            }
115
                        } else { // This is a test on a constant. For example when we have -- VMYSQLUTF8UNICODE, we test constant $conf->global->UTF8UNICODE
116
                            $dbcollation = strtoupper(preg_replace('/_/', '', $conf->db->dolibarr_main_db_collation));
117
                            //var_dump($reg[2]);
118
                            //var_dump($dbcollation);
119
                            if (empty($conf->db->dolibarr_main_db_collation) || ($reg[2] != $dbcollation)) {
120
                                $qualified = 0;
121
                            }
122
                            //var_dump($qualified);
123
                        }
124
                    }
125
                }
126
127
                if ($qualified) {
128
                    // Version qualified, delete SQL comments
129
                    $buf = preg_replace('/^--\sV(MYSQL|PGSQL)([^\s]*)/i', '', $buf);
130
                    //print "Ligne $i qualifi?e par version: ".$buf.'<br>';
131
                }
132
            }
133
134
            // Add line buf to buffer if not a comment
135
            if ($nocommentremoval || !preg_match('/^\s*--/', $buf)) {
136
                if (empty($nocommentremoval)) {
137
                    $buf = preg_replace('/([,;ERLT\)])\s*--.*$/i', '\1', $buf); //remove comment from a line that not start with -- before add it to the buffer
138
                }
139
                if ($buffer) {
140
                    $buffer .= ' ';
141
                }
142
                $buffer .= trim($buf);
143
            }
144
145
            //print $buf.'<br>';exit;
146
147
            if (preg_match('/;/', $buffer)) {   // If string contains ';', it's end of a request string, we save it in arraysql.
148
                // Found new request
149
                if ($buffer) {
150
                    $arraysql[$i] = $buffer;
151
                }
152
                $i++;
153
                $buffer = '';
154
            }
155
        }
156
157
        if ($buffer) {
158
            $arraysql[$i] = $buffer;
159
        }
160
        fclose($fp);
161
    } else {
162
        dol_syslog("Admin.lib::run_sql failed to open file " . $sqlfile, LOG_ERR);
163
    }
164
165
    // Loop on each request to see if there is a __+MAX_table__ key
166
    $listofmaxrowid = array(); // This is a cache table
167
    foreach ($arraysql as $i => $sql) {
168
        $newsql = $sql;
169
170
        // Replace __+MAX_table__ with max of table
171
        while (preg_match('/__\+MAX_([A-Za-z0-9_]+)__/i', $newsql, $reg)) {
172
            $table = $reg[1];
173
            if (!isset($listofmaxrowid[$table])) {
174
                //var_dump($db);
175
                $sqlgetrowid = 'SELECT MAX(rowid) as max from ' . preg_replace('/^llx_/', MAIN_DB_PREFIX, $table);
176
                $resql = $db->query($sqlgetrowid);
177
                if ($resql) {
178
                    $obj = $db->fetch_object($resql);
179
                    $listofmaxrowid[$table] = $obj->max;
180
                    if (empty($listofmaxrowid[$table])) {
181
                        $listofmaxrowid[$table] = 0;
182
                    }
183
                } else {
184
                    if (!$silent) {
185
                        print '<tr><td class="tdtop"' . ($colspan ? ' colspan="' . $colspan . '"' : '') . '>';
186
                        print '<div class="error">' . $langs->trans("Failed to get max rowid for " . $table) . "</div>";
187
                        print '</td></tr>';
188
                    }
189
                    $error++;
190
                    break;
191
                }
192
            }
193
            // Replace __+MAX_llx_table__ with +999
194
            $from = '__+MAX_' . $table . '__';
195
            $to = '+' . $listofmaxrowid[$table];
196
            $newsql = str_replace($from, $to, $newsql);
197
            dol_syslog('Admin.lib::run_sql New Request ' . ($i + 1) . ' (replacing ' . $from . ' to ' . $to . ')', LOG_DEBUG);
198
199
            $arraysql[$i] = $newsql;
200
        }
201
202
        if ($offsetforchartofaccount > 0) {
203
            // Replace lines
204
            // 'INSERT INTO llx_accounting_account (entity, rowid, fk_pcg_version, pcg_type, account_number, account_parent, label, active) VALUES (__ENTITY__, 1401, 'PCG99-ABREGE', 'CAPIT', '1234', 1400,...'
205
            // with
206
            // 'INSERT INTO llx_accounting_account (entity, rowid, fk_pcg_version, pcg_type, account_number, account_parent, label, active) VALUES (__ENTITY__, 1401 + 200100000, 'PCG99-ABREGE','CAPIT', '1234', 1400 + 200100000,...'
207
            // Note: string with 'PCG99-ABREGE','CAPIT', 1234  instead of  'PCG99-ABREGE','CAPIT', '1234' is also supported
208
            $newsql = preg_replace('/VALUES\s*\(__ENTITY__, \s*(\d+)\s*,(\s*\'[^\',]*\'\s*,\s*\'[^\',]*\'\s*,\s*\'?[^\',]*\'?\s*),\s*\'?([^\',]*)\'?/ims', 'VALUES (__ENTITY__, \1 + ' . ((int)$offsetforchartofaccount) . ', \2, \3 + ' . ((int)$offsetforchartofaccount), $newsql);
209
            $newsql = preg_replace('/([,\s])0 \+ ' . ((int)$offsetforchartofaccount) . '/ims', '\1 0', $newsql);
210
            //var_dump($newsql);
211
            $arraysql[$i] = $newsql;
212
213
            // FIXME Because we force the rowid during insert, we must also update the sequence with postgresql by running
214
            // SELECT dol_util_rebuild_sequences();
215
        }
216
    }
217
218
    // Loop on each request to execute request
219
    $cursorinsert = 0;
220
    $listofinsertedrowid = array();
221
    $keyforsql = md5($sqlfile);
222
    foreach ($arraysql as $i => $sql) {
223
        if ($sql) {
224
            // Test if the SQL is allowed SQL
225
            if ($onlysqltoimportwebsite) {
226
                $newsql = str_replace(array("\'"), '__BACKSLASHQUOTE__', $sql); // Replace the \' char
227
228
                // Remove all strings contents including the ' so we can analyse SQL instruction only later
229
                $l = strlen($newsql);
230
                $is = 0;
231
                $quoteopen = 0;
232
                $newsqlclean = '';
233
                while ($is < $l) {
234
                    $char = $newsql[$is];
235
                    if ($char == "'") {
236
                        if ($quoteopen) {
237
                            $quoteopen--;
238
                        } else {
239
                            $quoteopen++;
240
                        }
241
                    } elseif (empty($quoteopen)) {
242
                        $newsqlclean .= $char;
243
                    }
244
                    $is++;
245
                }
246
                $newsqlclean = str_replace(array("null"), '__000__', $newsqlclean);
247
                //print $newsqlclean."<br>\n";
248
249
                $qualified = 0;
250
251
                // A very small control. This can still by bypassed by adding a second SQL request concatenated
252
                if (preg_match('/^--/', $newsqlclean)) {
253
                    $qualified = 1;
254
                } elseif (preg_match('/^UPDATE llx_website SET \w+ = \d+\+\d+ WHERE rowid = \d+;$/', $newsqlclean)) {
255
                    $qualified = 1;
256
                } elseif (preg_match('/^INSERT INTO llx_website_page\([a-z0-9_\s,]+\) VALUES\([0-9_\s,\+]+\);$/', $newsqlclean)) {
257
                    // Insert must match
258
                    // 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) VALUES(1+123, null, 17, , , , , , , , , , , null, , , , , );
259
                    $qualified = 1;
260
                }
261
262
                // Another check to allow some legitimate original urls
263
                if (!$qualified) {
264
                    if (preg_match('/^UPDATE llx_website SET \w+ = \'[a-zA-Z,\s]*\' WHERE rowid = \d+;$/', $sql)) {
265
                        $qualified = 1;
266
                    }
267
                }
268
269
                // We also check content
270
                $extractphp = dolKeepOnlyPhpCode($sql);
271
                $extractphpold = '';
272
273
                // Security analysis
274
                $errorphpcheck = checkPHPCode($extractphpold, $extractphp); // Contains the setEventMessages
275
                if ($errorphpcheck) {
276
                    $error++;
277
                    //print 'Request '.($i + 1)." contains non allowed instructions.<br>\n";
278
                    //print "newsqlclean = ".$newsqlclean."<br>\n";
279
                    dol_syslog('Admin.lib::run_sql Request ' . ($i + 1) . " contains PHP code and checking this code returns errorphpcheck='.$errorphpcheck.'", LOG_WARNING);
280
                    dol_syslog("sql=" . $sql, LOG_DEBUG);
281
                    break;
282
                }
283
284
285
                if (!$qualified) {
286
                    $error++;
287
                    //print 'Request '.($i + 1)." contains non allowed instructions.<br>\n";
288
                    //print "newsqlclean = ".$newsqlclean."<br>\n";
289
                    dol_syslog('Admin.lib::run_sql Request ' . ($i + 1) . " contains non allowed instructions.", LOG_WARNING);
290
                    dol_syslog('$newsqlclean=' . $newsqlclean, LOG_DEBUG);
291
                    break;
292
                }
293
            }
294
295
            // Replace the prefix tables
296
            if (MAIN_DB_PREFIX != 'llx_') {
297
                $sql = preg_replace('/llx_/i', MAIN_DB_PREFIX, $sql);
298
            }
299
300
            if (!empty($handler)) {
301
                $sql = preg_replace('/__HANDLER__/i', "'" . $db->escape($handler) . "'", $sql);
302
            }
303
304
            if (!empty($database)) {
305
                $sql = preg_replace('/__DATABASE__/i', $db->escape($database), $sql);
306
            }
307
308
            $newsql = preg_replace('/__ENTITY__/i', (!empty($entity) ? $entity : (string)$conf->entity), $sql);
309
310
            // Add log of request
311
            if (!$silent) {
312
                print '<tr class="trforrunsql' . $keyforsql . '"><td class="tdtop opacitymedium"' . ($colspan ? ' colspan="' . $colspan . '"' : '') . '>' . $langs->trans("Request") . ' ' . ($i + 1) . " sql='" . dol_htmlentities($newsql, ENT_NOQUOTES) . "'</td></tr>\n";
313
            }
314
            dol_syslog('Admin.lib::run_sql Request ' . ($i + 1), LOG_DEBUG);
315
            $sqlmodified = 0;
316
317
            // Replace for encrypt data
318
            if (preg_match_all('/__ENCRYPT\(\'([^\']+)\'\)__/i', $newsql, $reg)) {
319
                $num = count($reg[0]);
320
321
                for ($j = 0; $j < $num; $j++) {
322
                    $from = $reg[0][$j];
323
                    $to = $db->encrypt($reg[1][$j]);
324
                    $newsql = str_replace($from, $to, $newsql);
325
                }
326
                $sqlmodified++;
327
            }
328
329
            // Replace for decrypt data
330
            if (preg_match_all('/__DECRYPT\(\'([A-Za-z0-9_]+)\'\)__/i', $newsql, $reg)) {
331
                $num = count($reg[0]);
332
333
                for ($j = 0; $j < $num; $j++) {
334
                    $from = $reg[0][$j];
335
                    $to = $db->decrypt($reg[1][$j]);
336
                    $newsql = str_replace($from, $to, $newsql);
337
                }
338
                $sqlmodified++;
339
            }
340
341
            // Replace __x__ with the rowid of the result of the insert number x
342
            while (preg_match('/__([0-9]+)__/', $newsql, $reg)) {
343
                $cursor = $reg[1];
344
                if (empty($listofinsertedrowid[$cursor])) {
345
                    if (!$silent) {
346
                        print '<tr><td class="tdtop"' . ($colspan ? ' colspan="' . $colspan . '"' : '') . '>';
347
                        print '<div class="error">' . $langs->trans("FileIsNotCorrect") . "</div>";
348
                        print '</td></tr>';
349
                    }
350
                    $error++;
351
                    break;
352
                }
353
354
                $from = '__' . $cursor . '__';
355
                $to = $listofinsertedrowid[$cursor];
356
                $newsql = str_replace($from, $to, $newsql);
357
                $sqlmodified++;
358
            }
359
360
            if ($sqlmodified) {
361
                dol_syslog('Admin.lib::run_sql New Request ' . ($i + 1), LOG_DEBUG);
362
            }
363
364
            $result = $db->query($newsql, $usesavepoint);
365
            if ($result) {
366
                if (!$silent) {
367
                    print '<!-- Result = OK -->' . "\n";
368
                }
369
370
                if (preg_replace('/insert into ([^\s]+)/i', $newsql, $reg)) {
371
                    $cursorinsert++;
372
373
                    // It's an insert
374
                    $table = preg_replace('/([^a-zA-Z_]+)/i', '', $reg[1]);
375
                    $insertedrowid = $db->last_insert_id($table);
376
                    $listofinsertedrowid[$cursorinsert] = $insertedrowid;
377
                    dol_syslog('Admin.lib::run_sql Insert nb ' . $cursorinsert . ', done in table ' . $table . ', rowid is ' . $listofinsertedrowid[$cursorinsert], LOG_DEBUG);
378
                }
379
                //            print '<td class="right">OK</td>';
380
            } else {
381
                $errno = $db->errno();
382
                if (!$silent) {
383
                    print '<!-- Result = ' . $errno . ' -->' . "\n";
384
                }
385
386
                // Define list of errors we accept (array $okerrors)
387
                $okerrors = array(  // By default
388
                    'DB_ERROR_TABLE_ALREADY_EXISTS',
389
                    'DB_ERROR_COLUMN_ALREADY_EXISTS',
390
                    'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
391
                    'DB_ERROR_TABLE_OR_KEY_ALREADY_EXISTS', // PgSql use same code for table and key already exist
392
                    'DB_ERROR_RECORD_ALREADY_EXISTS',
393
                    'DB_ERROR_NOSUCHTABLE',
394
                    'DB_ERROR_NOSUCHFIELD',
395
                    'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
396
                    'DB_ERROR_NO_INDEX_TO_DROP',
397
                    'DB_ERROR_CANNOT_CREATE', // Qd contrainte deja existante
398
                    'DB_ERROR_CANT_DROP_PRIMARY_KEY',
399
                    'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS',
400
                    'DB_ERROR_22P02'
401
                );
402
                if ($okerror == 'none') {
403
                    $okerrors = array();
404
                }
405
406
                // Is it an error we accept
407
                if (!in_array($errno, $okerrors)) {
408
                    if (!$silent) {
409
                        print '<tr><td class="tdtop"' . ($colspan ? ' colspan="' . $colspan . '"' : '') . '>';
410
                        print '<div class="error">' . $langs->trans("Error") . " " . $db->errno() . " (Req " . ($i + 1) . "): " . $newsql . "<br>" . $db->error() . "</div>";
411
                        print '</td></tr>' . "\n";
412
                    }
413
                    dol_syslog('Admin.lib::run_sql Request ' . ($i + 1) . " Error " . $db->errno() . " " . $newsql . "<br>" . $db->error(), LOG_ERR);
414
                    $error++;
415
                }
416
            }
417
        }
418
    }
419
420
    if (!$silent) {
421
        print '<tr><td>' . $langs->trans("ProcessMigrateScript") . '</td>';
422
        print '<td class="right">';
423
        if ($error == 0) {
424
            print '<span class="ok">' . $langs->trans("OK") . '</span>';
425
        } else {
426
            print '<span class="error">' . $langs->trans("Error") . '</span>';
427
        }
428
429
        //if (!empty($conf->use_javascript_ajax)) {     // use_javascript_ajax is not defined
430
        print '<script type="text/javascript">
431
		jQuery(document).ready(function() {
432
			function init_trrunsql' . $keyforsql . '()
433
			{
434
				console.log("toggle .trforrunsql' . $keyforsql . '");
435
				jQuery(".trforrunsql' . $keyforsql . '").toggle();
436
			}
437
			init_trrunsql' . $keyforsql . '();
438
			jQuery(".trforrunsqlshowhide' . $keyforsql . '").click(function() {
439
				init_trrunsql' . $keyforsql . '();
440
			});
441
		});
442
		</script>';
443
        if (count($arraysql)) {
444
            print ' - <a class="trforrunsqlshowhide' . $keyforsql . '" href="#" title="' . ($langs->trans("ShowHideTheNRequests", count($arraysql))) . '">' . $langs->trans("ShowHideDetails") . '</a>';
445
        } else {
446
            print ' - <span class="opacitymedium">' . $langs->trans("ScriptIsEmpty") . '</span>';
447
        }
448
        //}
449
450
        print '</td></tr>' . "\n";
451
    }
452
453
    if ($error == 0) {
454
        $ok = 1;
455
    } else {
456
        $ok = 0;
457
    }
458
459
    return $ok;
460
}
461
462
/**
463
 *  Delete a constant
464
 *
465
 * @param DoliDB $db Database handler
466
 * @param string|int $name Name of constant or rowid of line
467
 * @param int $entity Multi company id, -1 for all entities
468
 * @return     int                     Return integer <0 if KO, >0 if OK
469
 *
470
 * @see        dolibarr_get_const(), dolibarr_set_const(), dol_set_user_param()
471
 */
472
function dolibarr_del_const($db, $name, $entity = 1)
473
{
474
    global $conf;
475
476
    if (empty($name)) {
477
        dol_print_error(null, 'Error call dolibar_del_const with parameter name empty');
478
        return -1;
479
    }
480
481
    $sql = "DELETE FROM " . MAIN_DB_PREFIX . "const";
482
    $sql .= " WHERE (" . $db->decrypt('name') . " = '" . $db->escape($name) . "'";
483
    if (is_numeric($name)) {
484
        $sql .= " OR rowid = " . ((int)$name);
485
    }
486
    $sql .= ")";
487
    if ($entity >= 0) {
488
        $sql .= " AND entity = " . ((int)$entity);
489
    }
490
491
    dol_syslog("admin.lib::dolibarr_del_const", LOG_DEBUG);
492
    $resql = $db->query($sql);
493
    if ($resql) {
494
        $conf->global->$name = '';
495
        return 1;
496
    } else {
497
        dol_print_error($db);
498
        return -1;
499
    }
500
}
501
502
/**
503
 *  Get the value of a setup constant from database
504
 *
505
 * @param DoliDB $db Database handler
506
 * @param string $name Name of constant
507
 * @param int $entity Multi company id
508
 * @return     string                  Value of constant
509
 *
510
 * @see        dolibarr_del_const(), dolibarr_set_const(), dol_set_user_param()
511
 */
512
function dolibarr_get_const($db, $name, $entity = 1)
513
{
514
    $value = '';
515
516
    $sql = "SELECT " . $db->decrypt('value') . " as value";
517
    $sql .= " FROM " . MAIN_DB_PREFIX . "const";
518
    $sql .= " WHERE name = " . $db->encrypt($name);
519
    $sql .= " AND entity = " . ((int)$entity);
520
521
    dol_syslog("admin.lib::dolibarr_get_const", LOG_DEBUG);
522
    $resql = $db->query($sql);
523
    if ($resql) {
524
        $obj = $db->fetch_object($resql);
525
        if ($obj) {
526
            include_once DOL_DOCUMENT_ROOT . '/core/lib/security.lib.php';
527
            $value = dolDecrypt($obj->value);
528
        }
529
    }
530
    return $value;
531
}
532
533
/**
534
 *  Insert a parameter (key,value) into database (delete old key then insert it again).
535
 *
536
 * @param DoliDB $db Database handler
537
 * @param string $name Name of constant
538
 * @param string $value Value of constant
539
 * @param string $type Type of constant. Deprecated, only strings are allowed for $value. Caller must json encode/decode to store other type of data.
540
 * @param int $visible Is constant visible in Setup->Other page (0 by default)
541
 * @param string $note Note on parameter
542
 * @param int $entity Multi company id (0 means all entities)
543
 * @return     int                     -1 if KO, 1 if OK
544
 *
545
 * @see        dolibarr_del_const(), dolibarr_get_const(), dol_set_user_param()
546
 */
547
function dolibarr_set_const($db, $name, $value, $type = 'chaine', $visible = 0, $note = '', $entity = 1)
548
{
549
    global $conf;
550
551
    // Clean parameters
552
    $name = trim($name);
553
554
    // Check parameters
555
    if (empty($name)) {
556
        dol_print_error($db, "Error: Call to function dolibarr_set_const with wrong parameters");
557
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
558
    }
559
560
    //dol_syslog("dolibarr_set_const name=$name, value=$value type=$type, visible=$visible, note=$note entity=$entity");
561
562
    $db->begin();
563
564
    $sql = "DELETE FROM " . MAIN_DB_PREFIX . "const";
565
    $sql .= " WHERE name = " . $db->encrypt($name);
566
    if ($entity >= 0) {
567
        $sql .= " AND entity = " . ((int)$entity);
568
    }
569
570
    dol_syslog("admin.lib::dolibarr_set_const", LOG_DEBUG);
571
    $resql = $db->query($sql);
572
573
    if (strcmp($value, '')) {   // true if different. Must work for $value='0' or $value=0
574
        if (!preg_match('/^(MAIN_LOGEVENTS|MAIN_AGENDA_ACTIONAUTO)/', $name) && (preg_match('/(_KEY|_EXPORTKEY|_SECUREKEY|_SERVERKEY|_PASS|_PASSWORD|_PW|_PW_TICKET|_PW_EMAILING|_SECRET|_SECURITY_TOKEN|_WEB_TOKEN)$/', $name))) {
575
            // This seems a sensitive constant, we encrypt its value
576
            // To list all sensitive constant, you can make a
577
            // WHERE name like '%\_KEY' or name like '%\_EXPORTKEY' or name like '%\_SECUREKEY' or name like '%\_SERVERKEY' or name like '%\_PASS' or name like '%\_PASSWORD' or name like '%\_SECRET'
578
            // or name like '%\_SECURITY_TOKEN' or name like '%\WEB_TOKEN'
579
            include_once DOL_DOCUMENT_ROOT . '/core/lib/security.lib.php';
580
            $newvalue = dolEncrypt($value);
581
        } else {
582
            $newvalue = $value;
583
        }
584
585
        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "const(name, value, type, visible, note, entity)";
586
        $sql .= " VALUES (";
587
        $sql .= $db->encrypt($name);
588
        $sql .= ", " . $db->encrypt($newvalue);
589
        $sql .= ", '" . $db->escape($type) . "', " . ((int)$visible) . ", '" . $db->escape($note) . "', " . ((int)$entity) . ")";
590
591
        //print "sql".$value."-".pg_escape_string($value)."-".$sql;exit;
592
        //print "xx".$db->escape($value);
593
        dol_syslog("admin.lib::dolibarr_set_const", LOG_DEBUG);
594
        $resql = $db->query($sql);
595
    }
596
597
    if ($resql) {
598
        $db->commit();
599
        $conf->global->$name = $value;
600
        return 1;
601
    } else {
602
        $error = $db->lasterror();
603
        $db->rollback();
604
        return -1;
605
    }
606
}
607
608
/**
609
 * Prepare array with list of tabs
610
 *
611
 * @param int $nbofactivatedmodules Number if activated modules
612
 * @param int $nboftotalmodules Nb of total modules
613
 * @param int $nbmodulesnotautoenabled Nb of modules not auto enabled that are activated
614
 * @return  array                               Array of tabs to show
615
 */
616
function modules_prepare_head($nbofactivatedmodules, $nboftotalmodules, $nbmodulesnotautoenabled)
617
{
618
    global $langs, $form;
619
620
    $desc = $langs->trans("ModulesDesc", '{picto}');
621
    $desc = str_replace('{picto}', img_picto('', 'switch_off'), $desc);
622
623
    $h = 0;
624
    $head = array();
625
    $mode = getDolGlobalString('MAIN_MODULE_SETUP_ON_LIST_BY_DEFAULT', 'commonkanban');
626
    $head[$h][0] = constant('BASE_URL') . "/admin/modules.php?mode=" . $mode;
627
    if ($nbmodulesnotautoenabled <= getDolGlobalInt('MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING', 1)) { // If only minimal initial modules enabled)
628
        //$head[$h][1] = $form->textwithpicto($langs->trans("AvailableModules"), $desc);
629
        $head[$h][1] = $langs->trans("AvailableModules");
630
        $head[$h][1] .= $form->textwithpicto('', $langs->trans("YouMustEnableOneModule") . '.<br><br><span class="opacitymedium">' . $desc . '</span>', 1, 'warning');
631
    } else {
632
        //$head[$h][1] = $langs->trans("AvailableModules").$form->textwithpicto('<span class="badge marginleftonly">'.$nbofactivatedmodules.' / '.$nboftotalmodules.'</span>', $desc, 1, 'help', '', 1, 3);
633
        $head[$h][1] = $langs->trans("AvailableModules") . '<span class="badge marginleftonly">' . $nbofactivatedmodules . ' / ' . $nboftotalmodules . '</span>';
634
    }
635
    $head[$h][2] = 'modules';
636
    $h++;
637
638
    $head[$h][0] = constant('BASE_URL') . "/admin/modules.php?mode=marketplace";
639
    $head[$h][1] = $langs->trans("ModulesMarketPlaces");
640
    $head[$h][2] = 'marketplace';
641
    $h++;
642
643
    $head[$h][0] = constant('BASE_URL') . "/admin/modules.php?mode=deploy";
644
    $head[$h][1] = $langs->trans("AddExtensionThemeModuleOrOther");
645
    $head[$h][2] = 'deploy';
646
    $h++;
647
648
    $head[$h][0] = constant('BASE_URL') . "/admin/modules.php?mode=develop";
649
    $head[$h][1] = $langs->trans("ModulesDevelopYourModule");
650
    $head[$h][2] = 'develop';
651
    $h++;
652
653
    return $head;
654
}
655
656
/**
657
 * Prepare array with list of tabs
658
 *
659
 * @return  array               Array of tabs to show
660
 */
661
function ihm_prepare_head()
662
{
663
    global $langs, $conf, $user;
664
    $h = 0;
665
    $head = array();
666
667
    $head[$h][0] = constant('BASE_URL') . "/admin/ihm.php?mode=other";
668
    $head[$h][1] = $langs->trans("LanguageAndPresentation");
669
    $head[$h][2] = 'other';
670
    $h++;
671
672
    $head[$h][0] = constant('BASE_URL') . "/admin/ihm.php?mode=template";
673
    $head[$h][1] = $langs->trans("SkinAndColors");
674
    $head[$h][2] = 'template';
675
    $h++;
676
677
    $head[$h][0] = constant('BASE_URL') . "/admin/ihm.php?mode=dashboard";
678
    $head[$h][1] = $langs->trans("Dashboard");
679
    $head[$h][2] = 'dashboard';
680
    $h++;
681
682
    $head[$h][0] = constant('BASE_URL') . "/admin/ihm.php?mode=login";
683
    $head[$h][1] = $langs->trans("LoginPage");
684
    $head[$h][2] = 'login';
685
    $h++;
686
687
    $head[$h][0] = constant('BASE_URL') . "/admin/ihm.php?mode=css";
688
    $head[$h][1] = $langs->trans("CSSPage");
689
    $head[$h][2] = 'css';
690
    $h++;
691
692
    complete_head_from_modules($conf, $langs, null, $head, $h, 'ihm_admin');
693
694
    complete_head_from_modules($conf, $langs, null, $head, $h, 'ihm_admin', 'remove');
695
696
697
    return $head;
698
}
699
700
/**
701
 * Prepare array with list of tabs
702
 *
703
 * @return  array               Array of tabs to show
704
 */
705
function security_prepare_head()
706
{
707
    global $db, $langs, $conf, $user;
708
    $h = 0;
709
    $head = array();
710
711
    $head[$h][0] = constant('BASE_URL') . "/admin/security_other.php";
712
    $head[$h][1] = $langs->trans("Miscellaneous");
713
    $head[$h][2] = 'misc';
714
    $h++;
715
716
    $head[$h][0] = constant('BASE_URL') . "/admin/security.php";
717
    $head[$h][1] = $langs->trans("Passwords");
718
    $head[$h][2] = 'passwords';
719
    $h++;
720
721
    $head[$h][0] = constant('BASE_URL') . "/admin/security_file.php";
722
    $head[$h][1] = $langs->trans("Files") . ' (' . $langs->trans("Upload") . ')';
723
    $head[$h][2] = 'file';
724
    $h++;
725
726
    /*
727
    $head[$h][0] = constant('BASE_URL')."/admin/security_file_download.php";
728
    $head[$h][1] = $langs->trans("Files").' ('.$langs->trans("Download").')';
729
    $head[$h][2] = 'filedownload';
730
    $h++;
731
    */
732
733
    $head[$h][0] = constant('BASE_URL') . "/admin/proxy.php";
734
    $head[$h][1] = $langs->trans("ExternalAccess");
735
    $head[$h][2] = 'proxy';
736
    $h++;
737
738
    $head[$h][0] = constant('BASE_URL') . "/admin/events.php";
739
    $head[$h][1] = $langs->trans("Audit");
740
    $head[$h][2] = 'audit';
741
    $h++;
742
743
744
    // Show permissions lines
745
    $nbPerms = 0;
746
    $sql = "SELECT COUNT(r.id) as nb";
747
    $sql .= " FROM " . MAIN_DB_PREFIX . "rights_def as r";
748
    $sql .= " WHERE r.libelle NOT LIKE 'tou%'"; // On ignore droits "tous"
749
    $sql .= " AND entity = " . ((int)$conf->entity);
750
    $sql .= " AND bydefault = 1";
751
    if (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS')) {
752
        $sql .= " AND r.perms NOT LIKE '%_advance'"; // Hide advanced perms if option is not enabled
753
    }
754
    $resql = $db->query($sql);
755
    if ($resql) {
756
        $obj = $db->fetch_object($resql);
757
        if ($obj) {
758
            $nbPerms = $obj->nb;
759
        }
760
    } else {
761
        dol_print_error($db);
762
    }
763
764
    if (getDolGlobalString('MAIN_SECURITY_USE_DEFAULT_PERMISSIONS')) {
765
        $head[$h][0] = constant('BASE_URL') . "/admin/perms.php";
766
        $head[$h][1] = $langs->trans("DefaultRights");
767
        if ($nbPerms > 0) {
768
            $head[$h][1] .= (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') ? '<span class="badge marginleftonlyshort">' . $nbPerms . '</span>' : '');
769
        }
770
        $head[$h][2] = 'default';
771
        $h++;
772
    }
773
774
    return $head;
775
}
776
777
/**
778
 * Prepare array with list of tabs
779
 *
780
 * @param object $object Descriptor class
781
 * @return  array               Array of tabs to show
782
 */
783
function modulehelp_prepare_head($object)
784
{
785
    global $langs, $conf;
786
    $h = 0;
787
    $head = array();
788
789
    // FIX for compatibility habitual tabs
790
    $object->id = $object->numero;
791
792
    $head[$h][0] = constant('BASE_URL') . "/admin/modulehelp.php?id=" . $object->id . '&mode=desc';
793
    $head[$h][1] = $langs->trans("Description");
794
    $head[$h][2] = 'desc';
795
    $h++;
796
797
    $head[$h][0] = constant('BASE_URL') . "/admin/modulehelp.php?id=" . $object->id . '&mode=feature';
798
    $head[$h][1] = $langs->trans("TechnicalServicesProvided");
799
    $head[$h][2] = 'feature';
800
    $h++;
801
802
    if ($object->isCoreOrExternalModule() == 'external') {
803
        $head[$h][0] = constant('BASE_URL') . "/admin/modulehelp.php?id=" . $object->id . '&mode=changelog';
804
        $head[$h][1] = $langs->trans("ChangeLog");
805
        $head[$h][2] = 'changelog';
806
        $h++;
807
    }
808
809
    complete_head_from_modules($conf, $langs, $object, $head, $h, 'modulehelp_admin');
810
811
    complete_head_from_modules($conf, $langs, $object, $head, $h, 'modulehelp_admin', 'remove');
812
813
814
    return $head;
815
}
816
817
/**
818
 * Prepare array with list of tabs
819
 *
820
 * @return  array               Array of tabs to show
821
 */
822
function translation_prepare_head()
823
{
824
    global $langs, $conf;
825
    $h = 0;
826
    $head = array();
827
828
    $head[$h][0] = constant('BASE_URL') . "/admin/translation.php?mode=searchkey";
829
    $head[$h][1] = $langs->trans("TranslationKeySearch");
830
    $head[$h][2] = 'searchkey';
831
    $h++;
832
833
    $head[$h][0] = constant('BASE_URL') . "/admin/translation.php?mode=overwrite";
834
    $head[$h][1] = '<span class="valignmiddle">' . $langs->trans("TranslationOverwriteKey") . '</span><span class="fa fa-plus-circle valignmiddle paddingleft"></span>';
835
    $head[$h][2] = 'overwrite';
836
    $h++;
837
838
    complete_head_from_modules($conf, $langs, null, $head, $h, 'translation_admin');
839
840
    complete_head_from_modules($conf, $langs, null, $head, $h, 'translation_admin', 'remove');
841
842
843
    return $head;
844
}
845
846
847
/**
848
 * Prepare array with list of tabs
849
 *
850
 * @return  array               Array of tabs to show
851
 */
852
function defaultvalues_prepare_head()
853
{
854
    global $langs, $conf, $user;
855
    $h = 0;
856
    $head = array();
857
858
    $head[$h][0] = constant('BASE_URL') . "/admin/defaultvalues.php?mode=createform";
859
    $head[$h][1] = $langs->trans("DefaultCreateForm");
860
    $head[$h][2] = 'createform';
861
    $h++;
862
863
    $head[$h][0] = constant('BASE_URL') . "/admin/defaultvalues.php?mode=filters";
864
    $head[$h][1] = $langs->trans("DefaultSearchFilters");
865
    $head[$h][2] = 'filters';
866
    $h++;
867
868
    $head[$h][0] = constant('BASE_URL') . "/admin/defaultvalues.php?mode=sortorder";
869
    $head[$h][1] = $langs->trans("DefaultSortOrder");
870
    $head[$h][2] = 'sortorder';
871
    $h++;
872
873
    if (!empty($conf->use_javascript_ajax)) {
874
        $head[$h][0] = constant('BASE_URL') . "/admin/defaultvalues.php?mode=focus";
875
        $head[$h][1] = $langs->trans("DefaultFocus");
876
        $head[$h][2] = 'focus';
877
        $h++;
878
879
        $head[$h][0] = constant('BASE_URL') . "/admin/defaultvalues.php?mode=mandatory";
880
        $head[$h][1] = $langs->trans("DefaultMandatory");
881
        $head[$h][2] = 'mandatory';
882
        $h++;
883
    }
884
885
    /*$head[$h][0] = constant('BASE_URL')."/admin/translation.php?mode=searchkey";
886
    $head[$h][1] = $langs->trans("TranslationKeySearch");
887
    $head[$h][2] = 'searchkey';
888
    $h++;*/
889
890
    complete_head_from_modules($conf, $langs, null, $head, $h, 'defaultvalues_admin');
891
892
    complete_head_from_modules($conf, $langs, null, $head, $h, 'defaultvalues_admin', 'remove');
893
894
895
    return $head;
896
}
897
898
899
/**
900
 *  Return list of session
901
 *
902
 * @return array<string,array{login:string,age:int,creation:int,modification:int,raw:string}>  Array list of sessions
903
 */
904
function listOfSessions()
905
{
906
    global $conf;
907
908
    $arrayofSessions = array();
909
    // session.save_path can be returned empty so we set a default location and work from there
910
    $sessPath = '/tmp';
911
    $iniPath = ini_get("session.save_path");
912
    if ($iniPath) {
913
        $sessPath = $iniPath;
914
    }
915
    $sessPath .= '/'; // We need the trailing slash
916
    dol_syslog('admin.lib:listOfSessions sessPath=' . $sessPath);
917
918
    $dh = @opendir(dol_osencode($sessPath));
919
    if ($dh) {
920
        while (($file = @readdir($dh)) !== false) {
921
            if (preg_match('/^sess_/i', $file) && $file != "." && $file != "..") {
922
                $fullpath = $sessPath . $file;
923
                if (!@is_dir($fullpath) && is_readable($fullpath)) {
924
                    $sessValues = file_get_contents($fullpath); // get raw session data
925
                    // Example of possible value
926
                    //$sessValues = 'newtoken|s:32:"1239f7a0c4b899200fe9ca5ea394f307";dol_loginmesg|s:0:"";newtoken|s:32:"1236457104f7ae0f328c2928973f3cb5";dol_loginmesg|s:0:"";token|s:32:"123615ad8d650c5cc4199b9a1a76783f";
927
                    // dol_login|s:5:"admin";dol_authmode|s:8:"dolibarr";dol_tz|s:1:"1";dol_tz_string|s:13:"Europe/Berlin";dol_dst|i:0;dol_dst_observed|s:1:"1";dol_dst_first|s:0:"";dol_dst_second|s:0:"";dol_screenwidth|s:4:"1920";
928
                    // dol_screenheight|s:3:"971";dol_company|s:12:"MyBigCompany";dol_entity|i:1;mainmenu|s:4:"home";leftmenuopened|s:10:"admintools";idmenu|s:0:"";leftmenu|s:10:"admintools";';
929
930
                    if (
931
                        preg_match('/dol_login/i', $sessValues) && // limit to dolibarr session
932
                        (preg_match('/dol_entity\|i:' . $conf->entity . ';/i', $sessValues) || preg_match('/dol_entity\|s:([0-9]+):"' . $conf->entity . '"/i', $sessValues)) && // limit to current entity
933
                        preg_match('/dol_company\|s:([0-9]+):"(' . getDolGlobalString('MAIN_INFO_SOCIETE_NOM') . ')"/i', $sessValues)
934
                    ) { // limit to company name
935
                        $tmp = explode('_', $file);
936
                        $idsess = $tmp[1];
937
                        $regs = array();
938
                        $loginfound = preg_match('/dol_login\|s:[0-9]+:"([A-Za-z0-9]+)"/i', $sessValues, $regs);
939
                        if ($loginfound) {
940
                            $arrayofSessions[$idsess]["login"] = $regs[1];
941
                        }
942
                        $arrayofSessions[$idsess]["age"] = time() - filectime($fullpath);
943
                        $arrayofSessions[$idsess]["creation"] = filectime($fullpath);
944
                        $arrayofSessions[$idsess]["modification"] = filemtime($fullpath);
945
                        $arrayofSessions[$idsess]["raw"] = $sessValues;
946
                    }
947
                }
948
            }
949
        }
950
        @closedir($dh);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for closedir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

950
        /** @scrutinizer ignore-unhandled */ @closedir($dh);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
951
    }
952
953
    return $arrayofSessions;
954
}
955
956
/**
957
 *  Purge existing sessions
958
 *
959
 * @param int $mysessionid To avoid to try to delete my own session
960
 * @return     int                         >0 if OK, <0 if KO
961
 */
962
function purgeSessions($mysessionid)
963
{
964
    global $conf;
965
966
    $sessPath = ini_get("session.save_path") . "/";
967
    dol_syslog('admin.lib:purgeSessions mysessionid=' . $mysessionid . ' sessPath=' . $sessPath);
968
969
    $error = 0;
970
971
    $dh = @opendir(dol_osencode($sessPath));
972
    if ($dh) {
973
        while (($file = @readdir($dh)) !== false) {
974
            if ($file != "." && $file != "..") {
975
                $fullpath = $sessPath . $file;
976
                if (!@is_dir($fullpath)) {
977
                    $sessValues = file_get_contents($fullpath); // get raw session data
978
979
                    if (
980
                        preg_match('/dol_login/i', $sessValues) && // limit to dolibarr session
981
                        preg_match('/dol_entity\|s:([0-9]+):"(' . $conf->entity . ')"/i', $sessValues) && // limit to current entity
982
                        preg_match('/dol_company\|s:([0-9]+):"(' . getDolGlobalString('MAIN_INFO_SOCIETE_NOM') . ')"/i', $sessValues)
983
                    ) { // limit to company name
984
                        $tmp = explode('_', $file);
985
                        $idsess = $tmp[1];
986
                        // We remove session if it's not ourself
987
                        if ($idsess != $mysessionid) {
988
                            $res = @unlink($fullpath);
989
                            if (!$res) {
990
                                $error++;
991
                            }
992
                        }
993
                    }
994
                }
995
            }
996
        }
997
        @closedir($dh);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for closedir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

997
        /** @scrutinizer ignore-unhandled */ @closedir($dh);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
998
    }
999
1000
    if (!$error) {
1001
        return 1;
1002
    } else {
1003
        return -$error;
1004
    }
1005
}
1006
1007
1008
/**
1009
 *  Enable a module
1010
 *
1011
 * @param string $value Name of module to activate
1012
 * @param int $withdeps Activate/Disable also all dependencies
1013
 * @param int $noconfverification Remove verification of $conf variable for module
1014
 * @return     array{nbmodules?:int,errors:string[],nbperms?:int}  array('nbmodules'=>nb modules activated with success, 'errors=>array of error messages, 'nbperms'=>Nb permission added);
1015
 */
1016
function activateModule($value, $withdeps = 1, $noconfverification = 0)
1017
{
1018
    global $db, $langs, $conf, $mysoc;
1019
1020
    $ret = array();
1021
1022
    // Check parameters
1023
    if (empty($value)) {
1024
        $ret['errors'] = array('ErrorBadParameter');
1025
        return $ret;
1026
    }
1027
1028
    $ret = array('nbmodules' => 0, 'errors' => array(), 'nbperms' => 0);
1029
    $modName = $value;
1030
    /*
1031
    $modFile = $modName . ".class.php";
1032
1033
    // Loop on each directory to fill $modulesdir
1034
    $modulesdir = dolGetModulesDirs();
1035
1036
    // Loop on each modulesdir directories
1037
    $found = false;
1038
    foreach ($modulesdir as $dir) {
1039
        if (file_exists($dir . $modFile)) {
1040
            $found = @include_once $dir . $modFile;
1041
            if ($found) {
1042
                break;
1043
            }
1044
        }
1045
    }
1046
1047
    $objMod = new $modName($db);
1048
    */
1049
    $objMod = DolibarrModules::getModule($modName);
1050
1051
    // Test if PHP version ok
1052
    $verphp = Version::arrayPhp();
1053
    $vermin = isset($objMod->phpmin) ? $objMod->phpmin : 0;
1054
    if (is_array($vermin) && Version::compare($verphp, $vermin) < 0) {
1055
        $ret['errors'][] = $langs->trans("ErrorModuleRequirePHPVersion", Version::toString($vermin));
1056
        return $ret;
1057
    }
1058
1059
    // Test if Dolibarr version ok
1060
    $verdol = Version::toArray();
1061
    $vermin = isset($objMod->need_dolibarr_version) ? $objMod->need_dolibarr_version : 0;
1062
    //print 'version: '.Version::compare($verdol,$vermin).' - '.join(',',$verdol).' - '.join(',',$vermin);exit;
1063
    if (is_array($vermin) && Version::compare($verdol, $vermin) < 0) {
1064
        $ret['errors'][] = $langs->trans("ErrorModuleRequireDolibarrVersion", Version::toString($vermin));
1065
        return $ret;
1066
    }
1067
1068
    // Test if javascript requirement ok
1069
    if (!empty($objMod->need_javascript_ajax) && empty($conf->use_javascript_ajax)) {
1070
        $ret['errors'][] = $langs->trans("ErrorModuleRequireJavascript");
1071
        return $ret;
1072
    }
1073
1074
    $const_name = $objMod->const_name;
1075
    if ($noconfverification == 0) {
1076
        if (getDolGlobalString($const_name)) {
1077
            return $ret;
1078
        }
1079
    }
1080
1081
    $result = $objMod->init(); // Enable module
1082
1083
    if ($result <= 0) {
1084
        $ret['errors'][] = $objMod->error;
1085
    } else {
1086
        if ($withdeps) {
1087
            if (isset($objMod->depends) && is_array($objMod->depends) && !empty($objMod->depends)) {
1088
                // Activation of modules this module depends on
1089
                // this->depends may be array('modModule1', 'mmodModule2') or array('always'=>array('modModule1'), 'FR'=>array('modModule2"))
1090
                foreach ($objMod->depends as $key => $modulestringorarray) {
1091
                    //var_dump((! is_numeric($key)) && ! preg_match('/^always/', $key) && $mysoc->country_code && ! preg_match('/^'.$mysoc->country_code.'/', $key));exit;
1092
                    if ((!is_numeric($key)) && !preg_match('/^always/', $key) && $mysoc->country_code && !preg_match('/^' . $mysoc->country_code . '/', $key)) {
1093
                        dol_syslog("We are not concerned by dependency with key=" . $key . " because our country is " . $mysoc->country_code);
1094
                        continue;
1095
                    }
1096
1097
                    if (!is_array($modulestringorarray)) {
1098
                        $modulestringorarray = array($modulestringorarray);
1099
                    }
1100
1101
                    foreach ($modulestringorarray as $modulestring) {
1102
                        $module = DolibarrModules::getModule($modulestring);
1103
                        if ($module === null) {
1104
                            continue;
1105
                        }
1106
1107
                        /*
1108
                        $activate = false;
1109
                        $activateerr = '';
1110
                        foreach ($modulesdir as $dir) {
1111
                            if (file_exists($dir . $modulestring . ".class.php")) {
1112
                                $resarray = activateModule($modulestring);
1113
                                if (empty($resarray['errors'])) {
1114
                                    $activate = true;
1115
                                } else {
1116
                                    $activateerr = implode(', ', $resarray['errors']);
1117
                                    foreach ($resarray['errors'] as $errorMessage) {
1118
                                        dol_syslog($errorMessage, LOG_ERR);
1119
                                    }
1120
                                }
1121
                                break;
1122
                            }
1123
                        }
1124
                        */
1125
                        $resarray = activateModule($modulestring);
1126
                        $activate = empty($resArray['errors']);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $resArray does not exist. Did you maybe mean $resarray?
Loading history...
1127
1128
                        if ($activate) {
1129
                            $ret['nbmodules'] += $resarray['nbmodules'];
1130
                            $ret['nbperms'] += $resarray['nbperms'];
1131
                        } else {
1132
                            $activateerr = implode(', ', $resarray['errors']);
1133
                            foreach ($resarray['errors'] as $errorMessage) {
1134
                                dol_syslog($errorMessage, LOG_ERR);
1135
                            }
1136
                            if ($activateerr) {
1137
                                $ret['errors'][] = $activateerr;
1138
                            }
1139
                            $ret['errors'][] = $langs->trans('activateModuleDependNotSatisfied', $objMod->name, $modulestring);
1140
                        }
1141
                    }
1142
                }
1143
            }
1144
1145
            if (isset($objMod->conflictwith) && is_array($objMod->conflictwith) && !empty($objMod->conflictwith)) {
1146
                // Deactivation des modules qui entrent en conflict
1147
                foreach ($objMod->conflictwith as $module_name) {
1148
                    unActivateModule($module_name, 0);
1149
                }
1150
            }
1151
        }
1152
    }
1153
1154
    if (!count($ret['errors'])) {
1155
        $ret['nbmodules']++;
1156
        $ret['nbperms'] += (is_array($objMod->rights) ? count($objMod->rights) : 0);
1157
    }
1158
1159
    return $ret;
1160
}
1161
1162
1163
/**
1164
 *  Disable a module
1165
 *
1166
 * @param string $value Nom du module a desactiver
1167
 * @param int $requiredby 1=Desactive aussi modules dependants
1168
 * @return     string                           Error message or '';
1169
 */
1170
function unActivateModule($value, $requiredby = 1)
1171
{
1172
    // Check parameters
1173
    if (empty($value)) {
1174
        return 'ErrorBadParameter';
1175
    }
1176
1177
    $objMod = DolibarrModules::getModule($value);
1178
    if ($objMod === null) {
1179
        DolibarrModules::forceDeactivate($value);
1180
        return 'ErrorModuleDoesNotExists';
1181
    }
1182
1183
    $ret = 0;
1184
    $result = $objMod->remove();
1185
    if ($result <= 0) {
1186
        $ret = $objMod->error;
1187
    }
1188
1189
    // Disable modules that depends on module we disable
1190
    if (!$ret && $requiredby && is_object($objMod) && is_array($objMod->requiredby)) {
1191
        $countrb = count($objMod->requiredby);
1192
        for ($i = 0; $i < $countrb; $i++) {
1193
            //var_dump($objMod->requiredby[$i]);
1194
            unActivateModule($objMod->requiredby[$i]);
1195
        }
1196
    }
1197
1198
    return $ret;
1199
}
1200
1201
1202
/**
1203
 *  Add external modules to list of dictionaries.
1204
 *  Addition is done into var $taborder, $tabname, etc... that are passed with pointers.
1205
 *
1206
 * @param array $taborder Taborder
1207
 * @param array $tabname Tabname
1208
 * @param array $tablib Tablib
1209
 * @param array $tabsql Tabsql
1210
 * @param array $tabsqlsort Tabsqlsort
1211
 * @param array $tabfield Tabfield
1212
 * @param array $tabfieldvalue Tabfieldvalue
1213
 * @param array $tabfieldinsert Tabfieldinsert
1214
 * @param array $tabrowid Tabrowid
1215
 * @param array $tabcond Tabcond
1216
 * @param array $tabhelp Tabhelp
1217
 * @param array $tabcomplete Tab complete (will replace all other in future). Key is table name.
1218
 * @return     int         1
1219
 */
1220
function complete_dictionary_with_modules(&$taborder, &$tabname, &$tablib, &$tabsql, &$tabsqlsort, &$tabfield, &$tabfieldvalue, &$tabfieldinsert, &$tabrowid, &$tabcond, &$tabhelp, &$tabcomplete)
1221
{
1222
    global $db, $modules, $conf, $langs;
1223
1224
    dol_syslog("complete_dictionary_with_modules Search external modules to complete the list of dictionary tables", LOG_DEBUG, 1);
1225
1226
    // Search modules
1227
    $modulesdir = dolGetModulesDirs();
1228
    $i = 0; // is a sequencer of modules found
1229
    $j = 0; // j is module number. Automatically affected if module number not defined.
1230
1231
    $allModules = DolibarrModules::getModules($modulesdir);
1232
    foreach ($allModules as $modName => $filename) {
1233
        $objMod = DolibarrModules::getObj($db, $modName, $filename);
1234
        if (!isset($objMod)) {
1235
            print info_admin("admin/modules.php Warning bad descriptor file : " . $filename . " (Class " . $modName . " not found into file)", 0, 0, '1', 'warning');
1236
            continue;
1237
        }
1238
1239
        if ($objMod->numero > 0) {
1240
            $j = $objMod->numero;
1241
        } else {
1242
            $j = 1000 + $i;
1243
        }
1244
1245
        $modulequalified = 1;
1246
1247
        // We discard modules according to features level (PS: if module is activated we always show it)
1248
        $const_name = 'MAIN_MODULE_' . strtoupper(preg_replace('/^mod/i', '', get_only_class($objMod)));
1249
        if ($objMod->version == 'development' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2 && !getDolGlobalString($const_name)) {
1250
            $modulequalified = 0;
1251
        }
1252
        if ($objMod->version == 'experimental' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1 && !getDolGlobalString($const_name)) {
1253
            $modulequalified = 0;
1254
        }
1255
        // If module is not activated disqualified
1256
        if (!getDolGlobalString($const_name)) {
1257
            $modulequalified = 0;
1258
        }
1259
1260
        if ($modulequalified) {
1261
            // Load languages files of module
1262
            if (isset($objMod->langfiles) && is_array($objMod->langfiles)) {
1263
                foreach ($objMod->langfiles as $langfile) {
1264
                    $langs->load($langfile);
1265
                }
1266
            }
1267
1268
            // phpcs:disable
1269
            // Complete the arrays &$tabname,&$tablib,&$tabsql,&$tabsqlsort,&$tabfield,&$tabfieldvalue,&$tabfieldinsert,&$tabrowid,&$tabcond
1270
            if (empty($objMod->dictionaries) && !empty($objMod->{"dictionnaries"})) {
1271
                $objMod->dictionaries = $objMod->{"dictionnaries"}; // For backward compatibility
1272
            }
1273
            // phpcs:enable
1274
1275
            if (!empty($objMod->dictionaries)) {
1276
                //var_dump($objMod->dictionaries['tabname']);
1277
                $nbtabname = $nbtablib = $nbtabsql = $nbtabsqlsort = $nbtabfield = $nbtabfieldvalue = $nbtabfieldinsert = $nbtabrowid = $nbtabcond = $nbtabfieldcheck = $nbtabhelp = 0;
1278
                $tabnamerelwithkey = array();
1279
                foreach ($objMod->dictionaries['tabname'] as $key => $val) {
1280
                    $tmptablename = preg_replace('/' . MAIN_DB_PREFIX . '/', '', $val);
1281
                    $nbtabname++;
1282
                    $taborder[] = max($taborder) + 1;
1283
                    $tabname[] = $val;
1284
                    $tabnamerelwithkey[$key] = $val;
1285
                    $tabcomplete[$tmptablename]['picto'] = $objMod->picto;
1286
                }       // Position
1287
                foreach ($objMod->dictionaries['tablib'] as $key => $val) {
1288
                    $tmptablename = preg_replace('/' . MAIN_DB_PREFIX . '/', '', $tabnamerelwithkey[$key]);
1289
                    $nbtablib++;
1290
                    $tablib[] = $val;
1291
                    $tabcomplete[$tmptablename]['lib'] = $val;
1292
                }
1293
                foreach ($objMod->dictionaries['tabsql'] as $key => $val) {
1294
                    $tmptablename = preg_replace('/' . MAIN_DB_PREFIX . '/', '', $tabnamerelwithkey[$key]);
1295
                    $nbtabsql++;
1296
                    $tabsql[] = $val;
1297
                    $tabcomplete[$tmptablename]['sql'] = $val;
1298
                }
1299
                foreach ($objMod->dictionaries['tabsqlsort'] as $key => $val) {
1300
                    $tmptablename = preg_replace('/' . MAIN_DB_PREFIX . '/', '', $tabnamerelwithkey[$key]);
1301
                    $nbtabsqlsort++;
1302
                    $tabsqlsort[] = $val;
1303
                    $tabcomplete[$tmptablename]['sqlsort'] = $val;
1304
                }
1305
                foreach ($objMod->dictionaries['tabfield'] as $key => $val) {
1306
                    $tmptablename = preg_replace('/' . MAIN_DB_PREFIX . '/', '', $tabnamerelwithkey[$key]);
1307
                    $nbtabfield++;
1308
                    $tabfield[] = $val;
1309
                    $tabcomplete[$tmptablename]['field'] = $val;
1310
                }
1311
                foreach ($objMod->dictionaries['tabfieldvalue'] as $key => $val) {
1312
                    $tmptablename = preg_replace('/' . MAIN_DB_PREFIX . '/', '', $tabnamerelwithkey[$key]);
1313
                    $nbtabfieldvalue++;
1314
                    $tabfieldvalue[] = $val;
1315
                    $tabcomplete[$tmptablename]['value'] = $val;
1316
                }
1317
                foreach ($objMod->dictionaries['tabfieldinsert'] as $key => $val) {
1318
                    $tmptablename = preg_replace('/' . MAIN_DB_PREFIX . '/', '', $tabnamerelwithkey[$key]);
1319
                    $nbtabfieldinsert++;
1320
                    $tabfieldinsert[] = $val;
1321
                    $tabcomplete[$tmptablename]['fieldinsert'] = $val;
1322
                }
1323
                foreach ($objMod->dictionaries['tabrowid'] as $key => $val) {
1324
                    $tmptablename = preg_replace('/' . MAIN_DB_PREFIX . '/', '', $tabnamerelwithkey[$key]);
1325
                    $nbtabrowid++;
1326
                    $tabrowid[] = $val;
1327
                    $tabcomplete[$tmptablename]['rowid'] = $val;
1328
                }
1329
                foreach ($objMod->dictionaries['tabcond'] as $key => $val) {
1330
                    $tmptablename = preg_replace('/' . MAIN_DB_PREFIX . '/', '', $tabnamerelwithkey[$key]);
1331
                    $nbtabcond++;
1332
                    $tabcond[] = $val;
1333
                    $tabcomplete[$tmptablename]['rowid'] = $val;
1334
                }
1335
                if (!empty($objMod->dictionaries['tabhelp'])) {
1336
                    foreach ($objMod->dictionaries['tabhelp'] as $key => $val) {
1337
                        $tmptablename = preg_replace('/' . MAIN_DB_PREFIX . '/', '', $tabnamerelwithkey[$key]);
1338
                        $nbtabhelp++;
1339
                        $tabhelp[] = $val;
1340
                        $tabcomplete[$tmptablename]['help'] = $val;
1341
                    }
1342
                }
1343
                if (!empty($objMod->dictionaries['tabfieldcheck'])) {
1344
                    foreach ($objMod->dictionaries['tabfieldcheck'] as $key => $val) {
1345
                        $tmptablename = preg_replace('/' . MAIN_DB_PREFIX . '/', '', $tabnamerelwithkey[$key]);
1346
                        $nbtabfieldcheck++;
1347
                        $tabcomplete[$tmptablename]['fieldcheck'] = $val;
1348
                    }
1349
                }
1350
1351
                if ($nbtabname != $nbtablib || $nbtablib != $nbtabsql || $nbtabsql != $nbtabsqlsort) {
1352
                    print 'Error in descriptor of module ' . $const_name . '. Array ->dictionaries has not same number of record for key "tabname", "tablib", "tabsql" and "tabsqlsort"';
1353
                    //print "$const_name: $nbtabname=$nbtablib=$nbtabsql=$nbtabsqlsort=$nbtabfield=$nbtabfieldvalue=$nbtabfieldinsert=$nbtabrowid=$nbtabcond=$nbtabfieldcheck=$nbtabhelp\n";
1354
                } else {
1355
                    $taborder[] = 0; // Add an empty line
1356
                }
1357
            }
1358
1359
            $j++;
1360
            $i++;
1361
        } else {
1362
            dol_syslog("Module " . get_only_class($objMod) . " not qualified");
1363
        }
1364
    }
1365
1366
    dol_syslog("", LOG_DEBUG, -1);
1367
1368
    return 1;
1369
}
1370
1371
/**
1372
 *  Activate external modules mandatory when country is country_code
1373
 *
1374
 * @param string $country_code CountryCode
1375
 * @return     int         1
1376
 */
1377
function activateModulesRequiredByCountry($country_code)
1378
{
1379
    global $db, $conf, $langs;
1380
1381
    $modulesdir = dolGetModulesDirs();
1382
    $allModules = DolibarrModules::getModules($modulesdir);
1383
    foreach ($allModules as $modName => $filename) {
1384
        $objMod = DolibarrModules::getObj($db, $modName, $filename);
1385
        if (!isset($objMod)) {
1386
            print info_admin("admin/modules.php Warning bad descriptor file : " . $filename . " (Class " . $modName . " not found into file)", 0, 0, '1', 'warning');
1387
            continue;
1388
        }
1389
1390
        $modulequalified = 1;
1391
1392
        // We discard modules according to features level (PS: if module is activated we always show it)
1393
        $const_name = 'MAIN_MODULE_' . strtoupper(preg_replace('/^mod/i', '', get_only_class($objMod)));
1394
1395
        if ($objMod->version == 'development' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2) {
1396
            $modulequalified = 0;
1397
        }
1398
        if ($objMod->version == 'experimental' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1) {
1399
            $modulequalified = 0;
1400
        }
1401
        if (getDolGlobalString($const_name)) {
1402
            $modulequalified = 0; // already activated
1403
        }
1404
1405
        if ($modulequalified) {
1406
            // Load languages files of module
1407
            if (isset($objMod->automatic_activation) && is_array($objMod->automatic_activation) && isset($objMod->automatic_activation[$country_code])) {
1408
                activateModule($modName);
1409
1410
                setEventMessages($objMod->automatic_activation[$country_code], null, 'warnings');
1411
            }
1412
        } else {
1413
            dol_syslog("Module " . get_only_class($objMod) . " not qualified");
1414
        }
1415
    }
1416
1417
    return 1;
1418
}
1419
1420
/**
1421
 *  Search external modules to complete the list of contact element
1422
 *
1423
 * @param array<string,string> $elementList elementList
1424
 * @return     int         1
1425
 */
1426
function complete_elementList_with_modules(&$elementList)
1427
{
1428
    global $db, $modules, $conf, $langs;
1429
1430
    // Search modules
1431
    $filename = array();
1432
    $modules = array();
1433
    $orders = array();
1434
    $categ = array();
1435
    $dirmod = array();
1436
1437
    $i = 0; // is a sequencer of modules found
1438
    $j = 0; // j is module number. Automatically affected if module number not defined.
1439
1440
    dol_syslog("complete_elementList_with_modules Search external modules to complete the list of contact element", LOG_DEBUG, 1);
1441
1442
    $modulesdir = dolGetModulesDirs();
1443
    $allModules = DolibarrModules::getModules($modulesdir);
1444
    foreach ($allModules as $modName => $filename) {
1445
        $objMod = DolibarrModules::getObj($db, $modName, $filename);
1446
1447
        if (!isset($objMod)) {
1448
            print info_admin("admin/modules.php Warning bad descriptor file : " . $filename . " (Class " . $modName . " not found into file)", 0, 0, '1', 'warning');
1449
            continue;
1450
        }
1451
1452
        if ($objMod->numero > 0) {
1453
            $j = $objMod->numero;
1454
        } else {
1455
            $j = 1000 + $i;
1456
        }
1457
1458
        $modulequalified = 1;
1459
1460
        // We discard modules according to features level (PS: if module is activated we always show it)
1461
        $const_name = 'MAIN_MODULE_' . strtoupper(preg_replace('/^mod/i', '', get_only_class($objMod)));
1462
        if ($objMod->version == 'development' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2 && getDolGlobalString($const_name)) {
1463
            $modulequalified = 0;
1464
        }
1465
        if ($objMod->version == 'experimental' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1 && getDolGlobalString($const_name)) {
1466
            $modulequalified = 0;
1467
        }
1468
        // If module is not activated disqualified
1469
        if (!getDolGlobalString($const_name)) {
1470
            $modulequalified = 0;
1471
        }
1472
1473
        if ($modulequalified) {
1474
            // Load languages files of module
1475
            if (isset($objMod->langfiles) && is_array($objMod->langfiles)) {
1476
                foreach ($objMod->langfiles as $langfile) {
1477
                    $langs->load($langfile);
1478
                }
1479
            }
1480
1481
            $modules[$i] = $objMod;
1482
            $filename[$i] = $modName;
1483
            $orders[$i] = $objMod->family . "_" . $j; // Sort on family then module number
1484
            $dirmod[$i] = $dir;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dir seems to be never defined.
Loading history...
1485
            //print "x".$modName." ".$orders[$i]."\n<br>";
1486
1487
            if (!empty($objMod->module_parts['contactelement'])) {
1488
                if (is_array($objMod->module_parts['contactelement'])) {
1489
                    foreach ($objMod->module_parts['contactelement'] as $elem => $title) {
1490
                        $elementList[$elem] = $langs->trans($title);
1491
                    }
1492
                } else {
1493
                    $elementList[$objMod->name] = $langs->trans($objMod->name);
1494
                }
1495
            }
1496
1497
            $j++;
1498
            $i++;
1499
        } else {
1500
            dol_syslog("Module " . get_only_class($objMod) . " not qualified");
1501
        }
1502
    }
1503
1504
    dol_syslog("", LOG_DEBUG, -1);
1505
1506
    return 1;
1507
}
1508
1509
/**
1510
 *  Show array with constants to edit
1511
 *
1512
 * @param array<string,array{type:string,label:string}> $tableau Array of constants array('key'=>array('type'=>type, 'label'=>label)
1513
 *                                                                          where type can be 'string', 'text', 'textarea', 'html', 'yesno', 'emailtemplate:xxx', ...
1514
 * @param int<2,3> $strictw3c 0=Include form into table (deprecated), 1=Form is outside table to respect W3C (deprecated), 2=No form nor button at all, 3=No form nor button at all and each field has a unique name (form is output by caller, recommended)  (typed as int<2,3> to highlight the deprecated values)
1515
 * @param string $helptext Tooltip help to use for the column name of values
1516
 * @param string $text Text to use for the column name of values
1517
 * @return void
1518
 */
1519
function form_constantes($tableau, $strictw3c = 2, $helptext = '', $text = 'Value')
1520
{
1521
    global $db, $langs, $conf, $user;
1522
    global $_Avery_Labels;
1523
1524
    $form = new Form($db);
1525
1526
    if (empty($strictw3c)) {
1527
        dol_syslog("Warning: Function 'form_constantes' was called with parameter strictw3c = 0, this is deprecated. Value must be 2 now.", LOG_DEBUG);
1528
    }
1529
    if (!empty($strictw3c) && $strictw3c == 1) {
1530
        print "\n" . '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST">';
1531
        print '<input type="hidden" name="token" value="' . newToken() . '">';
1532
        print '<input type="hidden" name="action" value="updateall">';
1533
    }
1534
1535
    print '<div class="div-table-responsive-no-min">';
1536
    print '<table class="noborder centpercent">';
1537
    print '<tr class="liste_titre">';
1538
    print '<td class="">' . $langs->trans("Description") . '</td>';
1539
    print '<td>';
1540
    $text = $langs->trans($text);
1541
    print $form->textwithpicto($text, $helptext, 1, 'help', '', 0, 2, 'idhelptext');
1542
    print '</td>';
1543
    if (empty($strictw3c)) {
1544
        print '<td class="center" width="80">' . $langs->trans("Action") . '</td>';
1545
    }
1546
    print "</tr>\n";
1547
1548
    $label = '';
1549
    foreach ($tableau as $key => $const) {  // Loop on each param
1550
        $label = '';
1551
        // $const is a const key like 'MYMODULE_ABC'
1552
        if (is_numeric($key)) {     // Very old behaviour
1553
            $type = 'string';
1554
        } else {
1555
            if (is_array($const)) {
1556
                $type = $const['type'];
1557
                $label = $const['label'];
1558
                $const = $key;
1559
            } else {
1560
                $type = $const;
1561
                $const = $key;
1562
            }
1563
        }
1564
1565
        $sql = "SELECT ";
1566
        $sql .= "rowid";
1567
        $sql .= ", " . $db->decrypt('name') . " as name";
1568
        $sql .= ", " . $db->decrypt('value') . " as value";
1569
        $sql .= ", type";
1570
        $sql .= ", note";
1571
        $sql .= " FROM " . MAIN_DB_PREFIX . "const";
1572
        $sql .= " WHERE " . $db->decrypt('name') . " = '" . $db->escape($const) . "'";
1573
        $sql .= " AND entity IN (0, " . $conf->entity . ")";
1574
        $sql .= " ORDER BY name ASC, entity DESC";
1575
        $result = $db->query($sql);
1576
1577
        dol_syslog("List params", LOG_DEBUG);
1578
        if ($result) {
1579
            $obj = $db->fetch_object($result); // Take first result of select
1580
1581
            if (empty($obj)) {  // If not yet into table
1582
                $obj = (object)array('rowid' => '', 'name' => $const, 'value' => '', 'type' => $type, 'note' => '');
1583
            }
1584
1585
            if (empty($strictw3c)) {
1586
                print "\n" . '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST">';
1587
                print '<input type="hidden" name="token" value="' . newToken() . '">';
1588
                print '<input type="hidden" name="page_y" value="' . newToken() . '">';
1589
            }
1590
1591
            print '<tr class="oddeven">';
1592
1593
            // Show label of parameter
1594
            print '<td>';
1595
            if (empty($strictw3c)) {
1596
                print '<input type="hidden" name="action" value="update">';
1597
            }
1598
            print '<input type="hidden" name="rowid' . (empty($strictw3c) ? '' : '[]') . '" value="' . $obj->rowid . '">';
1599
            print '<input type="hidden" name="constname' . (empty($strictw3c) ? '' : '[]') . '" value="' . $const . '">';
1600
            print '<input type="hidden" name="constnote_' . $obj->name . '" value="' . nl2br(dol_escape_htmltag($obj->note)) . '">';
1601
            print '<input type="hidden" name="consttype_' . $obj->name . '" value="' . ($obj->type ? $obj->type : 'string') . '">';
1602
            if (!empty($tableau[$key]['tooltip'])) {
1603
                print $form->textwithpicto($label ? $label : $langs->trans('Desc' . $const), $tableau[$key]['tooltip']);
1604
            } else {
1605
                print($label ? $label : $langs->trans('Desc' . $const));
1606
            }
1607
1608
            if ($const == 'ADHERENT_MAILMAN_URL') {
1609
                print '. ' . $langs->trans("Example") . ': <a href="#" id="exampleclick1">' . img_down() . '</a><br>';
1610
                //print 'http://lists.example.com/cgi-bin/mailman/admin/%LISTE%/members?adminpw=%MAILMAN_ADMINPW%&subscribees=%EMAIL%&send_welcome_msg_to_this_batch=1';
1611
                print '<div id="example1" class="hidden">';
1612
                print 'http://lists.example.com/cgi-bin/mailman/admin/%LISTE%/members/add?subscribees_upload=%EMAIL%&amp;adminpw=%MAILMAN_ADMINPW%&amp;subscribe_or_invite=0&amp;send_welcome_msg_to_this_batch=0&amp;notification_to_list_owner=0';
1613
                print '</div>';
1614
            } elseif ($const == 'ADHERENT_MAILMAN_UNSUB_URL') {
1615
                print '. ' . $langs->trans("Example") . ': <a href="#" id="exampleclick2">' . img_down() . '</a><br>';
1616
                print '<div id="example2" class="hidden">';
1617
                print 'http://lists.example.com/cgi-bin/mailman/admin/%LISTE%/members/remove?unsubscribees_upload=%EMAIL%&amp;adminpw=%MAILMAN_ADMINPW%&amp;send_unsub_ack_to_this_batch=0&amp;send_unsub_notifications_to_list_owner=0';
1618
                print '</div>';
1619
                //print 'http://lists.example.com/cgi-bin/mailman/admin/%LISTE%/members/remove?adminpw=%MAILMAN_ADMINPW%&unsubscribees=%EMAIL%';
1620
            } elseif ($const == 'ADHERENT_MAILMAN_LISTS') {
1621
                print '. ' . $langs->trans("Example") . ': <a href="#" id="exampleclick3">' . img_down() . '</a><br>';
1622
                print '<div id="example3" class="hidden">';
1623
                print 'mymailmanlist<br>';
1624
                print 'mymailmanlist1,mymailmanlist2<br>';
1625
                print 'TYPE:Type1:mymailmanlist1,TYPE:Type2:mymailmanlist2<br>';
1626
                if (isModEnabled('category')) {
1627
                    print 'CATEG:Categ1:mymailmanlist1,CATEG:Categ2:mymailmanlist2<br>';
1628
                }
1629
                print '</div>';
1630
                //print 'http://lists.example.com/cgi-bin/mailman/admin/%LISTE%/members/remove?adminpw=%MAILMAN_ADMINPW%&unsubscribees=%EMAIL%';
1631
            } elseif (in_array($const, ['ADHERENT_MAIL_FROM', 'ADHERENT_CC_MAIL_FROM'])) {
1632
                print ' ' . img_help(1, $langs->trans("EMailHelpMsgSPFDKIM"));
1633
            }
1634
1635
            print "</td>\n";
1636
1637
            // Value
1638
            if ($const == 'ADHERENT_CARD_TYPE' || $const == 'ADHERENT_ETIQUETTE_TYPE') {
1639
                print '<td>';
1640
                $arrayoflabels = array();
1641
                $_Avery_Labels = AveryLabels::getAveryLabels();
1642
                foreach (array_keys($_Avery_Labels) as $codecards) {
1643
                    $arrayoflabels[$codecards] = $_Avery_Labels[$codecards]['name'];
1644
                }
1645
                print $form->selectarray('constvalue' . (empty($strictw3c) ? '' : ($strictw3c == 3 ? '_' . $const : '[]')), $arrayoflabels, ($obj->value ? $obj->value : 'CARD'), 1, 0, 0);
1646
                print '<input type="hidden" name="consttype" value="yesno">';
1647
                print '<input type="hidden" name="constnote' . (empty($strictw3c) ? '' : '[]') . '" value="' . nl2br(dol_escape_htmltag($obj->note)) . '">';
1648
                print '</td>';
1649
            } else {
1650
                print '<td>';
1651
                print '<input type="hidden" name="consttype' . (empty($strictw3c) ? '' : ($strictw3c == 3 ? '_' . $const : '[]')) . '" value="' . ($obj->type ? $obj->type : 'string') . '">';
1652
                print '<input type="hidden" name="constnote' . (empty($strictw3c) ? '' : ($strictw3c == 3 ? '_' . $const : '[]')) . '" value="' . nl2br(dol_escape_htmltag($obj->note)) . '">';
1653
                if ($obj->type == 'textarea' || in_array($const, array('ADHERENT_CARD_TEXT', 'ADHERENT_CARD_TEXT_RIGHT', 'ADHERENT_ETIQUETTE_TEXT'))) {
1654
                    print '<textarea class="flat" name="constvalue' . (empty($strictw3c) ? '' : ($strictw3c == 3 ? '_' . $const : '[]')) . '" cols="50" rows="5" wrap="soft">' . "\n";
1655
                    print $obj->value;
1656
                    print "</textarea>\n";
1657
                } elseif ($obj->type == 'html') {
1658
                    $doleditor = new DolEditor('constvalue' . (empty($strictw3c) ? '' : ($strictw3c == 3 ? '_' . $const : '[]')), $obj->value, '', 160, 'dolibarr_notes', '', false, false, isModEnabled('fckeditor'), ROWS_5, '90%');
1659
                    $doleditor->Create();
1660
                } elseif ($obj->type == 'yesno') {
1661
                    print $form->selectyesno('constvalue' . (empty($strictw3c) ? '' : ($strictw3c == 3 ? '_' . $const : '[]')), $obj->value, 1, false, 0, 1);
1662
                } elseif (preg_match('/emailtemplate/', $obj->type)) {
1663
                    $formmail = new FormMail($db);
1664
1665
                    $tmp = explode(':', $obj->type);
1666
1667
                    $nboftemplates = $formmail->fetchAllEMailTemplate($tmp[1], $user, null, -1); // We set lang=null to get in priority record with no lang
1668
                    //$arraydefaultmessage = $formmail->getEMailTemplate($db, $tmp[1], $user, null, 0, 1, '');
1669
                    $arrayofmessagename = array();
1670
                    if (is_array($formmail->lines_model)) {
1671
                        foreach ($formmail->lines_model as $modelmail) {
1672
                            //var_dump($modelmail);
1673
                            $moreonlabel = '';
1674
                            if (!empty($arrayofmessagename[$modelmail->label])) {
1675
                                $moreonlabel = ' <span class="opacitymedium">(' . $langs->trans("SeveralLangugeVariatFound") . ')</span>';
1676
                            }
1677
                            // The 'label' is the key that is unique if we exclude the language
1678
                            $arrayofmessagename[$modelmail->label . ':' . $tmp[1]] = $langs->trans(preg_replace('/\(|\)/', '', $modelmail->label)) . $moreonlabel;
1679
                        }
1680
                    }
1681
                    //var_dump($arraydefaultmessage);
1682
                    //var_dump($arrayofmessagename);
1683
                    print $form->selectarray('constvalue' . (empty($strictw3c) ? '' : ($strictw3c == 3 ? '_' . $const : '[]')), $arrayofmessagename, $obj->value . ':' . $tmp[1], 'None', 0, 0, '', 0, 0, 0, '', '', 1);
1684
                } elseif (preg_match('/MAIL_FROM$/i', $const)) {
1685
                    print img_picto('', 'email', 'class="pictofixedwidth"') . '<input type="text" class="flat minwidth300" name="constvalue' . (empty($strictw3c) ? '' : ($strictw3c == 3 ? '_' . $const : '[]')) . '" value="' . dol_escape_htmltag($obj->value) . '">';
1686
                } else { // type = 'string' ou 'chaine'
1687
                    print '<input type="text" class="flat minwidth300" name="constvalue' . (empty($strictw3c) ? '' : ($strictw3c == 3 ? '_' . $const : '[]')) . '" value="' . dol_escape_htmltag($obj->value) . '">';
1688
                }
1689
                print '</td>';
1690
            }
1691
1692
            // Submit
1693
            if (empty($strictw3c)) {
1694
                print '<td class="center">';
1695
                print '<input type="submit" class="button small reposition" value="' . $langs->trans("Update") . '" name="update">';
1696
                print "</td>";
1697
            }
1698
1699
            print "</tr>\n";
1700
1701
            if (empty($strictw3c)) {
1702
                print "</form>\n";
1703
            }
1704
        }
1705
    }
1706
    print '</table>';
1707
    print '</div>';
1708
1709
    if (!empty($strictw3c) && $strictw3c == 1) {
1710
        print '<div align="center"><input type="submit" class="button small reposition" value="' . $langs->trans("Update") . '" name="update"></div>';
1711
        print "</form>\n";
1712
    }
1713
}
1714
1715
1716
/**
1717
 *  Show array with constants to edit
1718
 *
1719
 * @param DolibarrModules[] $modules Array of all modules
1720
 * @return string                          HTML string with warning
1721
 */
1722
function showModulesExludedForExternal($modules)
1723
{
1724
    global $conf, $langs;
1725
1726
    $text = $langs->trans("OnlyFollowingModulesAreOpenedToExternalUsers");
1727
    $listofmodules = explode(',', getDolGlobalString('MAIN_MODULES_FOR_EXTERNAL')); // List of modules qualified for external user management
1728
1729
    $i = 0;
1730
    if (!empty($modules)) {
1731
        $tmpmodules = dol_sort_array($modules, 'module_position');
1732
        foreach ($tmpmodules as $module) {      // Loop on array of modules
1733
            $moduleconst = $module->const_name;
1734
            $modulename = strtolower($module->name);
1735
            //print 'modulename='.$modulename;
1736
1737
            //if (empty($conf->global->$moduleconst)) continue;
1738
            if (!in_array($modulename, $listofmodules)) {
1739
                continue;
1740
            }
1741
            //var_dump($modulename.' - '.$langs->trans('Module'.$module->numero.'Name'));
1742
1743
            if ($i > 0) {
1744
                $text .= ', ';
1745
            } else {
1746
                $text .= ' ';
1747
            }
1748
            $i++;
1749
1750
            $tmptext = $langs->trans('Module' . $module->numero . 'Name');
1751
            if ($tmptext != 'Module' . $module->numero . 'Name') {
1752
                $text .= $langs->trans('Module' . $module->numero . 'Name');
1753
            } else {
1754
                $text .= $langs->trans($module->name);
1755
            }
1756
        }
1757
    }
1758
1759
    return $text;
1760
}
1761
1762
1763
/**
1764
 *  Add document model used by doc generator
1765
 *
1766
 * @param string $name Model name
1767
 * @param string $type Model type
1768
 * @param string $label Model label
1769
 * @param string $description Model description
1770
 * @return     int                     Return integer <0 if KO, >0 if OK
1771
 */
1772
function addDocumentModel($name, $type, $label = '', $description = '')
1773
{
1774
    global $db, $conf;
1775
1776
    $db->begin();
1777
1778
    $sql = "INSERT INTO " . MAIN_DB_PREFIX . "document_model (nom, type, entity, libelle, description)";
1779
    $sql .= " VALUES ('" . $db->escape($name) . "','" . $db->escape($type) . "'," . ((int)$conf->entity) . ", ";
1780
    $sql .= ($label ? "'" . $db->escape($label) . "'" : 'null') . ", ";
1781
    $sql .= (!empty($description) ? "'" . $db->escape($description) . "'" : "null");
1782
    $sql .= ")";
1783
1784
    dol_syslog("admin.lib::addDocumentModel", LOG_DEBUG);
1785
    $resql = $db->query($sql);
1786
    if ($resql) {
1787
        $db->commit();
1788
        return 1;
1789
    } else {
1790
        dol_print_error($db);
1791
        $db->rollback();
1792
        return -1;
1793
    }
1794
}
1795
1796
/**
1797
 *  Delete document model used by doc generator
1798
 *
1799
 * @param string $name Model name
1800
 * @param string $type Model type
1801
 * @return     int                     Return integer <0 if KO, >0 if OK
1802
 */
1803
function delDocumentModel($name, $type)
1804
{
1805
    global $db, $conf;
1806
1807
    $db->begin();
1808
1809
    $sql = "DELETE FROM " . MAIN_DB_PREFIX . "document_model";
1810
    $sql .= " WHERE nom = '" . $db->escape($name) . "'";
1811
    $sql .= " AND type = '" . $db->escape($type) . "'";
1812
    $sql .= " AND entity = " . ((int)$conf->entity);
1813
1814
    dol_syslog("admin.lib::delDocumentModel", LOG_DEBUG);
1815
    $resql = $db->query($sql);
1816
    if ($resql) {
1817
        $db->commit();
1818
        return 1;
1819
    } else {
1820
        dol_print_error($db);
1821
        $db->rollback();
1822
        return -1;
1823
    }
1824
}
1825
1826
1827
/**
1828
 *  Return the php_info into an array
1829
 *
1830
 * @return     array       Array with PHP infos
1831
 */
1832
function phpinfo_array()
1833
{
1834
    ob_start();
1835
    phpinfo();
1836
    $phpinfostring = ob_get_contents();
1837
    ob_end_clean();
1838
1839
    $info_arr = array();
1840
    $info_lines = explode("\n", strip_tags($phpinfostring, "<tr><td><h2>"));
1841
    $cat = "General";
1842
    foreach ($info_lines as $line) {
1843
        // new cat?
1844
        $title = array();
1845
        preg_match("~<h2>(.*)</h2>~", $line, $title) ? $cat = $title[1] : null;
1846
        $val = array();
1847
        if (preg_match("~<tr><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td></tr>~", $line, $val)) {
1848
            $info_arr[trim($cat)][trim($val[1])] = $val[2];
1849
        } elseif (preg_match("~<tr><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td></tr>~", $line, $val)) {
1850
            $info_arr[trim($cat)][trim($val[1])] = array("local" => $val[2], "master" => $val[3]);
1851
        }
1852
    }
1853
    return $info_arr;
1854
}
1855
1856
/**
1857
 *  Return array head with list of tabs to view object information.
1858
 *
1859
 * @return array                       head array with tabs
1860
 */
1861
function company_admin_prepare_head()
1862
{
1863
    global $langs, $conf;
1864
1865
    $h = 0;
1866
    $head = array();
1867
1868
    $head[$h][0] = constant('BASE_URL') . "/admin/company.php";
1869
    $head[$h][1] = $langs->trans("Company");
1870
    $head[$h][2] = 'company';
1871
    $h++;
1872
1873
    $head[$h][0] = constant('BASE_URL') . "/admin/openinghours.php";
1874
    $head[$h][1] = $langs->trans("OpeningHours");
1875
    $head[$h][2] = 'openinghours';
1876
    $h++;
1877
1878
    $head[$h][0] = constant('BASE_URL') . "/admin/accountant.php";
1879
    $head[$h][1] = $langs->trans("Accountant");
1880
    $head[$h][2] = 'accountant';
1881
    $h++;
1882
1883
    $head[$h][0] = constant('BASE_URL') . "/admin/company_socialnetworks.php";
1884
    $head[$h][1] = $langs->trans("SocialNetworksInformation");
1885
    $head[$h][2] = 'socialnetworks';
1886
    $h++;
1887
1888
    complete_head_from_modules($conf, $langs, null, $head, $h, 'mycompany_admin', 'add');
1889
1890
    complete_head_from_modules($conf, $langs, null, $head, $h, 'mycompany_admin', 'remove');
1891
1892
    return $head;
1893
}
1894
1895
/**
1896
 *  Return array head with list of tabs to view object information.
1897
 *
1898
 * @return array                       head array with tabs
1899
 */
1900
function email_admin_prepare_head()
1901
{
1902
    global $langs, $conf, $user;
1903
1904
    $h = 0;
1905
    $head = array();
1906
1907
    if (!empty($user->admin) && (empty($_SESSION['leftmenu']) || $_SESSION['leftmenu'] != 'email_templates')) {
1908
        $head[$h][0] = constant('BASE_URL') . "/admin/mails.php";
1909
        $head[$h][1] = $langs->trans("OutGoingEmailSetup");
1910
        $head[$h][2] = 'common';
1911
        $h++;
1912
1913
        if (isModEnabled('mailing')) {
1914
            $head[$h][0] = constant('BASE_URL') . "/admin/mails_emailing.php";
1915
            $head[$h][1] = $langs->trans("OutGoingEmailSetupForEmailing", $langs->transnoentitiesnoconv("EMailing"));
1916
            $head[$h][2] = 'common_emailing';
1917
            $h++;
1918
        }
1919
1920
        if (isModEnabled('ticket')) {
1921
            $head[$h][0] = constant('BASE_URL') . "/admin/mails_ticket.php";
1922
            $head[$h][1] = $langs->trans("OutGoingEmailSetupForEmailing", $langs->transnoentitiesnoconv("Ticket"));
1923
            $head[$h][2] = 'common_ticket';
1924
            $h++;
1925
        }
1926
    }
1927
1928
    // admin and non admin can view this menu entry, but it is not shown yet when we on user menu "Email templates"
1929
    if (empty($_SESSION['leftmenu']) || $_SESSION['leftmenu'] != 'email_templates') {
1930
        $head[$h][0] = constant('BASE_URL') . "/admin/mails_senderprofile_list.php";
1931
        $head[$h][1] = $langs->trans("EmailSenderProfiles");
1932
        $head[$h][2] = 'senderprofiles';
1933
        $h++;
1934
    }
1935
1936
    $head[$h][0] = constant('BASE_URL') . "/admin/mails_templates.php";
1937
    $head[$h][1] = $langs->trans("EMailTemplates");
1938
    $head[$h][2] = 'templates';
1939
    $h++;
1940
1941
    $head[$h][0] = constant('BASE_URL') . "/admin/mails_ingoing.php";
1942
    $head[$h][1] = $langs->trans("InGoingEmailSetup", $langs->transnoentitiesnoconv("EMailing"));
1943
    $head[$h][2] = 'common_ingoing';
1944
    $h++;
1945
1946
    complete_head_from_modules($conf, $langs, null, $head, $h, 'email_admin', 'remove');
1947
1948
    return $head;
1949
}
1950