source: spip-zone/_core_/branches/spip-3.2/plugins/statistiques/genie/visites.php @ 109751

Last change on this file since 109751 was 109751, checked in by spip.franck@…, 2 years ago

Bonne année aussi aux plugins-dist :-D

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