public function run() { $project = 'test'; // Check for requested file if (!empty($this->config->filename) && !file_exists($this->config->filename)) { throw new NoSuchFile($this->config->filename); } elseif (!empty($this->config->dirname) && !file_exists($this->config->dirname)) { throw new NoSuchDir($this->config->filename); } // Check for requested analyze $analyzer = $this->config->program; if (Analyzer::getClass($analyzer)) { $analyzers_class = array($analyzer); } else { $r = Analyzer::getSuggestionClass($analyzer); if (count($r) > 0) { echo 'did you mean : ', implode(', ', str_replace('_', '/', $r)), "\n"; } throw new NoSuchAnalyzer($analyzer); } display("Cleaning DB\n"); $clean = new CleanDb($this->gremlin, $this->config, Tasks::IS_SUBTASK); $clean->run(); $load = new Load($this->gremlin, $this->config, Tasks::IS_SUBTASK); $load->run(); unset($load); display("Project loaded\n"); $analyze = new Analyze($this->gremlin, $this->config, Tasks::IS_SUBTASK); $analyze->run(); unset($analyze); $results = new Results($this->gremlin, $this->config, Tasks::IS_SUBTASK); $results->run(); unset($results); display("Analyzed project\n"); }
public function run() { $analyzer = $this->config->program; if (empty($analyzer)) { die('Provide the analyzer with the option -P X/Y. Aborting' . "\n"); } $analyzerClass = Analyzer::getClass($analyzer); if ($analyzerClass === false) { $die = "'{$analyzer}' doesn't exist. Aborting\n"; $r = Analyzer::getSuggestionClass($analyzer); if (count($r) > 0) { $die .= 'Did you mean : ' . implode(', ', str_replace('_', '/', $r)) . "\n"; } die($die); } $analyzer = Analyzer::getName($analyzerClass); $query = <<<GREMLIN g.V().hasLabel("Analysis").has("analyzer", "{$analyzer}").out().count(); GREMLIN; $vertices = $this->gremlin->query($query)->results; if (isset($vertices[0]->notCompatibleWithPhpVersion)) { die($this->config->program . " is not compatible with the running version of PHP. No result available.\n"); } if (isset($vertices[0]->notCompatibleWithPhpConfiguration)) { die($this->config->program . " is not compatible with the compilation of the running version of PHP. No result available.\n"); } $return = array(); if ($this->config->style == 'BOOLEAN') { $queryTemplate = 'g.V().hasLabel("Analysis").has("analyzer", "' . $analyzer . '").out().count().is(gt(0))'; $vertices = $this->gremlin->query($queryTemplate); $return[] = $vertices[0]; } elseif ($this->config->style == 'COUNTED_ALL') { $queryTemplate = 'g.V().hasLabel("Analysis").has("analyzer", "' . $analyzer . '").out().count()'; $vertices = $this->gremlin->query($queryTemplate)->results; $return[] = $vertices[0]; } elseif ($this->config->style == 'ALL') { $linksDown = Token::linksAsList(); $query = <<<GREMLIN g.V().hasLabel("Analysis").has("analyzer", "{$analyzer}").out('ANALYZED') .sideEffect{ line = it.get().value('line'); fullcode = it.get().value('fullcode'); file='None'; theFunction = 'None'; theClass='None'; theNamespace='None'; } .sideEffect{ line = it.get().value('line'); } .until( hasLabel('Project') ).repeat( __.in({$linksDown}) .sideEffect{ if (it.get().label() == 'Function') { theFunction = it.get().value('code')} } .sideEffect{ if (it.get().label() == 'Class') { theClass = it.get().value('fullcode')} } .sideEffect{ if (it.get().label() == 'File') { file = it.get().value('fullcode')} } ) .map{ ['line':line, 'file':file, 'fullcode':fullcode, 'function':theFunction, 'class':theClass, 'namespace':theNamespace]; } GREMLIN; $vertices = $this->gremlin->query($query)->results; $return = array(); foreach ($vertices as $k => $v) { $row = array($v->fullcode, $v->file, $v->line, $v->namespace, $v->class, $v->function); $return[] = $row; } } elseif ($this->config->style == 'DISTINCT') { $queryTemplate = 'g.V().hasLabel("Analysis").has("analyzer", "' . $analyzer . '").out("ANALYZED").values("code").unique()'; $vertices = $this->gremlin->query($queryTemplate)->results; $return = array(); foreach ($vertices as $k => $v) { $return[] = array($v); } } elseif ($this->config->style == 'COUNTED') { $queryTemplate = 'g.V().hasLabel("Analysis").has("analyzer", "' . $analyzer . '").out("ANALYZED").groupCount("m")by("code").cap("m")'; $vertices = $this->gremlin->query($queryTemplate)->results; $return = array(); foreach ($vertices[0] as $k => $v) { $return[$k] = $v; } } if ($this->config->json === true) { $text = json_encode($return); } elseif ($this->config->csv === true) { $text = array(array('Code', 'File', 'Namespace', 'Class', 'Function')); foreach ($return as $k => $v) { if (is_array($v)) { $text[] = $v; } else { $text[] = array($k, $v); } } } elseif ($this->config->html === true || $this->config->odt === true) { $text = ''; foreach ($return as $k => $r) { if ($this->config->style == 'COUNTED') { $text .= "+ {$k} => {$r}\n"; } else { $text .= "+ {$k}\n"; if (is_array($r)) { $text .= ' + ' . implode("\n + ", $r) . "\n"; } else { $text .= "+ {$r}\n"; } } } } else { // count also for $this->config->text == 1 $text = ''; foreach ($return as $k => $v) { if ($this->config->style == 'COUNTED') { $text .= "{$k} => {$v}\n"; } else { $text .= implode(', ', $v) . "\n"; } } } if ($this->config->output) { echo $text; } switch (1) { case $this->config->json: $extension = 'json'; break 1; case $this->config->odt: $extension = 'odt'; break 1; case $this->config->html: $extension = 'html'; break 1; case $this->config->csv: $extension = 'csv'; break 1; case $this->config->text: default: $extension = 'txt'; break 1; } if ($this->config->file != 'stdout') { $name = $this->config->file . '.' . $extension; if (file_exists($name)) { die("{$name} already exists. Aborting\n"); } if ($this->config->format == 'ODT') { $name1 = FILE . '.html'; file_put_contents($name1, $text); $name = FILE . '.' . $extension; shell_exec('pandoc -o ' . $name . ' ' . $name1); unlink($name1); } elseif ($this->config->format == 'CSV') { $csvFile = fopen($name, 'w'); foreach ($text as $t) { fputcsv($csvFile, $t); } fclose($csvFile); } else { file_put_contents($name, $text); } } }
public function run() { $project = $this->config->project; if ($project == 'default') { throw new ProjectNeeded($project); } if (!file_exists($this->config->projects_root . '/projects/' . $project)) { throw new NoSuchProject($project); } $this->checkTokenLimit(); $begin = microtime(true); Analyzer::$gremlinStatic = $this->gremlin; // Take this before we clean it up $rows = $this->datastore->getRow('analyzed'); $analyzed = array(); foreach ($rows as $row) { $analyzed[$row['analyzer']] = $row['counts']; } if ($this->config->program !== null) { $analyzer = $this->config->program; if (Analyzer::getClass($analyzer)) { $analyzers_class = array($analyzer); } else { $r = Analyzer::getSuggestionClass($analyzer); if (count($r) > 0) { echo 'did you mean : ', implode(', ', str_replace('_', '/', $r)), "\n"; } throw new NoSuchAnalyzer($analyzer); } } elseif (is_string($this->config->thema)) { $thema = $this->config->thema; if (!($analyzers_class = Analyzer::getThemeAnalyzers($thema))) { throw new NoSuchAnalyzer($thema); } $this->datastore->addRow('hash', array($this->config->thema => count($analyzers_class))); } else { die("Usage :php exakat analyze -T <\"Thema\"> -p <project>\n\nphp exakat analyze -P <One/rule> -p <project>\n"); } $this->log->log("Analyzing project {$project}"); $this->log->log("Runnable analyzers\t" . count($analyzers_class)); if ($this->config->noDependencies) { $dependencies2 = $analyzers_class; } else { $dependencies = array(); $dependencies2 = array(); foreach ($analyzers_class as $a) { $d = Analyzer::getInstance($a); $this->configName = str_replace('/', '_', $a); $d = $d->dependsOn(); if (!is_array($d)) { throw new DependsOnMustReturnArray(get_class($this)); } if (empty($d)) { $dependencies2[] = $a; } else { $diff = array_diff($d, $dependencies2); if (empty($diff)) { $dependencies2[] = $a; } else { $dependencies[$a] = $diff; } } } $c = count($dependencies) + 1; while (!empty($dependencies) && $c > count($dependencies)) { $c = count($dependencies); foreach ($dependencies as $a => &$d) { $diff = array_diff($d, $dependencies2); foreach ($diff as $k => $v) { if (!isset($dependencies[$v])) { $x = Analyzer::getInstance($v); if ($x === null) { display("No such dependency as '{$v}'. Ignoring\n"); continue; } $dep = $x->dependsOn(); if (count($dep) == 0) { $dependencies2[] = $v; ++$c; } else { $dependencies[$v] = $dep; $c += count($dep) + 1; } } elseif (count($dependencies[$v]) == 0) { $dependencies2[] = $v; unset($diff[$k]); } } if (empty($diff)) { $dependencies2[] = $a; unset($dependencies[$a]); } else { $d = $diff; } } unset($d); } if (!empty($dependencies)) { die("Dependencies depending on each other : can't finalize. Aborting\n" . print_r($dependencies, true)); } } $total_results = 0; $Php = new Phpexec($this->config->version); $progressBar = new Progressbar(0, count($dependencies2) + 1, exec('tput cols')); foreach ($dependencies2 as $analyzer_class) { if (!$this->config->verbose && !$this->config->quiet) { echo $progressBar->advance(); } $begin = microtime(true); $analyzer = Analyzer::getInstance($analyzer_class); $this->configName = str_replace(array('/', '\\', 'Exakat\\Analyzer\\'), array('_', '_', ''), $analyzer_class); if ($this->config->noRefresh === true && isset($analyzed[$analyzer_class])) { display("{$analyzer_class} is already processed\n"); continue 1; } $analyzer->init(); if (!$analyzer->checkPhpVersion($this->config->phpversion)) { $analyzerQuoted = str_replace('\\', '\\\\', get_class($analyzer)); $analyzer = str_replace('\\', '\\\\', $analyzer_class); $query = <<<GREMLIN result = g.addV('Noresult').property('code', 'Not Compatible With PhpVersion') .property('fullcode', 'Not Compatible With PhpVersion') .property('virtual', true) .property('notCompatibleWithPhpVersion', '{$this->config->phpversion}') .property('token', 'T_INCOMPATIBLE'); g.addV('Analysis').property('analyzer', '{$analyzerQuoted}').addE('ANALYZED').to(result); GREMLIN; $this->gremlin->query($query); $this->datastore->addRow('analyzed', array($analyzer_class => -2)); display("{$analyzer} is not compatible with PHP version {$this->config->phpversion}. Ignoring\n"); } elseif (!$analyzer->checkPhpConfiguration($Php)) { $analyzerQuoted = str_replace('\\', '\\\\', get_class($analyzer)); $analyzer = str_replace('\\', '\\\\', $analyzer_class); $query = <<<GREMLIN result = g.addV('Noresult').property('code', 'Not Compatible With Configuration') .property('fullcode', 'Not Compatible With Configuration') .property('virtual', true) .property('notCompatibleWithPhpConfiguration', '{$this->config->phpversion}') .property('token', 'T_INCOMPATIBLE'); index = g.addV('Analysis').property('analyzer', '{$analyzerQuoted}').addE('ANALYZED').to(result); GREMLIN; $this->gremlin->query($query); $this->datastore->addRow('analyzed', array($analyzer_class => -1)); display("{$analyzer} is not compatible with PHP configuration of this version. Ignoring\n"); } else { display("{$analyzer_class} running\n"); $analyzer->run(); $count = $analyzer->getRowCount(); $processed = $analyzer->getProcessedCount(); $queries = $analyzer->getQueryCount(); $rawQueries = $analyzer->getRawQueryCount(); $total_results += $count; display("{$analyzer_class} run ({$count} / {$processed})\n"); $end = microtime(true); $this->log->log("{$analyzer_class}\t" . ($end - $begin) . "\t{$count}\t{$processed}\t{$queries}\t{$rawQueries}"); // storing the number of row found in Hash table (datastore) $this->datastore->addRow('analyzed', array($analyzer_class => $count)); } } if (!$this->config->verbose && !$this->config->quiet) { echo $progressBar->advance(); } display("Done\n"); }
public function run() { if (!file_exists($this->config->projects_root . '/projects/' . $this->config->project)) { throw new NoSuchProject($this->config->project); } $res = $this->gremlin->query('g.V().hasLabel("Project").values("fullcode")'); if ($res->results[0] !== $this->config->project) { throw new NotProjectInGraph($this->config->project, $res->results[0]); } // move this to .dump.sqlite then rename at the end, or any imtermediate time // Mention that some are not yet arrived in the snitch $this->sqliteFile = $this->config->projects_root . '/projects/' . $this->config->project . '/.dump.sqlite'; $this->sqliteFileFinal = $this->config->projects_root . '/projects/' . $this->config->project . '/dump.sqlite'; if (file_exists($this->sqliteFile)) { unlink($this->sqliteFile); display('Removing old .dump.sqlite'); } $this->addSnitch(); Analyzer::initDocs(); Analyzer::$gremlinStatic = $this->gremlin; if ($this->config->update === true) { copy($this->sqliteFileFinal, $this->sqliteFile); $sqlite = new \Sqlite3($this->sqliteFile); } else { $sqlite = new \Sqlite3($this->sqliteFile); $this->getAtomCounts($sqlite); $this->collectStructures($sqlite); $sqlite->query('CREATE TABLE themas ( id INTEGER PRIMARY KEY AUTOINCREMENT, thema STRING )'); $sqlite->query('CREATE TABLE results ( id INTEGER PRIMARY KEY AUTOINCREMENT, fullcode STRING, file STRING, line INTEGER, namespace STRING, class STRING, function STRING, analyzer STRING, severity STRING )'); $sqlite->query('CREATE TABLE resultsCounts ( id INTEGER PRIMARY KEY AUTOINCREMENT, analyzer STRING, count INTEGER DEFAULT -6)'); display('Inited tables'); } $sqlQuery = <<<SQL DELETE FROM results WHERE analyzer = :analyzer SQL; $this->cleanResults = $sqlite->prepare($sqlQuery); $sqlQuery = <<<SQL REPLACE INTO results ("id", "fullcode", "file", "line", "namespace", "class", "function", "analyzer", "severity") VALUES ( NULL, :fullcode, :file, :line, :namespace, :class, :function, :analyzer, :severity ) SQL; $this->stmtResults = $sqlite->prepare($sqlQuery); $sqlQuery = <<<SQL REPLACE INTO resultsCounts ("id", "analyzer", "count") VALUES (NULL, :class, :count ) SQL; $this->stmtResultsCounts = $sqlite->prepare($sqlQuery); $themes = array(); if ($this->config->thema !== null) { $thema = $this->config->thema; $themes = Analyzer::getThemeAnalyzers($thema); if (empty($themes)) { $r = Analyzer::getSuggestionThema($thema); if (count($r) > 0) { echo 'did you mean : ', implode(', ', str_replace('_', '/', $r)), "\n"; } throw new NoSuchThema($thema); } display('Processing thema : ' . $thema); } elseif ($this->config->program !== null) { $analyzer = $this->config->program; if (!Analyzer::getClass($analyzer)) { $r = Analyzer::getSuggestionClass($analyzer); if (count($r) > 0) { echo 'did you mean : ', implode(', ', str_replace('_', '/', $r)), "\n"; } throw new NoSuchAnalyzer($analyzer); } $themes = array($analyzer); display('Processing one analyzer : ' . $analyzer); } else { display('No analysis dump requested (-T <thema> | -P <Analyzer>)'); $this->finish(); return; } /* $res = $sqlite->query('SELECT COUNT(*) FROM themas WHERE thema="'.$thema.'"'); $count = $res->fetchArray(\SQLITE3_NUM); if ($count === 1) { display("$thema was already run\n"); } else { display("$thema was not already run\n"); } die(); print_r($themes); */ $sqlitePath = $this->config->projects_root . '/projects/' . $this->config->project . '/datastore.sqlite'; $counts = array(); $datastore = new \Sqlite3($sqlitePath, \SQLITE3_OPEN_READONLY); $datastore->busyTimeout(5000); $res = $datastore->query('SELECT * FROM analyzed'); while ($row = $res->fetchArray(\SQLITE3_ASSOC)) { $counts[$row['analyzer']] = $row['counts']; } $this->log->log('count analyzed : ' . count($counts) . "\n"); $this->log->log('counts ' . implode(', ', $counts) . "\n"); $datastore->close(); unset($datastore); foreach ($themes as $id => $thema) { if (isset($counts[$thema])) { display($thema . ' : ' . ($counts[$thema] >= 0 ? 'Yes' : 'N/A') . "\n"); $this->processResults($thema, $counts[$thema]); unset($themes[$id]); } else { display($thema . " : No\n"); } } $this->log->log('Still ' . count($themes) . " to be processed\n"); display('Still ' . count($themes) . " to be processed\n"); if (count($themes) === 0) { if ($this->config->thema !== null) { $sqlite->query('INSERT INTO themas ("id", "thema") VALUES ( NULL, "' . $this->config->thema . '")'); } } $this->finish(); }