source: spip-zone/_core_/plugins/statistiques/action/statistiques_archiver.php @ 93626

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

Indentation et regles de codage selon http://www.spip.net/fr_article3497.html#regles_codage

File size: 11.3 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 * Action d'archivage des statistiques
15 *
16 * @plugin Statistiques pour SPIP
17 * @license GNU/GPL
18 * @package SPIP\Stats\Actions
19 **/
20
21if (!defined("_ECRIRE_INC_VERSION")) {
22        return;
23}
24
25
26if (!defined('STATISTIQUES_ARCHIVER_PAR_MOIS')) {
27        /**
28         * Nombre d'années après quoi on permet de concaténer les statistiques de visites par mois
29         *
30         * Après ce nombre d'années, on peut concaténer les données de visites d'articles par mois
31         * pour prendre moins de place dans la base de données
32         *
33         * @var int Nombre d'années
34         **/
35        define('STATISTIQUES_ARCHIVER_PAR_MOIS', 2);
36}
37
38if (!defined('STATISTIQUES_ARCHIVER_PAR_AN')) {
39        /**
40         * Nombre d'années après quoi on permet de concaténer les statistiques de visites par an
41         *
42         * Après ce nombre d'années, on peut concaténer les données de visites d'articles par années
43         * pour prendre moins de place dans la base de données
44         *
45         * @var int Nombre d'années
46         **/
47        define('STATISTIQUES_ARCHIVER_PAR_AN', 5);
48}
49
50
51/**
52 * Archiver ou nettoyer des statistiques
53 *
54 * @param string $arg
55 */
56function action_statistiques_archiver_dist($arg = null) {
57        if (!$arg) {
58                $securiser_action = charger_fonction('securiser_action', 'inc');
59                $arg = $securiser_action();
60        }
61
62        if (!autoriser('webmestre')) {
63                include_spip('inc/minipres');
64                minipres();
65        }
66
67        if (!in_array($arg, array(
68                'archiver_visites_articles',
69                'nettoyer_visites_articles',
70                'nettoyer_referers_articles'
71        ))
72        ) {
73                include_spip('inc/minipres');
74                minipres("Argument non compris");
75        }
76
77        $func = 'statistiques_' . $arg;
78        $func();
79}
80
81
82/**
83 * Logguer ces informations importantes.
84 *
85 * @uses spip_log()
86 * @param string $texte
87 **/
88function statistiques_archiver_log($texte) {
89        spip_log($texte, 'statistiques_archiver.' . _LOG_INFO_IMPORTANTE);
90}
91
92/**
93 * Nettoyer des lignes de visites d'articles incorrectes
94 *
95 * Supprime toutes les lignes qui ne font pas partie
96 * d'un article présent en base
97 **/
98function statistiques_nettoyer_visites_articles() {
99        statistiques_archiver_log("Supprimer les visites d'articles qui n'existent pas dans spip_articles.");
100        $i = sql_delete('spip_visites_articles', 'id_article NOT IN (SELECT id_article FROM spip_articles)');
101        statistiques_archiver_log("Fin de la suppression : $i lignes supprimées");
102}
103
104/**
105 * Nettoyer des lignes de referers d'articles incorrectes
106 *
107 * Supprime toutes les lignes qui ne font pas partie
108 * d'un article présent en base
109 **/
110function statistiques_nettoyer_referers_articles() {
111        statistiques_archiver_log("Supprimer les referers d'articles qui n'existent pas dans spip_articles.");
112        $i = sql_delete('spip_referers_articles', 'id_article NOT IN (SELECT id_article FROM spip_articles)');
113        statistiques_archiver_log("Fin de la suppression : $i lignes supprimées");
114}
115
116/**
117 * Archiver les visites d'articles
118 *
119 * @note
120 *   Cela peut prendre beaucoup de temps.
121 *
122 *   La base de test avait (en 2014) 12.500.000 d'entrées depuis 2005.
123 *   Cet archivage réduit à 1.200.000 entrées en réduisant
124 *   par mois jusqu'à 2012 inclu et par an jusqu'à 2009 inclu.
125 *
126 *   Cela prenait 8 minutes sur ma machine locale
127 *   (Intel Core i5-4258U CPU @ 2.40GHz × 4 avec disque SSD)
128 *
129 * @note
130 *   On peut suivre l'avancement dans le fichier de log
131 *   tail -f tmp/log/statistiques_archiver.log
132 *
133 * @note
134 *   On ne peut pas vraiment avec le code actuel de la fonction
135 *   appliquer les calculs sur l'ensemble d'un mois car cela
136 *   peut facilement surcharger la mémoire de php.
137 *
138 *   Du coup, on applique par petit bouts d'abord.
139 *
140 * @uses statistiques_concatener_visites_entre_jours()
141 * @uses statistiques_concatener_visites_par_mois()
142 * @uses statistiques_concatener_visites_par_an()
143 **/
144function statistiques_archiver_visites_articles() {
145
146        // Tenter de donner du temps au temps
147        @set_time_limit(15*60); // 15mn
148
149        $annee_par_mois = date('Y')-STATISTIQUES_ARCHIVER_PAR_MOIS;
150        $annee_par_an = date('Y')-STATISTIQUES_ARCHIVER_PAR_AN;
151
152        $annee_minimum = statistiques_concatener_annee_minimum();
153        if (!$annee_minimum) {
154                return false;
155        }
156
157        if ($annee_minimum > $annee_par_mois) {
158                statistiques_archiver_log("Il n'y a pas de statistiques assez anciennes pour concaténer par mois !");
159        } else {
160                // en plusieurs temps pour éviter trop de mémoire !
161                statistiques_concatener_visites_entre_jours($annee_par_mois, 1, 10);
162                statistiques_concatener_visites_entre_jours($annee_par_mois, 11, 20);
163                statistiques_concatener_visites_entre_jours($annee_par_mois, 21, 31);
164
165                // et on regroupe tout en 1 seul morceau.
166                statistiques_concatener_visites_par_mois($annee_par_mois);
167        }
168
169        if ($annee_minimum > $annee_par_an) {
170                statistiques_archiver_log("Il n'y a pas de statistiques assez anciennes pour concaténer par an !");
171        } else {
172                // et les vieilles années, on regroupe par an directement.
173                statistiques_concatener_visites_par_an($annee_par_an);
174        }
175
176        statistiques_archiver_log("* Optimiser la table spip_visites_articles après les travaux.");
177        sql_optimize('spip_visites_articles');
178}
179
180/**
181 * Concatène les statistiques de visites d'articles par mois
182 *
183 * @see statistiques_concatener_visites_entre_jours()
184 *
185 * @param int $annee
186 *    On concatène ce qui est avant cette année là.
187 **/
188function statistiques_concatener_visites_par_mois($annee) {
189        return statistiques_concatener_visites_entre_jours($annee, 1, 31);
190}
191
192
193/**
194 * Concatène les statistiques de visites d'articles par portion de mois (entre groupe de jours)
195 *
196 * @param int $annee
197 *    On concatène ce qui est avant cette année là.
198 * @param int $debut
199 *    Numéro de jour du début de la concaténation, exemple 1.
200 *    Le total des visites concaténé sera mis dans ce jour là.
201 * @param int $fin
202 *    Numéro de jour de fin de la concaténation, exemple 31.
203 *    Toutes les entrées entre le jour $debut+1 et $fin seront supprimées
204 *    et concaténées au jour $debut.
205 *
206 **/
207function statistiques_concatener_visites_entre_jours($annee, $debut, $fin) {
208
209        $annee_minimum = statistiques_concatener_annee_minimum();
210        if (!$annee_minimum) {
211                return false;
212        }
213
214        if ($annee_minimum > $annee) {
215                statistiques_archiver_log("Il n'y a pas de statistiques assez anciennes !");
216
217                return false;
218        }
219
220        // on a besoin pour le champ date d'une écriture sur 2 chiffres.
221        $debut = str_pad($debut, 2, '0', STR_PAD_LEFT);
222        $fin = str_pad($fin, 2, '0', STR_PAD_LEFT);
223
224        statistiques_archiver_log("\nConcaténer les visites d'articles (jours entre $debut et $fin)");
225        statistiques_archiver_log("===========================================================");
226
227        $annees = range($annee_minimum, $annee);
228        $mois = range(1, 12);
229
230        foreach ($annees as $a) {
231                statistiques_archiver_log("\n- Concaténer les visites de l'année : $a");
232
233                foreach ($mois as $m) {
234                        $m = str_pad($m, 2, '0', STR_PAD_LEFT);
235                        statistiques_concatener_visites_entre_periode("$a-$m-$debut", "$a-$m-$fin");
236                }
237        }
238}
239
240
241/**
242 * Retourne la plus petite année des visites d'articles
243 *
244 * @return int|bool
245 *     - int : l'année
246 *     - false : année non trouvée.
247 **/
248function statistiques_concatener_annee_minimum() {
249        static $annee_minimum = null;
250
251        // calcul de la plus petite année de statistiques
252        if (is_null($annee_minimum)) {
253                $annee_minimum = sql_getfetsel('YEAR(MIN(date))', 'spip_visites_articles', '', '', '', '0,1');
254        }
255
256        if (!$annee_minimum) {
257                statistiques_archiver_log("Erreur de calcul de la plus petite année de statistiques !");
258
259                return false;
260        }
261
262        return $annee_minimum;
263}
264
265
266/**
267 * Concatène les statistiques de visites d'articles par an
268 *
269 * @param int $annee
270 *    On concatène ce qui est avant cette année là.
271 *
272 **/
273function statistiques_concatener_visites_par_an($annee) {
274
275        $annee_minimum = statistiques_concatener_annee_minimum();
276        if (!$annee_minimum) {
277                return false;
278        }
279
280        if ($annee_minimum > $annee) {
281                statistiques_archiver_log("Il n'y a pas de statistiques assez anciennes !");
282
283                return false;
284        }
285
286        statistiques_archiver_log("\nConcaténer les visites d'articles (par an)");
287        statistiques_archiver_log("===========================================================");
288
289        $annees = range($annee_minimum, $annee);
290
291        foreach ($annees as $a) {
292                statistiques_archiver_log("\n- Concaténer les visites de l'année : $a");
293                statistiques_concatener_visites_entre_periode("$a-01-01", "$a-12-31");
294        }
295}
296
297
298/**
299 * Concatène les statistiques de visites d'articles entre 2 périodes.
300 *
301 * @param string $date_debut
302 *     Date de début tel que '2010-01-01'
303 * @param string $date_fin
304 *     Date de fin tel que '2010-12-31'
305 * @return bool
306 *     - false : aucune visite sur cette période
307 *     - true : il y avait des visites, elles ont été concaténées (ou l'étaient déjà)
308 *
309 **/
310function statistiques_concatener_visites_entre_periode($date_debut, $date_fin) {
311
312        // récupérer toutes les visites de cette période (année, mois, entre jour début et fin)
313        $visites = sql_allfetsel('id_article, date, visites', 'spip_visites_articles', array(
314                "date >= " . sql_quote($date_debut),
315                "date <= " . sql_quote($date_fin),
316        ));
317
318        if (!$visites) {
319                return false;
320        }
321
322        $liste = $updates = array();
323        $total = 0;
324
325        // - Crée un tableau plus simple (id_article => total des visites de la période) (permettant un array_diff_key facile).
326        // - Calcule au passage le total des visites de la période (pour le log)
327        // - Rempli un autre tableau ($updates) qui indique si cet article doit avoir ses visites concaténées sur cette période,
328        //   c'est à dire, si il y a une date qui n'est pas le début de période.
329        //   (évite de nombreuses requêtes si l'on exécute plusieurs fois le script)
330        foreach ($visites as $v) {
331                $id_article = $v['id_article'];
332                if (!isset($liste[$id_article])) {
333                        $liste[$id_article] = 0;
334                }
335                $liste[$id_article] += $v['visites'];
336                $total += $v['visites'];
337                if ($v['date'] != $date_debut) {
338                        $updates[$id_article] = true;
339                }
340        }
341
342        unset($visites);
343
344        $nb_articles = count($liste);
345
346        // juste ceux qui nécessitent une mise à jour (date <> de $debut de période)
347        $liste = array_intersect_key($liste, $updates);
348
349        statistiques_archiver_log("-- du $date_debut au $date_fin : $total visites dans $nb_articles articles");
350
351        if ($liste) {
352
353                // formater pour l'insertion dans la base.
354                $inserts = array();
355                foreach ($liste as $id_article => $visites) {
356                        $inserts[] = array(
357                                'id_article' => $id_article,
358                                'date' => $date_debut,
359                                'visites' => $visites,
360                        );
361                }
362
363                statistiques_archiver_log("--- concaténer les statistiques de " . count($liste) . " articles");
364
365                // /!\ Attention,
366                // Entre ces 2 requêtes, on peut perdre des données (si timeout ou autre)
367                // Transaction à faire ?
368
369                sql_delete('spip_visites_articles', array(
370                        "date >= " . sql_quote($date_debut),
371                        "date <= " . sql_quote($date_fin),
372                        sql_in('id_article', array_keys($liste)),
373                ));
374
375                sql_insertq_multi('spip_visites_articles', $inserts);
376        }
377
378        unset($liste, $inserts);
379
380        return true;
381}
Note: See TracBrowser for help on using the repository browser.