From 32fd6c2c3f78d3c7363a340794f6fb78bef1ce00 Mon Sep 17 00:00:00 2001 From: Fil <fil@rezo.net> Date: Wed, 16 Nov 2005 16:11:30 +0000 Subject: [PATCH] Nouveau modele de gestion des statistiques, qui devrait etre plus robuste et dont le code est plus simple ; mais attention il stocke des tas de fichiers temporaires dans ecrire/data/ Quelques corrections dans le parcours des repertoires (un fichier "0" pouvait bloquer SPIP) --- ecrire/inc_cron.php3 | 51 ++--- ecrire/inc_documents.php3 | 2 +- ecrire/inc_flock.php3 | 11 +- ecrire/inc_getdocument.php3 | 4 +- ecrire/inc_lang.php3 | 2 +- ecrire/inc_lang_raccourcis.php3 | 4 +- ecrire/inc_logos.php3 | 2 +- ecrire/inc_popularites.php3 | 81 -------- ecrire/inc_session.php3 | 2 +- ecrire/inc_statistiques.php3 | 117 ----------- ecrire/inc_visites.php3 | 281 +++++++++++++++++++++----- formulaires/inc-formulaire_admin.php3 | 20 ++ inc-cache.php3 | 6 +- inc-stats.php3 | 72 +++---- 14 files changed, 317 insertions(+), 338 deletions(-) delete mode 100644 ecrire/inc_popularites.php3 diff --git a/ecrire/inc_cron.php3 b/ecrire/inc_cron.php3 index 3121e0b760..fcb3df4af1 100644 --- a/ecrire/inc_cron.php3 +++ b/ecrire/inc_cron.php3 @@ -159,12 +159,9 @@ function taches_generales() { AND (lire_meta('quoi_de_neuf') == 'oui') AND _DIR_RESTREINT) $taches_generales['mail']= 3600 * 24 * lire_meta('jours_neuf'); - // Stat. Attention: la popularite DOIT preceder les visites - if (lire_meta("activer_statistiques") == "oui") { - $taches_generales['statistiques'] = 3600; - $taches_generales['popularites'] = 1800; - $taches_generales['visites'] = 3600 * 24; - } + // stats : toutes les 5 minutes on peut vider un panier de visites + if (lire_meta("activer_statistiques") == "oui") + $taches_generales['visites'] = 300; // syndication if (lire_meta("activer_syndic") == "oui") @@ -215,43 +212,25 @@ function cron_sites($t) { return $r; } -// calcule les stats en plusieurs etapes par tranche de 100 - -function cron_statistiques($t) { - $ref = calculer_n_referers(100); +// +// Calcule les stats en plusieurs etapes +// +function cron_visites($t) { + $encore = calculer_visites($t); // Si ce n'est pas fini on redonne la meme date au fichier .lock // pour etre prioritaire lors du cron suivant - if ($ref == 100) return (0 - $t); - - // Supprimer les referers trop vieux - supprimer_referers(); - supprimer_referers("article"); - return 1; -} - -function cron_popularites($t) { - calculer_popularites(); - return 1; -} - -function cron_visites($t) { - // Si le fichier .lock est absent, ne pas calculer (mais reparer la date - // du .lock de maniere a commencer a 00:00:01 demain). - if ($t) { - // il faut d'abord faire le calcul des popularites - include_ecrire('inc_popularites.php3'); + if ($encore) + return (0 - $t); + else { calculer_popularites(); - - calculer_visites(); + return 1; } - - // il vaut mieux le lancer peu apres minuit, - // donc on pretend avoir ete execute precisement "ce matin a 00:00:01" - // pour etre appele demain a la meme heure - return 0 - (strtotime(date("d F Y", time()))+60); } +// +// Mail des nouveautes +// function cron_mail($t) { $adresse_neuf = lire_meta('adresse_neuf'); $jours_neuf = lire_meta('jours_neuf'); diff --git a/ecrire/inc_documents.php3 b/ecrire/inc_documents.php3 index 7af2df819b..818b34bace 100644 --- a/ecrire/inc_documents.php3 +++ b/ecrire/inc_documents.php3 @@ -362,7 +362,7 @@ function fichiers_upload($dir) { $fichiers = array(); $d = opendir($dir); - while ($f = readdir($d)) { + while (($f = readdir($d)) !== false) { if (($f[0] != '.') AND is_readable("$dir/$f")) if (is_file("$dir/$f") AND $f != 'remove.txt') diff --git a/ecrire/inc_flock.php3 b/ecrire/inc_flock.php3 index a29199fdb0..12b3f8eff2 100644 --- a/ecrire/inc_flock.php3 +++ b/ecrire/inc_flock.php3 @@ -137,9 +137,8 @@ function supprimer_fichier($fichier) { // Retourne $subdir/ si le sous-repertoire peut etre cree, '' sinon // function creer_repertoire($base, $subdir) { - if (@file_exists("$base/.plat")) return ''; $path = $base.'/'.$subdir; - if (@file_exists($path)) return "$subdir/"; + if (@is_dir($path)) return "$subdir/"; @mkdir($path, 0777); @chmod($path, 0777); @@ -148,14 +147,10 @@ function creer_repertoire($base, $subdir) { @fputs($f, '<'.'?php $ok = true; ?'.'>'); @fclose($f); include("$path/.test"); + @unlink("$path/.test"); } if (!$ok) { - $f = @fopen("$base/.plat", "w"); - if ($f) - fclose($f); - else { - redirige_par_entete("spip_test_dirs.php3"); - } + redirige_par_entete("spip_test_dirs.php3"); } return ($ok? "$subdir/" : ''); } diff --git a/ecrire/inc_getdocument.php3 b/ecrire/inc_getdocument.php3 index c67179eaf4..9c8e39ba6d 100644 --- a/ecrire/inc_getdocument.php3 +++ b/ecrire/inc_getdocument.php3 @@ -37,7 +37,7 @@ function creer_repertoire_documents($ext) { // Efface le repertoire de maniere recursive ! function effacer_repertoire_temporaire($nom) { $d = opendir($nom); - while ($f = readdir($d)) { + while (($f = readdir($d)) !== false) { if (is_file("$nom/$f")) @unlink("$nom/$f"); else if ($f <> '.' AND $f <> '..' @@ -594,7 +594,7 @@ function identifie_repertoire_et_rubrique($DIR, $id_rubrique, $id_auteur, $art=0 $rubriques = array(); // collecte des 3 sortes d'entrees - while (($entree = readdir($handle)) != '') { + while (($entree = readdir($handle)) !== false) { $chemin = "$DIR/$entree"; if ($entree[0] !='.') { if (is_dir($chemin)) { diff --git a/ecrire/inc_lang.php3 b/ecrire/inc_lang.php3 index ac485f97de..1914f450c0 100644 --- a/ecrire/inc_lang.php3 +++ b/ecrire/inc_lang.php3 @@ -403,7 +403,7 @@ function init_langues() { $toutes_langs = Array(); if (!$all_langs || !$langue_site || !_DIR_RESTREINT) { if (!$d = @opendir(_DIR_LANG)) return; - while ($f = readdir($d)) { + while (($f = readdir($d)) !== false) { if (ereg('^spip_([a-z_]+)\.php3?$', $f, $regs)) $toutes_langs[] = $regs[1]; } diff --git a/ecrire/inc_lang_raccourcis.php3 b/ecrire/inc_lang_raccourcis.php3 index 34bad02b2f..d8080f03a0 100644 --- a/ecrire/inc_lang_raccourcis.php3 +++ b/ecrire/inc_lang_raccourcis.php3 @@ -35,7 +35,7 @@ debut_gauche(); $modules = array(); if (!$d = @opendir(_DIR_LANG)) return; -while ($f = readdir($d)) { +while (($f = readdir($d)) !== false) { if (ereg('^([a-z_]+)\.php3?$', $f, $regs)) $nom_module = $regs[1]; if (!ereg('^(spip|ecrire)\_', $nom_module) && ereg("^([a-zA-Z]+)\_".$spip_lang."$", $nom_module, $reps)) @@ -85,7 +85,7 @@ function afficher_raccourcis($module = "public") { echo "<div> </div>"; if (!$d = @opendir(_DIR_LANG)) return; - while ($f = readdir($d)) { + while (($f = readdir($d)) !== false) { if (ereg("^".$module."\_([a-z_]+)\.php3?$", $f, $regs)) $langue_module[$regs[1]] = traduire_nom_langue($regs[1]); } diff --git a/ecrire/inc_logos.php3 b/ecrire/inc_logos.php3 index 3e910c7eeb..d98ef146eb 100644 --- a/ecrire/inc_logos.php3 +++ b/ecrire/inc_logos.php3 @@ -133,7 +133,7 @@ function afficher_logo($racine, $titre, $logo, $id_objet, $id) { $afficher = ""; if ($GLOBALS['flag_upload']) { $myDir = opendir(_DIR_TRANSFERT); - while($entryName = readdir($myDir)){ + while(($entryName = readdir($myDir)) !== false){ if (!ereg("^\.",$entryName) AND eregi("(gif|jpg|png)$",$entryName)){ $entryName = addslashes($entryName); $afficher .= "\n<option value='$entryName'>$entryName</option>"; diff --git a/ecrire/inc_popularites.php3 b/ecrire/inc_popularites.php3 deleted file mode 100644 index 4347b81588..0000000000 --- a/ecrire/inc_popularites.php3 +++ /dev/null @@ -1,81 +0,0 @@ -<?php - -/***************************************************************************\ - * SPIP, Systeme de publication pour l'internet * - * * - * Copyright (c) 2001-2005 * - * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * - * * - * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * - * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * -\***************************************************************************/ - - -if (!defined("_ECRIRE_INC_VERSION")) return; - -// -// Popularite, modele logarithmique -// - -function calculer_popularites() { - - // Si c'est le premier appel (fichier .lock absent), ne pas calculer - $lock = _DIR_SESSIONS . 'popularites.lock'; - if (!$t = @filemtime($lock)) return; - spip_touch($lock); - - $duree = time() - $t; - // duree de demi-vie d'une visite dans le calcul de la popularite (en jours) - $demivie = 1; - // periode de reference en jours - $periode = 1; - // $a est le coefficient d'amortissement depuis la derniere mesure - $a = pow(2, - $duree / ($demivie * 24 * 3600)); - // $b est la constante multiplicative permettant d'avoir - // une visite par jour (periode de reference) = un point de popularite - // (en regime stationnaire) - // or, magie des maths, ca vaut log(2) * duree journee/demi-vie - // si la demi-vie n'est pas trop proche de la seconde ;) - $b = log(2) * $periode / $demivie; - - // oublier un peu le passe - spip_query("UPDATE spip_articles SET maj=maj, popularite = popularite * $a"); - - // ajouter les points visites - $count_article = Array(); - $query = "SELECT COUNT(*) as count,id_objet FROM spip_visites_temp WHERE maj > DATE_SUB(NOW(), INTERVAL $duree SECOND) AND type='article' GROUP BY id_objet"; - $res = spip_query($query); - while ($row = @spip_fetch_array($res)) { - $count_article[$row['count']] .= ','.$row['id_objet']; // l'objet a count visites - } - - foreach($count_article as $count => $articles) { - $query = "UPDATE spip_articles - SET maj=maj, popularite = GREATEST(1,popularite) + $b * $count - WHERE id_article IN (0$articles)"; - spip_query($query); - } - - // ajouter les points referers - $count_article = Array(); - $query = "SELECT COUNT(*) as count,id_objet FROM spip_referers_temp WHERE maj > DATE_SUB(NOW(), INTERVAL $duree SECOND) AND type='article' GROUP BY id_objet"; - $res = spip_query($query); - while ($row = @spip_fetch_array($res)) { - $count_article[$row['count']] .= ','.$row['id_objet']; // l'objet a count referers - } - - foreach($count_article as $count => $articles) { - $query = "UPDATE spip_articles - SET maj=maj, popularite = GREATEST(1,popularite) + $b * $count - WHERE id_article IN (0$articles)"; - spip_query($query); - } - - // et enregistrer les metas... - list($maxpop, $totalpop) = spip_fetch_array(spip_query("SELECT MAX(popularite), SUM(popularite) FROM spip_articles")); - ecrire_meta("popularite_max", $maxpop); - ecrire_meta("popularite_total", $totalpop); - ecrire_metas(); -} - -?> diff --git a/ecrire/inc_session.php3 b/ecrire/inc_session.php3 index 31755ce2fa..d304102a08 100644 --- a/ecrire/inc_session.php3 +++ b/ecrire/inc_session.php3 @@ -160,7 +160,7 @@ function zap_sessions ($id_auteur, $zap) { $dir = opendir(_DIR_SESSIONS); $t = time(); - while(($item = readdir($dir)) != '') { + while(($item = readdir($dir)) !== false) { $chemin = _DIR_SESSIONS . $item; if (ereg("^session_([0-9]+_)?([a-z0-9]+)\.php3$", $item, $regs)) { diff --git a/ecrire/inc_statistiques.php3 b/ecrire/inc_statistiques.php3 index 69d5acd82d..7aa76231b7 100644 --- a/ecrire/inc_statistiques.php3 +++ b/ecrire/inc_statistiques.php3 @@ -13,10 +13,6 @@ if (!defined("_ECRIRE_INC_VERSION")) return; -// -// Compiler les statistiques temporaires : visites -// - // Les deux fonctions suivantes sont adaptees du code des "Visiteurs", // par Jean-Paul Dezelus (http://www.phpinfo.net/applis/visiteurs/) @@ -144,119 +140,6 @@ function stats_show_keywords($kw_referer, $kw_referer_host) { } -// -// Optimiser les informations liees aux referers -// - -function supprimer_referers($type = "") { - $table = 'spip_referers'; - if ($type) { - $table .= '_'. $type . 's'; - $col_id = 'id_' . $type; - $query = "SELECT COUNT(DISTINCT $col_id) AS count FROM $table"; - $result = spip_query($query); - if ($row = @spip_fetch_array($result)) { - $count = $row['count']; - } - } - if (!$count) $count = 1; - $count = intval($count * 100); - $query = "SELECT visites FROM $table ". - "ORDER BY visites LIMIT 1 OFFSET $count"; - $result = spip_query($query); - $visites_min = 1; - if ($row = @spip_fetch_array($result)) { - $visites_min = $row['visites']; - } - - $query = "DELETE FROM $table WHERE (date < DATE_SUB(NOW(),INTERVAL 7 DAY) AND visites <= $visites_min) OR (date < DATE_SUB(NOW(),INTERVAL 30 DAY))"; - $result = spip_query($query); -} - - - -// -// Compiler les statistiques temporaires : referers (si active) -// - -function calculer_n_referers($nb_referers) { - $date = date("Y-m-d"); - - $result = spip_query("SELECT COUNT(DISTINCT ip) AS visites, referer, HEX(referer_md5) AS md5 ". - "FROM spip_referers_temp GROUP BY referer_md5 LIMIT $nb_referers"); - - $tous = spip_num_rows($result); - - $referer_insert = ""; - $referer_update = ""; - $referer_vus = ""; - - while ($row = @spip_fetch_array($result)) { - $visites = $row['visites']; - $referer = addslashes($row['referer']); - $referer_md5 = '0x'.$row['md5']; - $referer_update[$visites][] = $referer_md5; - $referer_insert[] = "('$date', '$referer', $referer_md5, $visites, $visites)"; - $referer_vus .= "," . $referer_md5; - } - if ($referer_vus) - $referer_vus = "referer_md5 IN (" . substr($referer_vus,1) . ")"; - - // Mise a jour de la base - if (is_array($referer_update)) { - while (list($visites, $referers) = each($referer_update)) { - $query = "UPDATE spip_referers SET visites = visites + $visites, visites_jour = visites_jour + $visites ". - "WHERE referer_md5 IN (".join(', ', $referers).")"; - $result = spip_query($query); - } - } - if (is_array($referer_insert)) { - $query_insert = "INSERT IGNORE INTO spip_referers ". - "(date, referer, referer_md5, visites, visites_jour) VALUES ".join(', ', $referer_insert); - $result_insert = spip_query($query_insert); - } - - // Ventiler ces referers article par article - $query = "SELECT COUNT(DISTINCT ip) AS visites, id_objet, referer, HEX(referer_md5) AS md5 FROM spip_referers_temp WHERE type='article'" - . ($referer_vus ? " AND $referer_vus" : '') - . " GROUP BY id_objet, referer_md5"; - $result = spip_query($query); - - $referer_insert = ""; - $referer_update = ""; - - while ($row = @spip_fetch_array($result)) { - $id_article = $row['id_objet']; - $visites = $row['visites']; - $referer = addslashes($row['referer']); - $referer_md5 = '0x'.$row['md5']; - - $referer_update[$visites][] = "(id_article=$id_article AND referer_md5=$referer_md5)"; - $referer_insert[] = "('$date', '$referer', $referer_md5, $id_article, $visites)"; - } - - // Mise a jour de la base - if (is_array($referer_update)) { - while (list($visites, $where) = each($referer_update)) { - $query = "UPDATE spip_referers_articles SET visites = visites + $visites ". - "WHERE ".join(' OR ', $where); - $result = spip_query($query); - } - } - if (is_array($referer_insert)) { - $query_insert = "INSERT IGNORE INTO spip_referers_articles ". - "(date, referer, referer_md5, id_article, visites) VALUES ".join(', ', $referer_insert); - $result_insert = spip_query($query_insert); - } - - // Effacer les referers traites - if ($referer_vus) { - spip_query("DELETE FROM spip_referers_temp WHERE $referer_vus"); - } - return $tous ; -} - - // // Afficher les referers d'un article (ou du site) // diff --git a/ecrire/inc_visites.php3 b/ecrire/inc_visites.php3 index cdbefa5910..f4409b5ce2 100644 --- a/ecrire/inc_visites.php3 +++ b/ecrire/inc_visites.php3 @@ -13,71 +13,254 @@ if (!defined("_ECRIRE_INC_VERSION")) return; -function calculer_visites() { - - // La date des enregistrements de spip_visites_temp correspond a la veille - // du calcul. - $hier = date("Y-m-d", time() - 24*3600); - - // Sur tout le site, nombre de visiteurs uniques pendant la periode - // qui precede (normalement, une journee) - $query = "SELECT COUNT(DISTINCT ip) AS total_visites FROM spip_visites_temp"; - $result = spip_query($query); - if ($row = @spip_fetch_array($result)) - $total_visites = $row['total_visites']; - else - $total_visites = 0; - spip_query("INSERT IGNORE INTO spip_visites - (date, visites) VALUES ('$hier', 0)"); - spip_query("UPDATE spip_visites SET visites = visites+$total_visites - WHERE date='$hier'"); - - // Nombre de visiteurs uniques par article - $query = "SELECT COUNT(DISTINCT ip) AS visites, id_objet - FROM spip_visites_temp WHERE type='article' GROUP BY id_objet"; - $result = spip_query($query); - - $visites_insert = array(); - $visites_update = array(); - - while ($row = @spip_fetch_array($result)) { - $id_article = $row['id_objet']; - $visites = $row['visites']; - $visites_update[$visites][] = $id_article; + + +### Pour se dę«arrasser du md5, comment faire ? Un index sur 'referer' ? +### ou alors la meme notion, mais sans passer par des fonctions HEX ? + + +// +// prendre en compte un fichier de visite +// +function compte_fichier_visite($fichier, +&$visites, &$visites_a, &$referers, &$referers_a, &$articles) { + + // Noter la visite du site (article 0) + $visites ++; + + $content = array(); + if (lire_fichier($fichier, $content)) + $content = unserialize($content); + + foreach ($content as $source => $num) { + list($log_type, $log_id_num, $log_referer) + = preg_split(",\t,", $source, 3); + + // Noter le referer + if ($log_referer) + $referers[$log_referer]++; + + // S'il s'agit d'un article, noter ses visites + if ($log_type == 'article' + AND $id_article = intval($log_id_num)) { + $articles[] = $id_article; + $visites_a[$id_article] ++; + if ($log_referer) + $referers_a[$id_article][$log_referer]++; + } + } +} + + +function calculer_visites($t) { + + // Initialisations + $visites = ''; # visites du site + $visites_a = array(); # tableau des visites des articles + $referers = array(); # referers du site + $referers_a = array(); # tableau des referers des articles + $articles = array(); # articles vus dans ce lot de visites + + // charger un certain nombre de fichiers de visites, + // et faire les calculs correspondants + + // 1. Chercher les paniers datant d'au moins 30 minutes + $date_init = date('YmdHi', time()-30*60); + $paniers = array(); + $dir = opendir(_DIR_SESSIONS); + while (($item = readdir($dir)) !== false) { + if (preg_match(',^stats_([0-9]{12})$,', $item, $regs) + AND $regs[1]<$date_init + AND is_dir(_DIR_SESSIONS.$item)) + $paniers[] = $item; } + closedir($dir); + + // 2. Manger 1000 fichiers de ces paniers (sans ordre particulier) + $compteur = 1000; + $pasfini = false; + foreach ($paniers as $panier) { + $dir = opendir(_DIR_SESSIONS.$panier); + while (($item = readdir($dir)) !== false) { + if (is_file($f = _DIR_SESSIONS.$panier.'/'.$item)) { + compte_fichier_visite($f, + $visites, $visites_a, $referers, $referers_a, $articles); + @unlink($f); + } + if (-- $compteur <= 0) { + $pasfini = true; + break; + } + } + // effacer le panier, sauf si on a atteint la limite de fichiers vus + closedir($dir); + if (!$pasfini) + @rmdir(_DIR_SESSIONS.$panier); + } + + if (!$visites) return; + + // Maintenant on dispose de plusieurs tableaux qu'il faut ventiler dans + // les tables spip_visites, spip_visites_articles, spip_referers + // et spip_referers_articles ; attention a affecter tout ca a la bonne + // date quand on est a cheval (entre minuit et 1 h du mat) + $date = date("Y-m-d", time() - 3600); + + // 1. les visites du site (facile) + spip_query("INSERT IGNORE INTO spip_visites + (date) VALUES ('$date')"); + spip_query("UPDATE spip_visites SET visites = visites+$visites + WHERE date='$date'"); - $query_effacer = "DELETE FROM spip_visites_temp"; - $result_effacer = spip_query($query_effacer); - - // Mise a jour de la base - foreach ($visites_update as $visites => $articles) { - // Augmenter les stats totales des articles - spip_query("UPDATE spip_articles SET maj=maj, - visites = visites + $visites - WHERE id_article IN (".join(',', $articles).")"); - // Inserer des visites pour la journee (si pas deja fait) - $insert = "('$hier',0,". join ("),('$hier',0,", $articles) . ')'; + // pour calcul_mysql_in + include_ecrire('inc_db_mysql.php3'); + + // 2. les visites des articles (en deux passes pour minimiser + // le nombre de requetes) + if ($articles) { + // s'assurer qu'un slot (date, visites, id) existe pour + // chaque article vu spip_query("INSERT IGNORE INTO spip_visites_articles - (date, visites, id_article) VALUES $insert"); - // Augmenter les stats des visites de la journee - spip_query("UPDATE spip_visites_articles - SET visites=visites+$visites WHERE date='$hier' - AND id_article IN (".join(',', $articles).")"); + (date, id_article) VALUES ('$date'," + . join("), ('$date',", $articles) + . ")"); + + // enregistrer les visites + $ar = array(); # tableau num -> liste des articles ayant num visites + foreach($visites_a as $id_article => $num) + $ar[$num][] = $id_article; + foreach ($ar as $num => $liste) { + spip_query("UPDATE spip_visites_articles + SET visites = visites+$num + WHERE date='$date' AND ". + calcul_mysql_in('id_article', join(',',$liste))); + ## Ajouter un JOIN sur le statut de l'article ? + } + } + + // 3. Les referers du site + if ($referers) { + $ar = array(); + // s'assurer d'un slot pour chacun + foreach ($referers as $referer => $num) { + $referer_md5 = '0x'.substr(md5($referer), 0, 15); + $insert[] = "('$date', '".addslashes($referer)."', + $referer_md5)"; + $ar[$num][] = $referer_md5; + } + spip_query("INSERT IGNORE INTO spip_referers + (date, referer, referer_md5) VALUES " + . join(', ', $insert)); + + // ajouter les visites + foreach ($ar as $num => $liste) { + spip_query("UPDATE spip_referers + SET visites = visites+$num, visites_jour = visites_jour+$num + WHERE ".calcul_mysql_in('referer_md5',join(',',$liste))); + } + } + + // 4. Les referers d'articles + if ($referers_a) { + $ar = array(); + $insert = array(); + // s'assurer d'un slot pour chacun + foreach ($referers_a as $id_article => $referers) + foreach ($referers as $referer => $num) { + $referer_md5 = '0x'.substr(md5($referer), 0, 15); + $insert[] = "('$date', '".addslashes($referer)."', + $referer_md5, $id_article)"; + $ar[$num][] = "(id_article=$id_article AND referer_md5=$referer_md5)"; + } + spip_query("INSERT IGNORE INTO spip_referers_articles + (date, referer, referer_md5) VALUES " + . join(', ', $insert)); + + // ajouter les visites + foreach ($ar as $num => $liste) { + spip_query("UPDATE spip_referers_articles + SET visites = visites+$num, visites_jour = visites_jour+$num + WHERE ".join(" OR ", $liste)); + ## Ajouter un JOIN sur le statut de l'article ? + } } + // 5. Calculer les popularites ; ici c'est presque comme les visites, + // sauf qu'on ajoute 1 point par referer + if ($visites_a) { + $points = array(); + foreach ($visites_a as $id_article => $v) { + // ajouter un point aux articles ayant un referer + if ($r = $referers_a[$id_article]) + $v += 1; // ou array_pop($r); + $points[$v][] = $id_article; + } + foreach ($points as $num => $liste) { + spip_query("UPDATE spip_articles + SET popularite = popularite + $num + WHERE ".calcul_mysql_in('id_article', join(',',$liste))); + } + } + + // S'il reste des fichiers a manger, le signaler pour reexecution rapide + return $pasfini; +} + + + +// +// Popularite, modele logarithmique +// + +function calculer_popularites() { + include_ecrire('inc_meta.php3'); + + // Si c'est le premier appel, ne pas calculer + $t = lire_meta('date_popularites'); + ecrire_meta('date_popularites', time()); + ecrire_metas(); + if (!$t) + return; + + $duree = time() - $t; + // duree de demi-vie d'une visite dans le calcul de la popularite (en jours) + $demivie = 1; + // periode de reference en jours + $periode = 1; + // $a est le coefficient d'amortissement depuis la derniere mesure + $a = pow(2, - $duree / ($demivie * 24 * 3600)); + // $b est la constante multiplicative permettant d'avoir + // une visite par jour (periode de reference) = un point de popularite + // (en regime stationnaire) + // or, magie des maths, ca vaut log(2) * duree journee/demi-vie + // si la demi-vie n'est pas trop proche de la seconde ;) + $b = log(2) * $periode / $demivie; + + // oublier un peu le passe + spip_query("UPDATE spip_articles SET maj=maj, popularite = popularite * $a"); + + // enregistrer les metas... + list($maxpop, $totalpop) = spip_fetch_array(spip_query("SELECT MAX(popularite), SUM(popularite) FROM spip_articles")); + ecrire_meta("popularite_max", $maxpop); + ecrire_meta("popularite_total", $totalpop); + + // Une fois par jour purger les referers du jour ; qui deviennent // donc ceux de la veille ; au passage on stocke une date_statistiques // dans spip_meta - cela permet au code d'etre "reentrant", ie ce cron // peut etre appele par deux bases SPIP ne partageant pas le meme // _DIR_SESSIONS, sans tout casser... $aujourdhui = date("Y-m-d"); - if ($date_referers = lire_meta('date_statistiques') - AND $date_referers != $aujourdhui) { + if ($date = lire_meta('date_statistiques') + AND $date != $aujourdhui) { spip_query("UPDATE spip_referers SET visites_veille=visites_jour, visites_jour=0"); } ecrire_meta('date_statistiques', $aujourdhui); + + // et c'est fini pour cette fois-ci ecrire_metas(); return 1; + } ?> diff --git a/formulaires/inc-formulaire_admin.php3 b/formulaires/inc-formulaire_admin.php3 index 2c5169f07a..c6b876a1fd 100644 --- a/formulaires/inc-formulaire_admin.php3 +++ b/formulaires/inc-formulaire_admin.php3 @@ -152,4 +152,24 @@ function balise_FORMULAIRE_ADMIN_dyn($float='', $debug='') { ) ); } + +// Un outil pour le bouton d'amin "statistiques" +function afficher_raccourci_stats($id_article) { + $query = "SELECT visites, popularite FROM spip_articles WHERE id_article=$id_article AND statut='publie'"; + $result = spip_query($query); + if ($row = @spip_fetch_array($result)) { + $visites = intval($row['visites']); + $popularite = ceil($row['popularite']); + + $query = "SELECT COUNT(DISTINCT ip) AS c FROM spip_visites_temp WHERE type='article' AND id_objet=$id_article"; + $result = spip_query($query); + if ($row = @spip_fetch_array($result)) { + $visites = $visites + $row['c']; + } + + return array('visites' => $visites, 'popularite' => $popularite); + } +} + + ?> diff --git a/inc-cache.php3 b/inc-cache.php3 index d8509d8130..16e8c54e03 100644 --- a/inc-cache.php3 +++ b/inc-cache.php3 @@ -167,7 +167,7 @@ function purger_repertoire($dir, $age='ignore', $regexp = '') { $handle = @opendir($dir); if (!$handle) return; - while (($fichier = @readdir($handle)) != '') { + while (($fichier = @readdir($handle)) !== false) { // Eviter ".", "..", ".htaccess", etc. if ($fichier[0] == '.') continue; if ($regexp AND !ereg($regexp, $fichier)) continue; @@ -241,7 +241,7 @@ function calculer_taille_dossier ($dir) { $handle = @opendir($dir); if (!$handle) return; - while (($fichier = @readdir($handle)) != '') { + while (($fichier = @readdir($handle)) !== false) { // Eviter ".", "..", ".htaccess", etc. if ($fichier[0] == '.') continue; if ($regexp AND !ereg($regexp, $fichier)) continue; @@ -257,7 +257,7 @@ function calculer_cache_vignettes() { $handle = @opendir(_DIR_IMG); if (!$handle) return; - while (($fichier = @readdir($handle)) != '') { + while (($fichier = @readdir($handle)) !== false) { // Eviter ".", "..", ".htaccess", etc. if ($fichier[0] == '.') continue; if ($regexp AND !ereg($regexp, $fichier)) continue; diff --git a/inc-stats.php3 b/inc-stats.php3 index 5a3b43b5d6..ae6e80a17b 100644 --- a/inc-stats.php3 +++ b/inc-stats.php3 @@ -32,50 +32,50 @@ function ecrire_stats() { $log_type = "autre"; // Conversion IP 4 octets -> entier 32 bits - if (ereg("^(::ffff:)?([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$", $log_ip, $r)) { - $log_ip = sprintf("0x%02x%02x%02x%02x", $r[2], $r[3], $r[4], $r[5]); - } - else return; + if (preg_match(",^(::ffff:)?([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$,", + $log_ip, $r)) + $log_ip = sprintf("%02x%02x%02x%02x", $r[2], $r[3], $r[4], $r[5]); + else + return; - // - // Loguer la visite dans la base si possible - // - if ($log_type != "autre") { - $query = "INSERT IGNORE INTO spip_visites_temp (ip, type, id_objet) ". - "VALUES ($log_ip, '$log_type', $log_id_num)"; - spip_query($query); + // Analyse du referer + if ($log_referer = $GLOBALS['HTTP_REFERER']) { + $url_site_spip = preg_replace(',^((https?|ftp)://)?(www\.)?,i', '', + lire_meta('adresse_site')); + if (($url_site_spip<>'') + AND strpos('-'.strtolower($log_referer), strtolower($url_site_spip)) + AND !$_GET['var_recherche']) + $log_referer = ''; + else + $referer_md5 = '0x'.substr(md5($log_referer), 0, 15); } // - // Loguer le referer + // stockage sous forme de fichier dans ecrire/data/stats_200511161005/ip // - $url_site_spip = lire_meta('adresse_site'); - $url_site_spip = eregi_replace("^((https?|ftp)://)?(www\.)?", "", $url_site_spip); - $log_referer = $GLOBALS['HTTP_REFERER']; - if (($url_site_spip<>'') AND strpos('-'.strtolower($log_referer), strtolower($url_site_spip)) AND !$GLOBALS['var_recherche']) $log_referer = ""; - if ($log_referer) { - $referer_md5 = '0x'.substr(md5($log_referer), 0, 15); - $query = "INSERT IGNORE INTO spip_referers_temp (ip, referer, referer_md5, type, id_objet) ". - "VALUES ($log_ip, '".addslashes($log_referer)."', $referer_md5, '$log_type', $log_id_num)"; - spip_query($query); - } -} - - -function afficher_raccourci_stats($id_article) { - $query = "SELECT visites, popularite FROM spip_articles WHERE id_article=$id_article AND statut='publie'"; - $result = spip_query($query); - if ($row = @spip_fetch_array($result)) { - $visites = intval($row['visites']); - $popularite = ceil($row['popularite']); - $query = "SELECT COUNT(DISTINCT ip) AS c FROM spip_visites_temp WHERE type='article' AND id_objet=$id_article"; - $result = spip_query($query); - if ($row = @spip_fetch_array($result)) { - $visites = $visites + $row['c']; + // 1. Chercher dans les paniers recents (moins de 30 minutes) s'il existe + // deja une session pour ce numero IP. Chaque panier couvre 5 minutes + $content = array(); + for ($i = -5; $i <= 0; $i++) { + $panier = date('YmdHi', (intval(time()/300)+$i)*300); + if (@file_exists($s = _DIR_SESSIONS.'stats_'.$panier.'/'.$log_ip)) { + lire_fichier($s, $content); + $content = @unserialize($content); + if ($i<0) @unlink($s); + break; } + } + + // 2. Determiner le fichier session dans le panier actuel + $panier = date('YmdHi', (intval(time()/300))*300); + $dir = _DIR_SESSIONS.creer_repertoire(_DIR_SESSIONS,'stats_'.$panier); - return array('visites' => $visites, 'popularite' => $popularite); + // 3. Plafonner le nombre de hits pris en compte pour un IP (robots etc.) + if (count($content) < 200) { + $entree = trim("$log_type\t$log_id_num\t$log_referer"); + $content[$entree] ++; + ecrire_fichier($s, serialize($content)); } } -- GitLab