public static function finalize() { if (!file_exists('nodes.csv')) { return false; } fclose(static::$fp_rels); fclose(static::$fp_nodes); $config = \Exakat\Config::factory(); $res = shell_exec(<<<SHELL cd ./batch-import java -server -Dfile.encoding=UTF-8 -Xmx4G -jar target/batch-import-jar-with-dependencies.jar {$config->neo4j_folder}/data/graph.db ../nodes.csv ../rels.csv 2>/dev/null cd {$config->neo4j_folder} ./bin/neo4j restart sleep 1 SHELL ); $context_options = array('http' => array('method' => 'GET', 'ignore_errors' => true, 'header' => <<<HEADER Content-type: application/json Accept: application/json User-Agent: Exakat v 1.0 HEADER )); $context = stream_context_create($context_options); $config = \Exakat\Config::factory(); $response = file_get_contents('http://' . $config->neo4j_host . ':' . $config->neo4j_port . '/db/data/', false, $context); if (strpos($response, 'NOT_FOUND') !== false) { $response = file_get_contents('http://' . $config->neo4j_host . ':' . $config->neo4j_port . '/db/data/', false, $context); } preg_match("/Importing (\\d+) Nodes/is", $res, $nodes); preg_match("/Importing (\\d+) Relationships/is", $res, $relations); $fnodes = -1; $fp = fopen('nodes.csv', 'r'); while (fgetcsv($fp, 100000, "\t", '"')) { ++$fnodes; } fclose($fp); $frels = -1; $fp = fopen('rels.csv', 'r'); while (fgetcsv($fp, 1000, "\t", '"')) { ++$frels; } fclose($fp); if ($fnodes != $nodes[1]) { display("Warning : didn't import enough nodes : {$fnodes} expected, {$nodes[1]} actually imported\n"); } else { display("{$nodes[1]} nodes imported\n"); display(number_format(filesize('nodes.csv') / 1024, 0) . " ko imported\n"); unlink('nodes.csv'); } if ($frels != $relations[1]) { display("Warning : didn't import enough relations : {$frels} expected, {$relations[1]} actually imported\n"); } else { display("{$relations[1]} relations imported\n"); unlink('rels.csv'); } return true; }
public function __construct() { $this->config = Config::factory(); $analyzers = Analyzer::getThemeAnalyzers($this->config->thema); $this->themesList = '("' . implode('", "', $analyzers) . '")'; $this->sqlite = new \Sqlite3($this->config->projects_root . '/projects/' . $this->config->project . '/dump.sqlite', \SQLITE3_OPEN_READONLY); $this->datastore = new Datastore($this->config); }
public function __construct($analyzer) { $config = Config::factory(); $this->analyzer = $analyzer; $filename = $config->dir_root . '/human/' . $this->language . '/' . str_replace('\\', '/', str_replace('Exakat\\Analyzer\\', '', $analyzer)) . '.ini'; if (file_exists($filename)) { $this->ini = parse_ini_file($filename) + $this->ini; } // else is the default values already defined above }
function display_r($object) { static $config; if ($config === null) { $config = \Exakat\Config::factory(); } if ($config->verbose) { print_r($object); } }
public function hasResults() { $config = Config::factory(); foreach ($config->other_php_versions as $version) { $r = Analyzer::$datastore->getRow('compilation' . $version); if (count($r) > 0) { return true; } } return false; }
public function __construct() { $config = Config::factory(); if ($config->is_phar) { $this->phar_tmp = tempnam(sys_get_temp_dir(), 'exzendf2') . '.sqlite'; copy($config->dir_root . '/data/zendf2.sqlite', $this->phar_tmp); $docPath = $this->phar_tmp; } else { $docPath = $config->dir_root . '/data/zendf2.sqlite'; } $this->sqlite = new \Sqlite3($docPath, SQLITE3_OPEN_READONLY); }
public function generate($folder, $name = 'txt') { $config = Config::factory(); $themes = $config->thema; $analyzers = array(); foreach ($themes as $theme) { $analyzers[] = Analyzer::getThemeAnalyzers($theme); } $analyzers = call_user_func_array('array_merge', $analyzers); display(count($analyzers) . " analyzers\n"); $res = $this->sqlite->query('SELECT distinct analyzer FROM results WHERE analyzer IN ("' . implode('","', $analyzers) . '") ORDER BY analyzer'); $skeleton = array(); while ($row = $res->fetchArray(SQLITE3_ASSOC)) { $skeleton[$row['analyzer']] = 0; } display(count($skeleton) . " distinct analyzers\n"); $titles = array(); foreach ($skeleton as $analyzer => $foo) { if ($analyzer == 'total') { continue; } $ini = parse_ini_file($this->config->dir_root . '/human/en/' . $analyzer . '.ini'); $titles[$analyzer] = '"' . $ini['name'] . '"'; } $all = array(); $res = $this->sqlite->query('SELECT * FROM results WHERE analyzer IN ("' . implode('","', $analyzers) . '") ORDER BY file'); $total = 0; while ($row = $res->fetchArray(SQLITE3_ASSOC)) { if (!isset($all[$row['file']])) { $all[$row['file']] = $skeleton; } ++$all[$row['file']][$row['analyzer']]; ++$total; } display($total . " issues read\n"); $txt = " \t" . implode("\t", array_values($titles)) . "\n"; foreach ($all as $file => $values) { $txt .= "{$file}\t" . implode("\t", array_values($values)) . "\n"; } file_put_contents($folder . '/' . $name . '.' . self::FILE_EXTENSION, $txt); display(count($all) . " issues reported\n"); print "Upload " . $name . '.' . self::FILE_EXTENSION . " on http://amp.pharm.mssm.edu/clustergrammer/\n"; }
function run($test, $number) { print "{$test}.{$number}\n"; $ini = parse_ini_file('../../projects/test/config.ini'); $phpversion = empty($ini['phpversion']) ? phpversion() : $ini['phpversion']; include_once '../../library/Exakat/Phpexec.php'; include_once '../../library/Exakat/Config.php'; $config = \Exakat\Config::factory(array('foo', '-p', 'test')); $versionPHP = 'php' . str_replace('.', '', $phpversion); $shell = $config->{$versionPHP} . ' -l ./source/' . $test . '.' . $number . '.php'; $res = shell_exec($shell); if (strpos('No syntax errors detected in', $res) !== false) { print "This script doesn't compile with " . PHP_VERSION . " .\n"; return; } $shell = 'cd ../..; php exakat cleandb; php exakat load -f ./tests/tokenizer/source/' . $test . '.' . $number . '.php -p test; php exakat export -text -f ./tests/tokenizer/exp/' . "{$test}.{$number}" . '.txt'; $res = shell_exec($shell); if (preg_match("/Warning : (.*?)\n/is", $res, $r) !== 0) { print "{$test} {$number} has some warning : {$r['1']}\n"; return; } if (!file_exists('./exp/' . "{$test}.{$number}" . '.txt')) { print "This script has no exp file.\n"; return; } if (filesize('./exp/' . "{$test}.{$number}" . '.txt') == 0) { unlink('./exp/' . "{$test}.{$number}" . '.txt'); print "This script has an empty exp file.\n"; return; } $exp = file_get_contents('./exp/' . "{$test}.{$number}" . '.txt'); if (strpos($exp, 'Parse error') !== false) { print "This script doesn't compile.\n"; return; } if (strpos($exp, 'Label : NEXT') !== false) { print "There are some unprocessed link in this script\n"; return; } }
public function query($query, $params = array(), $load = array()) { $fields = array('query' => $query); if (isset($params) && !empty($params)) { $fields['params'] = $params; } $fields_string = json_encode($fields); $ch = curl_init(); static $neo4j_host, $neo4j_auth; if (!isset($neo4j_host)) { $config = \Exakat\Config::factory(); $neo4j_host = $config->neo4j_host . ':' . $config->neo4j_port; if ($config->neo4j_login !== '') { $neo4j_auth = base64_encode($config->neo4j_login . ':' . $config->neo4j_password); } else { $neo4j_auth = ''; } } //set the url, number of POST vars, POST data $headers = array('Accept: application/json;stream=true', 'Content-type: application/json', 'Content-Length: ' . strlen($fields_string)); if (!empty($neo4j_auth)) { $headers[] = 'Authorization: Basic ' . $neo4j_auth; } curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_URL, 'http://' . $neo4j_host . '/db/data/cypher'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); //execute post $result = curl_exec($ch); //close connection curl_close($ch); if (isset($result->message)) { throw new \Exception($result->message); } return json_decode($result); }
public function generate($dirName, $fileName = null) { $sqlite = new \sqlite3($dirName . '/dump.sqlite', \SQLITE3_OPEN_READONLY); $sqlQuery = <<<SQL SELECT id AS id, fullcode AS code, file AS file, line AS line, analyzer AS analyzer FROM results WHERE analyzer IN {$this->themesList} SQL; $res = $sqlite->query($sqlQuery); $config = Config::factory(); $datastore = new Datastore($config); $items = array(); while ($row = $res->fetchArray(SQLITE3_ASSOC)) { $ini = parse_ini_file($config->dir_root . '/human/en/' . $row['analyzer'] . '.ini'); $row['error'] = $ini['name']; $a = Analyzer::getInstance($row['analyzer']); $row['severity'] = $a->getSeverity(); $row['impact'] = $a->getTimeToFix(); $row['recipes'] = $a->getThemes(); $items[] = $row; $this->count(); } if ($fileName === null) { $json = json_encode($items, JSON_PARTIAL_OUTPUT_ON_ERROR); // @todo Log if $json == false return $json; } else { file_put_contents($dirName . '/' . $fileName . '.' . self::FILE_EXTENSION, json_encode($items)); return true; } }
} } public static function autoload_test($name) { $path = dirname(__DIR__); $file = $path . '/tests/analyzer/' . str_replace('\\', DIRECTORY_SEPARATOR, $name) . '.php'; if (file_exists($file)) { include $file; } $file = $path . '/tests/tokenizer/' . str_replace('\\', DIRECTORY_SEPARATOR, $name) . '.php'; if (file_exists($file)) { include $file; } } public static function autoload_phpunit($name) { $file = 'Test/' . str_replace('_', '/', str_replace('Test\\', '', $name)) . '.php'; if (file_exists($file)) { include $file; } } } spl_autoload_register('Autoload::autoload_library'); require_once __DIR__ . '/../vendor/autoload.php'; // depending on your project this may not be necessary if (isset($argv)) { $config = \Exakat\Config::factory($argv); } else { $config = \Exakat\Config::factory($GLOBALS['argv']); } include 'helpers.php';
private function init_project($project, $repositoryURL) { if (!file_exists($this->config->projects_root . '/projects/' . $project)) { mkdir($this->config->projects_root . '/projects/' . $project, 0755); } else { display($this->config->projects_root . '/projects/' . $project . ' already exists. Reusing' . "\n"); } if (!file_exists($this->config->projects_root . '/projects/' . $project . '/log/')) { mkdir($this->config->projects_root . '/projects/' . $project . '/log/', 0755); } else { display($this->config->projects_root . '/projects/' . $project . '/log/ already exists. Ignoring' . "\n"); return null; } $this->datastore = new Datastore(Config::factory(), Datastore::CREATE); if (!file_exists($this->config->projects_root . '/projects/' . $project . '/config.ini')) { if ($this->config->symlink === true) { $vcs = 'symlink'; } elseif ($this->config->svn === true) { $vcs = 'svn'; } elseif ($this->config->git === true) { $vcs = 'git'; } elseif ($this->config->copy === true) { $vcs = 'copy'; } elseif ($this->config->bzr === true) { $vcs = 'bzr'; } elseif ($this->config->hg === true) { $vcs = 'hg'; } elseif ($this->config->composer === true) { $vcs = 'composer'; } else { $vcs = 'git'; } // default initial config. Found in test project. $configIni = <<<INI phpversion = 7.1 ignore_dirs[] = /test ignore_dirs[] = /tests ignore_dirs[] = /Tests ignore_dirs[] = /Test ignore_dirs[] = /example ignore_dirs[] = /examples ignore_dirs[] = /docs ignore_dirs[] = /doc ignore_dirs[] = /tmp ignore_dirs[] = /version ignore_dirs[] = /vendor ignore_dirs[] = /js ignore_dirs[] = /lang ignore_dirs[] = /data ignore_dirs[] = /css ignore_dirs[] = /cache ignore_dirs[] = /vendor ignore_dirs[] = /assets ignore_dirs[] = /spec ignore_dirs[] = /sql file_extensions = project_name = "{$project}"; project_url = "{$repositoryURL}"; project_vcs = "{$vcs}"; project_description = ""; project_packagist = ""; INI; file_put_contents($this->config->projects_root . '/projects/' . $project . '/config.ini', $configIni); } else { display($this->config->projects_root . '/projects/' . $project . '/config.ini already exists. Ignoring' . "\n"); } shell_exec('chmod -R g+w ' . $this->config->projects_root . '/projects/' . $project); $repositoryDetails = parse_url($repositoryURL); $skipFiles = false; if (!file_exists($this->config->projects_root . '/projects/' . $project . '/code/')) { switch (true) { // Symlink case $this->config->symlink === true: display('Symlink initialization : ' . realpath($repositoryURL)); symlink(realpath($repositoryURL), $this->config->projects_root . '/projects/' . $project . '/code'); break 1; // Empty initialization // Empty initialization case $this->config->copy === true: display('Copy initialization'); $total = copyDir(realpath($repositoryURL), $this->config->projects_root . '/projects/' . $project . '/code'); display($total . ' files were copied'); break 1; // Empty initialization // Empty initialization case $repositoryURL === '' || $repositoryURL === false: display('Empty initialization'); break 1; // composer archive (early in the list, as this won't have 'scheme' // composer archive (early in the list, as this won't have 'scheme' case $this->config->composer === true: display('Initialization with composer'); $res = shell_exec('composer --version'); if (strpos($res, 'Composer') === false) { throw new HelperException('Composer'); } // composer install $composer = new \stdClass(); $composer->require = new \stdClass(); $composer->require->{$repositoryURL} = 'dev-master'; $json = json_encode($composer); mkdir($this->config->projects_root . '/projects/' . $project . '/code', 0755); file_put_contents($this->config->projects_root . '/projects/' . $project . '/code/composer.json', $json); shell_exec('cd ' . $this->config->projects_root . '/projects/' . $project . '/code; composer -q install'); break 1; // SVN // SVN case isset($repositoryDetails['scheme']) && $repositoryDetails['scheme'] == 'svn' || $this->config->svn === true: $res = shell_exec('svn --version'); if (strpos($res, 'svn') === false) { throw new HelperException('SVN'); } display('SVN initialization'); shell_exec('cd ' . $this->config->projects_root . '/projects/' . $project . '; svn checkout ' . escapeshellarg($repositoryURL) . ' code'); break 1; // Bazaar // Bazaar case $this->config->bzr === true: $res = shell_exec('bzr --version'); if (strpos($res, 'Bazaar') === false) { throw new HelperException('Bazar'); } display('Bazaar initialization'); shell_exec('cd ' . $this->config->projects_root . '/projects/' . $project . '; bzr branch ' . escapeshellarg($repositoryURL) . ' code'); break 1; // HG // HG case $this->config->hg === true: $res = shell_exec('hg --version'); if (strpos($res, 'Mercurial') === false) { throw new HelperException('Mercurial'); } display('Mercurial initialization'); shell_exec('cd ' . $this->config->projects_root . '/projects/' . $project . '; hg clone ' . escapeshellarg($repositoryURL) . ' code'); break 1; // Tbz archive // Tbz archive case $this->config->tbz === true: display('Download the tar.bz2'); $binary = file_get_contents($repositoryURL); display('Saving'); $archiveFile = tempnam(sys_get_temp_dir(), 'archiveTgz') . '.tgz'; file_put_contents($archiveFile, $binary); display('Unarchive'); shell_exec('tar -jxf ' . $archiveFile . ' --directory ' . $this->config->projects_root . '/projects/' . $project . '/code/'); display('Cleanup'); unlink($archiveFile); break 1; // tgz archive // tgz archive case $this->config->tgz === true: display('Download the tar.gz'); $binary = file_get_contents($repositoryURL); display('Saving'); $archiveFile = tempnam(sys_get_temp_dir(), 'archiveTgz') . '.tgz'; file_put_contents($archiveFile, $binary); display('Unarchive'); mkdir($this->config->projects_root . '/projects/' . $project . '/code/'); shell_exec('tar -zxf ' . $archiveFile . ' -C ' . $this->config->projects_root . '/projects/' . $project . '/code/'); display('Cleanup'); unlink($archiveFile); break 1; // zip archive // zip archive case $this->config->zip === true: $res = shell_exec('zip --version'); if (strpos($res, 'Zip') === false) { throw new HelperException('zip'); } display('Download the zip'); $binary = file_get_contents($repositoryURL); display('Saving'); $archiveFile = tempnam(sys_get_temp_dir(), 'archiveZip') . '.zip'; file_put_contents($archiveFile, $binary); display('Unzip'); shell_exec('unzip ' . $archiveFile . ' -d ' . $this->config->projects_root . '/projects/' . $project . '/code/'); display('Cleanup'); unlink($archiveFile); break 1; // Git // Git is last, as it will act as a default // Git // Git is last, as it will act as a default case isset($repositoryDetails['scheme']) && $repositoryDetails['scheme'] == 'git' || $this->config->git === true: $res = shell_exec('git --version'); if (strpos($res, 'git') === false) { throw new HelperException('git'); } display('Git initialization'); $res = shell_exec('cd ' . $this->config->projects_root . '/projects/' . $project . '; git clone -q ' . $repositoryURL . ' code 2>&1 '); if (($offset = strpos($res, 'fatal: ')) !== false) { $this->datastore->addRow('hash', array('init error' => trim(substr($res, $offset + 7)))); display("An error prevented code initialization : " . trim(substr($res, $offset + 7)) . "\nNo code was loaded.\n"); $skipFiles = true; } break 1; default: display('No Initialization'); } } elseif (file_exists($this->config->projects_root . '/projects/' . $project . '/code/')) { display("Code folder is already there. Leaving it intact.\n"); } display("Counting files\n"); $this->datastore->addRow('hash', array('status' => 'Initproject')); if (!$skipFiles) { display("Running files\n"); $analyze = new Files($this->gremlin, $this->config); $analyze->run(); unset($analyze); } }
public function getTimeToFix() { if (Analyzer::$docs === null) { $config = Config::factory(); Analyzer::$docs = new Docs($config->dir_root . '/data/analyzers.sqlite'); } return Analyzer::$docs->getTimeToFix($this->analyzer); }
public function generate($folder, $name = 'dependencies') { $graph = new Gremlin3(Config::factory()); $links = array(); $nodes = array('class' => array(), 'trait' => array(), 'interface' => array(), 'unknown' => array()); $fullcode = array(); $query = <<<GREMLIN g.V().hasLabel("Class").map{[it.get().value("fullnspath"), it.get().value("fullcode")]} GREMLIN; $res = $graph->query($query); foreach ($res->results as $v) { $names[$v[0]] = $v[1]; $nodes['class'][] = $v[0]; } $query = <<<GREMLIN g.V().hasLabel("Trait").map{[it.get().value("fullnspath"), it.get().value("fullcode")]} GREMLIN; $res = $graph->query($query); foreach ($res->results as $v) { $names[$v[0]] = $v[1]; $nodes['trait'][] = $v[0]; } $query = <<<GREMLIN g.V().hasLabel("Interface").map{[it.get().value("fullnspath"), it.get().value("fullcode")]} GREMLIN; $res = $graph->query($query); foreach ($res->results as $v) { $names[$v[0]] = $v[1]; $nodes['interface'][] = $v[0]; } $nodesId = array_flip(call_user_func_array('array_merge', array_values($nodes))); // static constants $query = <<<GREMLIN g.V().hasLabel("Staticconstant").as('fullcode') .out('CLASS').as('destination') .repeat(__.in()).until(hasLabel("Class", "Trait", "Interface")).as('origin') .select('origin', 'destination', 'fullcode').by('fullnspath').by('fullnspath').by('fullcode') GREMLIN; $res = $graph->query($query); $total = 0; foreach ($res->results as $v) { if (!isset($nodesId[$v->origin])) { $nodes['unknown'][] = $v->origin; $nodesId[$v->origin] = count($nodes) - 1; } if (!isset($nodesId[$v->destination])) { $nodes['unknown'][] = $v->destination; $nodesId[$v->destination] = count($nodes) - 1; } $links[$nodesId[$v->destination] . ' -> ' . $nodesId[$v->origin]][] = 'staticconstant'; $fullcode[$nodesId[$v->destination] . ' -> ' . $nodesId[$v->origin]][] = $v->fullcode; ++$total; } print "{$total} Static constants\n"; // static property $query = <<<GREMLIN g.V().hasLabel("Staticproperty").as('fullcode') .out('CLASS').as('destination') .repeat(__.in()).until(hasLabel("Class", "Trait", "Interface")).as('origin') .select('origin', 'destination', 'fullcode').by('fullnspath').by('fullnspath').by('fullcode') GREMLIN; $res = $graph->query($query); $total = 0; foreach ($res->results as $v) { if (!isset($nodesId[$v->origin])) { $nodes['unknown'][] = $v->origin; $nodesId[$v->origin] = count($nodes) - 1; } if (!isset($nodesId[$v->destination])) { $nodes['unknown'][] = $v->destination; $nodesId[$v->destination] = count($nodes) - 1; } $links[$nodesId[$v->destination] . ' -> ' . $nodesId[$v->origin]][] = 'staticproperty'; $fullcode[$nodesId[$v->destination] . ' -> ' . $nodesId[$v->origin]][] = $v->fullcode; ++$total; } print "{$total} Static property\n"; // Instantiation $query = <<<GREMLIN g.V().hasLabel("New").as('fullcode') .out('NEW').as('destination') .repeat(__.in()).until(hasLabel("Class", "Trait", "Interface")).as('origin') .select('origin', 'destination', 'fullcode').by('fullnspath').by('fullnspath').by('fullcode') GREMLIN; $res = $graph->query($query); $total = 0; foreach ($res->results as $v) { if (!isset($nodesId[$v->origin])) { $nodes['unknown'][] = $v->origin; $nodesId[$v->origin] = count($nodes) - 1; } if (!isset($nodesId[$v->destination])) { $nodes['unknown'][] = $v->destination; $nodesId[$v->destination] = count($nodes) - 1; } $links[$nodesId[$v->destination] . ' -> ' . $nodesId[$v->origin]][] = 'instanciation'; $fullcode[$nodesId[$v->destination] . ' -> ' . $nodesId[$v->origin]][] = $v->fullcode; ++$total; } print "{$total} New\n"; // Typehint $query = <<<GREMLIN g.V().hasLabel("Function").as('fullcode') .out('ARGUMENTS').out("ARGUMENT").out("TYPEHINT").as('destination') .repeat(__.in()).until(hasLabel("Class", "Trait", "Interface")).as('origin') .select('origin', 'destination', 'fullcode').by('fullnspath').by('fullnspath').by('fullcode') GREMLIN; $res = $graph->query($query); $total = 0; foreach ($res->results as $v) { if (!isset($nodesId[$v->origin])) { $nodes['unknown'][] = $v->origin; $nodesId[$v->origin] = count($nodes) - 1; } if (!isset($nodesId[$v->destination])) { $nodes['unknown'][] = $v->destination; $nodesId[$v->destination] = count($nodes) - 1; } $links[$nodesId[$v->destination] . ' -> ' . $nodesId[$v->origin]][] = 'typehint'; $fullcode[$nodesId[$v->destination] . ' -> ' . $nodesId[$v->origin]][] = $v->fullcode; ++$total; } print "{$total} Typehint\n"; // instanceof $query = <<<GREMLIN g.V().hasLabel("Instanceof").as('fullcode') .out('CLASS').as('destination') .repeat(__.in()).until(hasLabel("Class", "Trait", "Interface")).as('origin') .select('origin', 'destination', 'fullcode').by('fullnspath').by('fullnspath').by('fullcode') GREMLIN; $res = $graph->query($query); $total = 0; foreach ($res->results as $v) { if (!isset($nodesId[$v[0]])) { $nodes['unknown'][] = $v[0]; $nodesId[$v[0]] = count($nodes) - 1; } if (!isset($nodesId[$v[1]])) { $nodes['unknown'][] = $v[1]; $nodesId[$v[1]] = count($nodes) - 1; } $links[$nodesId[$v[1]] . ' -> ' . $nodesId[$v[0]]][] = 'instanceof'; $fullcode[$nodesId[$v[1]] . ' -> ' . $nodesId[$v[0]]][] = $v[2]; ++$total; } print "{$total} Instanceof\n"; // static methods $query = <<<GREMLIN g.V().hasLabel("Staticmethodcall").as('fullcode') .out('CLASS').as('destination') .repeat(__.in()).until(hasLabel("Class", "Trait", "Interface")).as('origin') .select('origin', 'destination', 'fullcode').by('fullnspath').by('fullnspath').by('fullcode') GREMLIN; $res = $graph->query($query); $total = 0; foreach ($res->results as $v) { if (!isset($nodesId[$v->origin])) { $nodes['unknown'][] = $v->origin; $nodesId[$v->origin] = count($nodes) - 1; } if (!isset($nodesId[$v->destination])) { $nodes['unknown'][] = $v->destination; $nodesId[$v->destination] = count($nodes) - 1; } $links[$nodesId[$v->destination] . ' -> ' . $nodesId[$v->origin]][] = 'staticmethodcall'; $fullcode[$nodesId[$v->destination] . ' -> ' . $nodesId[$v->origin]][] = $v->fullcode; ++$total; } print "{$total} Static methods\n"; // Final preparation // Nodes $colors = array('class' => 'darkorange', 'trait' => 'gold', 'interface' => 'skyblue', 'unknown' => 'gray'); foreach ($nodes as $type => &$someNodes) { foreach ($someNodes as $id => &$n) { $n = <<<DOT {$nodesId[$n]} [label=<<table color='white' BORDER='0' CELLBORDER='1' CELLSPACING='0' > <tr> <td bgcolor='{$colors[$type]}'>{$n}</td> </tr> </table>> shape="none"]; DOT; } unset($n); } unset($someNodes); // print_r($nodes); // Links $colors = array('staticmethodcall' => 'firebrick2', 'staticconstant' => 'firebrick2', 'staticproperty' => 'firebrick2', 'instanceof' => 'chartreuse4', 'typehint' => 'chartreuse4', 'use' => 'darkgoldenrod2', 'instanciation' => 'black'); $linksDot = array(); foreach ($links as $link => $type) { foreach ($type as $id => $t) { $linksDot[] = $link . ' [shape="none" color="' . $colors[$t] . '" label="' . str_replace('"', '\\"', $fullcode[$link][$id]) . '"];'; } } unset($type); $dot = "digraph graphname {\n \n fontname = \"Bitstream Vera Sans\"\n fontsize = 14\n colorscheme = \"bugn9\"\n\n node [\n fontname = \"Bitstream Vera Sans\"\n fontsize = 14\n shape = \"record\"\n ]\n\n edge [\n fontname = \"Bitstream Vera Sans\"\n fontsize = 8\n arrowhead = \"empty\"\n width = \"2\"\n ]\n \n " . implode("\n", $nodes['class']) . "\n" . implode("\n", $nodes['trait']) . "\n" . implode("\n", $nodes['interface']) . "\n" . implode("\n", $nodes['unknown']) . "\n\n" . implode("\n", $linksDot) . "\n}\n"; print strlen($dot); print $folder . '/' . $name . '.' . self::FILE_EXTENSION; file_put_contents($folder . '/' . $name . '.' . self::FILE_EXTENSION, $dot); }
public function run() { $progress = 0; $project = $this->config->project; $this->project_dir = $this->config->projects_root . '/projects/' . $project; if ($this->config->project == "default") { throw new ProjectNeeded(); } if (!file_exists($this->config->projects_root . '/projects/' . $project)) { throw new NoSuchProject($this->config->project); } // cleaning log directory (possibly logs) $logs = glob($this->config->projects_root . '/projects/' . $project . '/log/*'); foreach ($logs as $log) { unlink($log); } $this->logTime('Start'); $this->addSnitch(array('step' => 'Start', 'project' => $this->config->project)); // cleaning datastore $this->datastore = new Datastore($this->config, Datastore::CREATE); $audit_start = time(); $this->datastore->addRow('hash', array('audit_start' => $audit_start, 'exakat_version' => Exakat::VERSION, 'exakat_build' => Exakat::BUILD)); display("Running project '{$project}'\n"); display("Cleaning DB\n"); $analyze = new CleanDb($this->gremlin, $this->config, Tasks::IS_SUBTASK); $analyze->run(); unset($analyze); $this->logTime('CleanDb'); $this->addSnitch(array('step' => 'Clean DB', 'project' => $this->config->project)); display("Search for external libraries\n"); $args = array(1 => 'findextlib', 2 => '-p', 3 => $this->config->project, 4 => '-u'); $configThema = Config::push($args); $analyze = new FindExternalLibraries($this->gremlin, $configThema, Tasks::IS_SUBTASK); $analyze->run(); $this->addSnitch(array('step' => 'External lib', 'project' => $this->config->project)); Config::pop(); unset($analyze); display("Running files\n"); $analyze = new Files($this->gremlin, $this->config, Tasks::IS_SUBTASK); $analyze->run(); unset($analyze); $this->logTime('Files'); $this->addSnitch(array('step' => 'Files', 'project' => $this->config->project)); $this->checkTokenLimit(); $analyze = new Load($this->gremlin, $this->config, Tasks::IS_SUBTASK); $analyze->run(); unset($analyze); display("Project loaded\n"); $this->logTime('Loading'); // paralell running exec($this->config->php . ' ' . $this->config->executable . ' magicnumber -p ' . $this->config->project . ' > /dev/null &'); $this->addSnitch(array('step' => 'Magic Numbers', 'project' => $this->config->project)); // Dump is a child process shell_exec($this->config->php . ' ' . $this->config->executable . ' dump -p ' . $this->config->project); foreach ($this->themes as $theme) { $this->addSnitch(array('step' => 'Analyze : ' . $theme, 'project' => $this->config->project)); $themeForFile = strtolower(str_replace(' ', '_', trim($theme, '"'))); $args = array(1 => 'analyze', 2 => '-p', 3 => $this->config->project, 4 => '-T', 5 => trim($theme, '"'), 6 => '-norefresh', 7 => '-u'); try { $configThema = Config::push($args); $analyze = new Analyze($this->gremlin, $configThema, Tasks::IS_SUBTASK); $analyze->run(); unset($analyze); rename($this->config->projects_root . '/projects/' . $project . '/log/analyze.log', $this->config->projects_root . '/projects/' . $project . '/log/analyze.' . $themeForFile . '.log'); Config::pop(); $args = array(1 => 'dump', 2 => '-p', 3 => $this->config->project, 4 => '-T', 5 => trim($theme, '"'), 6 => '-u'); $configThema = Config::push($args); $dump = new Dump($this->gremlin, $configThema, Tasks::IS_SUBTASK); $dump->run(); unset($dump); Config::pop(); } catch (\Exception $e) { echo "Error while running the Analyze {$theme} \n", $e->getMessage(), "\nTrying next analysis\n"; file_put_contents($this->config->projects_root . '/projects/' . $project . '/log/analyze.' . $themeForFile . '.final.log', $e->getMessage()); } } display("Analyzed project\n"); $this->logTime('Analyze'); $this->addSnitch(array('step' => 'Analyzed', 'project' => $this->config->project)); $this->logTime('Analyze'); $oldConfig = Config::factory(); foreach ($this->reports as $reportName => $formats) { foreach ($formats as $format => $fileName) { display("Reporting {$reportName} in {$format}\n"); $this->addSnitch(array('step' => 'Report : ' . $format, 'project' => $this->config->project)); $args = array(1 => 'report', 2 => '-p', 3 => $this->config->project, 4 => '-file', 5 => $fileName, 6 => '-format', 7 => $format); $this->config = Config::factory($args); try { $report = new Report2($this->gremlin, $this->config, Tasks::IS_SUBTASK); $report->run(); unset($report); } catch (\Exception $e) { echo "Error while building {$reportName} in {$format} \n", $e->getMessage(), "\nTrying next report\n"; } } } Config::factory($oldConfig); display("Reported project\n"); $audit_end = time(); // measure Neo4j's final size $res = shell_exec('du -sh ' . $this->config->neo4j_folder . ' 2>/dev/null'); $neo4jSize = trim(str_replace(basename($this->config->neo4j_folder), '', $res)); $this->datastore->addRow('hash', array('audit_end' => $audit_end, 'audit_length' => $audit_end - $audit_start, 'neo4jSize' => $neo4jSize)); $query = <<<GREMLIN g.V().where( __.sideEffect{x = []; }.in('ANALYZED').sideEffect{ x.add(it.get().value('analyzer')); }.barrier().sideEffect{ y = x.groupBy().findAll{ i,j -> j.size() > 1;};} ) .filter{ y.size() > 0; } .map{ y; }; GREMLIN; $res = $this->gremlin->query($query); if (!empty($res)) { file_put_contents($this->config->projects_root . '/projects/' . $project . '/log/doublons.log', var_export($res, true)); } $this->logTime('Final'); $this->removeSnitch(); display("End\n"); }
public static function findFiles($path, &$files, &$ignoredFiles) { $config = Config::factory(); $ignore_dirs = $config->ignore_dirs; $dir = $config->project; // Actually finding the files $ignoreDirs = array(); foreach ($ignore_dirs as $ignore) { if ($ignore[0] == '/') { $d = $config->projects_root . '/projects/' . $dir . '/code' . $ignore; if (!file_exists($d)) { continue; } $ignoreDirs[] = $ignore . '.*'; } else { $ignoreDirs[] = '.*' . $ignore . '.*'; } } if (empty($ignoreDirs)) { $regex = ''; } else { $regex = '#^(' . implode('|', $ignoreDirs) . ')#'; } $php = new Phpexec(); $ignoredFiles = array(); $d = getcwd(); if (!file_exists($path)) { display("No such file as " . $path . " when looking for files\n"); $files = array(); $ignoredFiles = array(); return; } chdir($path); $files = rglob('.'); chdir($d); $exts = $config->file_extensions; foreach ($files as $id => &$file) { $file = substr($file, 1); $ext = pathinfo($file, PATHINFO_EXTENSION); if (empty($ext)) { // it's OK. } elseif (!in_array($ext, $exts)) { // selection of extensions unset($files[$id]); $ignoredFiles[$file] = "Ignored extension ({$ext})"; } elseif (!empty($regex) && preg_match($regex, $file)) { // Matching the 'ignored dir' pattern unset($files[$id]); $ignoredFiles[$file] = 'Ignored dir'; } elseif ($php->countTokenFromFile($path . $file) < 2) { unset($files[$id]); $ignoredFiles[$file] = 'Not a PHP File'; } } }
protected function Dashboard($title) { $css = new \Stdclass(); $css->displayTitles = true; $css->titles = array('Library', 'Folder', 'Home page'); $css->readOrder = $css->titles; $titles = array('Code Smells' => 'Analyze', 'Dead Code' => 'Dead code', 'Security' => 'Security', 'Performances' => 'Performances'); $list = Analyzer::getThemeAnalyzers($titles[$title]); $where = 'WHERE analyzer in ("' . implode('", "', $list) . '")'; $res = $this->dump->query('SELECT severity, count(*) AS nb FROM results ' . $where . ' GROUP BY severity ORDER BY severity'); $severities = array(); while ($row = $res->fetchArray(\SQLITE3_ASSOC)) { $severities[$row['severity']] = array('severity' => $row['severity'], 'count' => $row['nb']); } $res = $this->dump->query('SELECT analyzer, count(*) AS nb, severity AS severity FROM results ' . $where . ' GROUP BY analyzer'); $listBySeverity = array(); $config = Config::factory(); while ($row = $res->fetchArray(\SQLITE3_ASSOC)) { $ini = parse_ini_file($config->dir_root . '/human/en/' . $row['analyzer'] . '.ini'); $listBySeverity[] = array('name' => $ini['name'], 'severity' => $row['severity'], 'count' => $row['nb']); } uasort($listBySeverity, function ($a, $b) { $s = array('Critical' => 6, 'Major' => 5, 'Middle' => 4, 'Minor' => 3, 'None' => 0); if ($s[$a['severity']] > $s[$b['severity']]) { return -1; } elseif ($s[$a['severity']] < $s[$b['severity']]) { return 1; } else { return 0; } }); $listBySeverity = array_slice($listBySeverity, 0, 5); $res = $this->dump->query('SELECT file, count(*) AS nb FROM results ' . $where . ' GROUP BY file ORDER BY count(*) DESC LIMIT 5'); $listByFile = array(); while ($row = $res->fetchArray(\SQLITE3_ASSOC)) { $listByFile[] = array('name' => $row['file'], 'severity' => '', 'count' => $row['nb']); } $info = array('upLeft' => $severities, 'upRight' => ' ', 'downLeft' => $listBySeverity, 'downRight' => $listByFile); return $this->formatDashboard($info, $css); }
private static function saveTokenCounts() { $config = Config::factory(); $datastore = new Datastore($config); $datastore->addRow('tokenCounts', static::$tokenCounts); }
public function generic_test($file) { list($analyzer, $number) = explode('.', $file); $analyzer = str_replace('_', '/', $analyzer); // Test are run with test project. $ini = parse_ini_file('../../projects/test/config.ini'); $phpversion = empty($ini['phpversion']) ? phpversion() : $ini['phpversion']; $test_config = str_replace('_', '/', substr(get_class($this), 5)); // initialize Config (needed by phpexec) $config = \Exakat\Config::factory(array('foo', '-p', 'test')); $analyzerobject = ExakatAnalyzer::getInstance($test_config); if (!$analyzerobject->checkPhpVersion($phpversion)) { $this->markTestSkipped('Needs version ' . $analyzerobject->getPhpVersion() . '.'); } require 'exp/' . str_replace('_', '/', $file) . '.php'; $versionPHP = 'php' . str_replace('.', '', $phpversion); $res = shell_exec($config->{$versionPHP} . ' -l ./source/' . str_replace('_', '/', $file) . '.php 2>/dev/null'); if (strpos($res, 'No syntax errors detected') === false) { $this->markTestSkipped('Compilation problem : "' . $res . '".'); } $Php = new Phpexec($phpversion); if (!$analyzerobject->checkPhpConfiguration($Php)) { $message = array(); $confs = $analyzerobject->getPhpConfiguration(); if (is_array($confs)) { foreach ($confs as $name => $value) { $confs[] = "{$name} => {$value}"; } $confs = join(', ', $confs); } $this->markTestSkipped('Needs configuration : ' . $confs . '.'); } $analyzer = escapeshellarg($test_config); $source = 'source/' . str_replace('_', '/', $file) . '.php'; if (is_dir($source)) { $shell = 'cd ../..; php exakat test -r -d ./tests/analyzer/' . $source . ' -P ' . $analyzer . ' -p test -q -o -json'; } else { $shell = 'cd ../..; php exakat test -f ./tests/analyzer/' . $source . ' -P ' . $analyzer . ' -p test -q -o -json'; } $shell_res = shell_exec($shell); $res = json_decode($shell_res); if ($res === null) { $this->assertTrue(false, "Json couldn't be decoded : '{$shell_res}'\n{$shell}"); } if (empty($res)) { $list = array(); } else { $list = array(); foreach ($res as $r) { $list[] = $r[0]; } $this->assertNotEquals(count($list), 0, 'No values were read from the analyzer'); } if (isset($expected) && is_array($expected)) { $missing = array(); foreach ($expected as $e) { if (($id = array_search($e, $list)) !== false) { unset($list[$id]); } else { $missing[] = $e; } } $list = array_map(function ($x) { return str_replace("'", "\\'", $x); }, $list); $this->assertEquals(count($missing), 0, count($missing) . " expected values were not found :\n '" . join("',\n '", $missing) . "'\n\nin the " . count($list) . " received values of \n '" . join("', \n '", $list) . "'\n\nsource/{$file}.php\nexp/{$file}.php\nphpunit --filter={$number} Test/{$analyzer}.php\n\n"); // also add a phpunit --filter to rerun it easily } if (isset($expected_not) && is_array($expected)) { $extra = array(); foreach ($expected_not as $e) { if ($id = array_search($e, $list)) { $extra[] = $e; unset($list[$id]); } } // the not expected $this->assertEquals(count($extra), 0, count($extra) . " values were found and shouldn't be : " . join(', ', $extra) . ""); } // the remainings $this->assertEquals(count($list), 0, count($list) . " values were found and are unprocessed : " . join(', ', $list) . ""); }
public function __construct($phpversion = null) { $config = Config::factory(); if ($phpversion === null) { $phpversion = $config->phpversion; } $this->requestedVersion = substr($phpversion, 0, 3); $this->version = $phpversion; $phpversion3 = substr($phpversion, 0, 3); $this->isCurrentVersion = substr(PHP_VERSION, 0, 3) === $phpversion3; if ($this->isCurrentVersion === true) { preg_match('/^(\\d\\.\\d+\\.\\d+)$/', PHP_VERSION, $r); $this->actualVersion = $r[1]; if (substr($this->actualVersion, 0, 3) !== $this->requestedVersion) { throw new NoPhpBinary('PHP binary for version ' . $this->requestedVersion . ' (' . $_SERVER['_'] . ') doesn\'t have the right middle version : "' . $this->actualVersion . '". Please, check config/exakat.ini'); } } switch ($phpversion3) { case '5.2': $this->phpexec = $config->php52; break 1; case '5.3': $this->phpexec = $config->php53; break 1; case '5.4': $this->phpexec = $config->php54; break 1; case '5.5': $this->phpexec = $config->php55; break 1; case '5.6': $this->phpexec = $config->php56; break 1; case '7.0': $this->phpexec = $config->php70; break 1; case '7.1': $this->phpexec = $config->php71; break 1; case '7.2': $this->phpexec = $config->php72; break 1; default: $this->phpexec = $config->php; // PHP will be always valid if we use the one that is currently executing us $this->actualVersion = PHP_VERSION; } if (preg_match('/^php:(.+?)$/', $this->phpexec)) { $folder = $config->projects_root; $res = shell_exec('docker run -it --rm --name php4exakat -v "$PWD":' . $folder . ' -w ' . $folder . ' ' . $this->phpexec . ' php -v 2>&1'); if (substr($res, 0, 4) !== 'PHP ') { throw new NoPhpBinary('Error when accessing Docker\'s PHP : "' . $res . '". Please, check config/exakat.ini'); } else { $this->phpexec = 'docker run -it --rm --name php4exakat -v "$PWD":' . $folder . ' -w ' . $folder . ' ' . $this->phpexec . ' php '; } } else { if (empty($this->phpexec)) { throw new NoPhpBinary('No PHP binary for version ' . $phpversion . ' is available. Please, check config/exakat.ini'); } if (!file_exists($this->phpexec)) { throw new NoPhpBinary('PHP binary for version ' . $phpversion . ' is not valid : "' . $this->phpexec . '". Please, check config/exkat.ini'); } if (!is_executable($this->phpexec)) { throw new NoPhpBinary('PHP binary for version ' . $phpversion . ' exists but is not executable : "' . $this->phpexec . '". Please, check config/exakat.ini'); } } }