,{$u}Uims", '', $texte); // \W matche tous les caracteres non ascii apres 0x80 // et vide donc les chaines constitues de caracteres unicodes uniquement // on remplace par un match qui elimine uniquement // les non \w et les non unicodes $texte = trim(preg_replace(",[^\w\x80-\xFF]+,ims", ' ', $texte)); // on utilise spip_strlen pour compter la longueur correcte // pour les chaines unicodes return spip_strlen($texte); } /** * Retourne un tableau d'analyse du texte transmis * Cette analyse concerne principalement des statistiques sur les liens * * @param string $texte texte d'entree * @return array rapport d'analyse */ function nospam_analyser_spams($texte) { $infos = array( 'caracteres_utiles' => 0, // nombre de caracteres sans les liens 'nombre_liens' => 0, // nombre de liens 'caracteres_texte_lien_min' => 0, // nombre de caracteres du plus petit titre de lien 'contenu_cache' => false, // du contenu est caché en CSS ? ); if (!$texte) { return $infos; } // on travaille d'abord sur le texte 'brut' tel que saisi par // l'utilisateur pour ne pas avoir les class= et style= que spip ajoute // sur les raccourcis. // on ne tient pas compte des blocs et ni de leurs contenus include_spip('inc/texte_mini'); if (!function_exists('echappe_html')) { // SPIP 2.x include_spip('inc/texte'); } $texte_humain = echappe_html($texte); // on repère dans ce qui reste la présence de style= ou class= qui peuvent // servir à masquer du contenu // les spammeurs utilisent le laxisme des navigateurs pour envoyer aussi style = // soyons donc mefiant // (mais en enlevant le base64 !) $texte_humain = str_replace('class="base64"', '', $texte_humain); $hidden = ',(<(img|object)|\s(?:style|class)\s*=[^>]+>),UimsS'; if (preg_match($hidden, $texte_humain)) { // suspicion de spam $infos['contenu_cache'] = true; } include_spip('inc/texte'); $texte = propre($texte); // caracteres_utiles $infos['caracteres_utiles'] = nospam_compter_caracteres_utiles($texte, false); // nombre de liens $liens = array_filter(extraire_balises($texte, 'a'), 'nospam_pas_lien_ancre'); $infos['nombre_liens'] = count($liens); $infos['liens'] = $liens; // taille du titre de lien minimum if (count($liens)) { // supprimer_tags() s'applique a tout le tableau, // mais attention a verifier dans le temps que ca continue a fonctionner # $titres_liens = array_map('supprimer_tags', $liens); $titres_liens = supprimer_tags($liens); $titres_liens = array_map('strlen', $titres_liens); $infos['caracteres_texte_lien_min'] = min($titres_liens); } return $infos; } /** * Vérifier si un lien est *n'est pas* une ancre : dans ce cas, ne pas le compte (ici, fonction de filtre de tableau) * Cette analyse concerne principalement des statistiques sur les liens * * @param string $texte lien * @return boolean : true -> */ function nospam_pas_lien_ancre($texte) { return substr(extraire_attribut($texte, 'href'), 0, 1) == '#' ? false : true; } /** * Compare les domaines des liens fournis avec la presence dans la base * * @param array $liens * liste des liens html * @param int $seuil * seuil de detection de presence : nombre d'enregistrement qui ont deja un lien avec le meme domaine * @param string $table * table sql * @param array $champs * champs a prendre en compte dans la detection * @param null|string $condstatut * condition sur le statut='spam' pour ne regarder que les enregistrement en statut spam * @return bool */ function nospam_rechercher_presence_liens_spammes($liens, $seuil, $table, $champs, $condstatut = null) { include_spip('inc/filtres'); if (is_null($condstatut)) { $condstatut = 'statut='.sql_quote('spam'); } if ($condstatut) { $condstatut = "$condstatut AND "; } // limiter la recherche au mois precedent $trouver_table = charger_fonction('trouver_table', 'base'); if ($desc = $trouver_table($table) and isset($desc['date'])) { $depuis = date('Y-m-d H:i:s', strtotime('-1 month')); $condstatut .= $desc['date'].'>'.sql_quote($depuis).' AND '; } // Ne pas prendre en compte les liens sur les domaines explicitement autorisés // Il ne faut ni http(s):// ni www dedans, juste le NDD (et éventuellement un sous domaine) if (defined('NOSPAM_DOMAINES_AMIS') and NOSPAM_DOMAINES_AMIS) { $amis = explode(',', NOSPAM_DOMAINES_AMIS); $amis = array_filter(array_map('trim', $amis)); } else { $amis = array(); } foreach (array($GLOBALS['meta']['adresse_site'],url_de_base()) as $a) { $host = parse_url($a, PHP_URL_HOST); if ($host) { $host = explode('.', $host); $amis[] = implode('.', array_slice($host, -2)); } } if (count($amis)) { $amis = array_unique($amis); $amis = array_map('preg_quote', $amis); $amis = '/('.implode('|', $amis).')$/'; spip_log("domaines whitelist pour les liens spams : $amis", 'nospam'); } else { $amis = ''; } $hosts = array(); foreach ($liens as $lien) { $url = extraire_attribut($lien, 'href'); if ($parse = parse_url($url) and !empty($parse['host']) and (!$amis or !preg_match($amis, $parse['host']))) { $hosts[] = $parse['host']; } } $hosts = array_unique($hosts); $hosts = array_filter($hosts); // pour chaque host figurant dans un lien, regarder si on a pas deja eu des spams avec ce meme host // auquel cas on refuse poliment le message foreach ($hosts as $h) { $like = ' LIKE '.sql_quote("%$h%"); $where = $condstatut . '('.implode("$like OR ", $champs)."$like)"; if (($n=sql_countsel($table, $where))>=$seuil) { // loger les 10 premiers messages concernes pour aider le webmestre $_id = id_table_objet($table); $all = sql_allfetsel($_id, $table, $where, '', '', '0,10'); if (function_exists('array_column')) { $all = array_column($all, $_id); } else { $all = array_map('reset', $all); } spip_log("$n liens trouves $like dans table $table (".implode(',', $all).') [champs '.implode(',', $champs).']', 'nospam'); return $h; } } return false; }