visites.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2014 *
  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. if (!defined("_ECRIRE_INC_VERSION")) return;
  12. if (!defined('_CRON_LOT_FICHIERS_VISITE')) define('_CRON_LOT_FICHIERS_VISITE', 100);
  13. ### Pour se debarrasser du md5, comment faire ? Un index sur 'referer' ?
  14. ### ou alors la meme notion, mais sans passer par des fonctions HEX ?
  15. //
  16. // prendre en compte un fichier de visite
  17. //
  18. // http://code.spip.net/@compte_fichier_visite
  19. function compte_fichier_visite($fichier, &$visites, &$visites_a, &$referers, &$referers_a) {
  20. // Noter la visite du site (article 0)
  21. $visites ++;
  22. $content = array();
  23. if (lire_fichier($fichier, $content))
  24. $content = @unserialize($content);
  25. if (!is_array($content)) return;
  26. foreach ($content as $source => $num) {
  27. list($log_type, $log_id_num, $log_referer)
  28. = preg_split(",\t,", $source, 3);
  29. // Noter le referer
  30. if ($log_referer)
  31. $referers[$log_referer]++;
  32. // S'il s'agit d'un article, noter ses visites
  33. if ($log_type == 'article'
  34. AND $id_article = intval($log_id_num)) {
  35. $visites_a[$id_article] ++;
  36. if ($log_referer)
  37. $referers_a[$id_article][$log_referer]++;
  38. }
  39. }
  40. }
  41. // http://code.spip.net/@calculer_visites
  42. function calculer_visites($t) {
  43. include_spip('base/abstract_sql');
  44. // Initialisations
  45. $visites = array(); # visites du site
  46. $visites_a = array(); # tableau des visites des articles
  47. $referers = array(); # referers du site
  48. $referers_a = array(); # tableau des referers des articles
  49. // charger un certain nombre de fichiers de visites,
  50. // et faire les calculs correspondants
  51. // Traiter jusqu'a 100 sessions datant d'au moins 30 minutes
  52. $sessions = preg_files(sous_repertoire(_DIR_TMP, 'visites'));
  53. $compteur = _CRON_LOT_FICHIERS_VISITE;
  54. $date_init = time()-30*60;
  55. foreach ($sessions as $item) {
  56. if (($d=@filemtime($item)) < $date_init) {
  57. if (!$d) $d = $date_init; // si le fs ne donne pas de date, on prend celle du traitement, mais tout cela risque d'etre bien douteux
  58. $d = date("Y-m-d",$d);
  59. spip_log("traite la session $item");
  60. compte_fichier_visite($item,
  61. $visites[$d], $visites_a[$d], $referers[$d], $referers_a[$d]);
  62. spip_unlink($item);
  63. if (--$compteur <= 0)
  64. break;
  65. }
  66. #else spip_log("$item pas vieux");
  67. }
  68. if (!count($visites))
  69. return;
  70. include_spip('genie/popularites');
  71. list($a,$b) = genie_popularite_constantes(24*3600);
  72. // Maintenant on dispose de plusieurs tableaux qu'il faut ventiler dans
  73. // les tables spip_visites, spip_visites_articles, spip_referers
  74. // et spip_referers_articles ; attention a affecter tout ca a la bonne
  75. // date (celle de la visite, pas celle du traitement)
  76. foreach(array_keys($visites) as $date)
  77. if ($visites[$date]) {
  78. // 1. les visites du site (facile)
  79. if (!sql_countsel('spip_visites', "date='$date'"))
  80. sql_insertq('spip_visites',
  81. array('date' => $date, 'visites' => $visites[$date]));
  82. else
  83. sql_update('spip_visites', array('visites' => "visites+".intval($visites[$date])), "date='$date'");
  84. // 2. les visites des articles
  85. if ($visites_a[$date]) {
  86. $ar = array(); # tableau num -> liste des articles ayant num visites
  87. foreach($visites_a[$date] as $id_article => $n) {
  88. if (!sql_countsel('spip_visites_articles',
  89. "id_article=$id_article AND date='$date'")){
  90. sql_insertq('spip_visites_articles',
  91. array('id_article' => $id_article,
  92. 'visites' => 0,
  93. 'date' => $date));
  94. }
  95. $ar[$n][] = $id_article;
  96. }
  97. foreach ($ar as $n => $liste) {
  98. $tous = sql_in('id_article', $liste);
  99. sql_update('spip_visites_articles',
  100. array('visites' => "visites+$n"),
  101. "date='$date' AND $tous");
  102. $ref = $noref = array();
  103. foreach($liste as $id) {
  104. if (isset($referers_a[$id]))
  105. $ref[]= $id ;
  106. else $noref[]=$id;
  107. }
  108. // il faudrait ponderer la popularite ajoutee ($n) par son anciennete eventuelle
  109. // sur le modele de ce que fait genie/popularites
  110. if (count($noref))
  111. sql_update('spip_articles',
  112. array('visites' => "visites+$n",
  113. 'popularite' => "popularite+".number_format(round($n*$b,2), 2, '.', ''),
  114. 'maj' => 'maj'),
  115. sql_in('id_article',$noref));
  116. if (count($ref))
  117. sql_update('spip_articles',
  118. array('visites' => "visites+".($n+1),
  119. 'popularite' => "popularite+".number_format(round($n*$b,2), 2, '.', ''),
  120. 'maj' => 'maj'),
  121. sql_in('id_article',$ref));
  122. ## Ajouter un JOIN sur le statut de l'article ?
  123. }
  124. }
  125. // 3. Les referers du site
  126. // insertion pour les nouveaux, au tableau des increments sinon
  127. if ($referers[$date]) {
  128. $ar = array();
  129. $trouver_table = charger_fonction('trouver_table', 'base');
  130. $desc = $trouver_table('referers');
  131. $n = preg_match('/(\d+)/',$desc['field']['referer'], $r);
  132. $n = $n ? $r[1] : 255;
  133. foreach ($referers[$date] as $referer => $num) {
  134. $referer_md5 = sql_hex(substr(md5($referer), 0, 15));
  135. $referer = substr($referer,0,$n);
  136. if (!sql_countsel('spip_referers', "referer_md5=$referer_md5"))
  137. sql_insertq('spip_referers',
  138. array('visites' => $num,
  139. 'visites_jour' => $num,
  140. 'visites_veille' => $num,
  141. 'date' => $date,
  142. 'referer' => $referer,
  143. 'referer_md5' => $referer_md5));
  144. else $ar[$num][] = $referer_md5;
  145. }
  146. // appliquer les increments sur les anciens
  147. // attention on appelle sql_in en mode texte et pas array
  148. // pour ne pas passer sql_quote() sur les '0x1234' de referer_md5, cf #849
  149. foreach ($ar as $num => $liste) {
  150. sql_update('spip_referers', array('visites' => "visites+$num", 'visites_jour' => "visites_jour+$num"), sql_in('referer_md5',join(', ', $liste)));
  151. }
  152. }
  153. // 4. Les referers d'articles
  154. if ($referers_a[$date]) {
  155. $ar = array();
  156. $insert = array();
  157. // s'assurer d'un slot pour chacun
  158. foreach ($referers_a[$date] as $id_article => $referers)
  159. foreach ($referers as $referer => $num) {
  160. $referer_md5 = sql_hex(substr(md5($referer), 0, 15));
  161. $prim = "(id_article=$id_article AND referer_md5=$referer_md5)";
  162. if (!sql_countsel('spip_referers_articles', $prim))
  163. sql_insertq('spip_referers_articles',
  164. array('visites' => $num,
  165. 'id_article' => $id_article,
  166. 'referer' => $referer,
  167. 'referer_md5' => $referer_md5));
  168. else $ar[$num][] = $prim;
  169. }
  170. // ajouter les visites
  171. foreach ($ar as $num => $liste) {
  172. sql_update('spip_referers_articles', array('visites' => "visites+$num"), join(" OR ", $liste));
  173. ## Ajouter un JOIN sur le statut de l'article ?
  174. }
  175. }
  176. }
  177. // S'il reste des fichiers a manger, le signaler pour reexecution rapide
  178. if ($compteur==0) {
  179. spip_log("il reste des visites a traiter...");
  180. return -$t;
  181. }
  182. }
  183. /**
  184. * Nettoyer les IPs des flooders 24H apres leur dernier passage
  185. */
  186. function visites_nettoyer_flood(){
  187. if (is_dir($dir=_DIR_TMP.'flood/')){
  188. include_spip('inc/invalideur');
  189. if (!defined('_IP_FLOOD_TTL')) define('_IP_FLOOD_TTL',24*3600); // 24H par defaut
  190. $options = array(
  191. 'mtime' => $_SERVER['REQUEST_TIME'] - _IP_FLOOD_TTL,
  192. );
  193. purger_repertoire($dir,$options);
  194. }
  195. }
  196. /**
  197. * Cron de calcul de statistiques des visites
  198. *
  199. * Calcule les stats en plusieurs étapes
  200. * @uses calculer_visites()
  201. *
  202. * @param int $t
  203. * Timestamp de la dernière exécution de cette tâche
  204. * @return int
  205. * Positif si la tâche a été terminée, négatif pour réexécuter cette tâche
  206. **/
  207. function genie_visites_dist($t) {
  208. $encore = calculer_visites($t);
  209. // Si ce n'est pas fini on redonne la meme date au fichier .lock
  210. // pour etre prioritaire lors du cron suivant
  211. if ($encore)
  212. return (0 - $t);
  213. // nettoyer les IP des floodeurs quand on a fini de compter les stats
  214. visites_nettoyer_flood();
  215. return 1;
  216. }
  217. ?>