Drupal investigation

Reporting.php 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. <?php
  2. /**
  3. * A class to manage reporting.
  4. *
  5. * PHP version 5
  6. *
  7. * @category PHP
  8. * @package PHP_CodeSniffer
  9. * @author Gabriele Santini <gsantini@sqli.com>
  10. * @author Greg Sherwood <gsherwood@squiz.net>
  11. * @copyright 2009-2014 SQLI <www.sqli.com>
  12. * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
  13. * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  14. * @link http://pear.php.net/package/PHP_CodeSniffer
  15. */
  16. /**
  17. * A class to manage reporting.
  18. *
  19. * @category PHP
  20. * @package PHP_CodeSniffer
  21. * @author Gabriele Santini <gsantini@sqli.com>
  22. * @author Greg Sherwood <gsherwood@squiz.net>
  23. * @copyright 2009-2014 SQLI <www.sqli.com>
  24. * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
  25. * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  26. * @version Release: @package_version@
  27. * @link http://pear.php.net/package/PHP_CodeSniffer
  28. */
  29. class PHP_CodeSniffer_Reporting
  30. {
  31. /**
  32. * Total number of files that contain errors or warnings.
  33. *
  34. * @var int
  35. */
  36. public $totalFiles = 0;
  37. /**
  38. * Total number of errors found during the run.
  39. *
  40. * @var int
  41. */
  42. public $totalErrors = 0;
  43. /**
  44. * Total number of warnings found during the run.
  45. *
  46. * @var int
  47. */
  48. public $totalWarnings = 0;
  49. /**
  50. * Total number of errors/warnings that can be fixed.
  51. *
  52. * @var int
  53. */
  54. public $totalFixable = 0;
  55. /**
  56. * When the PHPCS run started.
  57. *
  58. * @var float
  59. */
  60. public static $startTime = 0;
  61. /**
  62. * A list of reports that have written partial report output.
  63. *
  64. * @var array
  65. */
  66. private $_cachedReports = array();
  67. /**
  68. * A cache of report objects.
  69. *
  70. * @var array
  71. */
  72. private $_reports = array();
  73. /**
  74. * A cache of opened tmp files.
  75. *
  76. * @var array
  77. */
  78. private $_tmpFiles = array();
  79. /**
  80. * Produce the appropriate report object based on $type parameter.
  81. *
  82. * @param string $type The type of the report.
  83. *
  84. * @return PHP_CodeSniffer_Report
  85. * @throws PHP_CodeSniffer_Exception If report is not available.
  86. */
  87. public function factory($type)
  88. {
  89. $type = ucfirst($type);
  90. if (isset($this->_reports[$type]) === true) {
  91. return $this->_reports[$type];
  92. }
  93. if (strpos($type, '.') !== false) {
  94. // This is a path to a custom report class.
  95. $filename = realpath($type);
  96. if ($filename === false) {
  97. echo 'ERROR: Custom report "'.$type.'" not found'.PHP_EOL;
  98. exit(2);
  99. }
  100. $reportClassName = 'PHP_CodeSniffer_Reports_'.basename($filename);
  101. $reportClassName = substr($reportClassName, 0, strpos($reportClassName, '.'));
  102. include_once $filename;
  103. } else {
  104. $filename = $type.'.php';
  105. $reportClassName = 'PHP_CodeSniffer_Reports_'.$type;
  106. if (class_exists($reportClassName, true) === false) {
  107. echo 'ERROR: Report type "'.$type.'" not found'.PHP_EOL;
  108. exit(2);
  109. }
  110. }//end if
  111. $reportClass = new $reportClassName();
  112. if (false === ($reportClass instanceof PHP_CodeSniffer_Report)) {
  113. throw new PHP_CodeSniffer_Exception('Class "'.$reportClassName.'" must implement the "PHP_CodeSniffer_Report" interface.');
  114. }
  115. $this->_reports[$type] = $reportClass;
  116. return $this->_reports[$type];
  117. }//end factory()
  118. /**
  119. * Actually generates the report.
  120. *
  121. * @param PHP_CodeSniffer_File $phpcsFile The file that has been processed.
  122. * @param array $cliValues An array of command line arguments.
  123. *
  124. * @return void
  125. */
  126. public function cacheFileReport(PHP_CodeSniffer_File $phpcsFile, array $cliValues)
  127. {
  128. if (isset($cliValues['reports']) === false) {
  129. // This happens during unit testing, or any time someone just wants
  130. // the error data and not the printed report.
  131. return;
  132. }
  133. $reportData = $this->prepareFileReport($phpcsFile);
  134. $errorsShown = false;
  135. foreach ($cliValues['reports'] as $report => $output) {
  136. $reportClass = $this->factory($report);
  137. $report = get_class($reportClass);
  138. ob_start();
  139. $result = $reportClass->generateFileReport($reportData, $phpcsFile, $cliValues['showSources'], $cliValues['reportWidth']);
  140. if ($result === true) {
  141. $errorsShown = true;
  142. }
  143. $generatedReport = ob_get_contents();
  144. ob_end_clean();
  145. if ($output === null && $cliValues['reportFile'] !== null) {
  146. $output = $cliValues['reportFile'];
  147. }
  148. if ($output === null) {
  149. // Using a temp file.
  150. if (isset($this->_tmpFiles[$report]) === false) {
  151. if (function_exists('sys_get_temp_dir') === true) {
  152. // This is needed for HHVM support, but only available from 5.2.1.
  153. $this->_tmpFiles[$report] = fopen(tempnam(sys_get_temp_dir(), 'phpcs'), 'w');
  154. } else {
  155. $this->_tmpFiles[$report] = tmpfile();
  156. }
  157. }
  158. fwrite($this->_tmpFiles[$report], $generatedReport);
  159. } else {
  160. $flags = FILE_APPEND;
  161. if (isset($this->_cachedReports[$report]) === false) {
  162. $this->_cachedReports[$report] = true;
  163. $flags = null;
  164. }
  165. file_put_contents($output, $generatedReport, $flags);
  166. }//end if
  167. }//end foreach
  168. if ($errorsShown === true) {
  169. $this->totalFiles++;
  170. $this->totalErrors += $reportData['errors'];
  171. $this->totalWarnings += $reportData['warnings'];
  172. $this->totalFixable += $reportData['fixable'];
  173. }
  174. }//end cacheFileReport()
  175. /**
  176. * Generates and prints a final report.
  177. *
  178. * Returns an array with the number of errors and the number of
  179. * warnings, in the form ['errors' => int, 'warnings' => int].
  180. *
  181. * @param string $report Report type.
  182. * @param boolean $showSources Show sources?
  183. * @param array $cliValues An array of command line arguments.
  184. * @param string $reportFile Report file to generate.
  185. * @param integer $reportWidth Report max width.
  186. *
  187. * @return int[]
  188. */
  189. public function printReport(
  190. $report,
  191. $showSources,
  192. array $cliValues,
  193. $reportFile='',
  194. $reportWidth=80
  195. ) {
  196. $reportClass = $this->factory($report);
  197. $report = get_class($reportClass);
  198. if ($reportFile !== null) {
  199. $filename = $reportFile;
  200. $toScreen = false;
  201. if (file_exists($filename) === true
  202. && isset($this->_cachedReports[$report]) === true
  203. ) {
  204. $reportCache = file_get_contents($filename);
  205. } else {
  206. $reportCache = '';
  207. }
  208. } else {
  209. if (isset($this->_tmpFiles[$report]) === true) {
  210. $data = stream_get_meta_data($this->_tmpFiles[$report]);
  211. $filename = $data['uri'];
  212. $reportCache = file_get_contents($filename);
  213. fclose($this->_tmpFiles[$report]);
  214. } else {
  215. $reportCache = '';
  216. $filename = null;
  217. }
  218. $toScreen = true;
  219. }//end if
  220. ob_start();
  221. $reportClass->generate(
  222. $reportCache,
  223. $this->totalFiles,
  224. $this->totalErrors,
  225. $this->totalWarnings,
  226. $this->totalFixable,
  227. $showSources,
  228. $reportWidth,
  229. $toScreen
  230. );
  231. $generatedReport = ob_get_contents();
  232. ob_end_clean();
  233. if ($cliValues['colors'] !== true || $reportFile !== null) {
  234. $generatedReport = preg_replace('`\033\[[0-9]+m`', '', $generatedReport);
  235. }
  236. if ($reportFile !== null) {
  237. if (PHP_CODESNIFFER_VERBOSITY > 0) {
  238. echo $generatedReport;
  239. }
  240. file_put_contents($reportFile, $generatedReport.PHP_EOL);
  241. } else {
  242. echo $generatedReport;
  243. if ($filename !== null && file_exists($filename) === true) {
  244. unlink($filename);
  245. }
  246. }
  247. return array(
  248. 'errors' => $this->totalErrors,
  249. 'warnings' => $this->totalWarnings,
  250. );
  251. }//end printReport()
  252. /**
  253. * Pre-process and package violations for all files.
  254. *
  255. * Used by error reports to get a packaged list of all errors in each file.
  256. *
  257. * @param PHP_CodeSniffer_File $phpcsFile The file that has been processed.
  258. *
  259. * @return array
  260. */
  261. public function prepareFileReport(PHP_CodeSniffer_File $phpcsFile)
  262. {
  263. $report = array(
  264. 'filename' => $phpcsFile->getFilename(),
  265. 'errors' => $phpcsFile->getErrorCount(),
  266. 'warnings' => $phpcsFile->getWarningCount(),
  267. 'fixable' => $phpcsFile->getFixableCount(),
  268. 'messages' => array(),
  269. );
  270. if ($report['errors'] === 0 && $report['warnings'] === 0) {
  271. // Prefect score!
  272. return $report;
  273. }
  274. $errors = array();
  275. // Merge errors and warnings.
  276. foreach ($phpcsFile->getErrors() as $line => $lineErrors) {
  277. if (is_array($lineErrors) === false) {
  278. continue;
  279. }
  280. foreach ($lineErrors as $column => $colErrors) {
  281. $newErrors = array();
  282. foreach ($colErrors as $data) {
  283. $newErrors[] = array(
  284. 'message' => $data['message'],
  285. 'source' => $data['source'],
  286. 'severity' => $data['severity'],
  287. 'fixable' => $data['fixable'],
  288. 'type' => 'ERROR',
  289. );
  290. }//end foreach
  291. $errors[$line][$column] = $newErrors;
  292. }//end foreach
  293. ksort($errors[$line]);
  294. }//end foreach
  295. foreach ($phpcsFile->getWarnings() as $line => $lineWarnings) {
  296. if (is_array($lineWarnings) === false) {
  297. continue;
  298. }
  299. foreach ($lineWarnings as $column => $colWarnings) {
  300. $newWarnings = array();
  301. foreach ($colWarnings as $data) {
  302. $newWarnings[] = array(
  303. 'message' => $data['message'],
  304. 'source' => $data['source'],
  305. 'severity' => $data['severity'],
  306. 'fixable' => $data['fixable'],
  307. 'type' => 'WARNING',
  308. );
  309. }//end foreach
  310. if (isset($errors[$line]) === false) {
  311. $errors[$line] = array();
  312. }
  313. if (isset($errors[$line][$column]) === true) {
  314. $errors[$line][$column] = array_merge(
  315. $newWarnings,
  316. $errors[$line][$column]
  317. );
  318. } else {
  319. $errors[$line][$column] = $newWarnings;
  320. }
  321. }//end foreach
  322. ksort($errors[$line]);
  323. }//end foreach
  324. ksort($errors);
  325. $report['messages'] = $errors;
  326. return $report;
  327. }//end prepareFileReport()
  328. /**
  329. * Start recording time for the run.
  330. *
  331. * @return void
  332. */
  333. public static function startTiming()
  334. {
  335. self::$startTime = microtime(true);
  336. }//end startTiming()
  337. /**
  338. * Print information about the run.
  339. *
  340. * @return void
  341. */
  342. public static function printRunTime()
  343. {
  344. $time = ((microtime(true) - self::$startTime) * 1000);
  345. if ($time > 60000) {
  346. $mins = floor($time / 60000);
  347. $secs = round((($time % 60000) / 1000), 2);
  348. $time = $mins.' mins';
  349. if ($secs !== 0) {
  350. $time .= ", $secs secs";
  351. }
  352. } else if ($time > 1000) {
  353. $time = round(($time / 1000), 2).' secs';
  354. } else {
  355. $time = round($time).'ms';
  356. }
  357. $mem = round((memory_get_peak_usage(true) / (1024 * 1024)), 2).'Mb';
  358. echo "Time: $time; Memory: $mem".PHP_EOL.PHP_EOL;
  359. }//end printRunTime()
  360. }//end class