diff --git a/htdocs/admin/system/filecheck.php b/htdocs/admin/system/filecheck.php index 8aed7d193f9..60c20dfafe7 100644 --- a/htdocs/admin/system/filecheck.php +++ b/htdocs/admin/system/filecheck.php @@ -152,7 +152,7 @@ if (GETPOST('target') == 'remote') } -if ($xml) +if (! $error && $xml) { $checksumconcat = array(); $file_list = array(); @@ -395,19 +395,34 @@ if ($xml) var_dump($checksumget); var_dump($checksumtoget); var_dump($checksumget == $checksumtoget);*/ - print_fiche_titre($langs->trans("GlobalChecksum")).'
'; - print $langs->trans("ExpectedChecksum").' = '. ($checksumtoget ? $checksumtoget : $langs->trans("Unknown")) .'
'; - print $langs->trans("CurrentChecksum").' = '; + + $outexpectedchecksum = ($checksumtoget ? $checksumtoget : $langs->trans("Unknown")); if ($checksumget == $checksumtoget) { - if (count($file_list['added'])) print $checksumget.' - '.$langs->trans("FileIntegrityIsOkButFilesWereAdded").''; - else print ''.$checksumget.''; + if (count($file_list['added'])) + { + $resultcode = 'warning'; + $resultcomment='FileIntegrityIsOkButFilesWereAdded'; + $outcurrentchecksum = $checksumget.' - '.$langs->trans("FileIntegrityIsOkButFilesWereAdded").''; + } + else + { + $resultcode = 'ok'; + $resultcomment='Success'; + $outcurrentchecksum = ''.$checksumget.''; + } } else { - print ''.$checksumget.''; + $resultcode = 'error'; + $resultcomment='Error'; + $outcurrentchecksum = ''.$checksumget.''; } + print_fiche_titre($langs->trans("GlobalChecksum")).'
'; + print $langs->trans("ExpectedChecksum").' = '. $outexpectedchecksum .'
'; + print $langs->trans("CurrentChecksum").' = '. $outcurrentchecksum; + print '
'; print '
'; @@ -424,43 +439,3 @@ $db->close(); exit($error); - -/** - * Function to get list of updated or modified files. - * $file_list is used as global variable - * - * @param array $file_list Array for response - * @param SimpleXMLElement $dir SimpleXMLElement of files to test - * @param string $path Path of files relative to $pathref. We start with ''. Used by recursive calls. - * @param string $pathref Path ref (DOL_DOCUMENT_ROOT) - * @param array $checksumconcat Array of checksum - * @return array Array of filenames - */ -function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathref = '', &$checksumconcat = array()) -{ - $exclude = 'install'; - - foreach ($dir->md5file as $file) // $file is a simpleXMLElement - { - $filename = $path.$file['name']; - $file_list['insignature'][] = $filename; - - //if (preg_match('#'.$exclude.'#', $filename)) continue; - - if (!file_exists($pathref.'/'.$filename)) - { - $file_list['missing'][] = array('filename'=>$filename, 'expectedmd5'=>(string) $file); - } - else - { - $md5_local = md5_file($pathref.'/'.$filename); - if ($md5_local != (string) $file) $file_list['updated'][] = array('filename'=>$filename, 'expectedmd5'=>(string) $file, 'md5'=>(string) $md5_local); - $checksumconcat[] = $md5_local; - } - } - - foreach ($dir->dir as $subdir) getFilesUpdated($file_list, $subdir, $path.$subdir['name'].'/', $pathref, $checksumconcat); - - return $file_list; -} - diff --git a/htdocs/api/class/api_setup.class.php b/htdocs/api/class/api_setup.class.php index 9a5b18ca95d..caba92f2947 100644 --- a/htdocs/api/class/api_setup.class.php +++ b/htdocs/api/class/api_setup.class.php @@ -329,7 +329,7 @@ class Setup extends DolibarrApi * * @throws RestException */ - function getListOfEvents($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $type = '', $module = '', $sqlfilters = '') + function getListOfEventTypes($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $type = '', $module = '', $sqlfilters = '') { $list = array(); @@ -577,4 +577,345 @@ class Setup extends DolibarrApi return $list; } + + /** + * Do a test of integrity for files and setup. + * + * @param string $target Can be 'local' or 'default' or Url of the signatures file to use for the test. Must be reachable by the tested Dolibarr. + * @return Result of file and setup integrity check + * + * @url GET checkintegrity + * + * @throws RestException + */ + function getCheckIntegrity($target) + { + global $langs, $conf; + + if (! DolibarrApiAccess::$user->admin + && (empty($conf->global->API_LOGIN_ALLOWED_FOR_INTEGRITY_CHECK) || DolibarrApiAccess::$user->login != $conf->global->API_LOGIN_ALLOWED_FOR_INTEGRITY_CHECK)) + { + throw new RestException(503, 'Error API open to admin users only or to login user defined with constant API_LOGIN_ALLOWED_FOR_INTEGRITY_CHECK'); + } + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php'; + + $langs->load("admin"); + + $outexpectedchecksum = ''; + $outcurrentchecksum = ''; + + // Modified or missing files + $file_list = array('missing' => array(), 'updated' => array()); + + // Local file to compare to + $xmlshortfile = GETPOST('xmlshortfile')?GETPOST('xmlshortfile'):'/install/filelist-'.DOL_VERSION.'.xml'; + $xmlfile = DOL_DOCUMENT_ROOT.$xmlshortfile; + // Remote file to compare to + $xmlremote = ($target == 'default' ? '' : $target); + if (empty($xmlremote) && ! empty($conf->global->MAIN_FILECHECK_URL)) $xmlremote = $conf->global->MAIN_FILECHECK_URL; + $param='MAIN_FILECHECK_URL_'.DOL_VERSION; + if (empty($xmlremote) && ! empty($conf->global->$param)) $xmlremote = $conf->global->$param; + if (empty($xmlremote)) $xmlremote = 'https://www.dolibarr.org/files/stable/signatures/filelist-'.DOL_VERSION.'.xml'; + + if ($target == 'local') + { + if (dol_is_file($xmlfile)) + { + $xml = simplexml_load_file($xmlfile); + } + else + { + throw new RestException(500, $langs->trans('XmlNotFound') . ': ' . $xmlfile); + $error++; + } + } + else + { + $xmlarray = getURLContent($xmlremote); + + // Return array('content'=>response,'curl_error_no'=>errno,'curl_error_msg'=>errmsg...) + if (! $xmlarray['curl_error_no'] && $xmlarray['http_code'] != '404') + { + $xmlfile = $xmlarray['content']; + //print "eee".$xmlfile."eee"; + $xml = simplexml_load_string($xmlfile); + } + else + { + $errormsg=$langs->trans('XmlNotFound') . ': ' . $xmlremote.' - '.$xmlarray['http_code'].' '.$xmlarray['curl_error_no'].' '.$xmlarray['curl_error_msg']; + throw new RestException(500, $errormsg); + $error++; + } + } + + + + if (! $error && $xml) + { + $checksumconcat = array(); + $file_list = array(); + $out = ''; + + // Forced constants + if (is_object($xml->dolibarr_constants[0])) + { + $out.=load_fiche_titre($langs->trans("ForcedConstants")); + + $out.='
'; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''."\n"; + + $i = 0; + foreach ($xml->dolibarr_constants[0]->constant as $constant) // $constant is a simpleXMLElement + { + $constname=$constant['name']; + $constvalue=(string) $constant; + $constvalue = (empty($constvalue)?'0':$constvalue); + // Value found + $value=''; + if ($constname && $conf->global->$constname != '') $value=$conf->global->$constname; + $valueforchecksum=(empty($value)?'0':$value); + + $checksumconcat[]=$valueforchecksum; + + $i++; + $out.=''; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $out.="\n"; + } + + if ($i==0) + { + $out.=''; + } + $out.='
#' . $langs->trans("Constant") . '' . $langs->trans("ExpectedValue") . '' . $langs->trans("Value") . '
'.$i.''.$constname.''.$constvalue.''.$valueforchecksum.'
'.$langs->trans("None").'
'; + $out.='
'; + + $out.='
'; + } + + // Scan htdocs + if (is_object($xml->dolibarr_htdocs_dir[0])) + { + //var_dump($xml->dolibarr_htdocs_dir[0]['includecustom']);exit; + $includecustom=(empty($xml->dolibarr_htdocs_dir[0]['includecustom'])?0:$xml->dolibarr_htdocs_dir[0]['includecustom']); + + // Defined qualified files (must be same than into generate_filelist_xml.php) + $regextoinclude='\.(php|css|html|js|json|tpl|jpg|png|gif|sql|lang)$'; + $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 + $scanfiles = dol_dir_list(DOL_DOCUMENT_ROOT, 'files', 1, $regextoinclude, $regextoexclude); + + // Fill file_list with files in signature, new files, modified files + $ret = getFilesUpdated($file_list, $xml->dolibarr_htdocs_dir[0], '', DOL_DOCUMENT_ROOT, $checksumconcat, $scanfiles); // Fill array $file_list + // Complete with list of new files + foreach ($scanfiles as $keyfile => $valfile) + { + $tmprelativefilename=preg_replace('/^'.preg_quote(DOL_DOCUMENT_ROOT,'/').'/','', $valfile['fullname']); + if (! in_array($tmprelativefilename, $file_list['insignature'])) + { + $md5newfile=@md5_file($valfile['fullname']); // Can fails if we don't have permission to open/read file + $file_list['added'][]=array('filename'=>$tmprelativefilename, 'md5'=>$md5newfile); + } + } + + // Files missings + $out.=load_fiche_titre($langs->trans("FilesMissing")); + + $out.='
'; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''."\n"; + $tmpfilelist = dol_sort_array($file_list['missing'], 'filename'); + if (is_array($tmpfilelist) && count($tmpfilelist)) + { + $i = 0; + foreach ($tmpfilelist as $file) + { + $i++; + $out.=''; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $out.="\n"; + } + } + else + { + $out.=''; + } + $out.='
#' . $langs->trans("Filename") . '' . $langs->trans("ExpectedChecksum") . '
'.$i.''.$file['filename'].''.$file['expectedmd5'].'
'.$langs->trans("None").'
'; + $out.='
'; + + $out.='
'; + + // Files modified + $out.=load_fiche_titre($langs->trans("FilesModified")); + + $totalsize=0; + $out.='
'; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''."\n"; + $tmpfilelist2 = dol_sort_array($file_list['updated'], 'filename'); + if (is_array($tmpfilelist2) && count($tmpfilelist2)) + { + $i = 0; + foreach ($tmpfilelist2 as $file) + { + $i++; + $out.=''; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $size = dol_filesize(DOL_DOCUMENT_ROOT.'/'.$file['filename']); + $totalsize += $size; + $out.='' . "\n"; + $out.='' . "\n"; + $out.="\n"; + } + $out.=''; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $out.="\n"; + } + else + { + $out.=''; + } + $out.='
#' . $langs->trans("Filename") . '' . $langs->trans("ExpectedChecksum") . '' . $langs->trans("CurrentChecksum") . '' . $langs->trans("Size") . '' . $langs->trans("DateModification") . '
'.$i.''.$file['filename'].''.$file['expectedmd5'].''.$file['md5'].''.dol_print_size($size).''.dol_print_date(dol_filemtime(DOL_DOCUMENT_ROOT.'/'.$file['filename']),'dayhour').'
'.$langs->trans("Total").''.dol_print_size($totalsize).'
'.$langs->trans("None").'
'; + $out.='
'; + + $out.='
'; + + // Files added + $out.=load_fiche_titre($langs->trans("FilesAdded")); + + $totalsize = 0; + $out.='
'; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''; + $out.=''."\n"; + $tmpfilelist3 = dol_sort_array($file_list['added'], 'filename'); + if (is_array($tmpfilelist3) && count($tmpfilelist3)) + { + $i = 0; + foreach ($tmpfilelist3 as $file) + { + $i++; + $out.=''; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $size = dol_filesize(DOL_DOCUMENT_ROOT.'/'.$file['filename']); + $totalsize += $size; + $out.='' . "\n"; + $out.='' . "\n"; + $out.="\n"; + } + $out.=''; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $out.='' . "\n"; + $out.="\n"; + } + else + { + $out.=''; + } + $out.='
#' . $langs->trans("Filename") . '' . $langs->trans("ExpectedChecksum") . '' . $langs->trans("CurrentChecksum") . '' . $langs->trans("Size") . '' . $langs->trans("DateModification") . '
'.$i.''.$file['filename'].''.$file['expectedmd5'].''.$file['md5'].''.dol_print_size($size).''.dol_print_date(dol_filemtime(DOL_DOCUMENT_ROOT.'/'.$file['filename']),'dayhour').'
'.$langs->trans("Total").''.dol_print_size($totalsize).'
'.$langs->trans("None").'
'; + $out.='
'; + + + // Show warning + if (empty($tmpfilelist) && empty($tmpfilelist2) && empty($tmpfilelist3)) + { + //setEventMessage($langs->trans("FileIntegrityIsStrictlyConformedWithReference")); + } + else + { + //setEventMessage($langs->trans("FileIntegritySomeFilesWereRemovedOrModified"), 'warnings'); + } + } + else + { + throw new RestException(500, 'Error: Failed to found dolibarr_htdocs_dir into XML file '.$xmlfile); + $error++; + } + + + // Scan scripts + + + asort($checksumconcat); // Sort list of checksum + //var_dump($checksumconcat); + $checksumget = md5(join(',',$checksumconcat)); + $checksumtoget = trim((string) $xml->dolibarr_htdocs_dir_checksum); + + $outexpectedchecksum = ($checksumtoget ? $checksumtoget : $langs->trans("Unknown")); + if ($checksumget == $checksumtoget) + { + if (count($file_list['added'])) + { + $resultcode = 'warning'; + $resultcomment='FileIntegrityIsOkButFilesWereAdded'; + //$outcurrentchecksum = $checksumget.' - '.$langs->trans("FileIntegrityIsOkButFilesWereAdded").''; + $outcurrentchecksum = $checksumget; + } + else + { + $resultcode = 'ok'; + $resultcomment='Success'; + //$outcurrentchecksum = ''.$checksumget.''; + $outcurrentchecksum = $checksumget; + } + } + else + { + $resultcode = 'error'; + $resultcomment='Error'; + //$outcurrentchecksum = ''.$checksumget.''; + $outcurrentchecksum = $checksumget; + } + } + else { + throw new RestException(404, 'No signature file known'); + } + + return array('resultcode'=>$resultcode, 'resultcomment'=>$resultcomment, 'expectedchecksum'=> $outexpectedchecksum, 'currentchecksum'=> $outcurrentchecksum, 'out'=>$out); + } + } diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 220a390d577..daf4621ebcb 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -2723,3 +2723,44 @@ function dol_readcachefile($directory, $filename) $object = unserialize(file_get_contents($cachefile)); return $object; } + + +/** + * Function to get list of updated or modified files. + * $file_list is used as global variable + * + * @param array $file_list Array for response + * @param SimpleXMLElement $dir SimpleXMLElement of files to test + * @param string $path Path of files relative to $pathref. We start with ''. Used by recursive calls. + * @param string $pathref Path ref (DOL_DOCUMENT_ROOT) + * @param array $checksumconcat Array of checksum + * @return array Array of filenames + */ +function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathref = '', &$checksumconcat = array()) +{ + $exclude = 'install'; + + foreach ($dir->md5file as $file) // $file is a simpleXMLElement + { + $filename = $path.$file['name']; + $file_list['insignature'][] = $filename; + + //if (preg_match('#'.$exclude.'#', $filename)) continue; + + if (!file_exists($pathref.'/'.$filename)) + { + $file_list['missing'][] = array('filename'=>$filename, 'expectedmd5'=>(string) $file); + } + else + { + $md5_local = md5_file($pathref.'/'.$filename); + if ($md5_local != (string) $file) $file_list['updated'][] = array('filename'=>$filename, 'expectedmd5'=>(string) $file, 'md5'=>(string) $md5_local); + $checksumconcat[] = $md5_local; + } + } + + foreach ($dir->dir as $subdir) getFilesUpdated($file_list, $subdir, $path.$subdir['name'].'/', $pathref, $checksumconcat); + + return $file_list; +} +