public function generate($folder, $name = null) { $sqlite = new \Sqlite3($folder . '/dump.sqlite'); $sqlQuery = 'SELECT * FROM results WHERE analyzer in ' . $this->themesList; $res = $sqlite->query($sqlQuery); $results = array(); $titleCache = array(); $severityCache = array(); $results = array(); while ($row = $res->fetchArray(SQLITE3_ASSOC)) { if (!isset($titleCache[$row['analyzer']])) { $analyzer = Analyzer::getInstance($row['analyzer']); $titleCache[$row['analyzer']] = $analyzer->getDescription()->getName(); $severityCache[$row['analyzer']] = $analyzer->getSeverity(); $clearphp = $analyzer->getDescription()->getClearPHP(); } else { $clearphp = ''; } $message = array('code' => $row['fullcode'], 'line' => $row['line'], 'clearphp' => $clearphp); if (!isset($results[$titleCache[$row['analyzer']]])) { $results[$titleCache[$row['analyzer']]] = array(); } $results[$titleCache[$row['analyzer']]][] = $message; $this->count(); } if ($name === null) { return json_encode($results); } else { file_put_contents($folder . '/' . $name . '.' . self::FILE_EXTENSION, json_encode($results)); return true; } }
public function generate($folder, $name = null) { $list = Analyzer::getThemeAnalyzers($this->themesToShow); $list = '"' . join('", "', $list) . '"'; $sqlite = new \Sqlite3($folder . '/dump.sqlite'); $sqlQuery = 'SELECT * FROM results WHERE analyzer in (' . $list . ')'; $res = $sqlite->query($sqlQuery); $results = array(); $titleCache = array(); $severityCache = array(); while ($row = $res->fetchArray(SQLITE3_ASSOC)) { if (!isset($results[$row['file']])) { $file = array('errors' => 0, 'warnings' => 0, 'fixable' => 0, 'filename' => $row['file'], 'messages' => array()); $results[$row['file']] = $file; } if (!isset($titleCache[$row['analyzer']])) { $analyzer = Analyzer::getInstance($row['analyzer']); $titleCache[$row['analyzer']] = $analyzer->getDescription()->getName(); $severityCache[$row['analyzer']] = $analyzer->getSeverity(); } $message = array('type' => 'warning', 'source' => $row['analyzer'], 'severity' => $severityCache[$row['analyzer']], 'fixable' => 'fixable', 'message' => $titleCache[$row['analyzer']]); if (!isset($results[$row['file']]['messages'][$row['line']])) { $results[$row['file']]['messages'][$row['line']] = array(0 => array()); } $results[$row['file']]['messages'][$row['line']][0][] = $message; ++$results[$row['file']]['warnings']; $this->count(); } if ($name === null) { return json_encode($results); } else { file_put_contents($folder . '/' . $name . '.' . self::FILE_EXTENSION, json_encode($results)); return true; } }
public function run() { $result = new \Stdclass(); $analyzers = Analyzer::getThemeAnalyzers('OneFile'); foreach ($analyzers as $analyzer) { $a = Analyzer::getInstance($analyzer); $results = $a->getArray(); if (!empty($results)) { $result->{$a->getDescription()->getName()} = $results; } } file_put_contents($this->config->projects_root . '/projects/' . $project . '/onepage.json', json_encode($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 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) . ""); }
private function generateAnalyzersList() { $analyzers = ''; foreach (Analyzer::getThemeAnalyzers($this->themesToShow) as $analyzer) { $analyzer = Analyzer::getInstance($analyzer); $description = $analyzer->getDescription(); $analyzers .= "<tr><td>" . $description->getName() . "</td></tr>\n"; } $html = $this->getBasedPage('proc_analyzers'); $html = $this->injectBloc($html, 'ANALYZERS', $analyzers); $this->putBasedPage('proc_analyzers', $html); }
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"); }
private function processResults($class, $count) { $this->cleanResults->bindValue(':analyzer', $class, \SQLITE3_TEXT); $this->cleanResults->execute(); $this->stmtResultsCounts->bindValue(':class', $class, \SQLITE3_TEXT); $this->stmtResultsCounts->bindValue(':count', $count, \SQLITE3_INTEGER); $result = $this->stmtResultsCounts->execute(); $this->log->log("{$class} : {$count}\n"); // No need to go further if ($count <= 0) { return; } $this->stmtResults->bindValue(':class', $class, \SQLITE3_TEXT); $analyzer = Analyzer::getInstance($class); $res = $analyzer->getDump(); $saved = 0; $severity = $analyzer->getSeverity(); foreach ($res as $id => $result) { if (!is_object($result)) { $this->log->log("Object expected but not found\n" . print_r($result, true) . "\n"); continue; } if (!isset($result->class)) { continue; } $this->stmtResults->bindValue(':fullcode', $result->fullcode, \SQLITE3_TEXT); $this->stmtResults->bindValue(':file', $result->file, \SQLITE3_TEXT); $this->stmtResults->bindValue(':line', $result->line, \SQLITE3_INTEGER); $this->stmtResults->bindValue(':namespace', $result->{'namespace'}, \SQLITE3_TEXT); $this->stmtResults->bindValue(':class', $result->class, \SQLITE3_TEXT); $this->stmtResults->bindValue(':function', $result->function, \SQLITE3_TEXT); $this->stmtResults->bindValue(':analyzer', $class, \SQLITE3_TEXT); $this->stmtResults->bindValue(':severity', $severity, \SQLITE3_TEXT); $this->stmtResults->execute(); ++$saved; } $this->log->log("{$class} : dumped {$saved}"); if ($count != $saved) { display("{$saved} results saved, {$count} expected for {$class}\n"); } else { display("All {$saved} results saved for {$class}\n"); } }
public function generate($folder, $name = 'report') { $finalName = $name; $name = '.' . $name; if ($name === null) { return "Can't produce Devoops format to stdout"; } // Clean final destination if ($folder . '/' . $finalName !== '/') { rmdirRecursive($folder . '/' . $finalName); } if (file_exists($folder . '/' . $finalName)) { display($folder . '/' . $finalName . " folder was not cleaned. Please, remove it before producing the report. Aborting report\n"); return; } // Clean temporary destination if (file_exists($folder . '/' . $name)) { rmdirRecursive($folder . '/' . $name); } mkdir($folder . '/' . $name, Devoops::FOLDER_PRIVILEGES); mkdir($folder . '/' . $name . '/ajax', Devoops::FOLDER_PRIVILEGES); copyDir($this->config->dir_root . '/media/devoops/css', $folder . '/' . $name . '/css'); copyDir($this->config->dir_root . '/media/devoops/img', $folder . '/' . $name . '/img'); copyDir($this->config->dir_root . '/media/devoops/js', $folder . '/' . $name . '/js'); copyDir($this->config->dir_root . '/media/devoops/plugins', $folder . '/' . $name . '/plugins'); display("Copied media files"); $this->dump = new \Sqlite3($folder . '/dump.sqlite', SQLITE3_OPEN_READONLY); $this->datastore = new \sqlite3($folder . '/datastore.sqlite', \SQLITE3_OPEN_READONLY); // Compatibility $compatibility = array('Compilation' => 'Compilation'); foreach ($this->config->other_php_versions as $code) { if ($code == 52) { continue; } $version = $code[0] . '.' . substr($code, 1); $compatibility['Compatibility ' . $version] = 'Compatibility'; } // Analyze $analyze = array(); //count > 0 AND print 'SELECT * FROM resultsCounts WHERE analyzer in ' . $this->themesList . ' ORDER BY id'; $res = $this->sqlite->query('SELECT * FROM resultsCounts WHERE analyzer in ' . $this->themesList); while ($row = $res->fetchArray()) { $analyzer = Analyzer::getInstance($row['analyzer']); $this->analyzers[$analyzer->getDescription()->getName()] = $analyzer; $analyze[$analyzer->getDescription()->getName()] = 'OneAnalyzer'; } uksort($analyze, function ($a, $b) { return -strnatcmp($a, $b); }); $analyze = array_merge(array('Results Counts' => 'AnalyzersResultsCounts'), $analyze); // Files $files = array(); $res = $this->sqlite->query('SELECT DISTINCT file FROM results ORDER BY file'); while ($row = $res->fetchArray()) { $files[$row['file']] = 'OneFile'; } $files = array_merge(array('Files Counts' => 'FilesResultsCounts'), $files); $summary = array('Report presentation' => array('Audit configuration' => 'AuditConfiguration', 'Processed Files' => 'ProcessedFiles', 'Non-processed Files' => 'NonProcessedFiles'), 'Zend Framework' => $analyze); $summaryHtml = $this->makeSummary($summary); $faviconHtml = ''; if (file_exists($this->config->dir_root . '/projects/' . $this->config->project . '/code/favicon.ico')) { // Should be checked and reported copy($this->config->dir_root . '/projects/' . $this->config->project . '/code/favicon.ico', $folder . '/' . $name . '/img/' . $this->config->project . '.ico'); $faviconHtml = <<<HTML <img src="img/{$this->config->project}.ico" class="img-circle" alt="{$this->config->project} logo" /> HTML; if (!empty($this->config->project_url)) { $faviconHtml = "<a href=\"{$this->config->project_url}\" class=\"avatar\">{$faviconHtml}</a>"; } $faviconHtml = <<<HTML \t\t\t\t<div class="avatar"> \t\t\t\t\t{$faviconHtml} \t\t\t\t</div> HTML; } $html = file_get_contents($this->config->dir_root . '/media/devoops/index.exakat.html'); $html = str_replace('<menu>', $summaryHtml, $html); $html = str_replace('EXAKAT_VERSION', Exakat::VERSION, $html); $html = str_replace('EXAKAT_BUILD', Exakat::BUILD, $html); $html = str_replace('PROJECT_NAME', $this->config->project_name, $html); $html = str_replace('PROJECT_FAVICON', $faviconHtml, $html); file_put_contents($folder . '/' . $name . '/index.html', $html); foreach ($summary as $titleUp => $section) { foreach ($section as $title => $method) { if (method_exists($this, $method)) { $html = $this->{$method}($title); } else { $html = 'Using default for ' . $title . "\n"; display($html); } $filename = $this->makeFileName($title); $html = <<<HTML <script language="javascript"> if (!document.getElementById("main")) { window.location.href = "../index.html#ajax/{$filename}"; } </script > <div class="row"> \t<div id="breadcrumb" class="col-xs-12"> \t\t<a href="#" class="show-sidebar"> \t\t\t<i class="fa fa-bars"></i> \t\t</a> \t\t<ol class="breadcrumb pull-left"> \t\t\t<li><a href="index.html">Dashboard</a></li> \t\t\t<li><a href="#ajax/About-This-Report.html">About This Report</a></li> \t\t</ol> \t</div> </div> <h4 class="page-header">{$title}</h4> <div class="row"> \t<div class="col-xs-12"> {$html} </div> </div> HTML; file_put_contents($folder . '/' . $name . '/ajax/' . $filename, $html); } } rename($folder . '/' . $name, $folder . '/' . $finalName); return ''; }
protected function OneFile($title) { $css = new \Stdclass(); $css->displayTitles = true; $css->titles = array('Code', 'Analyzer', 'Line'); $css->sort = $css->titles; $return = $this->formatText('All results for the file : ' . $title, 'textLead'); $data = array(); $sqliteTitle = $this->dump->escapeString($title); $sqlQuery = <<<SQL SELECT fullcode as Code, analyzer AS Analyzer, line AS Line FROM results WHERE file="{$sqliteTitle}" AND analyzer IN {$this->themesList} SQL; $res = $this->dump->query($sqlQuery); while ($row = $res->fetchArray(SQLITE3_ASSOC)) { $analyzer = Analyzer::getInstance($row['Analyzer']); $row['File'] = $analyzer->getDescription()->getName(); $data[] = $row; } $return .= $this->formatHorizontal($data, $css); return $return; }