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

Last change on this file since 93092 was 93092, checked in by gilles.vincent@…, 5 years ago

Mise en forme plus homegene et plus lisible, pour les declarations des fonctions
Regles :

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