source: spip-zone/_core_/plugins/statistiques/genie/visites.php @ 92685

Last change on this file since 92685 was 92685, checked in by marcimat@…, 5 years ago

Un peu de phpdoc sur les statistiques encore
(et correction d'un @uses)

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