Mise à jour 4.4.6 plugins/dist et plugins/auto, bug dans referers

Titre : [statistiques] table_objet_sql() reçoit un array dans referenceurs.php → fatal PHP 8

Contexte

  • SPIP : x.y.z (prod)
  • PHP : 8.x
  • Plugins noyau : statistiques (version livrée avec x.y.z)
  • Plugins : statsobjets 2.1.0, referer_spam 1.2.1
  • Hébergeur/OS : …

Reproduction

  1. Activer Statistiques et StatsObjets.
  2. Aller dans : Activités → Statistiques → Liens entrants.
  3. Avec certains objets passés par l’interface, l’erreur survient.

Résultat obtenu

table_objet_sql(): Argument #1 ($type) must be of type string, array given
…/ecrire/base/objets.php:1074
appelé depuis …/plugins-dist/statistiques/inc/referenceurs.php:191

Résultat attendu
Affichage normal des référents.

Analyse
referenceurs.php::referes() peut recevoir $objets sous forme de tableau (extraction depuis spip_referers_objets ou appels externes). La boucle foreach ($objets as $objet) envoie ensuite un élément potentiellement tableau à table_objet_sql($objet), qui attend une chaîne.

Correctif proposé (défensif)

  • Extraire proprement la colonne objet depuis sql_allfetsel.
  • Aplatir/normaliser $objets en tableau de chaînes.
  • Passer chaque $objet par objet_type() avant table_objet_sql().

Diff minimal sur plugins-dist/statistiques/inc/referenceurs.php :

--- a/plugins-dist/statistiques/inc/referenceurs.php
+++ b/plugins-dist/statistiques/inc/referenceurs.php
@@ function referes(string $referermd5, $objets = null, string $serveur = ''): string {
-       if ($stats_objets) {
-               if ($objets = sql_allfetsel('DISTINCT objet', 'spip_referers_objets')) {
-                       $objets_par_defaut = array_values($objets);
-               }
-       }
+       if ($stats_objets) {
+               if ($tmp = sql_allfetsel('DISTINCT objet', 'spip_referers_objets')) {
+                       // extraire colonne 'objet', nettoyer et dédupliquer
+                       $liste = array_column($tmp, 'objet');
+                       $liste = array_filter(array_map('strval', $liste));
+                       $liste = array_values(array_unique($liste));
+                       $objets_par_defaut = $liste;
+               }
+       }
        if (sql_fetsel('*', 'spip_visites_articles', '', '', '', '0,1')) {
                $objets_par_defaut[] = 'article';
-               // (pas de déduplication ici)
+               $objets_par_defaut = array_values(array_unique($objets_par_defaut));
        }
@@
- elseif (is_array($objets)) {
-       // laisser tel quel
- }
+ elseif (is_array($objets)) {
+       // aplatir d’éventuels sous-tableaux
+       $flat = [];
+       foreach ($objets as $o) {
+               $flat[] = is_array($o) ? reset($o) : $o;
+       }
+       $objets = array_values(array_unique(array_filter(array_map('strval', $flat))));
+ }
@@
- foreach ($objets as $objet) {
-       $table_objet_sql = table_objet_sql($objet);
+ foreach ($objets as $objet) {
+       if (is_array($objet)) {
+               $objet = reset($objet);
+       }
+       $objet = objet_type($objet);
+       $table_objet_sql = table_objet_sql($objet);
        $id_table_objet = id_table_objet($objet);

Remarque front/squelettes (optionnel)
Dans prive/squelettes/contenu/stats_referers.html, on peut aussi normaliser côté gabarit pour éviter de passer un tableau :

#SET{objet_norm,#ENV{objet}|table_valeur{0,#ENV{objet}}}
… utiliser #GET{objet_norm} à la place de #ENV{objet} …

Mais le correctif robuste est côté PHP.

Merci.

Merci !

Je l’ai indiqué dans le ticket : Erreur table_objet_sql (#11) · Issues · spip-contrib-extensions / statistiques_objets · GitLab

ok je n’avais pas vu ce ticket

Le mer. 15 oct. 2025 à 11:00, RealET via Discuter de SPIP <noreply@discuter.spip.net> a écrit :

RealET
Octobre 15

Merci !

Je l’ai indiqué dans le ticket : Erreur table_objet_sql (#11) · Issues · spip-contrib-extensions / statistiques_objets · GitLab


Voir le sujet ou répondre à cet e-mail pour répondre.

Pour vous désabonner de ces e-mails, cliquez ici.

J’ai essayé de tester ton patch, mais il y a des parties de code que je ne trouve pas dans l’original :
// (pas de déduplication ici) par exemple

Est-ce que tu pourrais faire une PR sur : spip / stats · GitLab ?

désolé mais je n’arrive pas à me connecter sur Gitlab voici le code nettoyé :


/**
* Recherche des objets pointés par un referer
*
* @param string $referermd5
* @param array|string $objets
* @param string $serveur
* @return string
*/
function referes(string $referermd5, $objets = null, string $serveur = ''): string {
static $objets_par_defaut;

include_spip('base/objets'); // au cas où
$trouver_table = charger_fonction('trouver_table', 'base');

// si aucun type d'objet n'est donné en paramètre,
// on va chercher tous les types d'objets référencés dans les tables des referers
if (!$objets) {
if (null === $objets_par_defaut) {
$objets_par_defaut = [];
// plugin stats objets ?
$stats_objets = $trouver_table('spip_referers_objets');
if ($stats_objets) {
if ($tmp = sql_allfetsel('DISTINCT objet', 'spip_referers_objets')) {
$liste = array_column($tmp, 'objet');
$liste = array_values(array_unique(array_filter(array_map('strval', $liste))));
$objets_par_defaut = $liste;
}
}
if (sql_fetsel('*', 'spip_visites_articles', '', '', '', '0,1')) {
$objets_par_defaut[] = 'article';
$objets_par_defaut = array_values(array_unique($objets_par_defaut));
}
}
$objets = $objets_par_defaut;
}
// sinon on s'assure d'avoir un array propre
elseif (is_string($objets)) {
$objets = [$objets];
} elseif (is_array($objets)) {
$flat = [];
foreach ($objets as $o) {
$flat[] = is_array($o) ? reset($o) : $o;
}
$objets = array_values(array_unique(array_filter(array_map('strval', $flat))));
}

$retours = [];
$res_objets = [];
foreach ($objets as $objet) {
if (is_array($objet)) {
$objet = reset($objet);
}
$objet = objet_type($objet);

$table_objet_sql = table_objet_sql($objet); // spip_articles
$id_table_objet = id_table_objet($objet); // id_article
$desc = $trouver_table($table_objet_sql);
$champ_titre = $desc['titre'] ?? 'titre'; // titre, nom...

$table_referers = ($objet === 'article') ? 'spip_referers_articles' : 'spip_referers_objets';
$on = ($objet === 'article')
? 'J1.id_article = J2.id_article'
: '(J1.objet=' . sql_quote($objet) . " AND J1.id_objet = J2.$id_table_objet)";

if (
$res = sql_allfetsel(
"J2.$id_table_objet, J2.$champ_titre",
"$table_referers AS J1 LEFT JOIN $table_objet_sql AS J2 ON $on",
"(referer_md5='$referermd5' AND J1.maj>=DATE_SUB(" . sql_quote(date('Y-m-d H:i:s')) . ', INTERVAL 2 DAY))',
'',
'titre',
'',
'',
$serveur
)
) {
$res_objets[$objet] = $res;
}
}

foreach ($res_objets as $objet => $res) {
$id_table_objet = id_table_objet($objet);
foreach ($res as $k => $ligne) {
$titre = typo($ligne['titre']);
$url = generer_objet_url($ligne[$id_table_objet], $objet, '', '', true);
$retours[$k] = "<a href='$url'><i>$titre</i></a>";
}
}

if (count($retours) > 1) {
return '&rarr; ' . join(',<br />&rarr; ', $retours);
}
if (count($retours) == 1) {
return '&rarr; ' . array_shift($retours);
}

return '';
}

Le mer. 15 oct. 2025 à 11:37, RealET via Discuter de SPIP <noreply@discuter.spip.net> a écrit :

RealET
Octobre 15

J’ai essayé de tester ton patch, mais il y a des parties de code que je ne trouve pas dans l’original :
// (pas de déduplication ici) par exemple

Est-ce que tu pourrais faire une PR sur : spip / stats · GitLab ?


Voir le sujet ou répondre à cet e-mail pour répondre.

Pour vous désabonner de ces e-mails, cliquez ici.

Il faudrait que tu modifie ton message en tourant le code avec le bouton
image

Là, c’est inutilisable.

Salut,

Je l’ai fais pour lui

un modo

1 « J'aime »

Mais les Tabs ont été perdus :frowning:

ça je les vois pas, @pb38550 je te laisse modifier ou refaire un message avec les cote pour la mise en page

Est-ce que tu es bien inscrit sur la forge ? Partie « Contribuer au développement », dans cette page

Salut, je viens de valider ton compte, tu devrais pouvoir t’identifier ou lancer un rappel de mot de passe.