/classes/hooks.php

https://github.com/SeanJA/php-hook · PHP · 242 lines · 124 code · 22 blank · 96 comment · 19 complexity · 6a283a251f7dbb77e29a4ca8753666b4 MD5 · raw file

  1. <?php
  2. abstract class hooks {
  3. /**
  4. * The php binary location
  5. * @var type
  6. */
  7. public static $PHP = "/usr/bin/php";
  8. /**
  9. * Debug functions to catch
  10. * @var array
  11. */
  12. public static $debug_functions = array(
  13. 'var_dump',
  14. 'var_export',
  15. 'print_r',
  16. 'debug_backtrace',
  17. );
  18. public static $debug_patterns = array(
  19. 'xdebug_.*?',
  20. );
  21. /**
  22. * Holds the error messages
  23. * @var string
  24. */
  25. protected $msg = '';
  26. /**
  27. * Subversion repository path
  28. * @var string
  29. */
  30. protected $_repository;
  31. /**
  32. * Transaction number
  33. * @var int
  34. */
  35. protected $_transaction;
  36. /**
  37. * Commit message string
  38. * @var string
  39. */
  40. protected $_logMessage;
  41. /**
  42. * Commit files list
  43. * @var array
  44. */
  45. protected $_commitList;
  46. /**
  47. * Changed files list
  48. * @var array
  49. */
  50. protected $_changedFiles;
  51. /**
  52. * Class constructor
  53. *
  54. * @param string $repository
  55. * @param string $transaction
  56. * @param array $tests array of test names to run
  57. */
  58. public function __construct($repository, $transaction, array $tests) {
  59. $this->_repository = $repository;
  60. $this->_transaction = $transaction;
  61. exit($this->runTests($tests));
  62. }
  63. /**
  64. * Run subversion pre-commit tests
  65. *
  66. * @param array $tests array of test names to run
  67. * @return int result code, 0 == all test passed, other value represents
  68. * number of failed tests
  69. */
  70. protected function runTests(array $tests) {
  71. $result = 0;
  72. $messages = '';
  73. foreach ($tests as $k => $v) {
  74. if (is_numeric($k)) {
  75. $test = $v;
  76. $params = array();
  77. } else {
  78. $test = $k;
  79. $params = $v;
  80. if (!is_array($params)) {
  81. throw new Exception('Test arguments should be in an array.');
  82. }
  83. }
  84. $method = "_test$test";
  85. $this->msg = '';
  86. $result +=!call_user_func_array(array($this, $method), $params);
  87. if ($this->msg) {
  88. $messages .= " *) $this->msg\n";
  89. }
  90. }
  91. if ($messages) {
  92. $messages = rtrim($messages);
  93. fwrite(STDERR, "----------------\n$messages\n----------------");
  94. }
  95. return ($result >= 1)? 1:0;
  96. }
  97. /**
  98. * Get commit log message
  99. *
  100. * @return string
  101. */
  102. abstract protected function getLogMessage();
  103. /**
  104. * Get content of file from current transaction
  105. *
  106. * @param string $file
  107. * @return string
  108. * @throws Exception
  109. */
  110. abstract protected function getFileContent($file);
  111. /**
  112. * Get svn properties for file
  113. *
  114. * @param string $file
  115. * @return array
  116. */
  117. abstract protected function getFileProps($file);
  118. /**
  119. * Get commit files list
  120. *
  121. * @return array filenames are keys and status letters are values
  122. */
  123. abstract protected function getCommitList();
  124. /**
  125. * Get array of modified and added files
  126. *
  127. * @param array $filetypes array of file types used for filtering
  128. * @return array
  129. */
  130. abstract protected function getChangedFiles(array $filetypes=array());
  131. /**
  132. * Check if log message validates length rules
  133. *
  134. * @param int $minlength minimum length of log message
  135. * @return bool
  136. */
  137. protected function _testLogMessageLength($minlength = 1) {
  138. $length = strlen(trim($this->getLogMessage()));
  139. if ($length < $minlength) {
  140. if ($minlength <= 1) {
  141. $this->msg = "Log message should not be empty.";
  142. } else {
  143. $this->msg = "Your log message is too short, be more descriptive.";
  144. }
  145. return false;
  146. }
  147. return true;
  148. }
  149. /**
  150. * Tests if the committed files pass PHP syntax checking
  151. *
  152. * @param array $filetypes array of file types which should be tested
  153. * @return bool
  154. */
  155. protected function _testPHPLint(array $filetypes=array()) {
  156. $result = true;
  157. $files = $this->getChangedFiles($filetypes);
  158. $tempDir = sys_get_temp_dir();
  159. foreach ($files as $file => $extension) {
  160. $content = $this->getFileContent($file);
  161. $tempfile = tempnam($tempDir, "stax_");
  162. file_put_contents($tempfile, $content);
  163. $tempfile = realpath($tempfile); //sort out the formatting of the filename
  164. $output = shell_exec(self::$PHP . ' -l "' . $tempfile . '"');
  165. //try to find a parse error text and chop it off
  166. $syntaxErrorMsg = preg_replace("/Errors parsing.*$/", "", $output, -1, $count);
  167. if ($count > 0) { //found errors
  168. $result = false;
  169. $syntaxErrorMsg = str_replace($tempfile, $file, $syntaxErrorMsg); //replace temp filename with real filename
  170. $syntaxErrorMsg = rtrim($syntaxErrorMsg);
  171. $this->msg .= "\t[$file] PHP lint error in file. Message: $syntaxErrorMsg\n";
  172. }
  173. unlink($tempfile);
  174. }
  175. return $result;
  176. }
  177. /**
  178. * Check if files have var_dump, var_export, or print_r in them
  179. *
  180. * @param array $filetypes
  181. * @return bool
  182. */
  183. protected function _testDebugOutput(array $filetypes = array()) {
  184. $result = true;
  185. $files = $this->getChangedFiles($filetypes);
  186. static $debug_bypass;
  187. if(!is_bool($debug_bypass)){
  188. $message = trim($this->_getLogMessage());
  189. if(stripos($message, '!debug') === 0){
  190. $debug_bypass = true;
  191. } else {
  192. $debug_bypass = false;
  193. }
  194. }
  195. if($debug_bypass){
  196. return true;
  197. }
  198. foreach ($files as $file => $extension) {
  199. $content = $this->getFileContent($file);
  200. $tokens = token_get_all($content);
  201. foreach ($tokens as $t) {
  202. foreach ($tokens as $t) {
  203. //if the token id is an int (sometimes it isn't)
  204. if (is_int($t[0])) {
  205. //if it matches our debug stuff...
  206. if ($t[0] == T_STRING && (in_array($t[1], self::$debug_functions) || preg_match('/(' . implode('|', self::$debug_patterns) . ')/', $t[1]))) {
  207. $this->msg .= "\t[$file] " . $t[1] . " found on line " . $t[2] . "\n";
  208. $result = false;
  209. }
  210. }
  211. }
  212. }
  213. }
  214. if (!$result) {
  215. $this->msg = rtrim($this->msg);
  216. $this->msg = "Debug output found:\n$this->msg";
  217. }
  218. return $result;
  219. }
  220. }