Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

311 lignes
8.5 KiB

  1. <?php
  2. /**
  3. * @package Grav\Plugin\Admin
  4. *
  5. * @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Plugin\Admin;
  9. use Grav\Common\Config\Config;
  10. use Grav\Common\Grav;
  11. use Grav\Common\Page\Interfaces\PageInterface;
  12. /**
  13. * Class Popularity
  14. * @package Grav\Plugin
  15. */
  16. class Popularity
  17. {
  18. /** @var Config */
  19. protected $config;
  20. protected $data_path;
  21. protected $daily_file;
  22. protected $monthly_file;
  23. protected $totals_file;
  24. protected $visitors_file;
  25. protected $daily_data;
  26. protected $monthly_data;
  27. protected $totals_data;
  28. protected $visitors_data;
  29. const DAILY_FORMAT = 'd-m-Y';
  30. const MONTHLY_FORMAT = 'm-Y';
  31. const DAILY_FILE = 'daily.json';
  32. const MONTHLY_FILE = 'monthly.json';
  33. const TOTALS_FILE = 'totals.json';
  34. const VISITORS_FILE = 'visitors.json';
  35. public function __construct()
  36. {
  37. $this->config = Grav::instance()['config'];
  38. $this->data_path = Grav::instance()['locator']->findResource('log://popularity', true, true);
  39. $this->daily_file = $this->data_path . '/' . self::DAILY_FILE;
  40. $this->monthly_file = $this->data_path . '/' . self::MONTHLY_FILE;
  41. $this->totals_file = $this->data_path . '/' . self::TOTALS_FILE;
  42. $this->visitors_file = $this->data_path . '/' . self::VISITORS_FILE;
  43. }
  44. public function trackHit()
  45. {
  46. // Don't track bot or crawler requests
  47. if (!Grav::instance()['browser']->isHuman()) {
  48. return;
  49. }
  50. // Respect visitors "do not track" setting
  51. if (!Grav::instance()['browser']->isTrackable()) {
  52. return;
  53. }
  54. /** @var PageInterface $page */
  55. $page = Grav::instance()['page'];
  56. $relative_url = str_replace(Grav::instance()['base_url_relative'], '', $page->url());
  57. // Don't track error pages or pages that have no route
  58. if ($page->template() === 'error' || !$page->route()) {
  59. return;
  60. }
  61. // Make sure no 'widcard-style' ignore matches this url
  62. foreach ((array)$this->config->get('plugins.admin.popularity.ignore') as $ignore) {
  63. if (fnmatch($ignore, $relative_url)) {
  64. return;
  65. }
  66. }
  67. // initial creation if it doesn't exist
  68. if (!file_exists($this->data_path)) {
  69. mkdir($this->data_path);
  70. $this->flushPopularity();
  71. }
  72. // Update the data we want to track
  73. $this->updateDaily();
  74. $this->updateMonthly();
  75. $this->updateTotals($page->route());
  76. $this->updateVisitors(Grav::instance()['uri']->ip());
  77. }
  78. protected function updateDaily()
  79. {
  80. if (!$this->daily_data) {
  81. $this->daily_data = $this->getData($this->daily_file);
  82. }
  83. $day_month_year = date(self::DAILY_FORMAT);
  84. // get the daily access count
  85. if (array_key_exists($day_month_year, $this->daily_data)) {
  86. $this->daily_data[$day_month_year] = (int)$this->daily_data[$day_month_year] + 1;
  87. } else {
  88. $this->daily_data[$day_month_year] = 1;
  89. }
  90. // keep correct number as set by history
  91. $count = (int)$this->config->get('plugins.admin.popularity.history.daily', 30);
  92. $total = count($this->daily_data);
  93. if ($total > $count) {
  94. $this->daily_data = array_slice($this->daily_data, -$count, $count, true);
  95. }
  96. file_put_contents($this->daily_file, json_encode($this->daily_data));
  97. }
  98. /**
  99. * @return array
  100. */
  101. public function getDailyChartData()
  102. {
  103. if (!$this->daily_data) {
  104. $this->daily_data = $this->getData($this->daily_file);
  105. }
  106. $limit = (int)$this->config->get('plugins.admin.popularity.dashboard.days_of_stats', 7);
  107. $chart_data = array_slice($this->daily_data, -$limit, $limit);
  108. $labels = [];
  109. $data = [];
  110. /** @var Admin $admin */
  111. $admin = Grav::instance()['admin'];
  112. foreach ($chart_data as $date => $count) {
  113. $labels[] = $admin::translate([
  114. 'PLUGIN_ADMIN.' . strtoupper(date('D', strtotime($date)))]) .
  115. '<br>' . date('M d', strtotime($date));
  116. $data[] = $count;
  117. }
  118. return ['labels' => $labels, 'data' => $data];
  119. }
  120. /**
  121. * @return int
  122. */
  123. public function getDailyTotal()
  124. {
  125. if (!$this->daily_data) {
  126. $this->daily_data = $this->getData($this->daily_file);
  127. }
  128. if (isset($this->daily_data[date(self::DAILY_FORMAT)])) {
  129. return $this->daily_data[date(self::DAILY_FORMAT)];
  130. }
  131. return 0;
  132. }
  133. /**
  134. * @return int
  135. */
  136. public function getWeeklyTotal()
  137. {
  138. if (!$this->daily_data) {
  139. $this->daily_data = $this->getData($this->daily_file);
  140. }
  141. $day = 0;
  142. $total = 0;
  143. foreach (array_reverse($this->daily_data) as $daily) {
  144. $total += $daily;
  145. $day++;
  146. if ($day === 7) {
  147. break;
  148. }
  149. }
  150. return $total;
  151. }
  152. /**
  153. * @return int
  154. */
  155. public function getMonthlyTotal()
  156. {
  157. if (!$this->monthly_data) {
  158. $this->monthly_data = $this->getData($this->monthly_file);
  159. }
  160. if (isset($this->monthly_data[date(self::MONTHLY_FORMAT)])) {
  161. return $this->monthly_data[date(self::MONTHLY_FORMAT)];
  162. }
  163. return 0;
  164. }
  165. protected function updateMonthly()
  166. {
  167. if (!$this->monthly_data) {
  168. $this->monthly_data = $this->getData($this->monthly_file);
  169. }
  170. $month_year = date(self::MONTHLY_FORMAT);
  171. // get the monthly access count
  172. if (array_key_exists($month_year, $this->monthly_data)) {
  173. $this->monthly_data[$month_year] = (int)$this->monthly_data[$month_year] + 1;
  174. } else {
  175. $this->monthly_data[$month_year] = 1;
  176. }
  177. // keep correct number as set by history
  178. $count = (int)$this->config->get('plugins.admin.popularity.history.monthly', 12);
  179. $total = count($this->monthly_data);
  180. $this->monthly_data = array_slice($this->monthly_data, $total - $count, $count);
  181. file_put_contents($this->monthly_file, json_encode($this->monthly_data));
  182. }
  183. /**
  184. * @return array
  185. */
  186. protected function getMonthyChartData()
  187. {
  188. if (!$this->monthly_data) {
  189. $this->monthly_data = $this->getData($this->monthly_file);
  190. }
  191. $labels = [];
  192. $data = [];
  193. foreach ($this->monthly_data as $date => $count) {
  194. $labels[] = date('M', strtotime($date));
  195. $data[] = $count;
  196. }
  197. return ['labels' => $labels, 'data' => $data];
  198. }
  199. /**
  200. * @param string $url
  201. */
  202. protected function updateTotals($url)
  203. {
  204. if (!$this->totals_data) {
  205. $this->totals_data = $this->getData($this->totals_file);
  206. }
  207. // get the totals for this url
  208. if (array_key_exists($url, $this->totals_data)) {
  209. $this->totals_data[$url] = (int)$this->totals_data[$url] + 1;
  210. } else {
  211. $this->totals_data[$url] = 1;
  212. }
  213. file_put_contents($this->totals_file, json_encode($this->totals_data));
  214. }
  215. /**
  216. * @param string $ip
  217. */
  218. protected function updateVisitors($ip)
  219. {
  220. if (!$this->visitors_data) {
  221. $this->visitors_data = $this->getData($this->visitors_file);
  222. }
  223. // update with current timestamp
  224. $this->visitors_data[hash('sha1', $ip)] = time();
  225. $visitors = $this->visitors_data;
  226. arsort($visitors);
  227. $count = (int)$this->config->get('plugins.admin.popularity.history.visitors', 20);
  228. $this->visitors_data = array_slice($visitors, 0, $count, true);
  229. file_put_contents($this->visitors_file, json_encode($this->visitors_data));
  230. }
  231. /**
  232. * @param string $path
  233. *
  234. * @return array
  235. */
  236. protected function getData($path)
  237. {
  238. if (file_exists($path)) {
  239. return (array)json_decode(file_get_contents($path), true);
  240. }
  241. return [];
  242. }
  243. public function flushPopularity()
  244. {
  245. file_put_contents($this->daily_file, []);
  246. file_put_contents($this->monthly_file, []);
  247. file_put_contents($this->totals_file, []);
  248. file_put_contents($this->visitors_file, []);
  249. }
  250. }