PageRenderTime 44ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins-dist/statistiques/genie/visites.php

https://bitbucket.org/re_al_/real.test.spip
PHP | 331 lines | 207 code | 34 blank | 90 comment | 37 complexity | 79e8ebf8e7ca0884d50b0379c6a25382 MD5 | raw file
Possible License(s): LGPL-2.1, MIT
  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2016 *
  6. * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
  7. * *
  8. * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
  9. * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
  10. \***************************************************************************/
  11. /**
  12. * Gestion du compage des statistiques de visites (cron)
  13. *
  14. * @plugin Statistiques pour SPIP
  15. * @license GNU/GPL
  16. * @package SPIP\Statistiques\Genie
  17. **/
  18. if (!defined("_ECRIRE_INC_VERSION")) {
  19. return;
  20. }
  21. if (!defined('_CRON_LOT_FICHIERS_VISITE')) {
  22. define('_CRON_LOT_FICHIERS_VISITE', 100);
  23. }
  24. ### Pour se debarrasser du md5, comment faire ? Un index sur 'referer' ?
  25. ### ou alors la meme notion, mais sans passer par des fonctions HEX ?
  26. /**
  27. * Prendre en compte un fichier de visite
  28. *
  29. * @param string $fichier
  30. * Nom du fichier de visite
  31. * @param int $visites
  32. * Nombre de visites
  33. * @param array $visites_a
  34. * Couples id_article => nombre : comptage par identifiant d'article
  35. * @param array $referers
  36. * Couples url_referer => nombre : comptage par url de referer
  37. * @param array $referers_a
  38. * Couples id_article => array (url_referer => nombre) : comptage par article puis url de referer
  39. * @return void
  40. **/
  41. function compte_fichier_visite($fichier, &$visites, &$visites_a, &$referers, &$referers_a) {
  42. // Noter la visite du site (article 0)
  43. $visites++;
  44. $content = array();
  45. if (lire_fichier($fichier, $content)) {
  46. $content = @unserialize($content);
  47. }
  48. if (!is_array($content)) {
  49. return;
  50. }
  51. foreach ($content as $source => $num) {
  52. list($log_type, $log_id_num, $log_referer)
  53. = preg_split(",\t,", $source, 3);
  54. // Noter le referer
  55. if ($log_referer) {
  56. if (!isset($referers[$log_referer])) {
  57. $referers[$log_referer] = 0;
  58. }
  59. $referers[$log_referer]++;
  60. }
  61. // S'il s'agit d'un article, noter ses visites
  62. if ($log_type == 'article'
  63. and $id_article = intval($log_id_num)
  64. ) {
  65. if (!isset($visites_a[$id_article])) {
  66. $visites_a[$id_article] = 0;
  67. }
  68. $visites_a[$id_article]++;
  69. if ($log_referer) {
  70. if (!isset($referers_a[$id_article][$log_referer])) {
  71. $referers_a[$id_article][$log_referer] = 0;
  72. }
  73. $referers_a[$id_article][$log_referer]++;
  74. }
  75. }
  76. }
  77. }
  78. /**
  79. * Calcule les statistiques de visites, en plusieurs étapes
  80. *
  81. * @uses compte_fichier_visite()
  82. * @uses genie_popularite_constantes()
  83. *
  84. * @param int $t
  85. * Timestamp de la dernière exécution de cette tâche
  86. * @return null|int
  87. * - null si aucune visite à prendre en compte ou si tous les fichiers de visite sont traités,
  88. * - entier négatif s'il reste encore des fichiers à traiter
  89. **/
  90. function calculer_visites($t) {
  91. include_spip('base/abstract_sql');
  92. // Initialisations
  93. $visites = array(); # visites du site
  94. $visites_a = array(); # tableau des visites des articles
  95. $referers = array(); # referers du site
  96. $referers_a = array(); # tableau des referers des articles
  97. // charger un certain nombre de fichiers de visites,
  98. // et faire les calculs correspondants
  99. // Traiter jusqu'a 100 sessions datant d'au moins 30 minutes
  100. $sessions = preg_files(sous_repertoire(_DIR_TMP, 'visites'));
  101. $compteur = _CRON_LOT_FICHIERS_VISITE;
  102. $date_init = time() - 30 * 60;
  103. foreach ($sessions as $item) {
  104. if (($d = @filemtime($item)) < $date_init) {
  105. if (!$d) {
  106. $d = $date_init;
  107. } // si le fs ne donne pas de date, on prend celle du traitement, mais tout cela risque d'etre bien douteux
  108. $d = date("Y-m-d", $d);
  109. spip_log("traite la session $item");
  110. compte_fichier_visite($item,
  111. $visites[$d], $visites_a[$d], $referers[$d], $referers_a[$d]);
  112. spip_unlink($item);
  113. if (--$compteur <= 0) {
  114. break;
  115. }
  116. }
  117. #else spip_log("$item pas vieux");
  118. }
  119. if (!count($visites)) {
  120. return;
  121. }
  122. include_spip('genie/popularites');
  123. list($a, $b) = genie_popularite_constantes(24 * 3600);
  124. // Maintenant on dispose de plusieurs tableaux qu'il faut ventiler dans
  125. // les tables spip_visites, spip_visites_articles, spip_referers
  126. // et spip_referers_articles ; attention a affecter tout ca a la bonne
  127. // date (celle de la visite, pas celle du traitement)
  128. foreach (array_keys($visites) as $date) {
  129. if ($visites[$date]) {
  130. // 1. les visites du site (facile)
  131. if (!sql_countsel('spip_visites', "date='$date'")) {
  132. sql_insertq('spip_visites',
  133. array('date' => $date, 'visites' => $visites[$date]));
  134. } else {
  135. sql_update('spip_visites', array('visites' => "visites+" . intval($visites[$date])), "date='$date'");
  136. }
  137. // 2. les visites des articles
  138. if ($visites_a[$date]) {
  139. $ar = array(); # tableau num -> liste des articles ayant num visites
  140. foreach ($visites_a[$date] as $id_article => $n) {
  141. if (!sql_countsel('spip_visites_articles',
  142. "id_article=$id_article AND date='$date'")
  143. ) {
  144. sql_insertq('spip_visites_articles',
  145. array(
  146. 'id_article' => $id_article,
  147. 'visites' => 0,
  148. 'date' => $date
  149. ));
  150. }
  151. $ar[$n][] = $id_article;
  152. }
  153. foreach ($ar as $n => $liste) {
  154. $tous = sql_in('id_article', $liste);
  155. sql_update('spip_visites_articles',
  156. array('visites' => "visites+$n"),
  157. "date='$date' AND $tous");
  158. $ref = $noref = array();
  159. foreach ($liste as $id) {
  160. if (isset($referers_a[$id])) {
  161. $ref[] = $id;
  162. } else {
  163. $noref[] = $id;
  164. }
  165. }
  166. // il faudrait ponderer la popularite ajoutee ($n) par son anciennete eventuelle
  167. // sur le modele de ce que fait genie/popularites
  168. if (count($noref)) {
  169. sql_update('spip_articles',
  170. array(
  171. 'visites' => "visites+$n",
  172. 'popularite' => "popularite+" . number_format(round($n * $b, 2), 2, '.', ''),
  173. 'maj' => 'maj'
  174. ),
  175. sql_in('id_article', $noref));
  176. }
  177. if (count($ref)) {
  178. sql_update('spip_articles',
  179. array(
  180. 'visites' => "visites+" . ($n + 1),
  181. 'popularite' => "popularite+" . number_format(round($n * $b, 2), 2, '.', ''),
  182. 'maj' => 'maj'
  183. ),
  184. sql_in('id_article', $ref));
  185. }
  186. ## Ajouter un JOIN sur le statut de l'article ?
  187. }
  188. }
  189. if (!isset($GLOBALS['meta']['activer_referers']) or $GLOBALS['meta']['activer_referers'] == "oui") {
  190. // 3. Les referers du site
  191. // insertion pour les nouveaux, au tableau des increments sinon
  192. if ($referers[$date]) {
  193. $ar = array();
  194. $trouver_table = charger_fonction('trouver_table', 'base');
  195. $desc = $trouver_table('referers');
  196. $n = preg_match('/(\d+)/', $desc['field']['referer'], $r);
  197. $n = $n ? $r[1] : 255;
  198. foreach ($referers[$date] as $referer => $num) {
  199. $referer_md5 = sql_hex(substr(md5($referer), 0, 15));
  200. $referer = substr($referer, 0, $n);
  201. if (!sql_countsel('spip_referers', "referer_md5=$referer_md5")) {
  202. sql_insertq('spip_referers',
  203. array(
  204. 'visites' => $num,
  205. 'visites_jour' => $num,
  206. 'visites_veille' => 0,
  207. 'date' => $date,
  208. 'referer' => $referer,
  209. 'referer_md5' => $referer_md5
  210. ));
  211. } else {
  212. $ar[$num][] = $referer_md5;
  213. }
  214. }
  215. // appliquer les increments sur les anciens
  216. // attention on appelle sql_in en mode texte et pas array
  217. // pour ne pas passer sql_quote() sur les '0x1234' de referer_md5, cf #849
  218. foreach ($ar as $num => $liste) {
  219. sql_update('spip_referers', array('visites' => "visites+$num", 'visites_jour' => "visites_jour+$num"),
  220. sql_in('referer_md5', join(', ', $liste)));
  221. }
  222. }
  223. // 4. Les referers d'articles
  224. if ($referers_a[$date]) {
  225. $ar = array();
  226. $insert = array();
  227. // s'assurer d'un slot pour chacun
  228. foreach ($referers_a[$date] as $id_article => $referers) {
  229. foreach ($referers as $referer => $num) {
  230. $referer_md5 = sql_hex(substr(md5($referer), 0, 15));
  231. $prim = "(id_article=$id_article AND referer_md5=$referer_md5)";
  232. if (!sql_countsel('spip_referers_articles', $prim)) {
  233. sql_insertq('spip_referers_articles',
  234. array(
  235. 'visites' => $num,
  236. 'id_article' => $id_article,
  237. 'referer' => $referer,
  238. 'referer_md5' => $referer_md5
  239. ));
  240. } else {
  241. $ar[$num][] = $prim;
  242. }
  243. }
  244. }
  245. // ajouter les visites
  246. foreach ($ar as $num => $liste) {
  247. sql_update('spip_referers_articles', array('visites' => "visites+$num"), join(" OR ", $liste));
  248. ## Ajouter un JOIN sur le statut de l'article ?
  249. }
  250. }
  251. }
  252. }
  253. }
  254. // S'il reste des fichiers a manger, le signaler pour reexecution rapide
  255. if ($compteur == 0) {
  256. spip_log("il reste des visites a traiter...");
  257. return -$t;
  258. }
  259. }
  260. /**
  261. * Nettoyer les IPs des flooders 24H apres leur dernier passage
  262. */
  263. function visites_nettoyer_flood() {
  264. if (is_dir($dir = _DIR_TMP . 'flood/')) {
  265. include_spip('inc/invalideur');
  266. if (!defined('_IP_FLOOD_TTL')) {
  267. define('_IP_FLOOD_TTL', 24 * 3600);
  268. } // 24H par defaut
  269. $options = array(
  270. 'mtime' => $_SERVER['REQUEST_TIME'] - _IP_FLOOD_TTL,
  271. );
  272. purger_repertoire($dir, $options);
  273. }
  274. }
  275. /**
  276. * Cron de calcul de statistiques des visites
  277. *
  278. * Calcule les stats en plusieurs étapes
  279. *
  280. * @uses calculer_visites()
  281. *
  282. * @param int $t
  283. * Timestamp de la dernière exécution de cette tâche
  284. * @return int
  285. * Positif si la tâche a été terminée, négatif pour réexécuter cette tâche
  286. **/
  287. function genie_visites_dist($t) {
  288. $encore = calculer_visites($t);
  289. // Si ce n'est pas fini on redonne la meme date au fichier .lock
  290. // pour etre prioritaire lors du cron suivant
  291. if ($encore) {
  292. return (0 - $t);
  293. }
  294. // nettoyer les IP des floodeurs quand on a fini de compter les stats
  295. visites_nettoyer_flood();
  296. return 1;
  297. }