problems.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. <?php
  2. namespace Grav\Plugin;
  3. use Grav\Common\Cache;
  4. use Grav\Common\Plugin;
  5. use Grav\Common\Uri;
  6. class ProblemsPlugin extends Plugin
  7. {
  8. protected $results = array();
  9. protected $check;
  10. /**
  11. * @return array
  12. */
  13. public static function getSubscribedEvents()
  14. {
  15. return [
  16. 'onPluginsInitialized' => ['onPluginsInitialized', 0],
  17. 'onFatalException' => ['onFatalException', 0]
  18. ];
  19. }
  20. public function onFatalException()
  21. {
  22. if ($this->isAdmin()) {
  23. $this->active = false;
  24. return;
  25. }
  26. // Run through potential issues
  27. if ($this->problemChecker()) {
  28. $this->renderProblems();
  29. }
  30. }
  31. public function onPluginsInitialized()
  32. {
  33. if ($this->isAdmin()) {
  34. $this->active = false;
  35. return;
  36. }
  37. /** @var Cache $cache */
  38. $cache = $this->grav['cache'];
  39. $validated_prefix = 'problem-check-';
  40. $this->check = CACHE_DIR . $validated_prefix . $cache->getKey();
  41. if (!file_exists($this->check)) {
  42. // If no issues remain, save a state file in the cache
  43. if (!$this->problemChecker()) {
  44. // delete any existing validated files
  45. foreach (new \GlobIterator(CACHE_DIR . $validated_prefix . '*') as $fileInfo) {
  46. @unlink($fileInfo->getPathname());
  47. }
  48. // create a file in the cache dir so it only runs on cache changes
  49. touch($this->check);
  50. } else {
  51. $this->renderProblems();
  52. }
  53. }
  54. }
  55. protected function renderProblems()
  56. {
  57. $theme = 'antimatter';
  58. /** @var Uri $uri */
  59. $uri = $this->grav['uri'];
  60. $baseUrlRelative = $uri->rootUrl(false);
  61. $themeUrl = $baseUrlRelative . '/' . USER_PATH . basename(THEMES_DIR) . '/' . $theme;
  62. $problemsUrl = $baseUrlRelative . '/user/plugins/problems';
  63. $html = file_get_contents(__DIR__ . '/html/problems.html');
  64. $problems = '';
  65. foreach ($this->results as $key => $result) {
  66. if ($key == 'files') {
  67. foreach ($result as $filename => $file_result) {
  68. foreach ($file_result as $status => $text) {
  69. $problems .= $this->getListRow($status, '<b>' . $filename . '</b> ' . $text);
  70. }
  71. }
  72. } else {
  73. foreach ($result as $status => $text) {
  74. $problems .= $this->getListRow($status, $text);
  75. }
  76. }
  77. }
  78. $html = str_replace('%%BASE_URL%%', $baseUrlRelative, $html);
  79. $html = str_replace('%%THEME_URL%%', $themeUrl, $html);
  80. $html = str_replace('%%PROBLEMS_URL%%', $problemsUrl, $html);
  81. $html = str_replace('%%PROBLEMS%%', $problems, $html);
  82. echo $html;
  83. exit();
  84. }
  85. protected function getListRow($status, $text)
  86. {
  87. if ($status == 'error') {
  88. $icon = 'fa-times';
  89. } elseif ($status == 'info') {
  90. $icon = 'fa-info';
  91. } else {
  92. $icon = 'fa-check';
  93. }
  94. $output = "\n";
  95. $output .= '<li class="' . $status . ' clearfix"><i class="fa fa-fw '. $icon . '"></i><p>'. $text . '</p></li>';
  96. return $output;
  97. }
  98. protected function problemChecker()
  99. {
  100. $min_php_version = '5.4.0';
  101. $problems_found = false;
  102. $essential_files = [
  103. 'cache' => true,
  104. 'logs' => true,
  105. 'images' => true,
  106. 'assets' => true,
  107. 'system' => false,
  108. 'user/data' => true,
  109. 'user/pages' => false,
  110. 'user/config' => false,
  111. 'user/plugins/error' => false,
  112. 'user/plugins' => false,
  113. 'user/themes' => false,
  114. 'vendor' => false
  115. ];
  116. if (version_compare(GRAV_VERSION, '0.9.27', ">=")) {
  117. $essential_files['backup'] = true;
  118. $backup_folder = ROOT_DIR . 'backup';
  119. // try to create backup folder if missing
  120. if (!file_exists($backup_folder)) {
  121. mkdir($backup_folder, 0770);
  122. }
  123. }
  124. // Check PHP version
  125. if (version_compare(phpversion(), $min_php_version, '<')) {
  126. $problems_found = true;
  127. $php_version_adjective = 'lower';
  128. $php_version_status = 'error';
  129. } else {
  130. $php_version_adjective = 'greater';
  131. $php_version_status = 'success';
  132. }
  133. $this->results['php'] = [$php_version_status => 'Your PHP version (' . phpversion() . ') is '. $php_version_adjective . ' than the minimum required: <b>' . $min_php_version . '</b>'];
  134. // Check for GD library
  135. if (defined('GD_VERSION') && function_exists('gd_info')) {
  136. $gd_adjective = '';
  137. $gd_status = 'success';
  138. } else {
  139. $problems_found = true;
  140. $gd_adjective = 'not ';
  141. $gd_status = 'error';
  142. }
  143. $this->results['gd'] = [$gd_status => 'PHP GD (Image Manipulation Library) is '. $gd_adjective . 'installed'];
  144. // Check for PHP CURL library
  145. if (function_exists('curl_version')) {
  146. $curl_adjective = '';
  147. $curl_status = 'success';
  148. } else {
  149. $problems_found = true;
  150. $curl_adjective = 'not ';
  151. $curl_status = 'error';
  152. }
  153. $this->results['curl'] = [$curl_status => 'PHP Curl (Data Transfer Library) is '. $curl_adjective . 'installed'];
  154. // Check for essential files & perms
  155. $file_problems = [];
  156. foreach ($essential_files as $file => $check_writable) {
  157. $file_path = ROOT_DIR . $file;
  158. $is_dir = false;
  159. if (!file_exists($file_path)) {
  160. $problems_found = true;
  161. $file_status = 'error';
  162. $file_adjective = 'does not exist';
  163. } else {
  164. $file_status = 'success';
  165. $file_adjective = 'exists';
  166. $is_writeable = is_writable($file_path);
  167. $is_dir = is_dir($file_path);
  168. if ($check_writable) {
  169. if (!$is_writeable) {
  170. $file_status = 'error';
  171. $problems_found = true;
  172. $file_adjective .= ' but is <b class="underline">not writeable</b>';
  173. } else {
  174. $file_adjective .= ' and <b class="underline">is writeable</b>';
  175. }
  176. }
  177. }
  178. $file_problems[$file_path] = [$file_status => $file_adjective];
  179. }
  180. if (sizeof($file_problems) > 0) {
  181. $this->results['files'] = $file_problems;
  182. }
  183. return $problems_found;
  184. }
  185. }