2023-08-23 14:24:52 +02:00
#!/usr/bin/env php
< ? php
/*
2024-04-30 08:35:45 +02:00
* Copyright ( C ) 2023 - 2024 Laurent Destailleur < eldy @ users . sourceforge . net >
2024-02-17 16:46:06 +01:00
* Copyright ( C ) 2024 MDW < mdeweerd @ users . noreply . github . com >
2024-04-23 11:50:10 +02:00
* Copyright ( C ) 2024 Frédéric France < frederic . france @ free . fr >
2023-08-23 14:24:52 +02:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < https :// www . gnu . org / licenses />.
*/
/**
* \file dev / tools / apstats . php
2024-04-22 13:57:12 +02:00
* \brief Script to report Advanced Statistics and Status on a PHP project
2023-08-23 14:24:52 +02:00
*/
$sapi_type = php_sapi_name ();
$script_file = basename ( __FILE__ );
$path = dirname ( __FILE__ ) . '/' ;
// Test si mode batch
$sapi_type = php_sapi_name ();
if ( substr ( $sapi_type , 0 , 3 ) == 'cgi' ) {
echo " Error: You are using PHP for CGI. To execute " . $script_file . " from command line, you must use PHP for CLI mode. \n " ;
exit ();
}
2023-12-04 10:22:29 +01:00
error_reporting ( E_ALL & ~ E_DEPRECATED );
2023-08-23 14:24:52 +02:00
define ( 'PRODUCT' , " apstats " );
define ( 'VERSION' , " 1.0 " );
2024-02-11 13:35:49 +01:00
// Include Dolibarr environment
2024-02-12 02:01:51 +01:00
if ( ! is_readable ( " { $path } ../../htdocs/config/config.php " )) {
define ( " DOL_DOCUMENT_ROOT " , __DIR__ . " /../../htdocs " );
} else {
require_once $path . '../../htdocs/master.inc.php' ;
}
2024-02-11 13:35:49 +01:00
require_once $path . '../../htdocs/core/lib/files.lib.php' ;
2024-02-12 02:01:51 +01:00
require_once $path . '../../htdocs/core/lib/functions.lib.php' ;
2024-02-11 13:35:49 +01:00
require_once $path . '../../htdocs/core/lib/geturl.lib.php' ;
2023-08-23 14:24:52 +02:00
print '***** ' . constant ( 'PRODUCT' ) . ' - ' . constant ( 'VERSION' ) . ' *****' . " \n " ;
if ( empty ( $argv [ 1 ])) {
2024-02-12 02:01:51 +01:00
print 'You must run this tool at the root of the project.' . " \n " ;
print 'Usage: ' . constant ( 'PRODUCT' ) . '.php pathto/outputfile.html [--dir-scc=pathtoscc|disabled] [--dir-phpstan=pathtophpstan|disabled] [--dir-phan=path/to/phan|disabled]' . " \n " ;
2024-04-22 15:02:43 +02:00
print 'Example: ' . constant ( 'PRODUCT' ) . '.php documents/apstats/index.html --dir-scc=/snap/bin --dir-phpstan=~/git/phpstan/htdocs/includes/bin --dir-phan=~/vendor/bin/phan --url-site=https://www.dolibarr.org' ;
2023-08-23 14:24:52 +02:00
exit ( 0 );
}
$outputpath = $argv [ 1 ];
$outputdir = dirname ( $outputpath );
$outputfile = basename ( $outputpath );
2024-04-05 13:44:59 +02:00
$outputfilerss = preg_replace ( '/\.\w+$/i' , '' , $outputfile ) . '-security.rss' ;
2023-08-23 14:24:52 +02:00
2023-12-04 10:22:29 +01:00
if ( ! is_dir ( $outputdir )) {
2023-08-23 14:24:52 +02:00
print 'Error: dir ' . $outputdir . ' does not exists or is not writable' . " \n " ;
exit ( 1 );
}
$dirscc = '' ;
$dirphpstan = '' ;
2024-02-12 02:01:51 +01:00
$dir_phan = '' ;
$datatable_script = '' ;
2024-04-05 14:11:34 +02:00
$url_root = '' ;
2024-04-22 15:02:43 +02:00
$url_site = '' ;
$url_flux = '' ;
2024-04-05 15:32:46 +02:00
$project = '' ;
2023-08-23 14:24:52 +02:00
$i = 0 ;
while ( $i < $argc ) {
$reg = array ();
2024-02-12 02:01:51 +01:00
if ( preg_match ( '/^--dir-scc=(.*)$/' , $argv [ $i ], $reg )) {
2023-08-27 15:45:29 +02:00
$dirscc = $reg [ 1 ];
2024-02-12 02:01:51 +01:00
} elseif ( preg_match ( '/^--dir-phpstan=(.*)$/' , $argv [ $i ], $reg )) {
2023-08-23 14:24:52 +02:00
$dirphpstan = $reg [ 1 ];
2024-02-12 02:01:51 +01:00
} elseif ( preg_match ( '/^--dir-phan=(.*)$/' , $argv [ $i ], $reg )) {
$dir_phan = $reg [ 1 ];
2024-04-05 14:11:34 +02:00
} elseif ( preg_match ( '/^--url-root=(.*)$/' , $argv [ $i ], $reg )) {
$url_root = $reg [ 1 ];
2024-04-22 15:02:43 +02:00
} elseif ( preg_match ( '/^--url-site=(.*)$/' , $argv [ $i ], $reg )) {
$url_site = $reg [ 1 ];
2024-04-05 15:32:46 +02:00
} elseif ( preg_match ( '/^--project-name=(.*)$/' , $argv [ $i ], $reg )) {
$project = $reg [ 1 ];
2023-08-23 14:24:52 +02:00
}
2024-04-05 15:32:46 +02:00
2023-08-23 14:24:52 +02:00
$i ++ ;
}
2024-04-30 08:35:45 +02:00
// PHPSTAN setup
2024-11-04 23:53:20 +01:00
$PHPSTANLEVEL = 9 ;
2024-04-07 15:02:00 +02:00
2024-04-30 08:35:45 +02:00
// PHAN setup. Configuration is required, otherwise phan is disabled.
2024-04-07 15:02:00 +02:00
$PHAN_CONFIG = " { $path } phan/config_extended.php " ;
2024-04-30 08:35:45 +02:00
$PHAN_BASELINE = " { $path } phan/baseline_extended.txt " ; // BASELINE is ignored if it does not exist
2024-04-07 15:02:00 +02:00
$PHAN_MIN_PHP = " 7.0 " ;
$PHAN_MEMORY_OPT = " --memory-limit 5G " ;
if ( ! is_readable ( $PHAN_CONFIG )) {
2024-02-17 16:46:06 +01:00
print " Skipping phan - configuration not found \n " ;
2024-02-12 02:01:51 +01:00
// Disable phan while not integrated yet
$dir_phan = 'disabled' ;
}
2023-08-23 14:24:52 +02:00
2024-02-17 16:46:06 +01:00
2024-02-11 16:39:31 +01:00
// Start getting data
2023-08-23 14:24:52 +02:00
2024-02-11 16:39:31 +01:00
$timestart = time ();
2023-08-23 14:24:52 +02:00
2024-01-14 12:26:37 +01:00
// Retrieve the .git information
2024-01-13 15:20:28 +01:00
$urlgit = 'https://github.com/Dolibarr/dolibarr/blob/develop/' ;
2023-08-23 14:24:52 +02:00
// Count lines of code of application
2024-02-12 02:01:51 +01:00
$output_arrproj = array ();
$output_arrdep = array ();
2024-02-11 13:35:49 +01:00
if ( $dirscc != 'disabled' ) {
$commandcheck = ( $dirscc ? $dirscc . '/' : '' ) . 'scc . --exclude-dir=htdocs/includes,htdocs/custom,htdocs/theme/common/fontawesome-5,htdocs/theme/common/octicons' ;
print 'Execute SCC to count lines of code in project: ' . $commandcheck . " \n " ;
$resexecproj = 0 ;
exec ( $commandcheck , $output_arrproj , $resexecproj );
2023-08-23 14:24:52 +02:00
2024-02-11 13:35:49 +01:00
// Count lines of code of dependencies
$commandcheck = ( $dirscc ? $dirscc . '/' : '' ) . 'scc htdocs/includes htdocs/theme/common/fontawesome-5 htdocs/theme/common/octicons' ;
print 'Execute SCC to count lines of code in dependencies: ' . $commandcheck . " \n " ;
$resexecdep = 0 ;
exec ( $commandcheck , $output_arrdep , $resexecdep );
}
2023-08-23 14:24:52 +02:00
2024-04-07 11:46:12 +02:00
// Get technical debt with PHPStan
2024-04-28 16:20:44 +02:00
$output_arrtd = array ();
if ( $dirphpstan != 'disabled' ) {
$commandcheck = ( $dirphpstan ? $dirphpstan . '/' : '' ) . 'phpstan --version' ;
print 'Execute PHPStan to get the version: ' . $commandcheck . " \n " ;
$resexectd = 0 ;
exec ( $commandcheck , $output_arrtd , $resexectd );
}
$phpstanversion = $output_arrtd [ 0 ];
2024-02-12 02:01:51 +01:00
$output_arrtd = array ();
2024-02-11 13:35:49 +01:00
if ( $dirphpstan != 'disabled' ) {
2025-01-05 14:46:26 +01:00
$commandcheck = ( $dirphpstan ? $dirphpstan . '/' : '' ) . 'phpstan --level=' . $PHPSTANLEVEL . ' -v analyze -a dev/build/phpstan/bootstrap.php --memory-limit 8G --error-format=github -c ~/preview.dolibarr.org/dolibarr/dev/tools/phpstan/phpstan_v1_apstats.neon' ;
2024-02-11 13:35:49 +01:00
print 'Execute PHPStan to get the technical debt: ' . $commandcheck . " \n " ;
$resexectd = 0 ;
exec ( $commandcheck , $output_arrtd , $resexectd );
}
2023-08-23 14:24:52 +02:00
2024-04-07 11:46:12 +02:00
// Get technical debt with Phan
2024-02-12 02:01:51 +01:00
$output_phan_json = array ();
$res_exec_phan = 0 ;
if ( $dir_phan != 'disabled' ) {
2024-04-07 15:02:00 +02:00
if ( is_readable ( $PHAN_BASELINE )) {
$PHAN_BASELINE_OPT = " -B ' ${ PHAN_BASELINE } ' " ;
} else {
$PHAN_BASELINE_OPT = '' ;
}
2024-02-12 02:01:51 +01:00
// Get technical debt (phan)
$commandcheck
= ( $dir_phan ? $dir_phan . DIRECTORY_SEPARATOR : '' )
2024-04-07 15:02:00 +02:00
. " phan --output-mode json $PHAN_MEMORY_OPT -k ' $PHAN_CONFIG ' $PHAN_BASELINE_OPT --analyze-twice --minimum-target-php-version $PHAN_MIN_PHP " ;
2024-02-12 02:01:51 +01:00
print 'Execute Phan to get the technical debt: ' . $commandcheck . " \n " ;
exec ( $commandcheck , $output_phan_json , $res_exec_phan );
}
2023-08-23 14:24:52 +02:00
$arrayoflineofcode = array ();
$arraycocomo = array ();
2023-08-23 17:53:12 +02:00
$arrayofmetrics = array (
2023-12-04 10:22:29 +01:00
'proj' => array ( 'Bytes' => 0 , 'Files' => 0 , 'Lines' => 0 , 'Blanks' => 0 , 'Comments' => 0 , 'Code' => 0 , 'Complexity' => 0 ),
'dep' => array ( 'Bytes' => 0 , 'Files' => 0 , 'Lines' => 0 , 'Blanks' => 0 , 'Comments' => 0 , 'Code' => 0 , 'Complexity' => 0 )
2023-08-23 17:53:12 +02:00
);
2023-08-23 14:24:52 +02:00
// Analyse $output_arrproj
foreach ( array ( 'proj' , 'dep' ) as $source ) {
print 'Analyze SCC result for lines of code for ' . $source . " \n " ;
if ( $source == 'proj' ) {
$output_arr = & $output_arrproj ;
} elseif ( $source == 'dep' ) {
$output_arr = & $output_arrdep ;
} else {
print 'Bad value for $source' ;
die ();
}
foreach ( $output_arr as $line ) {
if ( preg_match ( '/^(───|Language|Total)/' , $line )) {
continue ;
}
//print $line."<br>\n";
if ( preg_match ( '/^Estimated Cost.*\$(.*)/i' , $line , $reg )) {
2023-08-23 18:26:27 +02:00
$arraycocomo [ $source ][ 'currency' ] = preg_replace ( '/[^\d\.]/' , '' , str_replace ( array ( ',' , ' ' ), array ( '' , '' ), $reg [ 1 ]));
2023-08-23 14:24:52 +02:00
}
if ( preg_match ( '/^Estimated Schedule Effort.*\s([\d\s,]+)/i' , $line , $reg )) {
$arraycocomo [ $source ][ 'effort' ] = str_replace ( array ( ',' , ' ' ), array ( '.' , '' ), $reg [ 1 ]);
}
if ( preg_match ( '/^Estimated People.*\s([\d\s,]+)/i' , $line , $reg )) {
$arraycocomo [ $source ][ 'people' ] = str_replace ( array ( ',' , ' ' ), array ( '.' , '' ), $reg [ 1 ]);
}
if ( preg_match ( '/^Processed\s(\d+)\s/i' , $line , $reg )) {
$arrayofmetrics [ $source ][ 'Bytes' ] = $reg [ 1 ];
}
if ( preg_match ( '/^(.*)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/' , $line , $reg )) {
$arrayoflineofcode [ $source ][ $reg [ 1 ]][ 'Files' ] = $reg [ 2 ];
$arrayoflineofcode [ $source ][ $reg [ 1 ]][ 'Lines' ] = $reg [ 3 ];
$arrayoflineofcode [ $source ][ $reg [ 1 ]][ 'Blanks' ] = $reg [ 4 ];
$arrayoflineofcode [ $source ][ $reg [ 1 ]][ 'Comments' ] = $reg [ 5 ];
$arrayoflineofcode [ $source ][ $reg [ 1 ]][ 'Code' ] = $reg [ 6 ];
$arrayoflineofcode [ $source ][ $reg [ 1 ]][ 'Complexity' ] = $reg [ 7 ];
}
}
2023-08-23 17:53:12 +02:00
2023-08-26 10:16:46 +02:00
if ( ! empty ( $arrayoflineofcode [ $source ])) {
foreach ( $arrayoflineofcode [ $source ] as $key => $val ) {
$arrayofmetrics [ $source ][ 'Files' ] += $val [ 'Files' ];
$arrayofmetrics [ $source ][ 'Lines' ] += $val [ 'Lines' ];
$arrayofmetrics [ $source ][ 'Blanks' ] += $val [ 'Blanks' ];
$arrayofmetrics [ $source ][ 'Comments' ] += $val [ 'Comments' ];
$arrayofmetrics [ $source ][ 'Code' ] += $val [ 'Code' ];
$arrayofmetrics [ $source ][ 'Complexity' ] += $val [ 'Complexity' ];
}
2023-08-23 17:53:12 +02:00
}
2023-08-23 14:24:52 +02:00
}
2024-01-13 12:05:37 +01:00
// Search the max
2024-02-12 02:01:51 +01:00
$arrayofmax = array ( 'Lines' => 0 );
2024-01-13 12:05:37 +01:00
foreach ( array ( 'proj' , 'dep' ) as $source ) {
2024-02-11 13:35:49 +01:00
if ( ! empty ( $arrayoflineofcode [ $source ])) {
foreach ( $arrayoflineofcode [ $source ] as $val ) {
$arrayofmax [ 'Lines' ] = max ( $arrayofmax [ 'Lines' ], $val [ 'Lines' ]);
}
}
}
2024-02-12 02:01:51 +01:00
$nbofmonth = 2 ;
$delay = ( 3600 * 24 * 30 * $nbofmonth );
2024-02-11 16:39:31 +01:00
// Get stats on nb of commits
2024-04-23 12:55:21 +02:00
$commandcheck = " git log --all --shortstat --no-renames --no-merges --use-mailmap --pretty= " . escapeshellarg ( 'format:%cI;%H;%aN;%aE;%ce;%s' ) . " --since= " . dol_print_date ( dol_now () - $delay , '%Y-%m-%d' ); // --since= --until=...
2024-02-11 16:39:31 +01:00
print 'Execute git log to get list of commits: ' . $commandcheck . " \n " ;
$output_arrglpu = array ();
$resexecglpu = 0 ;
//exec($commandcheck, $output_arrglpu, $resexecglpu);
2024-02-11 13:35:49 +01:00
2024-04-07 11:46:12 +02:00
// Get git information for security alerts
2024-04-18 17:40:44 +02:00
$nbofmonth = 3 ;
2024-02-11 15:42:03 +01:00
$delay = ( 3600 * 24 * 30 * $nbofmonth );
2024-02-11 16:39:31 +01:00
$arrayofalerts = array ();
2024-02-11 13:35:49 +01:00
2024-04-23 12:55:21 +02:00
$commandcheck = " git log --all --shortstat --no-renames --use-mailmap --pretty= " . escapeshellarg ( 'format:%cI;%H;%aN;%aE;%ce;%s' ) . " --since= " . escapeshellarg ( dol_print_date ( dol_now () - $delay , '%Y-%m-%d' )) . " | grep -i -E " . escapeshellarg ( " (#yogosha|CVE|Sec:|Sec ) " );
2024-02-11 18:07:55 +01:00
print 'Execute git log to get commits related to security: ' . $commandcheck . " \n " ;
2024-02-11 16:39:31 +01:00
$output_arrglpu = array ();
$resexecglpu = 0 ;
exec ( $commandcheck , $output_arrglpu , $resexecglpu );
foreach ( $output_arrglpu as $val ) {
2024-04-05 10:59:40 +02:00
// Parse the line to split interesting data
2024-02-11 16:39:31 +01:00
$tmpval = cleanVal2 ( $val );
2024-04-05 10:59:40 +02:00
if ( preg_match ( '/(#yogosha|CVE|Sec:|Sec\s)/i' , $tmpval [ 'title' ])) {
2024-02-11 18:07:55 +01:00
$alreadyfound = '' ;
$alreadyfoundcommitid = '' ;
foreach ( $arrayofalerts as $val ) {
if ( $val [ 'issueidyogosha' ] && $val [ 'issueidyogosha' ] == $tmpval [ 'issueidyogosha' ]) { // Already in list
$alreadyfound = 'yogosha' ;
$alreadyfoundcommitid = $val [ 'commitid' ];
break ;
}
if ( $val [ 'issueid' ] && $val [ 'issueid' ] == $tmpval [ 'issueid' ]) { // Already in list
$alreadyfound = 'git' ;
$alreadyfoundcommitid = $val [ 'commitid' ];
break ;
}
if ( $val [ 'issueidcve' ] && $val [ 'issueidcve' ] == $tmpval [ 'issueidcve' ]) { // Already in list
$alreadyfound = 'cve' ;
$alreadyfoundcommitid = $val [ 'commitid' ];
break ;
}
2024-04-07 11:46:12 +02:00
if ( $val [ 'title' ] && $val [ 'title' ] == $tmpval [ 'title' ]) { // Already in list
$alreadyfound = 'title' ;
2024-04-08 14:00:13 +02:00
$alreadyfoundcommitid = $val [ 'commitid' ];
2024-04-07 11:46:12 +02:00
break ;
}
2024-02-11 18:07:55 +01:00
}
//$alreadyfound=0;
if ( ! $alreadyfound ) {
2024-04-23 11:50:10 +02:00
// Get branch names
2024-04-23 12:27:01 +02:00
$commandgetbranch = " git branch -r --contains ' " . $tmpval [ 'commitid' ] . " ' " ;
2024-04-23 11:50:10 +02:00
print 'Execute git branch to get the name of branches for the commit: ' . $commandgetbranch . " \n " ;
$output_arrgetbranch = array ();
$resexecgetbranch = 0 ;
exec ( $commandgetbranch , $output_arrgetbranch , $resexecgetbranch );
foreach ( $output_arrgetbranch as $valbranch ) {
if ( empty ( $tmpval [ 'branch' ])) {
$tmpval [ 'branch' ] = array ();
}
if ( preg_match ( '/^\s*origin\/(develop|\d)/' , $valbranch )) {
$tmpval [ 'branch' ][] = preg_replace ( '/^\s*origin\//' , '' , $valbranch );
}
}
2024-02-11 18:07:55 +01:00
$arrayofalerts [ $tmpval [ 'commitid' ]] = $tmpval ;
} else {
if ( empty ( $arrayofalerts [ $alreadyfoundcommitid ][ 'commitidbis' ])) {
$arrayofalerts [ $alreadyfoundcommitid ][ 'commitidbis' ] = array ();
}
2024-04-23 12:55:21 +02:00
// Get branch names
$commandgetbranch = " git branch -r --contains ' " . $tmpval [ 'commitid' ] . " ' " ;
print 'Execute git branch to get the name of branches for the commit: ' . $commandgetbranch . " \n " ;
$output_arrgetbranch = array ();
$resexecgetbranch = 0 ;
exec ( $commandgetbranch , $output_arrgetbranch , $resexecgetbranch );
foreach ( $output_arrgetbranch as $valbranch ) {
if ( empty ( $tmpval [ 'branch' ])) {
$tmpval [ 'branch' ] = array ();
}
if ( preg_match ( '/^\s*origin\/(develop|\d)/' , $valbranch )) {
$tmpval [ 'branch' ][] = preg_replace ( '/^\s*origin\//' , '' , $valbranch );
}
}
/* var_dump ( $tmpval [ 'commitid' ] . ' ' . $alreadyfoundcommitid );
var_dump ( $arrayofalerts [ $alreadyfoundcommitid ][ 'branch' ]);
var_dump ( $tmpval ); */
$arrayofalerts [ $alreadyfoundcommitid ][ 'branch' ] = array_merge ( $arrayofalerts [ $alreadyfoundcommitid ][ 'branch' ], $tmpval [ 'branch' ]);
2024-02-11 18:07:55 +01:00
$arrayofalerts [ $alreadyfoundcommitid ][ 'commitidbis' ][] = $tmpval [ 'commitid' ];
}
2024-02-11 16:39:31 +01:00
}
}
2024-02-11 13:35:49 +01:00
2024-02-11 16:39:31 +01:00
/*
//$urlgit = 'https://api.github.com/search/issues?q=is:pr+repo:Dolibarr/dolibarr+created:>'.dol_print_date(dol_now() - $delay, "%Y-%m");
$urlgit = 'https://api.github.com/search/commits?q=repo:Dolibarr/dolibarr+yogosha+created:>' . dol_print_date ( dol_now () - $delay , " %Y-%m " );
2024-02-11 13:35:49 +01:00
// Count lines of code of application
$newurl = $urlgit . '+CVE' ;
$result = getURLContent ( $newurl );
print 'Execute GET on github for ' . $newurl . " \n " ;
if ( $result && $result [ 'http_code' ] == 200 ) {
$arrayofalerts1 = json_decode ( $result [ 'content' ]);
foreach ( $arrayofalerts1 -> items as $val ) {
$tmpval = cleanVal ( $val );
if ( preg_match ( '/CVE/i' , $tmpval [ 'title' ])) {
$arrayofalerts [ $tmpval [ 'number' ]] = $tmpval ;
}
2024-01-13 12:05:37 +01:00
}
2024-02-11 13:35:49 +01:00
} else {
print 'Error: failed to get github response' ;
exit ( - 1 );
2024-01-13 12:05:37 +01:00
}
2024-02-11 13:35:49 +01:00
$newurl = $urlgit . '+yogosha' ;
$result = getURLContent ( $newurl );
print 'Execute GET on github for ' . $newurl . " \n " ;
if ( $result && $result [ 'http_code' ] == 200 ) {
$arrayofalerts2 = json_decode ( $result [ 'content' ]);
foreach ( $arrayofalerts2 -> items as $val ) {
$tmpval = cleanVal ( $val );
if ( preg_match ( '/yogosha:/i' , $tmpval [ 'title' ])) {
$arrayofalerts [ $tmpval [ 'number' ]] = $tmpval ;
}
}
} else {
print 'Error: failed to get github response' ;
exit ( - 1 );
}
$newurl = $urlgit . '+Sec:' ;
$result = getURLContent ( $newurl );
print 'Execute GET on github for ' . $newurl . " \n " ;
if ( $result && $result [ 'http_code' ] == 200 ) {
$arrayofalerts3 = json_decode ( $result [ 'content' ]);
foreach ( $arrayofalerts3 -> items as $val ) {
$tmpval = cleanVal ( $val );
if ( preg_match ( '/Sec:/i' , $tmpval [ 'title' ])) {
$arrayofalerts [ $tmpval [ 'number' ]] = $tmpval ;
}
}
} else {
print 'Error: failed to get github response' ;
exit ( - 1 );
}
2024-02-11 16:39:31 +01:00
*/
2024-01-13 12:05:37 +01:00
2023-12-15 10:28:16 +01:00
$timeend = time ();
2023-08-23 14:24:52 +02:00
/*
* View
*/
2023-09-22 04:59:32 +02:00
$html = '<html>' . " \n " ;
$html .= '<meta charset="utf-8">' . " \n " ;
2023-11-19 10:38:15 +01:00
$html .= '<meta http-equiv="refresh" content="300">' . " \n " ;
2023-09-22 04:59:32 +02:00
$html .= '<meta name="viewport" content="width=device-width, initial-scale=1.0">' . " \n " ;
2024-02-18 15:15:10 +01:00
$html .= '<meta name="keywords" content="erp, crm, dolibarr, statistics, project, security alerts">' . " \n " ;
$html .= '<meta name="title" content="Dolibarr project statistics">' . " \n " ;
$html .= '<meta name="description" content="Statistics about the Dolibarr ERP CRM Open Source project (lines of code, contributions, security alerts, technical debt...">' . " \n " ;
2023-09-22 04:59:32 +02:00
$html .= '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css" integrity="sha512-q3eWabyZPc1XTCmF+8/LuE1ozpg5xxn7iO89yfSOd5/oKvyqLngoNGsx8jq92Y8eXJ/IRxQbEC+FGSYxtk2oiw==" crossorigin="anonymous" referrerpolicy="no-referrer" />' . " \n " ;
$html .= '<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.0/jquery.min.js" integrity="sha512-3gJwYpMe3QewGELv8k/BX9vcqhryRdzRMxVfq6ngyWXwo03GFEzjsUm8Q7RZcHPHksttq7/GFoxjCVUjkjvPdw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>' . " \n " ;
2024-02-12 02:01:51 +01:00
$html .= '<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.7/css/jquery.dataTables.min.css">' ;
$html .= '<script src="https://cdn.datatables.net/1.13.7/js/jquery.dataTables.min.js"></script>' ;
2023-08-23 14:24:52 +02:00
$html .= '
< style >
body {
margin : 10 px ;
2023-08-23 17:53:12 +02:00
margin - left : 50 px ;
margin - right : 50 px ;
2023-08-23 14:24:52 +02:00
}
h1 {
font - size : 1.5 em ;
font - weight : bold ;
padding - top : 5 px ;
padding - bottom : 5 px ;
margin - top : 5 px ;
margin - bottom : 5 px ;
}
2023-08-23 17:53:12 +02:00
header {
text - align : center ;
}
2023-08-23 14:24:52 +02:00
header , section . chapter {
margin - top : 10 px ;
margin - bottom : 10 px ;
padding : 10 px ;
}
2023-08-23 17:53:12 +02:00
table {
border - collapse : collapse ;
}
th , td {
padding - top : 5 px ;
padding - bottom : 5 px ;
padding - left : 10 px ;
padding - right : 10 px ;
}
2023-08-23 14:24:52 +02:00
. left {
text - align : left ;
}
. right {
text - align : right ;
}
2023-09-22 04:59:32 +02:00
. nowrap {
white - space : nowrap ;
}
2023-12-15 11:18:04 +01:00
. opacitymedium {
2023-08-23 14:24:52 +02:00
opacity : 0.5 ;
}
2023-08-23 17:53:12 +02:00
. centpercent {
width : 100 % ;
}
2023-08-23 19:29:14 +02:00
. hidden {
display : none ;
}
2024-02-17 16:46:06 +01:00
. hiddenimp {
display : none ! important ;
}
2023-08-23 17:53:12 +02:00
. trgroup {
2024-01-13 11:48:54 +01:00
border - bottom : 1 px solid #aaa;
2023-08-23 17:53:12 +02:00
}
2024-02-11 18:07:55 +01:00
. tdoverflowmax100 {
max - width : 100 px ;
overflow : hidden ;
text - overflow : ellipsis ;
white - space : nowrap ;
}
. tdoverflowmax300 {
max - width : 300 px ;
overflow : hidden ;
text - overflow : ellipsis ;
white - space : nowrap ;
}
2023-09-01 19:38:47 +02:00
. seedetail {
color : #000088;
}
. box {
padding : 20 px ;
font - size : 1.2 em ;
margin - top : 10 px ;
2023-09-03 18:51:34 +02:00
margin - bottom : 10 px ;
width : 200 px ;
}
2024-02-17 16:46:06 +01:00
. inline - block {
display : inline - block ;
}
. inline {
display : inline ;
}
2023-09-03 18:51:34 +02:00
. box . inline - box {
display : inline - block ;
text - align : center ;
margin - left : 10 px ;
}
2024-01-13 11:40:04 +01:00
. boxallwidth {
border - radius : 9 px ;
border - color : #000;
border - width : 2 px ;
padding : 5 px ;
border - style : solid ;
2024-01-13 12:16:26 +01:00
background - color : #f8f8f8;
2024-01-13 11:40:04 +01:00
}
2023-09-03 18:51:34 +02:00
. back1 {
2023-09-05 22:41:17 +02:00
background - color : #884466;
2023-09-03 18:51:34 +02:00
color : #FFF;
}
2023-09-05 22:41:17 +02:00
. back2 {
background - color : #664488;
2023-09-03 18:51:34 +02:00
color : #FFF;
2023-09-01 19:38:47 +02:00
}
2024-02-17 16:46:06 +01:00
. badge {
padding : 2 px ;
background - color : #eee;
}
. seeothercommit , . seedetail {
cursor : pointer ;
}
2023-09-22 04:59:32 +02:00
div . fiche > form > div . div - table - responsive {
min - height : 392 px ;
}
div . fiche > form > div . div - table - responsive , div . fiche > form > div . div - table - responsive - no - min {
overflow - x : auto ;
}
. div - table - responsive {
line - height : 120 % ;
}
. div - table - responsive , . div - table - responsive - no - min {
overflow - x : auto ;
min - height : 0.01 % ;
}
2024-01-13 11:40:04 +01:00
. list_technical_debt {
2024-01-13 15:20:28 +01:00
/* font-size: smaller */
2024-01-13 11:40:04 +01:00
}
. pictofixedwidth {
font - size : smaller ;
width : 28 px ;
vertical - align : middle ;
}
2024-01-13 11:54:47 +01:00
. bargraph {
2024-01-13 11:59:37 +01:00
background - color : #358;
}
. small {
font - size : smaller ;
2024-01-13 11:54:47 +01:00
}
2024-01-13 15:25:10 +01:00
. fr {
float : right ;
}
2023-09-22 04:59:32 +02:00
/* Force values for small screen 767 */
@ media only screen and ( max - width : 767 px )
{
body {
margin : 5 px ;
margin - left : 5 px ;
margin - right : 5 px ;
}
2024-04-18 17:38:33 +02:00
. boxallwidth picture img {
width : 100 % ;
}
2023-09-22 04:59:32 +02:00
}
</ style > ' . " \n " ;
2023-08-23 14:24:52 +02:00
2023-09-22 04:36:44 +02:00
$html .= '<body>' . " \n " ;
2023-08-23 14:24:52 +02:00
2024-01-13 13:12:21 +01:00
// Header
2023-09-22 04:36:44 +02:00
$html .= '<header>' . " \n " ;
2024-04-22 13:57:12 +02:00
$html .= '<h1>Advanced Project Status</h1>' . " \n " ;
2023-08-23 14:24:52 +02:00
$currentDate = date ( " Y-m-d H:i:s " ); // Format: Year-Month-Day Hour:Minute:Second
2024-04-03 19:23:37 +02:00
$html .= '<span class="opacitymedium">Generated on ' . $currentDate . ' in ' . ( $timeend - $timestart ) . ' seconds by <a target="_blank" href="https://github.com/Dolibarr/dolibarr/blob/develop/dev/tools/apstats.php">apstats</a></span>' . " \n " ;
2023-09-22 04:36:44 +02:00
$html .= '</header>' . " \n " ;
2023-08-23 14:24:52 +02:00
2024-01-13 13:12:21 +01:00
// Lines of code
2023-11-19 10:38:15 +01:00
$html .= '<section class="chapter" id="linesofcode">' . " \n " ;
2024-01-13 11:40:04 +01:00
$html .= '<h2><span class="fas fa-code pictofixedwidth"></span>Lines of code</h2>' . " \n " ;
2023-09-22 04:59:32 +02:00
2024-01-04 16:15:20 +01:00
$html .= '<div class="boxallwidth">' . " \n " ;
2024-02-17 16:46:06 +01:00
$html .= '<div class="div-table-responsive">' . " \n " ;
2023-08-23 17:53:12 +02:00
$html .= '<table class="centpercent">' ;
2023-08-23 14:24:52 +02:00
$html .= '<tr class="loc">' ;
2024-02-17 17:02:14 +01:00
$html .= '<th class="left" style="min-width: 150px">Language</th>' ;
2023-08-23 17:53:12 +02:00
$html .= '<th class="right">Bytes</th>' ;
2023-08-23 14:24:52 +02:00
$html .= '<th class="right">Files</th>' ;
$html .= '<th class="right">Lines</th>' ;
2024-01-13 11:46:43 +01:00
$html .= '<th></th>' ;
2023-08-23 14:24:52 +02:00
$html .= '<th class="right">Blanks</th>' ;
$html .= '<th class="right">Comments</th>' ;
$html .= '<th class="right">Code</th>' ;
//$html .= '<td class="right">'.$val['Complexity'].'</td>';
2023-11-20 20:20:14 +01:00
$html .= '</tr>' ;
2023-08-23 14:24:52 +02:00
foreach ( array ( 'proj' , 'dep' ) as $source ) {
2023-08-23 17:53:12 +02:00
$html .= '<tr class="trgroup" id="source' . $source . '">' ;
2023-08-23 14:24:52 +02:00
if ( $source == 'proj' ) {
2023-12-15 14:41:03 +01:00
$html .= '<td>All files without dependencies' ;
2023-08-23 14:24:52 +02:00
} elseif ( $source == 'dep' ) {
2023-12-15 14:41:03 +01:00
$html .= '<td>All files of dependencies only' ;
2023-08-23 14:24:52 +02:00
}
2024-01-13 15:27:04 +01:00
$html .= ' <div class="seedetail fr" data-source="' . $source . '"><span class="fas fa-chart-bar pictofixedwidth"></span>See detail per file type...</span>' ;
2023-08-23 19:29:14 +02:00
$html .= '<td class="right">' . formatNumber ( $arrayofmetrics [ $source ][ 'Bytes' ]) . '</td>' ;
$html .= '<td class="right">' . formatNumber ( $arrayofmetrics [ $source ][ 'Files' ]) . '</td>' ;
$html .= '<td class="right">' . formatNumber ( $arrayofmetrics [ $source ][ 'Lines' ]) . '</td>' ;
2024-01-13 11:46:43 +01:00
$html .= '<td></td>' ;
2023-08-23 19:29:14 +02:00
$html .= '<td class="right">' . formatNumber ( $arrayofmetrics [ $source ][ 'Blanks' ]) . '</td>' ;
$html .= '<td class="right">' . formatNumber ( $arrayofmetrics [ $source ][ 'Comments' ]) . '</td>' ;
$html .= '<td class="right">' . formatNumber ( $arrayofmetrics [ $source ][ 'Code' ]) . '</td>' ;
2024-01-13 11:46:43 +01:00
//$html .= '<td></td>';
2023-08-23 17:53:12 +02:00
$html .= '</tr>' ;
2023-08-26 10:16:46 +02:00
if ( ! empty ( $arrayoflineofcode [ $source ])) {
foreach ( $arrayoflineofcode [ $source ] as $key => $val ) {
$html .= '<tr class="loc hidden source' . $source . ' language' . str_replace ( ' ' , '' , $key ) . '">' ;
$html .= '<td>' . $key . '</td>' ;
$html .= '<td class="right"></td>' ;
2023-09-22 04:59:32 +02:00
$html .= '<td class="right nowrap">' . ( empty ( $val [ 'Files' ]) ? '' : formatNumber ( $val [ 'Files' ])) . '</td>' ;
$html .= '<td class="right nowrap">' . ( empty ( $val [ 'Lines' ]) ? '' : formatNumber ( $val [ 'Lines' ])) . '</td>' ;
2024-01-13 11:46:43 +01:00
$html .= '<td class="nowrap">' ;
2024-01-13 12:16:26 +01:00
$percent = $val [ 'Lines' ] / $arrayofmax [ 'Lines' ];
2024-01-13 11:54:47 +01:00
$widthbar = round ( 200 * $percent );
2024-01-13 12:05:37 +01:00
$html .= '<div class="bargraph" style="width: ' . max ( 1 , $widthbar ) . 'px"> </div>' ;
2024-01-13 11:46:43 +01:00
$html .= '</td>' ;
2023-09-22 04:59:32 +02:00
$html .= '<td class="right nowrap">' . ( empty ( $val [ 'Blanks' ]) ? '' : formatNumber ( $val [ 'Blanks' ])) . '</td>' ;
$html .= '<td class="right nowrap">' . ( empty ( $val [ 'Comments' ]) ? '' : formatNumber ( $val [ 'Comments' ])) . '</td>' ;
$html .= '<td class="right nowrap">' . ( empty ( $val [ 'Code' ]) ? '' : formatNumber ( $val [ 'Code' ])) . '</td>' ;
2023-08-26 10:16:46 +02:00
//$html .= '<td class="right">'.(empty($val['Complexity']) ? '' : $val['Complexity']).'</td>';
2024-01-13 11:46:43 +01:00
/* $html .= '<td class="nowrap">' ;
$html .= '' ;
$html .= '</td>' ;
*/
2023-08-26 10:16:46 +02:00
$html .= '</tr>' ;
}
2023-08-23 14:24:52 +02:00
}
}
2024-01-13 11:46:43 +01:00
$html .= '<tr class="trgrouptotal">' ;
2023-08-23 17:53:12 +02:00
$html .= '<td class="left">Total</td>' ;
2023-09-22 04:59:32 +02:00
$html .= '<td class="right nowrap">' . formatNumber ( $arrayofmetrics [ 'proj' ][ 'Bytes' ] + $arrayofmetrics [ 'dep' ][ 'Bytes' ]) . '</td>' ;
$html .= '<td class="right nowrap">' . formatNumber ( $arrayofmetrics [ 'proj' ][ 'Files' ] + $arrayofmetrics [ 'dep' ][ 'Files' ]) . '</td>' ;
$html .= '<td class="right nowrap">' . formatNumber ( $arrayofmetrics [ 'proj' ][ 'Lines' ] + $arrayofmetrics [ 'dep' ][ 'Lines' ]) . '</td>' ;
2024-01-13 11:48:54 +01:00
$html .= '<td></td>' ;
2023-09-22 04:59:32 +02:00
$html .= '<td class="right nowrap">' . formatNumber ( $arrayofmetrics [ 'proj' ][ 'Blanks' ] + $arrayofmetrics [ 'dep' ][ 'Blanks' ]) . '</td>' ;
$html .= '<td class="right nowrap">' . formatNumber ( $arrayofmetrics [ 'proj' ][ 'Comments' ] + $arrayofmetrics [ 'dep' ][ 'Comments' ]) . '</td>' ;
$html .= '<td class="right nowrap">' . formatNumber ( $arrayofmetrics [ 'proj' ][ 'Code' ] + $arrayofmetrics [ 'dep' ][ 'Code' ]) . '</td>' ;
2023-08-23 14:24:52 +02:00
//$html .= '<td>'.$arrayofmetrics['Complexity'].'</td>';
2024-01-13 11:48:54 +01:00
//$html .= '<td></td>';
2023-08-23 14:24:52 +02:00
$html .= '</tr>' ;
2023-08-23 17:53:12 +02:00
$html .= '</table>' ;
2024-04-08 14:30:44 +02:00
2023-09-22 04:59:32 +02:00
$html .= '</div>' ;
2024-01-04 16:15:20 +01:00
$html .= '</div>' ;
2023-08-23 14:24:52 +02:00
2024-04-08 14:30:44 +02:00
// OSSINSIGHT graph
2024-04-10 01:50:29 +02:00
/*
2024-04-08 14:30:44 +02:00
$html .= <<< END
< br >
<!-- Copy - paste in your Readme . md file -->
< a href = " https://next.ossinsight.io/widgets/official/analyze-repo-loc-per-month?repo_id=1957456 " target = " _blank " style = " display: block " align = " center " >
< picture >
< source media = " (prefers-color-scheme: dark) " srcset = " https://next.ossinsight.io/widgets/official/analyze-repo-loc-per-month/thumbnail.png?repo_id=1957456&image_size=auto&color_scheme=dark " width = " 721 " height = " auto " >
< img alt = " Lines of Code Changes of Dolibarr/dolibarr " src = " https://next.ossinsight.io/widgets/official/analyze-repo-loc-per-month/thumbnail.png?repo_id=1957456&image_size=auto&color_scheme=light " width = " 721 " height = " auto " >
</ picture >
</ a >
<!-- Made with [ OSS Insight ]( https :// ossinsight . io / ) -->
END ;
2024-04-10 01:50:29 +02:00
*/
2024-04-08 14:30:44 +02:00
2023-09-22 04:36:44 +02:00
$html .= '</section>' . " \n " ;
2023-08-23 14:24:52 +02:00
2024-01-13 13:12:21 +01:00
2024-04-08 14:30:44 +02:00
2024-01-13 13:12:21 +01:00
// Contributions
$html .= '<section class="chapter" id="projectvalue">' . " \n " ;
2024-01-13 14:57:08 +01:00
$html .= '<h2><span class="fas fa-tasks pictofixedwidth"></span>Contributions</h2>' . " \n " ;
2024-01-13 13:12:21 +01:00
$html .= '<div class="boxallwidth">' . " \n " ;
2024-04-08 14:30:44 +02:00
$html .= <<< END
<!-- Copy - paste in your Readme . md file -->
< a href = " https://next.ossinsight.io/widgets/official/analyze-repo-pushes-and-commits-per-month?repo_id=1957456 " target = " _blank " style = " display: block " align = " center " >
< picture >
< source media = " (prefers-color-scheme: dark) " srcset = " https://next.ossinsight.io/widgets/official/analyze-repo-pushes-and-commits-per-month/thumbnail.png?repo_id=1957456&image_size=auto&color_scheme=dark " width = " 721 " height = " auto " >
< img alt = " Pushes and Commits of Dolibarr/dolibarr " src = " https://next.ossinsight.io/widgets/official/analyze-repo-pushes-and-commits-per-month/thumbnail.png?repo_id=1957456&image_size=auto&color_scheme=light " width = " 721 " height = " auto " >
</ picture >
</ a >
<!-- Made with [ OSS Insight ]( https :// ossinsight . io / ) -->
<!-- Copy - paste in your Readme . md file -->
< a href = " https://next.ossinsight.io/widgets/official/analyze-repo-pull-requests-size-per-month?repo_id=1957456 " target = " _blank " style = " display: block " align = " center " >
< picture >
< source media = " (prefers-color-scheme: dark) " srcset = " https://next.ossinsight.io/widgets/official/analyze-repo-pull-requests-size-per-month/thumbnail.png?repo_id=1957456&image_size=auto&color_scheme=dark " width = " 721 " height = " auto " >
< img alt = " Pull Request Size of Dolibarr/dolibarr " src = " https://next.ossinsight.io/widgets/official/analyze-repo-pull-requests-size-per-month/thumbnail.png?repo_id=1957456&image_size=auto&color_scheme=light " width = " 721 " height = " auto " >
</ picture >
</ a >
<!-- Made with [ OSS Insight ]( https :// ossinsight . io / ) -->
END ;
2024-01-13 14:55:21 +01:00
$html .= '<!-- ' ;
2024-01-13 14:31:31 +01:00
foreach ( $output_arrglpu as $line ) {
$html .= $line . " \n " ;
}
2024-01-13 14:55:21 +01:00
$html .= ' -->' ;
2024-01-13 13:12:21 +01:00
$html .= '</div>' ;
$html .= '</section>' . " \n " ;
2024-04-08 14:30:44 +02:00
// Community - Contributors
2024-01-13 13:12:21 +01:00
$html .= '<section class="chapter" id="projectvalue">' . " \n " ;
2024-01-13 14:57:08 +01:00
$html .= '<h2><span class="fas fa-user pictofixedwidth"></span>Contributors</h2>' . " \n " ;
2024-01-13 13:12:21 +01:00
$html .= '<div class="boxallwidth">' . " \n " ;
2024-04-08 14:59:21 +02:00
$html .= <<< END
2024-04-08 19:26:37 +02:00
< center >< br > Thumbs of most active contributors < br >
2024-04-08 16:37:33 +02:00
< br >
2024-08-17 14:10:10 +02:00
< a href = " https://github.com/Dolibarr/dolibarr/graphs/contributors " >< img src = " https://opencollective.com/dolibarr/contributors.svg?width=890&button=false " alt = " Dolibarr " data - canonical - src = " https://opencollective.com/dolibarr/contributors.svg?width=890&button=false " style = " max-width: 100%; " ></ a >
2024-04-08 16:37:33 +02:00
</ center >
< br >
2024-04-08 14:59:21 +02:00
END ;
/*
2024-04-08 14:30:44 +02:00
$html .= <<< END
<!-- Copy - paste in your Readme . md file -->
< a href = " https://next.ossinsight.io/widgets/official/compose-contributors?repo_id=1957456&limit=200 " target = " _blank " style = " display: block " align = " center " >
< picture >
< source media = " (prefers-color-scheme: dark) " srcset = " https://next.ossinsight.io/widgets/official/compose-contributors/thumbnail.png?repo_id=1957456&limit=200&image_size=auto&color_scheme=dark " width = " 655 " height = " auto " >
< img alt = " Contributors of Dolibarr/dolibarr " src = " https://next.ossinsight.io/widgets/official/compose-contributors/thumbnail.png?repo_id=1957456&limit=200&image_size=auto&color_scheme=light " width = " 655 " height = " auto " >
</ picture >
</ a >
<!-- Made with [ OSS Insight ]( https :// ossinsight . io / ) -->
END ;
2024-04-08 14:59:21 +02:00
*/
2024-04-08 14:30:44 +02:00
$html .= <<< END
< br >
<!-- Copy - paste in your Readme . md file -->
< a href = " https://next.ossinsight.io/widgets/official/analyze-repo-stars-history?repo_id=1957456 " target = " _blank " style = " display: block " align = " center " >
< picture >
< source media = " (prefers-color-scheme: dark) " srcset = " https://next.ossinsight.io/widgets/official/analyze-repo-stars-history/thumbnail.png?repo_id=1957456&image_size=auto&color_scheme=dark " width = " 721 " height = " auto " >
< img alt = " Star History of Dolibarr/dolibarr " src = " https://next.ossinsight.io/widgets/official/analyze-repo-stars-history/thumbnail.png?repo_id=1957456&image_size=auto&color_scheme=light " width = " 721 " height = " auto " >
</ picture >
</ a >
<!-- Made with [ OSS Insight ]( https :// ossinsight . io / ) -->
END ;
2024-01-13 13:12:21 +01:00
$html .= '</div>' ;
$html .= '</section>' . " \n " ;
// Project value
2023-11-19 10:38:15 +01:00
$html .= '<section class="chapter" id="projectvalue">' . " \n " ;
2024-01-13 12:18:32 +01:00
$html .= '<h2><span class="fas fa-dollar-sign pictofixedwidth"></span>Project value</h2>' . " \n " ;
2024-01-04 16:15:20 +01:00
$html .= '<div class="boxallwidth">' . " \n " ;
2023-09-03 18:51:34 +02:00
$html .= '<div class="box inline-box back1">' ;
2024-01-13 11:59:37 +01:00
$html .= 'COCOMO value<br><span class="small opacitymedium">(Basic organic model)</span><br>' ;
2023-09-22 04:36:44 +02:00
$html .= '<b>$' . formatNumber (( empty ( $arraycocomo [ 'proj' ][ 'currency' ]) ? 0 : $arraycocomo [ 'proj' ][ 'currency' ]) + ( empty ( $arraycocomo [ 'dep' ][ 'currency' ]) ? 0 : $arraycocomo [ 'dep' ][ 'currency' ]), 2 ) . '</b>' ;
2023-09-01 19:38:47 +02:00
$html .= '</div>' ;
2024-02-12 02:01:51 +01:00
if ( array_key_exists ( 'proj' , $arraycocomo )) {
$html .= '<div class="box inline-box back2">' ;
$html .= 'COCOMO effort<br><span class="small opacitymedium">(Basic organic model)</span><br>' ;
$html .= '<b>' . formatNumber ( $arraycocomo [ 'proj' ][ 'people' ] * $arraycocomo [ 'proj' ][ 'effort' ] + $arraycocomo [ 'dep' ][ 'people' ] * $arraycocomo [ 'dep' ][ 'effort' ]);
$html .= ' months people</b>' ;
$html .= '</div>' ;
}
2024-01-04 16:15:20 +01:00
$html .= '</div>' ;
2023-09-22 04:36:44 +02:00
$html .= '</section>' . " \n " ;
2024-03-10 22:13:37 +01:00
$tmpstan = '' ;
2023-12-15 10:28:16 +01:00
$nblines = 0 ;
2024-02-11 13:35:49 +01:00
if ( ! empty ( $output_arrtd )) {
foreach ( $output_arrtd as $line ) {
$reg = array ();
//print $line."\n";
preg_match ( '/^::error file=(.*),line=(\d+),col=(\d+)::(.*)$/' , $line , $reg );
if ( ! empty ( $reg [ 1 ])) {
if ( $nblines < 20 ) {
2024-03-10 22:13:37 +01:00
$tmpstan .= '<tr class="nohidden">' ;
2024-02-11 13:35:49 +01:00
} else {
2024-03-10 22:13:37 +01:00
$tmpstan .= '<tr class="hidden sourcephpstan">' ;
2024-02-11 13:35:49 +01:00
}
2024-03-10 22:13:37 +01:00
$tmpstan .= '<td>' . dolPrintLabel ( $reg [ 1 ]) . '</td>' ;
$tmpstan .= '<td class="">' ;
$tmpstan .= '<a href="' . ( $urlgit . $reg [ 1 ] . '#L' . $reg [ 2 ]) . '" target="_blank">' . dolPrintLabel ( $reg [ 2 ]) . '</a>' ;
$tmpstan .= '</td>' ;
$tmpstan .= '<td class="tdoverflowmax300" title="' . dolPrintHTMLForAttribute ( $reg [ 4 ]) . '">' . dolPrintLabel ( $reg [ 4 ]) . '</td>' ;
$tmpstan .= '</tr>' . " \n " ;
2024-02-25 18:36:40 +01:00
2024-02-11 13:35:49 +01:00
$nblines ++ ;
2024-01-13 15:06:49 +01:00
}
2023-09-22 04:36:44 +02:00
}
}
2023-12-15 10:28:16 +01:00
2024-02-25 18:36:40 +01:00
$tmpphan = '' ;
2024-02-12 02:01:51 +01:00
$phan_nblines = 0 ;
if ( count ( $output_phan_json ) != 0 ) {
$phan_notices = json_decode ( $output_phan_json [ count ( $output_phan_json ) - 1 ], true );
// Info: result code is $res_exec_phan
'@phan-var-force array<array{type:string,type_id:int,check_name:string,description:string,severity:int,location:array{path:string,lines:array{begin:int,end:int}}}> $phan_notices' ;
$phan_items = [];
foreach ( $phan_notices as $notice ) {
if ( ! empty ( $notice [ 'location' ])) {
$path = $notice [ 'location' ][ 'path' ];
2024-03-07 22:08:58 +01:00
if ( $path == 'internal' ) {
continue ;
}
2024-02-12 02:01:51 +01:00
$line_start = $notice [ 'location' ][ 'lines' ][ 'begin' ];
$line_end = $notice [ 'location' ][ 'lines' ][ 'end' ];
if ( $line_start == $line_end ) {
$line_range = " #L { $line_start } " ;
$line_range_txt = $line_start ;
} else {
$line_range = " #L { $line_start } -L { $line_end } " ;
$line_range_txt = " { $line_start } - { $line_end } " ;
}
2024-02-18 15:13:43 +01:00
$code_url_attr = dol_escape_htmltag ( $urlgit . $path . $line_range );
2024-02-12 02:01:51 +01:00
if ( $phan_nblines < 20 ) {
2024-02-25 18:55:22 +01:00
$tmpphan .= '<tr class="nohidden">' ;
2024-02-12 02:01:51 +01:00
} else {
2024-02-25 18:55:22 +01:00
$tmpphan .= '<tr class="hidden sourcephan">' ;
2024-02-12 02:01:51 +01:00
}
2024-02-25 20:53:42 +01:00
$tmpphan .= '<td>' . dolPrintLabel ( $path ) . '</td>' ;
2024-02-25 18:36:40 +01:00
$tmpphan .= '<td class="">' ;
$tmpphan .= '<a href="' . $code_url_attr . '" target="_blank">' . $line_range_txt . '</a>' ;
$tmpphan .= '</td>' ;
2024-03-17 22:04:10 +01:00
$tmpphan .= '<td class="tdoverflowmax300" title="' . dolPrintHTMLForAttribute ( $notice [ 'description' ]) . '">' . dolPrintLabel ( $notice [ 'description' ]) . '</td>' ;
2024-02-25 18:36:40 +01:00
$tmpphan .= '</tr>' ;
2024-02-25 18:55:22 +01:00
$tmpphan .= " \n " ;
2024-02-17 16:53:24 +01:00
2024-02-12 02:01:51 +01:00
$phan_nblines ++ ;
}
}
}
2024-02-11 13:35:49 +01:00
// Last security errors
2024-04-08 19:26:37 +02:00
$title_security_short = " Last security issues " ;
$title_security = ( $project ? " [ " . $project . " ] " : " " ) . $title_security_short ;
2024-02-11 13:35:49 +01:00
$html .= '<section class="chapter" id="linesofcode">' . " \n " ;
2024-04-08 19:26:37 +02:00
$html .= '<h2><span class="fas fa-code pictofixedwidth"></span>' . $title_security_short . ' <span class="opacitymedium">(last ' . ( $nbofmonth != 1 ? $nbofmonth . ' months' : 'month' ) . ')</span></h2>' . " \n " ;
2024-02-11 13:35:49 +01:00
$html .= '<div class="boxallwidth">' . " \n " ;
2024-02-17 16:46:06 +01:00
$html .= '<div class="div-table-responsive">' . " \n " ;
2024-02-11 13:35:49 +01:00
$html .= '<table class="list_technical_debt centpercent">' . " \n " ;
2024-12-17 11:07:57 +01:00
$html .= '<tr class="trgroup"><td>Commit ID</td><td>Date</td><td style="white-space: nowrap">Reported on<br>Yogosha</td><td style="white-space: nowrap">Reported on<br>GIT</td><td style="white-space: nowrap"><a href="https://www.cve.org/CVERecord/SearchResults?query=dolibarr">Reported on<br>CVE</a></td><td>Title</td><td>Branch of fix</td></tr>' . " \n " ;
2024-04-05 14:56:59 +02:00
foreach ( $arrayofalerts as $key => $alert ) {
2024-04-05 15:00:21 +02:00
$cve = '' ;
2024-04-05 15:32:46 +02:00
$yogosha = empty ( $alert [ 'issueidyogosha' ]) ? '' : $alert [ 'issueidyogosha' ];
2024-04-05 14:56:59 +02:00
$arrayofalerts [ $key ][ 'url_commit' ] = 'https://github.com/Dolibarr/dolibarr/commit/' . $alert [ 'commitid' ];
2024-04-05 14:11:34 +02:00
if ( ! empty ( $alert [ 'issueid' ])) {
2024-04-05 14:56:59 +02:00
$arrayofalerts [ $key ][ 'url_issue' ] = 'https://github.com/Dolibarr/dolibarr/issues/' . $alert [ 'issueid' ];
2024-04-05 14:11:34 +02:00
}
if ( ! empty ( $alert [ 'issueidcve' ])) {
$cve = preg_replace ( '/\s+/' , '-' , trim ( $alert [ 'issueidcve' ]));
2024-04-05 14:56:59 +02:00
$arrayofalerts [ $key ][ 'url_cve' ] = 'https://nvd.nist.gov/vuln/detail/CVE-' . $cve ;
2024-04-05 14:11:34 +02:00
}
2024-04-05 15:32:46 +02:00
$arrayofalerts [ $key ][ 'title' ] = ( $project ? " [ " . $project . " ] " : " " ) . 'Security alert - ' . ( $yogosha ? ' Yogosha #' . $yogosha . ' - ' : '' ) . ( $cve ? 'CVE-' . $cve . ' - ' : '' );
$arrayofalerts [ $key ][ 'title' ] .= 'Fix committed as: ' . dol_trunc ( $alert [ 'commitid' ], 8 );
2024-04-30 20:44:38 +02:00
2024-04-05 15:49:52 +02:00
$arrayofalerts [ $key ][ 'description' ] = '<![CDATA[Security alert<br>' ;
2024-04-05 14:11:34 +02:00
2024-02-17 16:46:06 +01:00
$html .= '<tr style="vertical-align: top;">' ;
2024-04-05 15:32:46 +02:00
2024-04-23 11:50:10 +02:00
// Commits ID - Add link to Github
2024-02-17 16:46:06 +01:00
$html .= '<td class="nowrap">' ;
2024-04-05 15:00:21 +02:00
$html .= '<a target="_blank" href="' . $arrayofalerts [ $key ][ 'url_commit' ] . '">' . dol_trunc ( $alert [ 'commitid' ], 8 ) . '</a>' ;
2024-04-05 15:51:41 +02:00
$arrayofalerts [ $key ][ 'description' ] .= " \n <br> " . 'Commit ID: <a href="' . $arrayofalerts [ $key ][ 'url_commit' ] . '">' . dol_trunc ( $alert [ 'commitid' ], 8 ) . '</a>' ;
2024-04-05 15:32:46 +02:00
2024-02-11 18:07:55 +01:00
if ( ! empty ( $alert [ 'commitidbis' ])) {
2024-02-17 16:46:06 +01:00
$html .= ' <div class="more inline"><span class="seeothercommit badge">+</span><div class="morediv hidden">' ;
2024-02-11 18:07:55 +01:00
foreach ( $alert [ 'commitidbis' ] as $tmpcommitidbis ) {
2024-02-17 16:46:06 +01:00
$html .= '<a target="_blank" href="https://github.com/Dolibarr/dolibarr/commit/' . $tmpcommitidbis . '">' . dol_trunc ( $tmpcommitidbis , 8 ) . '</a><br>' ;
2024-04-05 15:51:41 +02:00
$arrayofalerts [ $key ][ 'description' ] .= " \n <br> " . 'Commit ID: <a href="https://github.com/Dolibarr/dolibarr/commit/' . $tmpcommitidbis . '">' . dol_trunc ( $tmpcommitidbis , 8 ) . '</a>' ;
2024-02-11 18:07:55 +01:00
}
2024-02-17 16:46:06 +01:00
$html .= '</div></div>' ;
2024-02-11 18:07:55 +01:00
}
$html .= '</td>' ;
2024-04-23 11:50:10 +02:00
// Date creation
2024-02-11 18:07:55 +01:00
$html .= '<td style="white-space: nowrap">' ;
2024-02-17 16:53:24 +01:00
$html .= preg_replace ( '/T.*$/' , '' , $alert [ 'created_at' ]);
$html .= '</td>' ;
2024-04-23 11:50:10 +02:00
// Yogosha ID
2024-02-17 16:53:24 +01:00
$html .= '<td style="white-space: nowrap">' ;
2024-02-11 18:07:55 +01:00
if ( ! empty ( $alert [ 'issueidyogosha' ])) {
2024-02-11 18:09:20 +01:00
//$html .= '<a target="_blank" href="https://yogosha.com?'.$alert['issueidyogosha'].'">';
2024-02-17 17:07:13 +01:00
$html .= '#yogosha' . $alert [ 'issueidyogosha' ];
2024-04-05 15:51:41 +02:00
$arrayofalerts [ $key ][ 'description' ] .= " \n <br> " . 'Yogosha ID #' . $alert [ 'issueidyogosha' ];
2024-02-11 18:09:20 +01:00
//$html .= '</a>';
2024-02-11 18:07:55 +01:00
} else {
//$html .= '<span class="opacitymedium">public issue</span>';
}
$html .= '</td>' ;
2024-04-23 11:50:10 +02:00
// GIT Issue/PR ID
2024-02-11 18:07:55 +01:00
$html .= '<td style="white-space: nowrap">' ;
if ( ! empty ( $alert [ 'issueid' ])) {
2024-04-05 15:00:21 +02:00
$html .= '<a target="_blank" href="' . $arrayofalerts [ $key ][ 'url_issue' ] . '">#' . $alert [ 'issueid' ] . '</a>' ;
2024-04-05 15:51:41 +02:00
$arrayofalerts [ $key ][ 'description' ] .= " \n <br> " . 'GitHub ID <a href="' . $arrayofalerts [ $key ][ 'url_issue' ] . '" target="_blank">#' . $alert [ 'issueid' ] . '</a>' ;
2024-02-11 18:07:55 +01:00
} else {
//$html .= '<span class="opacitymedium">private</span>';
}
$html .= '</td>' ;
2024-04-23 11:50:10 +02:00
// CVE ID
2024-02-11 18:07:55 +01:00
$html .= '<td style="white-space: nowrap">' ;
if ( ! empty ( $alert [ 'issueidcve' ])) {
$cve = preg_replace ( '/\s+/' , '-' , trim ( $alert [ 'issueidcve' ]));
2024-04-05 15:04:18 +02:00
$html .= '<a target="_blank" href="' . $arrayofalerts [ $key ][ 'url_cve' ] . '">CVE-' . $cve . '</a>' ;
2024-04-05 15:51:41 +02:00
$arrayofalerts [ $key ][ 'description' ] .= " \n <br> " . 'CVE: <a href="' . $arrayofalerts [ $key ][ 'url_cve' ] . '">CVE-' . $cve . '</a>' ;
2024-02-11 18:07:55 +01:00
}
$html .= '</td>' ;
2024-04-23 11:50:10 +02:00
// Description
2024-02-17 23:47:47 +01:00
$html .= '<td class="tdoverflowmax300" title="' . dol_escape_htmltag ( $alert [ 'title' ]) . '">' . dol_escape_htmltag ( $alert [ 'title' ]) . '</td>' ;
2024-04-05 15:32:46 +02:00
2024-04-23 12:27:01 +02:00
// Branches
2024-04-23 11:50:10 +02:00
$html .= '<td style="white-space: nowrap">' ;
if ( ! empty ( $alert [ 'branch' ])) {
2024-04-23 12:55:21 +02:00
$listofbranchnames = implode ( ', ' , array_unique ( $alert [ 'branch' ]));
$html .= $listofbranchnames ;
$arrayofalerts [ $key ][ 'description' ] .= " \n <br><br> " . 'Branches of fix: ' . $listofbranchnames ;
2024-04-23 11:50:10 +02:00
}
$html .= '</td>' ;
2024-04-30 20:44:38 +02:00
$arrayofalerts [ $key ][ 'description' ] .= ']]>' ;
2024-02-11 13:35:49 +01:00
$html .= '</tr>' ;
}
$html .= '</table>' ;
$html .= '</div>' ;
$html .= '</div>' ;
2024-04-05 13:44:59 +02:00
2024-04-05 14:45:34 +02:00
$html .= '<br>' ;
2024-04-05 13:44:59 +02:00
$html .= 'You can use this URL for RSS notifications: <a href="/' . $outputfilerss . '">' . $outputfilerss . '</a><br><br>' ;
2024-02-11 13:35:49 +01:00
$html .= '</section>' ;
2024-04-05 14:11:34 +02:00
// Generate the RSS file
$fh = fopen ( $outputdir . '/' . $outputfilerss , 'w' );
if ( $fh ) {
2024-04-22 15:02:43 +02:00
if ( $url_root && empty ( $url_site )) {
2024-04-05 14:11:34 +02:00
$url_site = $url_root ;
2024-04-22 15:02:43 +02:00
}
if ( $url_root && empty ( $url_flux )) {
2024-04-05 14:11:34 +02:00
$url_flux = $url_root . '/' . $outputfilerss ;
}
// Generation of the feed
2024-04-05 15:01:59 +02:00
fwrite ( $fh , '<?xml version="1.0" encoding="UTF-8" ?>' . " \n " );
fwrite ( $fh , '<rss version="2.0">' . " \n " );
fwrite ( $fh , '<channel>' . " \n " );
fwrite ( $fh , '<title>' . htmlspecialchars ( $title_security ) . '</title>' . " \n " );
fwrite ( $fh , '<description>' . htmlspecialchars ( " Feed of the latest security reports on the project " ) . '</description>' . " \n " );
2024-04-30 21:13:53 +02:00
//fwrite($fh, '<atom:link href="https://cti.dolibarr.org/index-security.rss" rel="self" type="application/rss+xml" />'."\n");
2024-04-30 19:11:30 +02:00
fwrite ( $fh , '<language>en-US</language>' . " \n " );
2024-04-30 20:44:38 +02:00
fwrite ( $fh , '<lastBuildDate>' . date ( 'r' ) . '</lastBuildDate>' . " \n " );
/*
< lastBuildDate > Mon , 29 Apr 2024 11 : 33 : 54 + 0000 </ lastBuildDate >
< atom : link href = " https://cti.dolibarr.org/security-index.rss " rel = " self " type = " application/rss+xml " />
*/
2024-04-05 14:11:34 +02:00
if ( $url_site ) {
2024-04-05 15:01:59 +02:00
fwrite ( $fh , '<link>' . htmlspecialchars ( $url_site ) . '</link>' . " \n " );
2024-04-05 14:11:34 +02:00
}
2024-04-22 13:57:12 +02:00
// Image
fwrite ( $fh , '<image>' . " \n " );
fwrite ( $fh , '<url>https://www.dolibarr.org/medias/image/www.dolibarr.org/badge-openssf.png</url>' . " \n " );
2024-04-30 20:44:38 +02:00
fwrite ( $fh , '<title>' . htmlspecialchars ( $title_security ) . '</title>' . " \n " );
2024-04-22 15:02:43 +02:00
if ( $url_site ) {
fwrite ( $fh , '<link>' . htmlspecialchars ( $url_site ) . '</link>' . " \n " );
}
2024-04-22 13:57:12 +02:00
fwrite ( $fh , '</image>' . " \n " );
2024-04-05 14:11:34 +02:00
foreach ( $arrayofalerts as $alert ) {
2024-04-05 14:56:59 +02:00
$alert [ 'url_commit' ] = 'https://github.com/Dolibarr/dolibarr/commit/' . $alert [ 'commitid' ];
2024-04-05 15:01:59 +02:00
fwrite ( $fh , '<item>' . " \n " );
fwrite ( $fh , '<title>' . htmlspecialchars ( $alert [ 'title' ]) . '</title>' . " \n " );
2024-06-12 01:44:19 +02:00
// Description of alert, list of links to sources and branches of fixes
2024-04-05 15:34:30 +02:00
fwrite ( $fh , '<description>' . $alert [ 'description' ] . '</description>' . " \n " ); // no htmlspeciachars here
2024-04-05 15:01:59 +02:00
fwrite ( $fh , '<link>' . htmlspecialchars ( $alert [ 'url_commit' ]) . '</link>' . " \n " );
2024-04-30 21:02:02 +02:00
$tmpdate = strtotime ( $alert [ 'created_at' ]);
fwrite ( $fh , '<pubDate>' . htmlspecialchars ( date ( 'r' , $tmpdate )) . '</pubDate>' . " \n " );
2024-06-12 01:44:19 +02:00
fwrite ( $fh , '<guid isPermaLink="false"><![CDATA[' . htmlspecialchars ( $alert [ 'commitid' ]) . ']]></guid>' . " \n " ); // A hidden unique ID
2024-04-05 15:01:59 +02:00
fwrite ( $fh , '</item>' . " \n " );
2024-04-05 14:11:34 +02:00
}
2024-04-05 15:01:59 +02:00
fwrite ( $fh , '</channel>' . " \n " );
fwrite ( $fh , '</rss>' . " \n " );
2024-04-05 14:11:34 +02:00
fclose ( $fh );
2024-04-30 19:00:11 +02:00
print 'Generation of RSS output file ' . $outputdir . '/' . $outputfilerss . ' done.' . " \n " ;
2024-04-05 14:11:34 +02:00
} else {
2024-04-30 19:00:11 +02:00
print 'Failed to generate the RSS file ' . $outputdir . '/' . $outputfilerss . " \n " ;
2024-04-05 14:11:34 +02:00
}
2024-02-12 02:01:51 +01:00
// Technical debt PHPstan
2024-03-10 22:13:37 +01:00
if ( $dirphpstan != 'disabled' ) {
2024-02-18 15:13:43 +01:00
$datatable_script .= '
if ( typeof ( DataTable ) === " function " ) { jQuery ( " .sourcephpstan " ) . toggle ( true );}
2024-02-21 15:00:14 +01:00
let phpstantable = new DataTable ( " #technicaldebt table " , {
lengthMenu : [
[ 10 , 25 , 50 , 100 , - 1 ],
[ 10 , 25 , 50 , 100 , \ ' All\ ' ]
]});
2024-02-18 15:13:43 +01:00
' ;
2024-02-12 02:01:51 +01:00
$html .= '<section class="chapter" id="technicaldebt">' . " \n " ;
2024-04-30 08:35:45 +02:00
$html .= '<h2><span class="fas fa-book-dead pictofixedwidth"></span>Technical debt <span class="opacitymedium">(' . $phpstanversion . ' - level ' . $PHPSTANLEVEL . ' -> ' . $nblines . ' warnings)</span></h2>' . " \n " ;
2024-01-13 13:12:21 +01:00
2024-02-12 02:01:51 +01:00
$html .= '<div class="boxallwidth">' . " \n " ;
2024-02-17 16:46:06 +01:00
$html .= '<div class="div-table-responsive">' . " \n " ;
2024-02-12 02:01:51 +01:00
$html .= '<table class="list_technical_debt centpercent">' . " \n " ;
2024-02-18 15:13:43 +01:00
$html .= '<thead><tr class="trgroup"><td>File</td><td>Line</td><td>Type</td></tr></thead><tbody>' . " \n " ;
2024-03-10 22:13:37 +01:00
$html .= $tmpstan ;
2024-02-18 15:13:43 +01:00
$html .= '<tbody></table>' ;
2024-02-21 15:00:14 +01:00
// Disabled, no more required as list is managed with datatable
//$html .= '<div><span class="seedetail" data-source="phpstan" id="sourcephpstan">Show all...</span></div>';
2024-02-18 15:13:43 +01:00
$html .= '</div></div>' ;
2024-01-04 16:15:20 +01:00
2024-02-12 02:01:51 +01:00
$html .= '</section>' . " \n " ;
}
2024-01-04 16:15:20 +01:00
2024-02-12 02:01:51 +01:00
// Technical debt Phan
2024-03-10 18:50:02 +01:00
if ( $dir_phan != 'disabled' ) {
2024-02-12 02:01:51 +01:00
$datatable_script .= '
if ( typeof ( DataTable ) === " function " ) { jQuery ( " .sourcephan " ) . toggle ( true );}
2024-02-20 02:26:42 +01:00
let phantable = new DataTable ( " #technicaldebtphan table " , {
lengthMenu : [
[ 10 , 25 , 50 , 100 , - 1 ],
[ 10 , 25 , 50 , 100 , \ ' All\ ' ]
]});
2024-02-12 02:01:51 +01:00
' ;
$html .= '<section class="chapter" id="technicaldebtphan">' . " \n " ;
$html .= '<h2><span class="fas fa-book-dead pictofixedwidth"></span>Technical debt <span class="opacitymedium">(PHAN ' . $phan_nblines . ' warnings)</span></h2>' . " \n " ;
$html .= '<div class="boxallwidth">' . " \n " ;
2024-02-17 16:46:06 +01:00
$html .= '<div class="div-table-responsive">' . " \n " ;
2024-02-12 02:01:51 +01:00
$html .= '<table class="list_technical_debt centpercent">' . " \n " ;
$html .= '<thead><tr class="trgroup"><td>File</td><td>Line</td><td>Detail</td></tr></thead><tbody>' . " \n " ;
2024-02-25 18:36:40 +01:00
$html .= $tmpphan ;
2024-02-12 02:01:51 +01:00
$html .= '</tbody></table>' ;
2024-02-20 02:26:42 +01:00
// Disabled, no more required as list is managed with datatable
//$html .= '<div><span class="seedetail" data-source="phan" id="sourcephan">Show all...</span></div>';
2024-02-12 02:01:51 +01:00
$html .= '</div></div>' ;
$html .= '</section>' . " \n " ;
}
2023-08-23 14:24:52 +02:00
2024-01-13 13:12:21 +01:00
2024-02-11 13:35:49 +01:00
// JS code to allow to expand/collapse
2024-01-13 13:12:21 +01:00
2023-08-23 19:29:14 +02:00
$html .= '
< script >
$ ( document ) . ready ( function () {
2024-02-17 16:46:06 +01:00
$ ( " .seeothercommit " ) . on ( " click " , function () {
console . log ( " Click on seeothercommit " );
$ ( this ) . closest ( \ ' . more\ ' ) . find ( \ ' . morediv\ ' ) . toggle ();
});
$ ( " .seedetail " ) . on ( " click " , function () {
var source = $ ( this ) . attr ( " data-source " );
console . log ( " Click on " + source + " so we show class .source " + source );
jQuery ( " .source " + source ) . toggle ();
} );
'.$datatable_script.'
2023-08-23 19:29:14 +02:00
});
</ script >
' ;
2023-11-20 20:20:14 +01:00
$html .= '</body>' ;
2023-08-23 14:24:52 +02:00
$html .= '</html>' ;
2024-01-13 13:12:21 +01:00
// Output report into a HTML file
2023-08-23 14:24:52 +02:00
$fh = fopen ( $outputpath , 'w' );
if ( $fh ) {
fwrite ( $fh , $html );
fclose ( $fh );
2024-04-30 19:00:11 +02:00
print 'Generation of output file ' . $outputpath . ' done.' . " \n " ;
2023-08-23 14:24:52 +02:00
} else {
2024-04-30 19:00:11 +02:00
print 'Failed to open ' . $outputpath . ' for output.' . " \n " ;
2023-08-23 14:24:52 +02:00
}
2023-08-23 19:29:14 +02:00
2024-04-05 14:45:34 +02:00
2023-08-23 19:29:14 +02:00
/**
* function to format a number
*
* @ param string | int $number Number to format
* @ param int $nbdec Number of decimal digits
2024-01-12 17:14:13 +01:00
* @ return string Formatted string
2023-08-23 19:29:14 +02:00
*/
function formatNumber ( $number , $nbdec = 0 )
{
return number_format ( $number , 0 , '.' , ' ' );
}
2024-02-11 13:35:49 +01:00
/**
* cleanVal
*
* @ param array $val Array of a PR
* @ return Array of a PR
*/
function cleanVal ( $val )
{
$tmpval = array ();
$tmpval [ 'url' ] = $val -> url ;
$tmpval [ 'number' ] = $val -> number ;
$tmpval [ 'title' ] = $val -> title ;
$tmpval [ 'created_at' ] = $val -> created_at ;
$tmpval [ 'updated_at' ] = $val -> updated_at ;
return $tmpval ;
}
2024-02-11 16:39:31 +01:00
/**
* cleanVal2
*
* @ param array $val Array of a PR
* @ return Array of a PR
*/
function cleanVal2 ( $val )
{
$tmp = explode ( ';' , $val );
$tmpval = array ();
2024-02-11 18:07:55 +01:00
$tmpval [ 'commitid' ] = $tmp [ 1 ];
2024-02-11 16:39:31 +01:00
$tmpval [ 'url' ] = '' ;
2024-02-11 18:07:55 +01:00
$tmpval [ 'issueid' ] = '' ;
$tmpval [ 'issueidyogosha' ] = '' ;
$tmpval [ 'issueidcve' ] = '' ;
2024-02-12 02:01:51 +01:00
$tmpval [ 'title' ] = array_key_exists ( 5 , $tmp ) ? $tmp [ 5 ] : '' ;
$tmpval [ 'created_at' ] = array_key_exists ( 0 , $tmp ) ? $tmp [ 0 ] : '' ;
2024-02-11 16:39:31 +01:00
$tmpval [ 'updated_at' ] = '' ;
2024-02-11 18:07:55 +01:00
$reg = array ();
if ( preg_match ( '/#(\d+)/' , $tmpval [ 'title' ], $reg )) {
$tmpval [ 'issueid' ] = $reg [ 1 ];
}
if ( preg_match ( '/CVE([0-9\-\s]+)/' , $tmpval [ 'title' ], $reg )) {
$tmpval [ 'issueidcve' ] = preg_replace ( '/^\-/' , '' , trim ( $reg [ 1 ]));
}
if ( preg_match ( '/#yogosha(\d+)/i' , $tmpval [ 'title' ], $reg )) {
$tmpval [ 'issueidyogosha' ] = $reg [ 1 ];
}
2024-02-11 16:39:31 +01:00
return $tmpval ;
}