dolibarr  9.0.0
filecheck.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2005-2016 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 Frederic France <frederic.france@free.fr>
6  * Copyright (C) 2017 Nicolas ZABOURI <info@inovea-conseil.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
27 require '../../main.inc.php';
28 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
29 require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
30 
31 $langs->load("admin");
32 
33 if (!$user->admin)
35 
36 $error=0;
37 
38 
39 /*
40  * View
41  */
42 
43 @set_time_limit(300);
44 
45 llxHeader();
46 
47 print load_fiche_titre($langs->trans("FileCheckDolibarr"),'','title_setup');
48 
49 print $langs->trans("FileCheckDesc").'<br><br>';
50 
51 // Version
52 print '<div class="div-table-responsive-no-min">';
53 print '<table class="noborder" width="100%">';
54 print '<tr class="liste_titre"><td>'.$langs->trans("Version").'</td><td>'.$langs->trans("Value").'</td></tr>'."\n";
55 print '<tr class="oddeven"><td width="300">'.$langs->trans("VersionLastInstall").'</td><td>'.$conf->global->MAIN_VERSION_LAST_INSTALL.'</td></tr>'."\n";
56 print '<tr class="oddeven"><td width="300">'.$langs->trans("VersionLastUpgrade").'</td><td>'.$conf->global->MAIN_VERSION_LAST_UPGRADE.'</td></tr>'."\n";
57 print '<tr class="oddeven"><td width="300">'.$langs->trans("VersionProgram").'</td><td>'.DOL_VERSION;
58 // If current version differs from last upgrade
59 if (empty($conf->global->MAIN_VERSION_LAST_UPGRADE)) {
60  // Compare version with last install database version (upgrades never occured)
61  if (DOL_VERSION != $conf->global->MAIN_VERSION_LAST_INSTALL)
62  print ' '.img_warning($langs->trans("RunningUpdateProcessMayBeRequired",DOL_VERSION,$conf->global->MAIN_VERSION_LAST_INSTALL));
63 } else {
64  // Compare version with last upgrade database version
65  if (DOL_VERSION != $conf->global->MAIN_VERSION_LAST_UPGRADE)
66  print ' '.img_warning($langs->trans("RunningUpdateProcessMayBeRequired",DOL_VERSION,$conf->global->MAIN_VERSION_LAST_UPGRADE));
67 }
68 print '</td></tr>'."\n";
69 print '</table>';
70 print '</div>';
71 print '<br>';
72 
73 
74 // Modified or missing files
75 $file_list = array('missing' => array(), 'updated' => array());
76 
77 // Local file to compare to
78 $xmlshortfile = GETPOST('xmlshortfile','alpha')?GETPOST('xmlshortfile','alpha'):'/install/filelist-'.DOL_VERSION.(empty($conf->global->MAIN_FILECHECK_LOCAL_SUFFIX)?'':$conf->global->MAIN_FILECHECK_LOCAL_SUFFIX).'.xml';
79 $xmlfile = DOL_DOCUMENT_ROOT.$xmlshortfile;
80 // Remote file to compare to
81 $xmlremote = GETPOST('xmlremote');
82 if (empty($xmlremote) && ! empty($conf->global->MAIN_FILECHECK_URL)) $xmlremote = $conf->global->MAIN_FILECHECK_URL;
83 $param='MAIN_FILECHECK_URL_'.DOL_VERSION;
84 if (empty($xmlremote) && ! empty($conf->global->$param)) $xmlremote = $conf->global->$param;
85 if (empty($xmlremote)) $xmlremote = 'https://www.dolibarr.org/files/stable/signatures/filelist-'.DOL_VERSION.'.xml';
86 
87 
88 // Test if remote test is ok
89 $enableremotecheck = true;
90 if (preg_match('/beta|alpha|rc/i', DOL_VERSION) || ! empty($conf->global->MAIN_ALLOW_INTEGRITY_CHECK_ON_UNSTABLE)) $enableremotecheck=false;
91 $enableremotecheck = true;
92 
93 print '<form name="check" action="'.$_SERVER["PHP_SELF"].'">';
94 print $langs->trans("MakeIntegrityAnalysisFrom").':<br>';
95 print '<!-- for a local check target=local&xmlshortfile=... -->'."\n";
96 if (dol_is_file($xmlfile))
97 {
98  print '<input type="radio" name="target" value="local"'.((! GETPOST('target') || GETPOST('target') == 'local') ? 'checked="checked"':'').'"> '.$langs->trans("LocalSignature").' = ';
99  print '<input name="xmlshortfile" class="flat minwidth400" value="'.dol_escape_htmltag($xmlshortfile).'">';
100  print '<br>';
101 }
102 else
103 {
104  print '<input type="radio" name="target" value="local"> '.$langs->trans("LocalSignature").' = ';
105  print '<input name="xmlshortfile" class="flat minwidth400" value="'.dol_escape_htmltag($xmlshortfile).'">';
106  print ' <span class="warning">('.$langs->trans("AvailableOnlyOnPackagedVersions").')</span>';
107  print '<br>';
108 }
109 print '<!-- for a remote target=remote&xmlremote=... -->'."\n";
110 if ($enableremotecheck)
111 {
112  print '<input type="radio" name="target" value="remote"'.(GETPOST('target') == 'remote' ? 'checked="checked"':'').'> '.$langs->trans("RemoteSignature").' = ';
113  print '<input name="xmlremote" class="flat minwidth400" value="'.dol_escape_htmltag($xmlremote).'"><br>';
114 }
115 else
116 {
117  print '<input type="radio" name="target" value="remote" disabled="disabled"> '.$langs->trans("RemoteSignature").' = '.$xmlremote;
118  if (! GETPOST('xmlremote')) print ' <span class="warning">('.$langs->trans("FeatureAvailableOnlyOnStable").')</span>';
119  print '<br>';
120 }
121 print '<br><div class="center"><input type="submit" name="check" class="button" value="'.$langs->trans("Check").'"></div>';
122 print '</form>';
123 print '<br>';
124 print '<br>';
125 
126 if (GETPOST('target') == 'local')
127 {
128  if (dol_is_file($xmlfile))
129  {
130  $xml = simplexml_load_file($xmlfile);
131  }
132  else
133  {
134  print $langs->trans('XmlNotFound') . ': ' . $xmlfile;
135  $error++;
136  }
137 }
138 if (GETPOST('target') == 'remote')
139 {
140  $xmlarray = getURLContent($xmlremote);
141 
142  // Return array('content'=>response,'curl_error_no'=>errno,'curl_error_msg'=>errmsg...)
143  if (! $xmlarray['curl_error_no'] && $xmlarray['http_code'] != '404')
144  {
145  $xmlfile = $xmlarray['content'];
146  //print "xmlfilestart".$xmlfile."xmlfileend";
147  $xml = simplexml_load_string($xmlfile);
148  }
149  else
150  {
151  $errormsg=$langs->trans('XmlNotFound') . ': ' . $xmlremote.' - '.$xmlarray['http_code'].' '.$xmlarray['curl_error_no'].' '.$xmlarray['curl_error_msg'];
152  setEventMessages($errormsg, null, 'errors');
153  $error++;
154  }
155 }
156 
157 
158 if (! $error && $xml)
159 {
160  $checksumconcat = array();
161  $file_list = array();
162  $out = '';
163 
164  // Forced constants
165  if (is_object($xml->dolibarr_constants[0]))
166  {
167  $out.=load_fiche_titre($langs->trans("ForcedConstants"));
168 
169  $out.='<div class="div-table-responsive-no-min">';
170  $out.='<table class="noborder">';
171  $out.='<tr class="liste_titre">';
172  $out.='<td>#</td>';
173  $out.='<td>' . $langs->trans("Constant") . '</td>';
174  $out.='<td align="center">' . $langs->trans("ExpectedValue") . '</td>';
175  $out.='<td align="center">' . $langs->trans("Value") . '</td>';
176  $out.='</tr>'."\n";
177 
178  $i = 0;
179  foreach ($xml->dolibarr_constants[0]->constant as $constant) // $constant is a simpleXMLElement
180  {
181  $constname=$constant['name'];
182  $constvalue=(string) $constant;
183  $constvalue = (empty($constvalue)?'0':$constvalue);
184  // Value found
185  $value='';
186  if ($constname && $conf->global->$constname != '') $value=$conf->global->$constname;
187  $valueforchecksum=(empty($value)?'0':$value);
188 
189  $checksumconcat[]=$valueforchecksum;
190 
191  $i++;
192  $out.='<tr class="oddeven">';
193  $out.='<td>'.$i.'</td>' . "\n";
194  $out.='<td>'.$constname.'</td>' . "\n";
195  $out.='<td align="center">'.$constvalue.'</td>' . "\n";
196  $out.='<td align="center">'.$valueforchecksum.'</td>' . "\n";
197  $out.="</tr>\n";
198  }
199 
200  if ($i==0)
201  {
202  $out.='<tr class="oddeven"><td colspan="4" class="opacitymedium">'.$langs->trans("None").'</td></tr>';
203  }
204  $out.='</table>';
205  $out.='</div>';
206 
207  $out.='<br>';
208  }
209 
210  // Scan htdocs
211  if (is_object($xml->dolibarr_htdocs_dir[0]))
212  {
213  //var_dump($xml->dolibarr_htdocs_dir[0]['includecustom']);exit;
214  $includecustom=(empty($xml->dolibarr_htdocs_dir[0]['includecustom'])?0:$xml->dolibarr_htdocs_dir[0]['includecustom']);
215 
216  // Defined qualified files (must be same than into generate_filelist_xml.php)
217  $regextoinclude='\.(php|css|html|js|json|tpl|jpg|png|gif|sql|lang)$';
218  $regextoexclude='('.($includecustom?'':'custom|').'documents|conf|install|public\/test|Shared\/PCLZip|nusoap\/lib\/Mail|php\/example|php\/test|geoip\/sample.*\.php|ckeditor\/samples|ckeditor\/adapters)$'; // Exclude dirs
219  $scanfiles = dol_dir_list(DOL_DOCUMENT_ROOT, 'files', 1, $regextoinclude, $regextoexclude);
220 
221  // Fill file_list with files in signature, new files, modified files
222  $ret = getFilesUpdated($file_list, $xml->dolibarr_htdocs_dir[0], '', DOL_DOCUMENT_ROOT, $checksumconcat, $scanfiles); // Fill array $file_list
223  // Complete with list of new files
224  foreach ($scanfiles as $keyfile => $valfile)
225  {
226  $tmprelativefilename=preg_replace('/^'.preg_quote(DOL_DOCUMENT_ROOT,'/').'/','', $valfile['fullname']);
227  if (! in_array($tmprelativefilename, $file_list['insignature']))
228  {
229  $md5newfile=@md5_file($valfile['fullname']); // Can fails if we don't have permission to open/read file
230  $file_list['added'][]=array('filename'=>$tmprelativefilename, 'md5'=>$md5newfile);
231  }
232  }
233 
234  // Files missings
235  $out.=load_fiche_titre($langs->trans("FilesMissing"));
236 
237  $out.='<div class="div-table-responsive-no-min">';
238  $out.='<table class="noborder">';
239  $out.='<tr class="liste_titre">';
240  $out.='<td>#</td>';
241  $out.='<td>' . $langs->trans("Filename") . '</td>';
242  $out.='<td align="center">' . $langs->trans("ExpectedChecksum") . '</td>';
243  $out.='</tr>'."\n";
244  $tmpfilelist = dol_sort_array($file_list['missing'], 'filename');
245  if (is_array($tmpfilelist) && count($tmpfilelist))
246  {
247  $i = 0;
248  foreach ($tmpfilelist as $file)
249  {
250  $i++;
251  $out.='<tr class="oddeven">';
252  $out.='<td>'.$i.'</td>' . "\n";
253  $out.='<td>'.$file['filename'].'</td>' . "\n";
254  $out.='<td align="center">'.$file['expectedmd5'].'</td>' . "\n";
255  $out.="</tr>\n";
256  }
257  }
258  else
259  {
260  $out.='<tr class="oddeven"><td colspan="3" class="opacitymedium">'.$langs->trans("None").'</td></tr>';
261  }
262  $out.='</table>';
263  $out.='</div>';
264 
265  $out.='<br>';
266 
267  // Files modified
268  $out.=load_fiche_titre($langs->trans("FilesModified"));
269 
270  $totalsize=0;
271  $out.='<div class="div-table-responsive-no-min">';
272  $out.='<table class="noborder">';
273  $out.='<tr class="liste_titre">';
274  $out.='<td>#</td>';
275  $out.='<td>' . $langs->trans("Filename") . '</td>';
276  $out.='<td align="center">' . $langs->trans("ExpectedChecksum") . '</td>';
277  $out.='<td align="center">' . $langs->trans("CurrentChecksum") . '</td>';
278  $out.='<td align="right">' . $langs->trans("Size") . '</td>';
279  $out.='<td align="right">' . $langs->trans("DateModification") . '</td>';
280  $out.='</tr>'."\n";
281  $tmpfilelist2 = dol_sort_array($file_list['updated'], 'filename');
282  if (is_array($tmpfilelist2) && count($tmpfilelist2))
283  {
284  $i = 0;
285  foreach ($tmpfilelist2 as $file)
286  {
287  $i++;
288  $out.='<tr class="oddeven">';
289  $out.='<td>'.$i.'</td>' . "\n";
290  $out.='<td>'.$file['filename'].'</td>' . "\n";
291  $out.='<td align="center">'.$file['expectedmd5'].'</td>' . "\n";
292  $out.='<td align="center">'.$file['md5'].'</td>' . "\n";
293  $size = dol_filesize(DOL_DOCUMENT_ROOT.'/'.$file['filename']);
294  $totalsize += $size;
295  $out.='<td align="right">'.dol_print_size($size).'</td>' . "\n";
296  $out.='<td align="right">'.dol_print_date(dol_filemtime(DOL_DOCUMENT_ROOT.'/'.$file['filename']),'dayhour').'</td>' . "\n";
297  $out.="</tr>\n";
298  }
299  $out.='<tr class="liste_total">';
300  $out.='<td></td>' . "\n";
301  $out.='<td>'.$langs->trans("Total").'</td>' . "\n";
302  $out.='<td align="center"></td>' . "\n";
303  $out.='<td align="center"></td>' . "\n";
304  $out.='<td align="right">'.dol_print_size($totalsize).'</td>' . "\n";
305  $out.='<td align="right"></td>' . "\n";
306  $out.="</tr>\n";
307  }
308  else
309  {
310  $out.='<tr class="oddeven"><td colspan="6" class="opacitymedium">'.$langs->trans("None").'</td></tr>';
311  }
312  $out.='</table>';
313  $out.='</div>';
314 
315  $out.='<br>';
316 
317  // Files added
318  $out.=load_fiche_titre($langs->trans("FilesAdded"));
319 
320  $totalsize = 0;
321  $out.='<div class="div-table-responsive-no-min">';
322  $out.='<table class="noborder">';
323  $out.='<tr class="liste_titre">';
324  $out.='<td>#</td>';
325  $out.='<td>' . $langs->trans("Filename") . '</td>';
326  $out.='<td align="center">' . $langs->trans("ExpectedChecksum") . '</td>';
327  $out.='<td align="center">' . $langs->trans("CurrentChecksum") . '</td>';
328  $out.='<td align="right">' . $langs->trans("Size") . '</td>';
329  $out.='<td align="right">' . $langs->trans("DateModification") . '</td>';
330  $out.='</tr>'."\n";
331  $tmpfilelist3 = dol_sort_array($file_list['added'], 'filename');
332  if (is_array($tmpfilelist3) && count($tmpfilelist3))
333  {
334  $i = 0;
335  foreach ($tmpfilelist3 as $file)
336  {
337  $i++;
338  $out.='<tr class="oddeven">';
339  $out.='<td>'.$i.'</td>' . "\n";
340  $out.='<td>'.$file['filename'];
341  if (! preg_match('/^win/i',PHP_OS)) {
342  $htmltext=$langs->trans("YouCanDeleteFileOnServerWith", 'rm '.DOL_DOCUMENT_ROOT.'/'.$file['filename']);
343  $out.=' '.$form->textwithpicto('', $htmltext, 1, 'help', '', 0, 2, 'helprm');
344  }
345  $out.='</td>' . "\n";
346  $out.='<td align="center">'.$file['expectedmd5'].'</td>' . "\n";
347  $out.='<td align="center">'.$file['md5'].'</td>' . "\n";
348  $size = dol_filesize(DOL_DOCUMENT_ROOT.'/'.$file['filename']);
349  $totalsize += $size;
350  $out.='<td align="right">'.dol_print_size($size).'</td>' . "\n";
351  $out.='<td align="right">'.dol_print_date(dol_filemtime(DOL_DOCUMENT_ROOT.'/'.$file['filename']),'dayhour').'</td>' . "\n";
352  $out.="</tr>\n";
353  }
354  $out.='<tr class="liste_total">';
355  $out.='<td></td>' . "\n";
356  $out.='<td>'.$langs->trans("Total").'</td>' . "\n";
357  $out.='<td align="center"></td>' . "\n";
358  $out.='<td align="center"></td>' . "\n";
359  $out.='<td align="right">'.dol_print_size($totalsize).'</td>' . "\n";
360  $out.='<td align="right"></td>' . "\n";
361  $out.="</tr>\n";
362  }
363  else
364  {
365  $out.='<tr class="oddeven"><td colspan="5" class="opacitymedium">'.$langs->trans("None").'</td></tr>';
366  }
367  $out.='</table>';
368  $out.='</div>';
369 
370 
371  // Show warning
372  if (empty($tmpfilelist) && empty($tmpfilelist2) && empty($tmpfilelist3))
373  {
374  setEventMessages($langs->trans("FileIntegrityIsStrictlyConformedWithReference"), null, 'mesgs');
375  }
376  else
377  {
378  setEventMessages($langs->trans("FileIntegritySomeFilesWereRemovedOrModified"), null, 'warnings');
379  }
380  }
381  else
382  {
383  print 'Error: Failed to found dolibarr_htdocs_dir into XML file '.$xmlfile;
384  $error++;
385  }
386 
387 
388  // Scan scripts
389  /*
390  if (is_object($xml->dolibarr_script_dir[0]))
391  {
392  $file_list = array();
393  $ret = getFilesUpdated($file_list, $xml->dolibarr_htdocs_dir[0], '', ???, $checksumconcat); // Fill array $file_list
394  }*/
395 
396 
397  asort($checksumconcat); // Sort list of checksum
398  //var_dump($checksumconcat);
399  $checksumget = md5(join(',',$checksumconcat));
400  $checksumtoget = trim((string) $xml->dolibarr_htdocs_dir_checksum);
401 
402  /*var_dump(count($file_list['added']));
403  var_dump($checksumget);
404  var_dump($checksumtoget);
405  var_dump($checksumget == $checksumtoget);*/
406 
407  $outexpectedchecksum = ($checksumtoget ? $checksumtoget : $langs->trans("Unknown"));
408  if ($checksumget == $checksumtoget)
409  {
410  if (count($file_list['added']))
411  {
412  $resultcode = 'warning';
413  $resultcomment='FileIntegrityIsOkButFilesWereAdded';
414  $outcurrentchecksum = $checksumget.' - <span class="'.$resultcode.'">'.$langs->trans("FileIntegrityIsOkButFilesWereAdded").'</span>';
415  }
416  else
417  {
418  $resultcode = 'ok';
419  $resultcomment='Success';
420  $outcurrentchecksum = '<span class="'.$resultcode.'">'.$checksumget.'</span>';
421  }
422  }
423  else
424  {
425  $resultcode = 'error';
426  $resultcomment='Error';
427  $outcurrentchecksum = '<span class="'.$resultcode.'">'.$checksumget.'</span>';
428  }
429 
430  print load_fiche_titre($langs->trans("GlobalChecksum")).'<br>';
431  print $langs->trans("ExpectedChecksum").' = '. $outexpectedchecksum .'<br>';
432  print $langs->trans("CurrentChecksum").' = '. $outcurrentchecksum;
433 
434  print '<br>';
435  print '<br>';
436 
437  // Output detail
438  print $out;
439 }
440 
441 // End of page
442 llxFooter();
443 $db->close();
444 
445 exit($error);
llxFooter()
Empty footer.
Definition: wrapper.php:56
load_fiche_titre($titre, $morehtmlright='', $picto='title_generic.png', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
GETPOST($paramname, $check='none', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
print
Draft customers invoices.
Definition: index.php:91
setEventMessages($mesg, $mesgs, $style='mesgs')
Set event messages in dol_events session object.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
dol_filesize($pathoffile)
Return size of a file.
Definition: files.lib.php:552
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0)
Show a message to say access is forbidden and stop program Calling this function terminate execution ...
getURLContent($url, $postorget='GET', $param='', $followlocation=1, $addheaders=array())
Function get content from an URL (use proxy if proxy defined)
Definition: geturl.lib.php:34
llxHeader()
Empty header.
Definition: wrapper.php:44
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:59
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:451
dol_filemtime($pathoffile)
Return time of a file.
Definition: files.lib.php:564
getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path='', $pathref='', &$checksumconcat=array())
Function to get list of updated or modified files.
Definition: files.lib.php:2922