dolibarr 25.0.0-alpha
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-2026 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']);
491 $out .= ' <a href="#" class="showfilediff" data-file="'.dol_escape_htmltag($file['filename']).'" data-algo="'.dol_escape_htmltag($file['algo']).'" data-hash="'.dol_escape_htmltag($file['expectedhash']).'">';
492 $out .= img_picto($langs->trans("ShowDiffWithOriginal"), 'split', 'class="paddingleft"');
493 $out .= '</a>';
494 $out .= '</td>'."\n";
495 $out .= '<td class="center" title="'.dol_escape_htmltag($file['expectedhash']).'">'.dol_escape_htmltag(dol_trunc($file['expectedhash'], 16)).'</td>'."\n";
496 $out .= '<td class="center" title="'.dol_escape_htmltag($file['hash']).'">'.dol_escape_htmltag(dol_trunc($file['hash'], 16)).'</td>'."\n";
497 $out .= '<td class="right">';
498 if ($file['expectedsize']) {
499 $out .= dol_print_size((int) $file['expectedsize']);
500 }
501 $out .= '</td>'."\n";
502 $size = dol_filesize(DOL_DOCUMENT_ROOT.'/'.$file['filename']);
503 $totalsize += $size;
504 $out .= '<td class="right">'.dol_print_size($size).'</td>'."\n";
505 $out .= '<td class="right">'.dol_print_date(dol_filemtime(DOL_DOCUMENT_ROOT.'/'.$file['filename']), 'dayhour').'</td>'."\n";
506 $out .= "</tr>\n";
507 }
508 $out .= '<tr class="liste_total">';
509 $out .= '<td></td>'."\n";
510 $out .= '<td>'.$langs->trans("Total").'</td>'."\n";
511 $out .= '<td class="center"></td>'."\n";
512 $out .= '<td class="center"></td>'."\n";
513 $out .= '<td class="center"></td>'."\n";
514 $out .= '<td class="right">'.dol_print_size($totalsize).'</td>'."\n";
515 $out .= '<td class="right"></td>'."\n";
516 $out .= "</tr>\n";
517 } else {
518 $out .= '<tr class="oddeven"><td colspan="7"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
519 }
520 $out .= '</table>';
521 $out .= '</div>';
522
523 // Ajax loader for the per-file diff against the original version
524 $out .= '<script>'."\n";
525 $out .= 'jQuery(document).ready(function() {'."\n";
526 $out .= ' jQuery(".showfilediff").on("click", function(e) {'."\n";
527 $out .= ' e.preventDefault();'."\n";
528 $out .= ' var link = jQuery(this);'."\n";
529 $out .= ' var row = link.closest("tr");'."\n";
530 $out .= ' var existing = row.next(".filediffrow");'."\n";
531 $out .= ' if (existing.length) { existing.toggle(); return false; }'."\n";
532 $out .= ' var colspan = row.children("td").length;'."\n";
533 $out .= ' var newrow = jQuery(\'<tr class="filediffrow"><td colspan="\'+colspan+\'"><div class="filediffcontent opacitymedium">'.dol_escape_js($langs->trans("Loading")).'...</div></td></tr>\');'."\n";
534 $out .= ' row.after(newrow);'."\n";
535 $out .= ' jQuery.get("'.dol_escape_js(DOL_URL_ROOT).'/blockedlog/admin/filecheck_diff.php", { file: link.attr("data-file"), algo: link.attr("data-algo"), expectedhash: link.attr("data-hash"), token: "'.newToken().'" }, function(data) {'."\n";
536 $out .= ' newrow.find(".filediffcontent").removeClass("opacitymedium").html(data);'."\n";
537 $out .= ' }).fail(function() {'."\n";
538 $out .= ' newrow.find(".filediffcontent").html("'.dol_escape_js($langs->trans("Error")).'");'."\n";
539 $out .= ' });'."\n";
540 $out .= ' return false;'."\n";
541 $out .= ' });'."\n";
542 $out .= '});'."\n";
543 $out .= '</script>'."\n";
544
545 $out .= '<br>';
546
547 // Files added
548 if (empty($onlymodifiedorremoved)) {
549 $out .= load_fiche_titre($langs->trans("FilesAdded"));
550
551 $totalsize = 0;
552 $out .= '<div class="div-table-responsive-no-min">';
553 $out .= '<table class="noborder">';
554 $out .= '<tr class="liste_titre">';
555 $out .= '<td>#</td>';
556 $out .= '<td>'.$langs->trans("Filename").'</td>';
557 $out .= '<td class="center">'.$langs->trans("ExpectedChecksum").'</td>';
558 $out .= '<td class="center">'.$langs->trans("CurrentChecksum").'</td>';
559 $out .= '<td class="right">'.$langs->trans("Size").'</td>';
560 $out .= '<td class="right">'.$langs->trans("DateModification").'</td>';
561 $out .= '</tr>'."\n";
562 $tmpfilelist3 = dol_sort_array($file_list['added'], 'filename');
563 if (is_array($tmpfilelist3) && count($tmpfilelist3)) {
564 $i = 0;
565 foreach ($tmpfilelist3 as $file) {
566 $i++;
567 $out .= '<tr class="oddeven">';
568 $out .= '<td>'.$i.'</td>'."\n";
569 $out .= '<td>'.dol_escape_htmltag($file['filename']);
570 if (!preg_match('/^win/i', PHP_OS)) {
571 $htmltext = $langs->trans("YouCanDeleteFileOnServerWith", 'rm '.DOL_DOCUMENT_ROOT.$file['filename']); // The slash is included int file['filename']
572 $out .= ' '.$form->textwithpicto('', $htmltext, 1, 'help', '', 0, 2, 'helprm'.$i);
573 }
574 $out .= '</td>'."\n";
575 $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
576 $out .= '<td class="center" title="'.dol_escape_htmltag((string) $file['hash']).'">'.dol_escape_htmltag(dol_trunc($file['hash'], 16)).'</td>'."\n";
577 $size = dol_filesize(DOL_DOCUMENT_ROOT.'/'.$file['filename']);
578 $totalsize += $size;
579 $out .= '<td class="right">'.dol_print_size($size).'</td>'."\n";
580 $out .= '<td class="right nowraponall">'.dol_print_date(dol_filemtime(DOL_DOCUMENT_ROOT.'/'.$file['filename']), 'dayhour').'</td>'."\n";
581 $out .= "</tr>\n";
582 }
583 $out .= '<tr class="liste_total">';
584 $out .= '<td></td>'."\n";
585 $out .= '<td>'.$langs->trans("Total").'</td>'."\n";
586 $out .= '<td class="center"></td>'."\n";
587 $out .= '<td class="center"></td>'."\n";
588 $out .= '<td class="right">'.dol_print_size($totalsize).'</td>'."\n";
589 $out .= '<td class="right"></td>'."\n";
590 $out .= "</tr>\n";
591 } else {
592 $out .= '<tr class="oddeven"><td colspan="6"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
593 }
594 $out .= '</table>';
595 $out .= '</div>';
596 }
597 } else {
598 print '<div class="error">';
599 print 'Error: Failed to found <b>dolibarr_htdocs_dir</b> into content of XML file:<br>'.dol_escape_htmltag(dol_trunc($xmlfile, 500));
600 print '</div><br>';
601 $error++;
602 }
603
604
605 // Scan scripts
606 /*
607 if (is_object($xml->dolibarr_scripts_dir[0])) {
608 $file_list = array();
609 $ret = getFilesUpdated($file_list, $xml->dolibarr_htdocs_dir[0], '', ???, $checksumconcat); // Fill array $file_list
610 '@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';
611 }*/
612
613
614 // Section Globalchecksum
615 asort($checksumconcat); // Sort list of checksum
616
617 $checksumget = hash($algo, implode(',', $checksumconcat));
618
619 if ($mode == 'unalterable') {
620 $nameofsection = 'dolibarr_unalterable_files_checksum';
621 $checksumtoget = trim((string) $xml->dolibarr_unalterable_files_checksum);
622 } else {
623 $nameofsection = 'dolibarr_htdocs_dir_checksum';
624 $checksumtoget = trim((string) $xml->dolibarr_htdocs_dir_checksum);
625 }
626
627 $resultcomment = '';
628
629 $outexpectedchecksum = ($checksumtoget ? $checksumtoget : $langs->trans("Unknown"));
630 $outcurrentchecksumtext = '';
631 if ($checksumget == $checksumtoget) {
632 if (empty($onlymodifiedorremoved) && !empty($file_list['added'])) {
633 $resultcode = 'warning';
634 $resultcomment = 'FileIntegrityIsOkButFilesWereAdded';
635 $outcurrentchecksum = $checksumget;
636 $outcurrentchecksumtext .= img_picto('', 'tick').' <span class="'.$resultcode.'">'.$langs->trans($resultcomment).'</span>';
637 } else {
638 $resultcode = 'ok';
639 $resultcomment = 'Success';
640 $outcurrentchecksum = '<span class="'.$resultcode.'" title="Checksum of all current checksums concatenated separated by a comma">'.$checksumget.'</span>';
641 $outcurrentchecksumtext.= img_picto('', 'tick').' <span class="badge badge-status4 badge-status '.$resultcode.'">'.$langs->trans($resultcomment).'</span>';
642 }
643 } else {
644 $resultcode = 'error';
645 $resultcomment = 'FileIntegrityIsKO';
646 $outcurrentchecksum = '<span class="'.$resultcode.'" title="Checksum of all current checksums concatenated separated by a comma">'.$checksumget.'</span>';
647 $outcurrentchecksumtext .= img_picto('', 'error').' <span class="'.$resultcode.'">'.$langs->trans($resultcomment).'</span>';
648 }
649
650 // Show warning
651 if (empty($tmpfilelist) && empty($tmpfilelist2) && empty($tmpfilelist3) && $resultcode == 'ok') {
652 setEventMessages($langs->trans("FileIntegrityIsStrictlyConformedWithReference"), null, 'mesgs');
653 } else {
654 if ($resultcode == 'warning') {
655 setEventMessages($langs->trans($resultcomment), null, 'warnings');
656 } else {
657 setEventMessages($langs->trans("FileIntegritySomeFilesWereRemovedOrModified"), null, 'errors');
658 }
659 }
660
661 $outforlistoffiles = '';
662 if ($mode == 'unalterable') {
663 print load_fiche_titre($langs->trans("UnalterableFilesChecksum"));
664
665 // Print list of files
666 $outforlistoffiles = '<a href="#" onclick="console.log(\'Click\'); jQuery(\'#listofunalterablefiles\').toggle(); return false;">'.$langs->trans("ShowListOfFiles").'</a><br>';
667 $outforlistoffiles .= '<textarea id="listofunalterablefiles" class="hideobject quatrevingtpercent" rows="12" spellcheck="false">';
668 $i = 0;
669 foreach ($listoffilestoanalyze as $dirtoanalyze) {
670 $entry = array();
671 if (!empty($dirtoanalyze->md5file)) {
672 $entry = $dirtoanalyze->md5file;
673 $algo = 'md5';
674 } elseif (!empty($dirtoanalyze->sha256file)) {
675 $entry = $dirtoanalyze->sha256file;
676 $algo = 'sha256';
677 }
678
679 foreach ($entry as $filetoanalyze) {
680 if ($i) {
681 $outforlistoffiles .= "\n";
682 }
683 $outforlistoffiles .= (string) $dirtoanalyze['name'];
684 $outforlistoffiles .= '/';
685 $outforlistoffiles .= (string) $filetoanalyze['name'];
686 $i++;
687 }
688 }
689 $outforlistoffiles .= '</textarea>';
690 $outforlistoffiles .= '<br>';
691 } else {
692 print load_fiche_titre($langs->trans("GlobalChecksum"));
693 }
694
695
696 print '<div class="div-table-responsive-no-min">';
697 print '<table class="noborder">';
698 print '<tr class="liste_titre">';
699 print '<td>'.$langs->trans("ExpectedChecksum").' <span class="opacitymedium">('.$algo.')</span></td>';
700 print '<td>'.$langs->trans("CurrentChecksum").' <span class="opacitymedium">('.$algo.')</span></td>';
701 print '</tr>'."\n";
702
703 print '<tr><td>';
704 print '<span title="Checksum of all checksums in file separated by a comma and saved into '.$nameofsection.'">';
705 print $outexpectedchecksum;
706 print '</span>';
707 print '</td><td>';
708 print $outcurrentchecksum;
709 print '</td>';
710 print '</tr>';
711 print '</table>';
712 print $outcurrentchecksumtext.'<br>';
713
714 print '<br>';
715 print $outforlistoffiles;
716 print '<br><br>';
717
718
719 // Output detail
720 print $out;
721}
722
723// End of page
724llxFooter();
725$db->close();
726
727exit($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)
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...
newToken()
Return the value of token currently saved into session with name 'newtoken'.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=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.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='', $textonpictotooltip='', $cssfordropdown='info_admin')
Show information in HTML for admin users or standard users.
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.