09a4b1d93d3d69eb58c6d5bc1476198a8cf487b8
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
6 * Copyright (c) 2001-2019 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
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 \***************************************************************************/
14 * Fonctions d'appel aux serveurs SQL presentes dans le code compile
16 * NB : à l'exception des fonctions pour les balises dynamiques
18 * @package SPIP\Core\Compilateur\Quetes
21 if (!defined('_ECRIRE_INC_VERSION')) {
26 include_spip('base/abstract_sql');
29 * Retourne l'URL de redirection d'un article virtuel, seulement si il est publié
33 * @return array|bool|null
35 function quete_virtuel($id_article, $connect) {
39 array('id_article=' . intval($id_article), "statut='publie'"),
49 * Retourne le couple `parent,lang` pour toute table
51 * En pratique `id_rubrique` si présent (ou `id_parent` pour table rubriques)
52 * et champ `lang` si présent
54 * @param string $table
56 * @param string $connect
59 function quete_parent_lang($table, $id, $connect = '') {
60 static $cache_quete = array();
62 if (!isset($cache_quete[$connect][$table][$id])) {
63 if (!isset($cache_quete[$connect][$table]['_select'])) {
64 $trouver_table = charger_fonction('trouver_table', 'base');
65 if (!$desc = $trouver_table($table,
66 $connect) or !isset($desc['field']['id_rubrique'])
68 // pas de parent rubrique, on passe
69 $cache_quete[$connect][$table]['_select'] = false;
71 $select = ($table == 'spip_rubriques' ?
'id_parent' : 'id_rubrique');
72 $select .= isset($desc['field']['lang']) ?
', lang' : '';
73 $cache_quete[$connect][$table]['_select'] = $select;
74 $cache_quete[$connect][$table]['_id'] = id_table_objet(objet_type($table));
77 if ($cache_quete[$connect][$table]['_select']) {
78 $cache_quete[$connect][$table][$id] = sql_fetsel(
79 $cache_quete[$connect][$table]['_select'],
81 $cache_quete[$connect][$table]['_id'] . '=' . intval($id),
91 return isset($cache_quete[$connect][$table][$id]) ?
$cache_quete[$connect][$table][$id] : null;
96 * Retourne le parent d'une rubrique
98 * Repose sur la fonction quete_parent_lang pour la mutualisation
99 * +mise en cache SQL des requêtes
101 * @uses quete_parent_lang()
103 * @param int $id_rubrique
104 * @param string $connect
107 function quete_parent($id_rubrique, $connect = '') {
108 if (!$id_rubrique = intval($id_rubrique)) {
111 $id_parent = quete_parent_lang('spip_rubriques', $id_rubrique, $connect);
113 return $id_parent['id_parent'];
117 * Retourne la rubrique d'un article
119 * Repose sur la fonction quete_parent_lang pour la mutualisation
120 * +mise en cache SQL des requêtes
122 * @uses quete_parent_lang()
124 * @param int $id_article
128 function quete_rubrique($id_article, $serveur) {
129 $id_parent = quete_parent_lang('spip_articles', $id_article, $serveur);
131 return $id_parent['id_rubrique'];
136 * Retourne la profondeur d'une rubrique
138 * @uses quete_parent()
141 * @param string $connect
144 function quete_profondeur($id, $connect = '') {
148 $id = quete_parent($id, $connect);
156 * Retourne la condition sur la date lorsqu'il y a des post-dates
158 * @param string $champ_date
159 * Nom de la colonne de date dans la table SQL
160 * @param string $serveur
161 * @param bool $ignore_previsu
162 * true pour forcer le test même en prévisu
164 * Morceau de la requête SQL testant la date
166 function quete_condition_postdates($champ_date, $serveur = '', $ignore_previsu = false) {
167 if (defined('_VAR_PREVIEW') and _VAR_PREVIEW
and !$ignore_previsu) {
172 (isset($GLOBALS['meta']['date_prochain_postdate'])
173 and $GLOBALS['meta']['date_prochain_postdate'] > time())
174 ?
"$champ_date<" . sql_quote(date('Y-m-d H:i:s', $GLOBALS['meta']['date_prochain_postdate']), $serveur)
180 * Calculer la condition pour filtrer les status,
182 * @param string $mstatut
183 * Le champ de la table sur lequel porte la condition
184 * @param string $previsu
185 * Mode previsu : statut ou liste des statuts séparés par une virgule
186 * @param string $publie
187 * Mode publie : statut ou liste des statuts séparés par une virgule
188 * @param string $serveur
190 * @param bool $ignore_previsu
191 * true pour forcer le test même en prévisu
192 * @return array|string
194 function quete_condition_statut($mstatut, $previsu, $publie, $serveur = '', $ignore_previsu = false) {
195 static $cond = array();
196 $key = func_get_args();
197 $key = implode('-', $key);
198 if (isset($cond[$key])) {
202 $liste_statuts = $publie;
203 if (defined('_VAR_PREVIEW') and _VAR_PREVIEW
and !$ignore_previsu) {
204 $liste_statuts = $previsu;
207 if (strncmp($liste_statuts, '!', 1) == 0) {
209 $liste_statuts = substr($liste_statuts, 1);
211 // '' => ne rien afficher, '!'=> ne rien filtrer
212 if (!strlen($liste_statuts)) {
213 return $cond[$key] = ($not ?
'1=1' : '0=1');
216 $liste_statuts = explode(',', $liste_statuts);
218 foreach ($liste_statuts as $k => $v) {
219 // filtrage /auteur pour limiter les objets d'un statut (prepa en general)
220 // a ceux de l'auteur identifie
221 if (strpos($v, '/') !== false) {
222 $v = explode('/', $v);
225 $v = preg_replace(',\W,', '', $v);
226 if ($filtre == 'auteur'
227 and (strpos($mstatut, '.') !== false)
228 and $objet = explode('.', $mstatut)
229 and $id_table = reset($objet)
230 and $objet = objet_type($id_table)
232 $w = "$mstatut<>" . sql_quote($v);
234 // retrouver l’id_auteur qui a filé un lien de prévisu éventuellement,
235 // sinon l’auteur en session
236 include_spip('inc/securiser_action');
237 if ($desc = decrire_token_previsu()) {
238 $id_auteur = $desc['id_auteur'];
239 } elseif (isset($GLOBALS['visiteur_session']['id_auteur'])) {
240 $id_auteur = intval($GLOBALS['visiteur_session']['id_auteur']);
245 // dans ce cas (admin en general), pas de filtrage sur ce statut
246 if (!autoriser('previsualiser' . $v, $objet, '', $id_auteur)) {
247 // si pas d'auteur identifie pas de sous-requete car pas d'article qui matche
251 $primary = id_table_objet($objet);
252 $where[] = "($w OR $id_table.$primary IN (" . sql_get_select(
254 'spip_auteurs_liens AS ssss',
255 'ssss.objet=' . sql_quote($objet) . ' AND ssss.id_auteur=' . intval($id_auteur),
264 } // ignorer ce statut si on ne sait pas comment le filtrer
270 $liste_statuts[$k] = preg_replace(',\W,', '', $v);
272 $liste_statuts = array_filter($liste_statuts);
273 if (count($liste_statuts) == 1) {
274 $where[] = array('=', $mstatut, sql_quote(reset($liste_statuts), $serveur));
276 $where[] = sql_in($mstatut, $liste_statuts, $not, $serveur);
279 while (count($where) > 1) {
280 $and = array('AND', array_pop($where), array_pop($where));
283 $cond[$key] = reset($where);
285 $cond[$key] = array('NOT', $cond[$key]);
292 * Retourne le fichier d'un document
294 * @param int $id_document
295 * @param string $serveur
296 * @return array|bool|null
298 function quete_fichier($id_document, $serveur = '') {
299 return sql_getfetsel('fichier', 'spip_documents', ('id_document=' . intval($id_document)), '', array(), '', '', $serveur);
303 * Toute les infos sur un document
305 * @param int $id_document
306 * @param string $serveur
309 function quete_document($id_document, $serveur = '') {
310 return sql_fetsel('*', 'spip_documents', ('id_document=' . intval($id_document)), '', array(), '', '', $serveur);
314 * Récuperer une meta sur un site (spip) distant (en local il y a plus simple)
316 * @param string $nom Nom de la méta
317 * @param string $serveur Connecteur
318 * @return array|bool|null
320 function quete_meta($nom, $serveur) {
321 return sql_getfetsel('valeur', 'spip_meta', 'nom=' . sql_quote($nom), '', '', '', '', $serveur);
325 * Retourne le logo d'un objet, éventuellement par héritage
327 * Si flag != false, retourne le chemin du fichier, sinon retourne un tableau
329 * le chemin du fichier, celui du logo de survol, l'attribut style=w/h.
331 * @param string $cle_objet
332 * Nom de la clé de l'objet dont on veut chercher le logo.
333 * @param string $onoff
334 * Sélectionne quel(s) logo(s) : "on" pour le logo normal, "off" pour le logo de survol, ou "ON" pour l'ensemble.
336 * Identifiant de l'objet dont on veut chercher le logo.
337 * @param int $id_rubrique
338 * Identifiant de la rubrique parente si l'on veut aller chercher son logo
339 * dans le cas où l'objet demandé n'en a pas.
341 * Lorsque le drapeau est évalué comme "true", la fonction ne renvoie
342 * que le chemin du fichier, sinon elle renvoie le tableau plus complet.
343 * @return array|string
344 * Retourne soit un tableau, soit le chemin du fichier.
346 function quete_logo($cle_objet, $onoff, $id, $id_rubrique, $flag) {
347 include_spip('base/objets');
348 $nom = strtolower($onoff);
351 $objet = objet_type($cle_objet);
353 $on = quete_logo_objet($id, $objet, $nom);
357 return basename($on['chemin']);
359 $taille = @getimagesize
($on['chemin']);
361 // Si on a déjà demandé un survol directement ($onoff = off)
362 // ou qu'on a demandé uniquement le normal ($onoff = on)
363 // alors on ne cherche pas du tout le survol ici
364 if ($onoff != 'ON') {
367 // Sinon, c'est qu'on demande normal ET survol à la fois, donc on cherche maintenant le survol
368 $off = quete_logo_objet($id, $objet, 'off');
371 // on retourne une url du type IMG/artonXX?timestamp
372 // qui permet de distinguer le changement de logo
373 // et placer un expire sur le dossier IMG/
375 $on['chemin'] . ($on['timestamp'] ?
"?{$on['timestamp']}" : ''),
376 ($off ?
$off['chemin'] . ($off['timestamp'] ?
"?{$off['timestamp']}" : '') : ''),
377 (!$taille ?
'' : (' ' . $taille[3]))
379 $res['src'] = $res[0];
380 $res['logo_on'] = $res[0];
381 $res['logo_off'] = $res[1];
382 $res['width'] = ($taille ?
$taille[0] : '');
383 $res['height'] = ($taille ?
$taille[1] : '');
388 if (defined('_LOGO_RUBRIQUE_DESACTIVER_HERITAGE')) {
392 $cle_objet = 'id_rubrique';
396 if ($id and $cle_objet == 'id_rubrique') {
397 $id = quete_parent($id);
408 * Chercher le logo d'un contenu précis
410 * @param int $id_objet
411 * Idenfiant de l'objet dont on cherche le logo
412 * @param string $objet
413 * Type de l'objet dont on cherche le logo
414 * @param string $mode
415 * "on" ou "off" suivant le logo normal ou survol
417 function quete_logo_objet($id_objet, $objet, $mode) {
418 static $chercher_logo;
419 if (is_null($chercher_logo)) {
420 $chercher_logo = charger_fonction('chercher_logo', 'inc');
422 $cle_objet = id_table_objet($objet);
424 // On cherche pas la méthode classique
425 $infos_logo = $chercher_logo($id_objet, $cle_objet, $mode);
426 // Si la méthode classique a trouvé quelque chose, on utilise le nouveau format
427 if (!empty($infos_logo)) {
429 'chemin' => $infos_logo[0],
430 'timestamp' => $infos_logo[4],
434 // On passe cette recherche de logo dans un pipeline
435 $infos_logo = pipeline(
439 'id_objet' => $id_objet,
441 'cle_objet' => $cle_objet,
444 'data' => $infos_logo,
452 * Retourne le logo d’un fichier (document spip) sinon la vignette du type du fichier
454 * Fonction appeleé par la balise `#LOGO_DOCUMENT`
457 * @param string $connect
458 * @return bool|string
460 function quete_logo_file($row, $connect = null) {
461 include_spip('inc/documents');
462 $logo = vignette_logo_document($row, $connect);
464 $logo = image_du_document($row, $connect);
467 $f = charger_fonction('vignette', 'inc');
468 $logo = $f($row['extension'], false);
470 // si c'est une vignette type doc, la renvoyer direct
471 if (strcmp($logo, _DIR_PLUGINS
) == 0
472 or strcmp($logo, _DIR_PLUGINS_DIST
) == 0
473 or strcmp($logo, _DIR_RACINE
. 'prive/') == 0
478 return get_spip_doc($logo);
482 * Trouver l'image logo d'un document
485 * description du document, issue de la base
489 * alignement left/right
492 * '' => automatique (vignette sinon apercu sinon icone)
493 * icone => icone du type du fichier
494 * apercu => apercu de l'image exclusivement, meme si une vignette existe
495 * vignette => vignette exclusivement, ou rien si elle n'existe pas
500 * @param string $connect
504 function quete_logo_document($row, $lien, $align, $mode_logo, $x, $y, $connect = null) {
506 include_spip('inc/documents');
508 if (!in_array($mode_logo, array('icone', 'apercu'))) {
509 $logo = vignette_logo_document($row, $connect);
511 // si on veut explicitement la vignette, ne rien renvoyer si il n'y en a pas
512 if ($mode_logo == 'vignette' and !$logo) {
515 if ($mode_logo == 'icone') {
516 $row['fichier'] = '';
519 return vignette_automatique($logo, $row, $lien, $x, $y, $align, null, $connect);
523 * Retourne le chemin d’un document lorsque le connect est précisé
525 * Sur un connecteur distant, voir si on connait l’adresse du site (spip distant)
526 * et l’utiliser le cas échéant.
528 * @param string $fichier Chemin
529 * @param string $connect Nom du connecteur
530 * @return string|false
532 function document_spip_externe($fichier, $connect) {
534 $site = quete_meta('adresse_site', $connect);
536 $dir = quete_meta('dir_img', $connect);
537 return "$site/$dir$fichier";
544 * Retourne la vignette explicitement attachee a un document
545 * le resutat est un fichier local existant, ou une URL
546 * ou vide si pas de vignette
549 * @param string $connect
552 function vignette_logo_document($row, $connect = '') {
553 if (!$row['id_vignette']) {
556 $fichier = quete_fichier($row['id_vignette'], $connect);
557 if ($url = document_spip_externe($fichier, $connect)) {
561 $f = get_spip_doc($fichier);
562 if ($f and @file_exists
($f)) {
565 if ($row['mode'] !== 'vignette') {
569 return generer_url_entite($row['id_document'], 'document', '', '', $connect);
573 * Calcul pour savoir si un objet est expose dans le contexte
574 * fournit par $reference
577 * @param string $prim
578 * @param array $reference
580 * @param string $type
581 * @param string $connect
582 * @return bool|string
584 function calcul_exposer($id, $prim, $reference, $parent, $type, $connect = '') {
585 static $exposer = array();
587 // Que faut-il exposer ? Tous les elements de $reference
588 // ainsi que leur hierarchie ; on ne fait donc ce calcul
589 // qu'une fois (par squelette) et on conserve le resultat
591 if (!isset($exposer[$m = md5(serialize($reference))][$prim])) {
592 $principal = isset($reference[$type]) ?
$reference[$type] :
593 // cas de la pagination indecte @xx qui positionne la page avec l'id xx
594 // et donne la reference dynamique @type=xx dans le contexte
595 (isset($reference["@$type"]) ?
$reference["@$type"] : '');
596 // le parent fournit en argument est le parent de $id, pas celui de $principal
597 // il n'est donc pas utile
599 if (!$principal) { // regarder si un enfant est dans le contexte, auquel cas il expose peut etre le parent courant
600 $enfants = array('id_rubrique' => array('id_article'), 'id_groupe' => array('id_mot'));
601 if (isset($enfants[$type])) {
602 foreach ($enfants[$type] as $t) {
603 if (isset($reference[$t])
604 // cas de la reference donnee dynamiquement par la pagination
605 or isset($reference["@$t"])
608 $principal = isset($reference[$type]) ?
$reference[$type] : $reference["@$type"];
614 $exposer[$m][$type] = array();
616 $principaux = is_array($principal) ?
$principal : array($principal);
617 foreach ($principaux as $principal) {
618 $exposer[$m][$type][$principal] = true;
619 if ($type == 'id_mot') {
621 $parent = sql_getfetsel('id_groupe', 'spip_mots', 'id_mot=' . intval($principal), '', '', '', '', $connect);
624 $exposer[$m]['id_groupe'][$parent] = true;
627 if ($type != 'id_groupe') {
629 if ($type == 'id_rubrique') {
630 $parent = $principal;
632 if ($type == 'id_article') {
633 $parent = quete_rubrique($principal, $connect);
637 $exposer[$m]['id_rubrique'][$parent] = true;
638 } while ($parent = quete_parent($parent, $connect));
645 // And the winner is...
646 return isset($exposer[$m][$prim]) ?
isset($exposer[$m][$prim][$id]) : '';
650 * Trouver le numero de page d'une pagination indirecte
651 * lorsque debut_xxx=@123
652 * on cherche la page qui contient l'item dont la cle primaire vaut 123
654 * @param string $primary
655 * @param int|string $valeur
657 * @param objetc $iter
660 function quete_debut_pagination($primary, $valeur, $pas, $iter) {
661 // on ne devrait pas arriver ici si la cle primaire est inexistante
662 // ou composee, mais verifions
663 if (!$primary or preg_match('/[,\s]/', $primary)) {
668 while ($row = $iter->fetch() and $row[$primary] != $valeur) {
671 // si on a pas trouve
672 if ($row[$primary] != $valeur) {
676 // sinon, calculer le bon numero de page
677 return floor($pos / $pas) * $pas;