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

Last change on this file since 112357 was 112357, checked in by booz@…, 23 months ago

report de [112346]

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