Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 
 
 

311 líneas
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. }