dolibarr 24.0.0-beta
filecheck.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2005-2026 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
4 * Copyright (C) 2007-2012 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2015-2025 Frédéric France <frederic.france@free.fr>
6 * Copyright (C) 2017 Nicolas ZABOURI <info@inovea-conseil.com>
7 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
28// Load Dolibarr environment
29require '../../main.inc.php';
39require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
40require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
41require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
42require_once DOL_DOCUMENT_ROOT.'/blockedlog/lib/blockedlog.lib.php';
43
44$langs->load("admin");
45
46$mode = GETPOST('mode', 'aZ09');
47
48if (!$user->admin && !$user->hasRight('bockedlog', 'read')) {
50}
51
52$error = 0;
53
54// Version blockedlog
55$versionbadge = '<span class="badge-text badge-secondary">'.getBlockedLogVersionToShow();
56if ($mysoc->country_code == 'FR' && !constant('CERTIF_LNE')) {
57 // Can add an edditional mention
58 $versionbadge .= ' - '.$langs->trans("NeedAThirdPartyStatement");
59}
60$versionbadge .= '</span>';
61
62
63/*
64 * View
65 */
66
67@set_time_limit(300);
68
69llxHeader('', '', '', '', 0, 0, '', '', '', 'mod-admin page-system_filecheck');
70
71print load_fiche_titre($langs->trans("FileCheckDolibarr"), '', 'title_setup');
72
73print '<div class="opacitymedium hideonsmartphone justify">'.$langs->trans("FileCheckDesc").'</div>';
74if (isModEnabled('blockedlog')) {
75 print '<span class="opacitymedium">';
76 print $langs->trans("DataIntegrityDesc").': ';
77 print '</span>';
78 print '<a href="'.DOL_URL_ROOT.'/blockedlog/admin/blockedlog_list.php">'.img_picto('', 'url', 'class="pictofixedwidth"').$langs->trans("BlockedLog").'</a><br>';
79}
80print'<br>';
81
82
83// Version
84print '<div class="div-table-responsive-no-min">';
85print '<table class="noborder centpercent">';
86print '<tr class="liste_titre"><td>'.$langs->trans("Version").'</td><td></td></tr>'."\n";
87$htmltooltip = '';
88$htmltooltip .= $langs->trans("VersionLastInstall").': '.getDolGlobalString('MAIN_VERSION_LAST_INSTALL').'<br>'."\n";
89$htmltooltip .= $langs->trans("VersionLastUpgrade").': '.getDolGlobalString('MAIN_VERSION_LAST_UPGRADE').'<br>'."\n";
90
91print '<tr class="oddeven nohover">';
92print '<td width="300">'.$langs->trans("VersionProgram").'</td><td>';
93print '<span class="badge-text badge-secondary valignmiddle">'.DOL_VERSION.'</span>';
94// If current version differs from last upgrade
95if (!getDolGlobalString('MAIN_VERSION_LAST_UPGRADE')) {
96 // Compare version with last install database version (upgrades never occurred)
97 if (in_array(versioncompare(versiondolibarrarray(), preg_split('/[\-\.]/', getDolGlobalString('MAIN_VERSION_LAST_INSTALL'))), array(-2, -1, 1, 2))) {
98 print ' '.img_warning($langs->trans("RunningUpdateProcessMayBeRequired", DOL_VERSION, getDolGlobalString('MAIN_VERSION_LAST_INSTALL')));
99 }
100} else {
101 // Compare version with last upgrade database version
102 if (in_array(versioncompare(versiondolibarrarray(), preg_split('/[\-\.]/', getDolGlobalString('MAIN_VERSION_LAST_UPGRADE'))), array(-2, -1, 1, 2))) {
103 print ' '.img_warning($langs->trans("RunningUpdateProcessMayBeRequired", DOL_VERSION, getDolGlobalString('MAIN_VERSION_LAST_UPGRADE')));
104 }
105}
106print ' '.$form->textwithpicto('', $htmltooltip);
107print '</td></tr>'."\n";
108
109$showblockedlogversion = 0;
110if ($mysoc->country_code == 'FR') {
111 $showblockedlogversion = 1;
112}
114 $showblockedlogversion = 1;
115}
116
117if ($showblockedlogversion) {
118 print '<tr class="oddeven nohover">';
119 print '<td width="300">'.$langs->trans("VersionOfModule", $langs->transnoentitiesnoconv("BlockedLog")).'</td><td>';
120 print $versionbadge;
121 print '</td>';
122 print '</tr>';
123}
124
125print '</table>';
126print '</div>';
127
128// Add a complementary optional information
129$infotoshow = '';
130if ($mysoc->country_code == 'FR') {
131 $islne = isALNEQualifiedVersion(1, 1);
132 if ($islne) {
133 if (preg_match('/\-/', getBlockedLogVersionToShow())) {
134 // This is an alpha or beta version
135 $infotoshow = $langs->trans("LNECandidateVersionForCertificationFR", getBlockedLogVersionToShow());
136 } else {
137 $infotoshow = $langs->trans("LNECertifiedVersionFR", getBlockedLogVersionToShow());
138 }
139 } else {
140 $infotoshow = $langs->trans("NotCertifiedVersionFR", getBlockedLogVersionToShow());
141 }
142}
143if ($infotoshow) {
144 print info_admin($infotoshow, 0, 0, 'info');
145}
146
147print '<br><br>';
148
149
150// Modified or missing files
151$file_list = array('missing' => array(), 'updated' => array());
152
153// Local file to compare to
154$xmlshortfile = dol_sanitizeFileName(GETPOST('xmlshortfile', 'alpha') ? GETPOST('xmlshortfile', 'alpha') : 'filelist-'.DOL_VERSION.getDolGlobalString('MAIN_FILECHECK_LOCAL_SUFFIX').'.xml'.getDolGlobalString('MAIN_FILECHECK_LOCAL_EXT'));
155
156$xmlfile = DOL_DOCUMENT_ROOT.'/install/'.$xmlshortfile;
157if (!preg_match('/\.zip$/i', $xmlfile) && dol_is_file($xmlfile.'.zip')) {
158 $xmlfile .= '.zip';
159}
160
161// Remote file to compare to
162$xmlremote = GETPOST('xmlremote', 'alphanohtml');
163if (empty($xmlremote) && getDolGlobalString('MAIN_FILECHECK_URL')) {
164 $xmlremote = getDolGlobalString('MAIN_FILECHECK_URL');
165}
166$param = 'MAIN_FILECHECK_URL_'.DOL_VERSION;
167if (empty($xmlremote) && getDolGlobalString($param)) {
168 $xmlremote = getDolGlobalString($param);
169}
170if (empty($xmlremote)) {
171 $xmlremote = 'https://www.dolibarr.org/files/stable/signatures/filelist-'.DOL_VERSION.'.xml';
172}
173if (!preg_match('/^https?:\/\//', $xmlremote)) {
174 $langs->load("errors");
175 setEventMessages($langs->trans("ErrorURLMustStartWithHttp", $xmlremote), null, 'errors');
176 $error++;
177} elseif ($xmlremote && !preg_match('/\.xml$/', $xmlremote)) {
178 $langs->load("errors");
179 setEventMessages($langs->trans("ErrorURLMustEndWith", $xmlremote, '.xml'), null, 'errors');
180 $error++;
181}
182
183// Test if remote test is ok
184$enableremotecheck = true;
185if (preg_match('/beta|alpha|rc/i', DOL_VERSION) || getDolGlobalString('MAIN_ALLOW_INTEGRITY_CHECK_ON_UNSTABLE')) {
186 $enableremotecheck = false;
187}
188
189print '<form name="check" action="'.dolBuildUrl($_SERVER["PHP_SELF"]).'">';
190print '<input type="hidden" name="token" value="'.newToken().'">';
191print img_picto('', 'search', 'class="pictofixedwidth"').$langs->trans("MakeIntegrityAnalysisFrom").'...<br><br>';
192
193print '<div class="divsection">';
194print '<!-- for a local check target=local&xmlshortfile=... -->'."\n";
195if (dol_is_file($xmlfile)) {
196 print '<input type="radio" name="target" id="checkboxlocal" value="local"'.((!GETPOST('target') || GETPOST('target') == 'local') ? 'checked="checked"' : '').'"> <label for="checkboxlocal">'.$langs->trans("LocalSignature").'</label> = ';
197 print '<input name="xmlshortfile" class="flat minwidth400" value="'.dol_escape_htmltag($xmlshortfile).'" spellcheck="false">';
198 print '<br>';
199} else {
200 print '<input type="radio" name="target" id="checkboxlocal" value="local"> <label for="checkboxlocal">'.$langs->trans("LocalSignature").' = ';
201 print '<input name="xmlshortfile" class="flat minwidth400" value="'.dol_escape_htmltag($xmlshortfile).'" spellcheck="false">';
202 print '<br><span class="warning paddingtop inline-block">'.$langs->trans("AvailableOnlyOnPackagedVersions").'</span></label>';
203 print '<br>';
204}
205
206print '<br>';
207
208print '<!-- for a remote target=remote&xmlremote=... -->'."\n";
209if ($enableremotecheck) {
210 print '<input type="radio" name="target" id="checkboxremote" value="remote"'.(GETPOST('target') == 'remote' ? 'checked="checked"' : '').'> <label for="checkboxremote">'.$langs->trans("RemoteSignature").'</label> = ';
211 print '<input name="xmlremote" class="flat minwidth500" value="'.dol_escape_htmltag($xmlremote).'" spellcheck="false"><br>';
212} else {
213 print '<input type="radio" name="target" id="checkboxremote" value="remote" disabled="disabled"> '.$langs->trans("RemoteSignature").' = '.dol_escape_htmltag($xmlremote);
214 if (!GETPOST('xmlremote')) {
215 print ' <span class="warning">('.$langs->trans("FeatureAvailableOnlyOnStable").')</span>';
216 }
217 print '<br>';
218}
219print '</div>';
220
221// Option unalterable log
222print '<div class="center">';
223if ($mysoc->country_code == 'FR') {
224 print '<input type="checkbox" name="mode" id="mode" value="unalterable"'.($mode == 'unalterable' ? ' checked="checked"' : '').'>';
225 print '<label for="mode" class="opacitymedium">'.$langs->trans("AnalyzeUnalterableScopeOnly", $langs->transnoentitiesnoconv("BlockedLog")).'</label><br>';
226}
227print '<input type="submit" name="check" class="button" value="'.$langs->trans("Check").'">';
228print '</div>';
229print '</form>';
230print '<br>';
231print '<br>';
232
233if (GETPOST('target') == 'local') {
234 if (dol_is_file($xmlfile)) {
235 // If file is a zip file (.../filelist-x.y.z.xml.zip), we uncompress it before
236 if (preg_match('/\.zip$/i', $xmlfile)) {
237 dol_mkdir($conf->admin->dir_temp);
238 $xmlfilenew = preg_replace('/\.zip$/i', '', $xmlfile);
239 $result = dol_uncompress($xmlfile, $conf->admin->dir_temp);
240 if (empty($result['error'])) {
241 $xmlfile = $conf->admin->dir_temp.'/'.basename($xmlfilenew);
242 } else {
243 print $langs->trans('FailedToUncompressFile').': '.$xmlfile;
244 $error++;
245 }
246 }
247 $xml = simplexml_load_file($xmlfile);
248 if ($xml === false) {
249 print '<div class="warning">'.$langs->trans('XmlCorrupted').': '.$xmlfile.'</span>';
250 $error++;
251 }
252 } else {
253 print '<div class="warning">'.$langs->trans('XmlNotFound').': '.$xmlfile.'</span>';
254 $error++;
255 }
256}
257if (GETPOST('target') == 'remote') {
258 $xmlarray = getURLContent($xmlremote, 'GET', '', 1, array(), array('http', 'https'), 0); // Accept http or https links on external remote server only. Same is used into api_setup.class.php.
259
260 // Return array('content'=>response,'curl_error_no'=>errno,'curl_error_msg'=>errmsg...)
261 if (!$xmlarray['curl_error_no'] && $xmlarray['http_code'] != 400 && $xmlarray['http_code'] != 404) {
262 $xmlfile = $xmlarray['content'];
263 //print "xmlfilestart".$xmlfile."xmlfileend";
264 if (LIBXML_VERSION < 20900) {
265 // Avoid load of external entities (security problem).
266 // Required only if LIBXML_VERSION < 20900
267 // @phan-suppress-next-line PhanDeprecatedFunctionInternal
268 libxml_disable_entity_loader(true);
269 }
270
271 $xml = simplexml_load_string($xmlfile, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NONET);
272 } else {
273 $errormsg = $langs->trans('XmlNotFound').': '.$xmlremote.' - '.$xmlarray['http_code'].(($xmlarray['http_code'] == 400 && $xmlarray['content']) ? ' '.$xmlarray['content'] : '').' '.$xmlarray['curl_error_no'].' '.$xmlarray['curl_error_msg'];
274 setEventMessages($errormsg, null, 'errors');
275 $error++;
276 }
277}
278
279
280if (empty($error) && !empty($xml)) {
281 $checksumconcat = array();
282 $file_list = array();
283 $out = '';
284
285 $algo = (string) $xml['algo']; // When file is <checksum_list attrib="val" algo="xxx">...</checksum_list>, the first tag is root of the $xml
286 if (empty($algo)) {
287 //$algo = 'md5'; // For v22-
288 $algo = 'sha256'; // For v23+
289 }
290
291 // Forced constants
292 if (is_object($xml->dolibarr_constants[0]) || $mode == 'unalterable') {
293 $out .= load_fiche_titre($langs->trans("ForcedConstants"));
294
295 $out .= '<div class="div-table-responsive-no-min">';
296 $out .= '<table class="noborder">';
297 $out .= '<tr class="liste_titre">';
298 $out .= '<td>#</td>';
299 $out .= '<td>'.$langs->trans("Parameter").'</td>';
300 $out .= '<td class="center">'.$langs->trans("ExpectedValue").'</td>';
301 $out .= '<td class="center">'.$langs->trans("CurrentValue").'</td>';
302 $out .= '</tr>'."\n";
303
304 $i = 0;
305
306 if ($mode == 'unalterable') {
307 $i++;
308
309 $out .= '<tr class="oddeven">';
310 $out .= '<td>'.$i.'</td>'."\n";
311 $out .= '<td>'.$langs->trans("Country").'</td>'."\n";
312 $out .= '<td class="center"><span class="opacitymedium">'.$langs->trans("YourCountryCode").'</span></td>'."\n";
313 $out .= '<td class="center">'.$mysoc->country_code.'</td>'."\n";
314 $out .= "</tr>\n";
315
316 $i++;
317
318 $out .= '<tr class="oddeven">';
319 $out .= '<td>'.$i.'</td>'."\n";
320 $out .= '<td>'.$langs->trans("StatusOfModule", $langs->transnoentitiesnoconv("BlockedLog")).'</td>'."\n";
321 $out .= '<td class="center">'.$langs->trans("Enabled").'</td>'."\n";
322 $out .= '<td class="center">';
323 $out .= isModEnabled('blockedlog') ? '<span class="ok">'.$langs->trans("Enabled").'</span>' : '<span class="warning">'.$langs->trans("Disabled").'</span>';
324
325 include_once DOL_DOCUMENT_ROOT.'/core/modules/modBlockedLog.class.php';
326 $objMod = new modBlockedLog($db);
327 /*$modulename = $objMod->getName();
328 $moduledesc = $objMod->getDesc();
329 $moduleauthor = $objMod->getPublisher();
330 $moduledir = strtolower(preg_replace('/^mod/i', '', get_class($objMod)));*/
331 $const_name = 'MAIN_MODULE_'.strtoupper(preg_replace('/^mod/i', '', get_class($objMod)));
332
333 $htmltooltip = '<span class="opacitymedium">'.$langs->trans("LastActivationDate").':</span> ';
334 if (getDolGlobalString($const_name)) {
335 $htmltooltip .= dol_print_date($objMod->getLastActivationDate(), 'dayhour');
336 } else {
337 $htmltooltip .= $langs->trans("Disabled");
338 }
339 $tmp = $objMod->getLastActivationInfo();
340 $authorid = (empty($tmp['authorid']) ? '' : $tmp['authorid']);
341 if ($authorid > 0) {
342 $tmpuser = new User($db);
343 $tmpuser->fetch($authorid);
344 $htmltooltip .= '<br><span class="opacitymedium">'.$langs->trans("LastActivationAuthor").':</span> ';
345 $htmltooltip .= $tmpuser->getNomUrl(0, 'nolink', -1, 1);
346 }
347 $ip = (empty($tmp['ip']) ? '' : $tmp['ip']);
348 if ($ip) {
349 $htmltooltip .= '<br><span class="opacitymedium">'.$langs->trans("LastActivationIP").':</span> ';
350 $htmltooltip .= $ip;
351 }
352 $lastactivationversion = (empty($tmp['lastactivationversion']) ? '' : $tmp['lastactivationversion']);
353 if ($lastactivationversion && $lastactivationversion != 'dolibarr') {
354 $htmltooltip .= '<br><span class="opacitymedium">'.$langs->trans("LastActivationVersion").':</span> ';
355 $htmltooltip .= $lastactivationversion;
356 }
357
358 $out .= $form->textwithpicto('', $htmltooltip);
359
360 $out .= "</td>\n";
361 $out .= "</tr>\n";
362 }
363
364 foreach ($xml->dolibarr_constants[0]->constant as $constant) { // $constant is a simpleXMLElement
365 $constname = (string) $constant['name'];
366 $constvalue = (string) $constant;
367
368 $constvalue = (empty($constvalue) ? '0' : $constvalue);
369 // Value found
370 $value = '';
371 if ($constname && getDolGlobalString($constname) != '') {
372 $value = getDolGlobalString($constname);
373 }
374 $valueforchecksum = (empty($value) ? '0' : $value);
375
376 $checksumconcat[$constname] = $valueforchecksum;
377
378 $i++;
379
380 $out .= '<tr class="oddeven">';
381 $out .= '<td>'.$i.'</td>'."\n";
382 $out .= '<td>'.dol_escape_htmltag($constname).'</td>'."\n";
383 $out .= '<td class="center">'.dol_escape_htmltag($constvalue).'</td>'."\n";
384 $out .= '<td class="center">'.dol_escape_htmltag($valueforchecksum).'</td>'."\n";
385 $out .= "</tr>\n";
386 }
387
388 if ($i == 0 && $mode != 'unalterable') {
389 $out .= '<tr class="oddeven"><td colspan="4"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
390 }
391 $out .= '</table>';
392 $out .= '</div>';
393
394 $out .= '<br>';
395 }
396
397
398 $onlymodifiedorremoved = 0;
399 if ($mode == 'unalterable') {
400 $listoffilestoanalyze = $xml->dolibarr_unalterable_files[0];
401 $onlymodifiedorremoved = 1;
402 } else {
403 $listoffilestoanalyze = $xml->dolibarr_htdocs_dir[0];
404 $onlymodifiedorremoved = 0;
405 }
406
407
408 // Scan htdocs
409 if (is_object($listoffilestoanalyze)) {
410 // @phan-suppress-next-line PhanTypeArraySuspicious
411 $includecustom = (empty($listoffilestoanalyze['includecustom']) ? 0 : $listoffilestoanalyze['includecustom']);
412
413 // Define qualified files (must be same than into generate_filelist_xml.php and in api_setup.class.php)
414 $regextoinclude = '\.(php|php3|php4|php5|phtml|phps|phar|inc|css|scss|html|xml|js|json|tpl|jpg|jpeg|png|gif|ico|sql|lang|txt|yml|bak|md|mp3|mp4|wav|mkv|z|gz|zip|rar|tar|less|svg|eot|woff|woff2|ttf|manifest)$';
415 $regextoexclude = '('.($includecustom ? '' : 'custom|').'documents|conf|install|dejavu-fonts-ttf-.*|public\/test|sabre\/sabre\/.*\/tests|Shared\/PCLZip|nusoap\/lib\/Mail|php\/example|php\/test|geoip\/sample.*\.php|ckeditor\/samples|ckeditor\/adapters)$'; // Exclude dirs
416 $scanfiles = dol_dir_list(DOL_DOCUMENT_ROOT, 'files', 1, $regextoinclude, $regextoexclude);
417
418 // Fill file_list with files in signature, new files, modified files
419 getFilesUpdated($file_list, $listoffilestoanalyze, '', DOL_DOCUMENT_ROOT, $checksumconcat); // Fill array $file_list
420 '@phan-var-force array{insignature:string[],missing?:array<array{filename:string,expectedhash:string,expectedsize:string,algo:string}>,updated:array<array{filename:string,expectedhash:string,expectedsize:string,hash:string,algo:string}>} $file_list';
421
422 // Complete with list of new files into $file_list['added']
423 if (empty($onlymodifiedorremoved)) {
424 foreach ($scanfiles as $valfile) {
425 $tmprelativefilename = preg_replace('/^'.preg_quote(DOL_DOCUMENT_ROOT, '/').'/', '', $valfile['fullname']);
426 if (!in_array($tmprelativefilename, $file_list['insignature'])) {
427 $hashnewfile = @hash_file($algo, $valfile['fullname']); // Can fails if we don't have permission to open/read file
428 $file_list['added'][] = array('filename' => $tmprelativefilename, 'hash' => $hashnewfile, 'algo' => $algo);
429 }
430 }
431 }
432
433 // Files missing
434 $out .= load_fiche_titre($langs->trans("FilesMissing"));
435
436 $out .= '<div class="div-table-responsive-no-min">';
437 $out .= '<table class="noborder">';
438 $out .= '<tr class="liste_titre">';
439 $out .= '<td>#</td>';
440 $out .= '<td>'.$langs->trans("Filename").'</td>';
441 $out .= '<td class="right">'.$langs->trans("ExpectedSize").'</td>';
442 $out .= '<td class="center">'.$langs->trans("ExpectedChecksum").'</td>';
443 $out .= '</tr>'."\n";
444 $tmpfilelist = dol_sort_array($file_list['missing'], 'filename');
445 if (is_array($tmpfilelist) && count($tmpfilelist)) {
446 $i = 0;
447 foreach ($tmpfilelist as $file) {
448 $i++;
449 $out .= '<tr class="oddeven">';
450 $out .= '<td>'.$i.'</td>'."\n";
451 $out .= '<td>'.dol_escape_htmltag($file['filename']).'</td>'."\n";
452 $out .= '<td class="right">';
453 if (!empty($file['expectedsize'])) {
454 $out .= dol_print_size((int) $file['expectedsize']);
455 }
456 $out .= '</td>'."\n";
457 $out .= '<td class="center">'.dol_escape_htmltag($file['expectedhash']).'</td>'."\n";
458 $out .= "</tr>\n";
459 }
460 } else {
461 $out .= '<tr class="oddeven"><td colspan="4"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
462 }
463 $out .= '</table>';
464 $out .= '</div>';
465
466 $out .= '<br>';
467
468 // Files modified
469 $out .= load_fiche_titre($langs->trans("FilesModified"));
470
471 $totalsize = 0;
472 $out .= '<div class="div-table-responsive-no-min">';
473 $out .= '<table class="noborder">';
474 $out .= '<tr class="liste_titre">';
475 $out .= '<td>#</td>';
476 $out .= '<td>'.$langs->trans("Filename").'</td>';
477 $out .= '<td class="center">'.$langs->trans("ExpectedChecksum").'</td>';
478 $out .= '<td class="center">'.$langs->trans("CurrentChecksum").'</td>';
479 $out .= '<td class="right">'.$langs->trans("ExpectedSize").'</td>';
480 $out .= '<td class="right">'.$langs->trans("CurrentSize").'</td>';
481 $out .= '<td class="right">'.$langs->trans("DateModification").'</td>';
482 $out .= '</tr>'."\n";
483 $tmpfilelist2 = dol_sort_array($file_list['updated'], 'filename');
484 if (is_array($tmpfilelist2) && count($tmpfilelist2)) {
485 $i = 0;
486 foreach ($tmpfilelist2 as $file) {
487 $i++;
488 $out .= '<tr class="oddeven">';
489 $out .= '<td>'.$i.'</td>'."\n";
490 $out .= '<td>'.dol_escape_htmltag($file['filename']).'</td>'."\n";
491 $out .= '<td class="center" title="'.dol_escape_htmltag($file['expectedhash']).'">'.dol_escape_htmltag(dol_trunc($file['expectedhash'], 16)).'</td>'."\n";
492 $out .= '<td class="center" title="'.dol_escape_htmltag($file['hash']).'">'.dol_escape_htmltag(dol_trunc($file['hash'], 16)).'</td>'."\n";
493 $out .= '<td class="right">';
494 if ($file['expectedsize']) {
495 $out .= dol_print_size((int) $file['expectedsize']);
496 }
497 $out .= '</td>'."\n";
498 $size = dol_filesize(DOL_DOCUMENT_ROOT.'/'.$file['filename']);
499 $totalsize += $size;
500 $out .= '<td class="right">'.dol_print_size($size).'</td>'."\n";
501 $out .= '<td class="right">'.dol_print_date(dol_filemtime(DOL_DOCUMENT_ROOT.'/'.$file['filename']), 'dayhour').'</td>'."\n";
502 $out .= "</tr>\n";
503 }
504 $out .= '<tr class="liste_total">';
505 $out .= '<td></td>'."\n";
506 $out .= '<td>'.$langs->trans("Total").'</td>'."\n";
507 $out .= '<td class="center"></td>'."\n";
508 $out .= '<td class="center"></td>'."\n";
509 $out .= '<td class="center"></td>'."\n";
510 $out .= '<td class="right">'.dol_print_size($totalsize).'</td>'."\n";
511 $out .= '<td class="right"></td>'."\n";
512 $out .= "</tr>\n";
513 } else {
514 $out .= '<tr class="oddeven"><td colspan="7"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
515 }
516 $out .= '</table>';
517 $out .= '</div>';
518
519 $out .= '<br>';
520
521 // Files added
522 if (empty($onlymodifiedorremoved)) {
523 $out .= load_fiche_titre($langs->trans("FilesAdded"));
524
525 $totalsize = 0;
526 $out .= '<div class="div-table-responsive-no-min">';
527 $out .= '<table class="noborder">';
528 $out .= '<tr class="liste_titre">';
529 $out .= '<td>#</td>';
530 $out .= '<td>'.$langs->trans("Filename").'</td>';
531 $out .= '<td class="center">'.$langs->trans("ExpectedChecksum").'</td>';
532 $out .= '<td class="center">'.$langs->trans("CurrentChecksum").'</td>';
533 $out .= '<td class="right">'.$langs->trans("Size").'</td>';
534 $out .= '<td class="right">'.$langs->trans("DateModification").'</td>';
535 $out .= '</tr>'."\n";
536 $tmpfilelist3 = dol_sort_array($file_list['added'], 'filename');
537 if (is_array($tmpfilelist3) && count($tmpfilelist3)) {
538 $i = 0;
539 foreach ($tmpfilelist3 as $file) {
540 $i++;
541 $out .= '<tr class="oddeven">';
542 $out .= '<td>'.$i.'</td>'."\n";
543 $out .= '<td>'.dol_escape_htmltag($file['filename']);
544 if (!preg_match('/^win/i', PHP_OS)) {
545 $htmltext = $langs->trans("YouCanDeleteFileOnServerWith", 'rm '.DOL_DOCUMENT_ROOT.$file['filename']); // The slash is included int file['filename']
546 $out .= ' '.$form->textwithpicto('', $htmltext, 1, 'help', '', 0, 2, 'helprm'.$i);
547 }
548 $out .= '</td>'."\n";
549 $out .= '<td class="center" title="'.dol_escape_htmltag((string) $file['expectedhash']).'">'.dol_escape_htmltag(dol_trunc((string) $file['expectedhash'], 16)).'</td>'."\n"; // @phan-suppress-current-line PhanTypeInvalidDimOffset
550 $out .= '<td class="center" title="'.dol_escape_htmltag((string) $file['hash']).'">'.dol_escape_htmltag(dol_trunc($file['hash'], 16)).'</td>'."\n";
551 $size = dol_filesize(DOL_DOCUMENT_ROOT.'/'.$file['filename']);
552 $totalsize += $size;
553 $out .= '<td class="right">'.dol_print_size($size).'</td>'."\n";
554 $out .= '<td class="right nowraponall">'.dol_print_date(dol_filemtime(DOL_DOCUMENT_ROOT.'/'.$file['filename']), 'dayhour').'</td>'."\n";
555 $out .= "</tr>\n";
556 }
557 $out .= '<tr class="liste_total">';
558 $out .= '<td></td>'."\n";
559 $out .= '<td>'.$langs->trans("Total").'</td>'."\n";
560 $out .= '<td class="center"></td>'."\n";
561 $out .= '<td class="center"></td>'."\n";
562 $out .= '<td class="right">'.dol_print_size($totalsize).'</td>'."\n";
563 $out .= '<td class="right"></td>'."\n";
564 $out .= "</tr>\n";
565 } else {
566 $out .= '<tr class="oddeven"><td colspan="6"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
567 }
568 $out .= '</table>';
569 $out .= '</div>';
570 }
571 } else {
572 print '<div class="error">';
573 print 'Error: Failed to found <b>dolibarr_htdocs_dir</b> into content of XML file:<br>'.dol_escape_htmltag(dol_trunc($xmlfile, 500));
574 print '</div><br>';
575 $error++;
576 }
577
578
579 // Scan scripts
580 /*
581 if (is_object($xml->dolibarr_scripts_dir[0])) {
582 $file_list = array();
583 $ret = getFilesUpdated($file_list, $xml->dolibarr_htdocs_dir[0], '', ???, $checksumconcat); // Fill array $file_list
584 '@phan-var-force array{insignature:string[],missing?:array<array{filename:string,expectedhash:string,expectedsize:string,algo:string}>,updated:array<array{filename:string,expectedhash:string,expectedsize:string,hash:string,algo:string}>} $file_list';
585 }*/
586
587
588 // Section Globalchecksum
589 asort($checksumconcat); // Sort list of checksum
590
591 $checksumget = hash($algo, implode(',', $checksumconcat));
592
593 if ($mode == 'unalterable') {
594 $nameofsection = 'dolibarr_unalterable_files_checksum';
595 $checksumtoget = trim((string) $xml->dolibarr_unalterable_files_checksum);
596 } else {
597 $nameofsection = 'dolibarr_htdocs_dir_checksum';
598 $checksumtoget = trim((string) $xml->dolibarr_htdocs_dir_checksum);
599 }
600
601 $resultcomment = '';
602
603 $outexpectedchecksum = ($checksumtoget ? $checksumtoget : $langs->trans("Unknown"));
604 $outcurrentchecksumtext = '';
605 if ($checksumget == $checksumtoget) {
606 if (empty($onlymodifiedorremoved) && !empty($file_list['added'])) {
607 $resultcode = 'warning';
608 $resultcomment = 'FileIntegrityIsOkButFilesWereAdded';
609 $outcurrentchecksum = $checksumget;
610 $outcurrentchecksumtext .= img_picto('', 'tick').' <span class="'.$resultcode.'">'.$langs->trans($resultcomment).'</span>';
611 } else {
612 $resultcode = 'ok';
613 $resultcomment = 'Success';
614 $outcurrentchecksum = '<span class="'.$resultcode.'" title="Checksum of all current checksums concatenated separated by a comma">'.$checksumget.'</span>';
615 $outcurrentchecksumtext.= img_picto('', 'tick').' <span class="badge badge-status4 badge-status '.$resultcode.'">'.$langs->trans($resultcomment).'</span>';
616 }
617 } else {
618 $resultcode = 'error';
619 $resultcomment = 'FileIntegrityIsKO';
620 $outcurrentchecksum = '<span class="'.$resultcode.'" title="Checksum of all current checksums concatenated separated by a comma">'.$checksumget.'</span>';
621 $outcurrentchecksumtext .= img_picto('', 'error').' <span class="'.$resultcode.'">'.$langs->trans($resultcomment).'</span>';
622 }
623
624 // Show warning
625 if (empty($tmpfilelist) && empty($tmpfilelist2) && empty($tmpfilelist3) && $resultcode == 'ok') {
626 setEventMessages($langs->trans("FileIntegrityIsStrictlyConformedWithReference"), null, 'mesgs');
627 } else {
628 if ($resultcode == 'warning') {
629 setEventMessages($langs->trans($resultcomment), null, 'warnings');
630 } else {
631 setEventMessages($langs->trans("FileIntegritySomeFilesWereRemovedOrModified"), null, 'errors');
632 }
633 }
634
635 $outforlistoffiles = '';
636 if ($mode == 'unalterable') {
637 print load_fiche_titre($langs->trans("UnalterableFilesChecksum"));
638
639 // Print list of files
640 $outforlistoffiles = '<a href="#" onclick="console.log(\'Click\'); jQuery(\'#listofunalterablefiles\').toggle(); return false;">'.$langs->trans("ShowListOfFiles").'</a><br>';
641 $outforlistoffiles .= '<textarea id="listofunalterablefiles" class="hideobject quatrevingtpercent" rows="12" spellcheck="false">';
642 $i = 0;
643 foreach ($listoffilestoanalyze as $dirtoanalyze) {
644 $entry = array();
645 if (!empty($dirtoanalyze->md5file)) {
646 $entry = $dirtoanalyze->md5file;
647 $algo = 'md5';
648 } elseif (!empty($dirtoanalyze->sha256file)) {
649 $entry = $dirtoanalyze->sha256file;
650 $algo = 'sha256';
651 }
652
653 foreach ($entry as $filetoanalyze) {
654 if ($i) {
655 $outforlistoffiles .= "\n";
656 }
657 $outforlistoffiles .= (string) $dirtoanalyze['name'];
658 $outforlistoffiles .= '/';
659 $outforlistoffiles .= (string) $filetoanalyze['name'];
660 $i++;
661 }
662 }
663 $outforlistoffiles .= '</textarea>';
664 $outforlistoffiles .= '<br>';
665 } else {
666 print load_fiche_titre($langs->trans("GlobalChecksum"));
667 }
668
669
670 print '<div class="div-table-responsive-no-min">';
671 print '<table class="noborder">';
672 print '<tr class="liste_titre">';
673 print '<td>'.$langs->trans("ExpectedChecksum").' <span class="opacitymedium">('.$algo.')</span></td>';
674 print '<td>'.$langs->trans("CurrentChecksum").' <span class="opacitymedium">('.$algo.')</span></td>';
675 print '</tr>'."\n";
676
677 print '<tr><td>';
678 print '<span title="Checksum of all checksums in file separated by a comma and saved into '.$nameofsection.'">';
679 print $outexpectedchecksum;
680 print '</span>';
681 print '</td><td>';
682 print $outcurrentchecksum;
683 print '</td>';
684 print '</tr>';
685 print '</table>';
686 print $outcurrentchecksumtext.'<br>';
687
688 print '<br>';
689 print $outforlistoffiles;
690 print '<br><br>';
691
692
693 // Output detail
694 print $out;
695}
696
697// End of page
698llxFooter();
699$db->close();
700
701exit($error);
versiondolibarrarray()
Return version Dolibarr.
versioncompare($versionarray1, $versionarray2)
Compare 2 versions (stored into 2 arrays), to know if a version (a,b,c) is lower than (x,...
Definition admin.lib.php:72
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
getBlockedLogVersionToShow()
Define head array for tabs of blockedlog tools setup pages.
isALNEQualifiedVersion($ignoredev=0, $ignoremodule=0)
Return if the version is a candidate version to get the LNE certification and if the prerequisites ar...
isALNERunningVersion($blockedlogtestalreadydone=0, $blockedlogmodulealreadydone=0)
Return if the application is executed with the LNE requirements on.
Class to manage Dolibarr users.
Class to describe a BlockedLog module.
global $mysoc
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path='', $pathref='', &$checksumconcat=array())
Function to get list of updated or modified files.
dol_filemtime($pathoffile)
Return time of a file.
dol_filesize($pathoffile)
Return size of a file.
dol_uncompress($inputfile, $outputdir)
Uncompress a file.
dol_is_file($pathoffile)
Return if path is a file.
dol_dir_list($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:64
dol_print_size($size, $shortvalue=0, $shortunit=0)
Return string with formatted size.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='', $textonpictotooltip='')
Show information in HTML for admin users or standard users.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
getURLContent($url, $postorget='GET', $param='', $followlocation=1, $addheaders=array(), $allowedschemes=array('http', 'https'), $localurl=0, $ssl_verifypeer=-1, $timeoutconnect=0, $timeoutresponse=0, $otherCurlOptions=array(), $morelogsuffix='')
Function to get a content from an URL (use proxy if proxy defined).
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.