You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

990 lines
27 KiB

<?php
/***************************************************************************\
* SPIP, Système de publication pour l'internet *
* *
* Copyright © avec tendresse depuis 2001 *
* Arnaud Martin, Antoine Pitrou, Philippe Rivière, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribué sous licence GNU/GPL. *
* Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne. *
\***************************************************************************/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
include_spip('base/abstract_sql');
/**
* Production de la balise a+href à partir des raccourcis `[xxx->url]` etc.
*
* @note
* Compliqué car c'est ici qu'on applique typo(),
* et en plus, on veut pouvoir les passer en pipeline
*
* @see typo()
* @param string $lien
* @param string $texte
* @param string $class
* @param string $title
* @param string $hlang
* @param string $rel
* @param string $connect
* @param array $env
* @return string
*/
function inc_lien_dist(
$lien,
$texte = '',
$class = '',
$title = '',
$hlang = '',
$rel = '',
$connect = '',
$env = []
) {
static $u = null;
if (!$u) {
$u = url_de_base();
}
$typo = false;
// Si une langue est demandee sur un raccourci d'article, chercher
// la traduction ;
// - [{en}->art2] => traduction anglaise de l'article 2, sinon art 2
// - [{}->art2] => traduction en langue courante de l'art 2, sinon art 2
// s'applique a tout objet traduit
if (
$hlang
and $match = typer_raccourci($lien)
) {
@list($type, , $id, , $args, , $ancre) = $match;
$trouver_table = charger_fonction('trouver_table', 'base');
$desc = $trouver_table(table_objet($type, $connect), $connect);
if (
$desc
and $id_table_objet = $desc['key']['PRIMARY KEY']
) {
$table_objet_sql = $desc['table'];
if (
$row = sql_fetsel('*', $table_objet_sql, "$id_table_objet=" . intval($id))
and isset($row['id_trad'])
and isset($row['lang'])
and $id_dest = sql_getfetsel(
$id_table_objet,
$table_objet_sql,
'id_trad=' . intval($row['id_trad']) . ' AND lang=' . sql_quote($hlang)
)
and objet_test_si_publie($type, $id_dest)
) {
$lien = "$type$id_dest";
} else {
$hlang = '';
}
} else {
$hlang = '';
}
}
$mode = ($texte and $class) ? 'url' : 'tout';
$lang = '';
$lien = calculer_url($lien, $texte, $mode, $connect);
if ($mode === 'tout') {
$texte = $lien['titre'];
if (!$class and isset($lien['class'])) {
$class = $lien['class'];
}
$lang = isset($lien['lang']) ? $lien['lang'] : '';
$mime = isset($lien['mime']) ? " type='" . $lien['mime'] . "'" : '';
$lien = $lien['url'];
}
$lien = trim($lien);
if (strncmp($lien, '#', 1) == 0) { # ancres pures (internes a la page)
$class = 'spip_ancre';
} elseif (strncasecmp($lien, 'mailto:', 7) == 0) { # pseudo URL de mail
$class = 'spip_mail';
} elseif (strncmp($texte, '<html>', 6) == 0) { # cf traiter_lien_explicite
$class = 'spip_url';
# spip_out sur les URLs externes
if (
preg_match(',^\w+://,iS', $lien)
and strncasecmp($lien, url_de_base(), strlen(url_de_base()))
) {
$class .= ' spip_out';
}
} elseif (!$class) {
# spip_out sur les URLs externes
if (
preg_match(',^\w+://,iS', $lien)
and strncasecmp($lien, url_de_base(), strlen(url_de_base()))
) {
$class = 'spip_out'; # si pas spip_in|spip_glossaire
}
}
if ($class) {
$class = " class='$class'";
}
// Si l'objet n'est pas de la langue courante, on ajoute hreflang
if (!$hlang and isset($lang) and $lang !== $GLOBALS['spip_lang']) {
$hlang = $lang;
}
$lang = ($hlang ? " hreflang='$hlang'" : '');
if ($title) {
$title = ' title="' . attribut_html($title) . '"';
} else {
$title = ''; // $title peut etre 'false'
}
// rel=external pour les liens externes
if (
(strncmp($lien, 'http://', 7) == 0 or strncmp($lien, 'https://', 8) == 0)
and strncmp("$lien/", $u, strlen($u)) != 0
) {
$rel = trim("$rel external");
}
if ($rel) {
$rel = " rel='$rel'";
}
$lang_objet_prev = '';
if ($hlang and $hlang !== $GLOBALS['spip_lang']) {
$lang_objet_prev = isset($GLOBALS['lang_objet']) ? $GLOBALS['lang_objet'] : null;
$GLOBALS['lang_objet'] = $hlang;
}
// si pas de modele dans le texte du lien, on peut juste passer typo sur le texte, c'est plus rapide
// les rares cas de lien qui encapsule un modele passe en dessous, c'est plus lent
if (traiter_modeles($texte, false, '', $connect, null, $env) == $texte) {
$texte = typo($texte, true, $connect, $env);
$lien = '<a href="' . str_replace(
'"',
'&quot;',
$lien
) . "\"$class$lang$title$rel" . (isset($mime) ? $mime : '') . ">$texte</a>";
if ($lang_objet_prev !== '') {
if ($lang_objet_prev) {
$GLOBALS['lang_objet'] = $lang_objet_prev;
} else {
unset($GLOBALS['lang_objet']);
}
}
return $lien;
}
# ceci s'execute heureusement avant les tableaux et leur "|".
# Attention, le texte initial est deja echappe mais pas forcement
# celui retourne par calculer_url.
# Penser au cas [<imgXX|right>->URL], qui exige typo('<a>...</a>')
$lien = '<a href="' . str_replace('"', '&quot;', $lien) . "\"$class$lang$title$rel$mime>$texte</a>";
#$res = typo($lien, true, $connect, $env);
$p = $GLOBALS['toujours_paragrapher'];
$GLOBALS['toujours_paragrapher'] = false;
$res = propre($lien, $connect, $env);
$GLOBALS['toujours_paragrapher'] = $p;
// dans ce cas, echapons le resultat du modele pour que propre etc ne viennent pas pouicher le html
$res = echappe_html("<html>$res</html>");
if ($lang_objet_prev !== '') {
if ($lang_objet_prev) {
$GLOBALS['lang_objet'] = $lang_objet_prev;
} else {
unset($GLOBALS['lang_objet']);
}
}
return $res;
}
/**
* Générer le HTML d'un lien quelconque
*
* Cette fonction génère une balise `<a>` suivant de multiples arguments.
*
* @param array $args
* Tableau des arguments disponibles pour générer le lien :
* - texte : texte du lien, seul argument qui n'est pas un attribut
* - href
* - name
* - etc, tout autre attribut supplémentaire…
* @return string
* Retourne une balise HTML de lien ou une chaîne vide.
*/
function balise_a($args = []) {
$balise_a = '';
// Il faut soit au minimum un href OU un name pour réussir à générer quelque chose
if (is_array($args) and (isset($args['href']) or isset($args['name']))) {
include_spip('inc/filtres');
$texte = '';
// S'il y a un texte, on le récupère et on l'enlève des attributs
if (isset($args['texte']) and is_scalar($args['texte'])) {
$texte = $args['texte'];
unset($args['texte']);
} // Si on a un href sans texte, on en construit un avec l'URL
elseif (isset($args['href']) and is_scalar($args['href'])) {
static $lien_court;
if (!$lien_court) {
$lien_court = charger_fonction('lien_court', 'inc');
}
$texte = quote_amp($lien_court($args['href']));
}
// Il ne reste normalement plus que des attributs, on les ajoute à la balise
$balise_a = '<a';
foreach ($args as $attribut => $valeur) {
if (is_scalar($valeur) and !empty($valeur)) {
$balise_a .= ' ' . $attribut . '="' . attribut_html($valeur) . '"';
}
}
// Puis on ajoute le texte
$balise_a .= '>' . $texte . '</a>';
}
return $balise_a;
}
// Regexp des raccourcis, aussi utilisee pour la fusion de sauvegarde Spip
// Laisser passer des paires de crochets pour la balise multi
// mais refuser plus d'imbrications ou de mauvaises imbrications
// sinon les crochets ne peuvent plus servir qu'a ce type de raccourci
define('_RACCOURCI_LIEN', '/\[([^][]*?([[][^]>-]*[]][^][]*)*)->(>?)([^]]*)\]/msS');
// https://code.spip.net/@expanser_liens
function expanser_liens($t, $connect = '', $env = []) {
$t = pipeline('pre_liens', $t);
if (strpos($t, '\[') !== false or strpos($t, '\]') !== false) {
$t = str_replace(['\[', '\]'], ["\x1\x5", "\x1\x6"], $t);
}
expanser_un_lien($connect, 'init', $env);
if (strpos($t, '->') !== false) {
$t = preg_replace_callback(_RACCOURCI_LIEN, 'expanser_un_lien', $t);
}
// on passe a traiter_modeles la liste des liens reperes pour lui permettre
// de remettre le texte d'origine dans les parametres du modele
$t = traiter_modeles($t, false, false, $connect, expanser_un_lien('', 'sources'), $env);
if (strpos($t, "\x1") !== false) {
$t = str_replace(["\x1\x5", "\x1\x6"], ['[', ']'], $t);
}
$t = corriger_typo($t);
$t = expanser_un_lien($t, 'reinsert');
return $t;
}
function expanser_un_lien($reg, $quoi = 'echappe', $env = null) {
static $pile = [];
static $inserts;
static $sources;
static $regs;
static $k = 0;
static $lien;
static $connect = '';
static $contexte = [];
switch ($quoi) {
case 'init':
if (!$lien) {
$lien = charger_fonction('lien', 'inc');
}
if (!is_null($env)) {
$contexte = $env;
}
array_push($pile, [$inserts, $sources, $regs, $connect, $k]);
$inserts = $sources = $regs = [];
$connect = $reg; // stocker le $connect pour les appels a inc_lien_dist
$k = 0;
return;
break;
case 'echappe':
$inserts[$k] = '@@SPIP_ECHAPPE_LIEN_' . $k . '@@';
$sources[$k] = $reg[0];
#$titre=$reg[1];
list($titre, $bulle, $hlang) = traiter_raccourci_lien_atts($reg[1]);
$r = end($reg);
// la mise en lien automatique est passee par la a tort !
// corrigeons pour eviter d'avoir un <a...> dans un href...
if (strncmp($r, '<a', 2) == 0) {
$href = extraire_attribut($r, 'href');
// remplacons dans la source qui peut etre reinjectee dans les arguments
// d'un modele
$sources[$k] = str_replace($r, $href, $sources[$k]);
// et prenons le href comme la vraie url a linker
$r = $href;
}
$regs[$k] = $lien($r, $titre, '', $bulle, $hlang, '', $connect, $contexte);
return $inserts[$k++];
break;
case 'reinsert':
if (count($inserts)) {
$reg = str_replace($inserts, $regs, $reg);
}
list($inserts, $sources, $regs, $connect, $k) = array_pop($pile);
return $reg;
break;
case 'sources':
return [$inserts, $sources];
break;
}
}
/**
* Nettoie un texte en enlevant les raccourcis typo, sans les traiter
*
* On ne laisse que les titres des liens, en les explicitant si ce n’est pas fait.
*
* @param string $texte
* @param string $connect
* @return string
*/
function nettoyer_raccourcis_typo($texte, $connect = '') {
$texte = pipeline('nettoyer_raccourcis_typo', $texte);
// on utilise les \r pour passer entre les gouttes
$texte = str_replace("\r\n", "\n", $texte);
$texte = str_replace("\r", "\n", $texte);
// sauts de ligne et paragraphes
$texte = preg_replace("/\n\n+/", "\r", $texte);
// supprimer les traits, lignes etc
$texte = preg_replace("/(^|\r|\n)(-[-#\*]*\s?|_ )/", "\n", $texte);
// travailler en accents charset
$texte = unicode2charset(html2unicode($texte, true /* secure */));
if (preg_match_all(_RACCOURCI_LIEN, $texte, $regs, PREG_SET_ORDER)) {
include_spip('inc/texte');
foreach ($regs as $reg) {
list($titre, , ) = traiter_raccourci_lien_atts($reg[1]);
if (!$titre) {
$match = typer_raccourci($reg[count($reg) - 1]);
if (!isset($match[0])) {
$match[0] = '';
}
@list($type, , $id, , , , ) = $match;
if ($type) {
$url = generer_url_entite($id, $type, '', '', true);
if (is_array($url)) {
list($type, $id) = $url;
}
$titre = traiter_raccourci_titre($id, $type, $connect);
}
$titre = $titre ? $titre['titre'] : $match[0];
}
$titre = corriger_typo(supprimer_tags($titre));
$texte = str_replace($reg[0], $titre, $texte);
}
}
// supprimer les ancres
$texte = preg_replace(_RACCOURCI_ANCRE, '', $texte);
// supprimer les notes
$texte = preg_replace(',\[\[.*\]\],UimsS', '', $texte);
// supprimer les codes typos
$texte = str_replace(['}', '{'], '', $texte);
// supprimer les tableaux
$texte = preg_replace(",(?:^|\r|\n)\|.*\|(?:\r|\n|$),s", "\r", $texte);
// indiquer les sauts de paragraphes
$texte = str_replace("\r", "\n\n", $texte);
$texte = str_replace("\n\n+", "\n\n", $texte);
$texte = trim($texte);
return $texte;
}
// Repere dans la partie texte d'un raccourci [texte->...]
// la langue et la bulle eventuelles : [texte|title{lang}->...]
// accepte un niveau de paire de crochets dans le texte :
// [texte[]|title{lang}->...]
// mais refuse
// [texte[|title{lang}->...]
// pour ne pas confondre avec un autre raccourci
define('_RACCOURCI_ATTRIBUTS', '/^((?:[^[]*?(?:\[[^]]*\])?)*?)([|]([^<>]*?))?([{]([a-z_]*)[}])?$/');
// https://code.spip.net/@traiter_raccourci_lien_atts
function traiter_raccourci_lien_atts($texte) {
$bulle = $hlang = false;
// title et hreflang donnes par le raccourci ?
if (
strpbrk($texte, '|{') !== false
and preg_match(_RACCOURCI_ATTRIBUTS, $texte, $m)
) {
$n = count($m);
// |infobulle ?
if ($n > 2) {
$bulle = $m[3];
// {hreflang} ?
if ($n > 4) {
// si c'est un code de langue connu, on met un hreflang
if (traduire_nom_langue($m[5]) <> $m[5]) {
$hlang = $m[5];
} elseif (!$m[5]) {
$hlang = test_espace_prive() ?
$GLOBALS['lang_objet'] : $GLOBALS['spip_lang'];
// sinon c'est un italique ou un gras dans le title ou dans le texte du lien
} else {
if ($bulle) {
$bulle .= $m[4];
} else {
$m[1] .= $m[2] . $m[4];
}
}
}
// S'il n'y a pas de hreflang sous la forme {}, ce qui suit le |
// est peut-etre une langue
else {
if (preg_match('/^[a-z_]+$/', $m[3])) {
// si c'est un code de langue connu, on met un hreflang
// mais on laisse le title (c'est arbitraire tout ca...)
if (traduire_nom_langue($m[3]) <> $m[3]) {
$hlang = $m[3];
}
}
}
}
$texte = $m[1];
}
if ($bulle) {
$bulle = nettoyer_raccourcis_typo($bulle);
$bulle = corriger_typo($bulle);
}
return [trim($texte), $bulle, $hlang];
}
define('_EXTRAIRE_DOMAINE', '/^(?:(?:[^\W_]((?:[^\W_]|-){0,61}[^\W_,])?\.)+[a-z0-9]{2,6}|localhost)\b/Si');
define('_RACCOURCI_CHAPO', '/^(\W*)(\W*)(\w*\d+([?#].*)?)$/');
/**
* Retourne la valeur d'un champ de redirection (articles virtuels)
*
* L'entrée accepte plusiers types d'écritures :
* - une URL compète,
* - un lien SPIP tel que `[Lien->article23]`,
* - ou un raccourcis SPIP comme `rub2` ou `rubrique2`
*
* @param string $virtuel
* Texte qui définit la redirection, à analyser.
* Plusieurs types peuvent être acceptés :
* - un raccourci Spip habituel, tel que `[texte->TYPEnnn]`
* - un ultra raccourci Spip, tel que `TYPEnnn`
* - une URL standard
* @param bool $url
* false : retourne uniquement le nom du lien (TYPEnnn)
* true : retourne l'URL calculée pour le lien
* @return string
* Nom du lien ou URL
*/
function virtuel_redirige($virtuel, $url = false) {
if (!strlen($virtuel)) {
return '';
}
if (
!preg_match(_RACCOURCI_LIEN, $virtuel, $m)
and !preg_match(_RACCOURCI_CHAPO, $virtuel, $m)
) {
return $virtuel;
}
return !$url ? $m[3] : traiter_lien_implicite($m[3]);
}
// Cherche un lien du type [->raccourci 123]
// associe a une fonction generer_url_raccourci() definie explicitement
// ou implicitement par le jeu de type_urls courant.
//
// Valeur retournee selon le parametre $pour:
// 'tout' : tableau d'index url,class,titre,lang (vise <a href="U" class='C' hreflang='L'>T</a>)
// 'titre': seulement T ci-dessus (i.e. le TITRE ci-dessus ou dans table SQL)
// 'url': seulement U (i.e. generer_url_RACCOURCI)
// https://code.spip.net/@calculer_url
function calculer_url($ref, $texte = '', $pour = 'url', $connect = '', $echappe_typo = true) {
$r = traiter_lien_implicite($ref, $texte, $pour, $connect, $echappe_typo);
$r = ($r ? $r : traiter_lien_explicite($ref, $texte, $pour, $connect, $echappe_typo));
return $r;
}
define('_EXTRAIRE_LIEN', ',^\s*(http:?/?/?|mailto:?)\s*$,iS');
// https://code.spip.net/@traiter_lien_explicite
function traiter_lien_explicite($ref, $texte = '', $pour = 'url', $connect = '', $echappe_typo = true) {
if (preg_match(_EXTRAIRE_LIEN, $ref)) {
return ($pour != 'tout') ? '' : ['', '', '', ''];
}
$lien = entites_html(trim($ref));
// Liens explicites
if (!$texte) {
$texte = str_replace('"', '', $lien);
static $lien_court;
// evite l'affichage de trop longues urls.
if (!$lien_court) {
$lien_court = charger_fonction('lien_court', 'inc');
}
$texte = $lien_court($texte);
if ($echappe_typo) {
$texte = '<html>' . quote_amp($texte) . '</html>';
}
}
// petites corrections d'URL
if (preg_match('/^www\.[^@]+$/S', $lien)) {
$lien = 'http://' . $lien;
} else {
if (strpos($lien, '@') && email_valide($lien)) {
if (!$texte) {
$texte = $lien;
}
$lien = 'mailto:' . $lien;
}
}
if ($pour == 'url') {
return $lien;
}
if ($pour == 'titre') {
return $texte;
}
return ['url' => $lien, 'titre' => $texte];
}
function liens_implicite_glose_dist($texte, $id, $type, $args, $ancre, $connect = '') {
if (function_exists($f = 'glossaire_' . $ancre)) {
$url = $f($texte, $id);
} else {
$url = glossaire_std($texte);
}
return $url;
}
/**
* Transformer un lien raccourci art23 en son URL
* Par defaut la fonction produit une url prive si on est dans le prive
* ou publique si on est dans le public.
* La globale lien_implicite_cible_public permet de forcer un cas ou l'autre :
* $GLOBALS['lien_implicite_cible_public'] = true;
* => tous les liens raccourcis pointent vers le public
* $GLOBALS['lien_implicite_cible_public'] = false;
* => tous les liens raccourcis pointent vers le prive
* unset($GLOBALS['lien_implicite_cible_public']);
* => retablit le comportement automatique
*
* https://code.spip.net/@traiter_lien_implicite
*
* @param string $ref
* @param string $texte
* @param string $pour
* @param string $connect
* @return array|bool|string
*/
function traiter_lien_implicite($ref, $texte = '', $pour = 'url', $connect = '') {
$cible = ($connect ? $connect : (isset($GLOBALS['lien_implicite_cible_public']) ? $GLOBALS['lien_implicite_cible_public'] : null));
if (!($match = typer_raccourci($ref))) {
return false;
}
@list($type, , $id, , $args, , $ancre) = $match;
# attention dans le cas des sites le lien doit pointer non pas sur
# la page locale du site, mais directement sur le site lui-meme
$url = '';
if ($f = charger_fonction("implicite_$type", 'liens', true)) {
$url = $f($texte, $id, $type, $args, $ancre, $connect);
}
if (!$url) {
$url = generer_url_entite($id, $type, $args, $ancre, $cible);
}
if (!$url) {
return false;
}
if (is_array($url)) {
@list($type, $id) = $url;
$url = generer_url_entite($id, $type, $args, $ancre, $cible);
}
if ($pour === 'url') {
return $url;
}
$r = traiter_raccourci_titre($id, $type, $connect);
if ($r) {
$r['class'] = ($type == 'site') ? 'spip_out' : 'spip_in';
}
if ($texte = trim($texte)) {
$r['titre'] = $texte;
}
if (!@$r['titre']) {
$r['titre'] = _T($type) . " $id";
}
if ($pour == 'titre') {
return $r['titre'];
}
$r['url'] = $url;
// dans le cas d'un lien vers un doc, ajouter le type='mime/type'
if (
$type == 'document'
and $mime = sql_getfetsel(
'mime_type',
'spip_types_documents',
'extension IN (' . sql_get_select('extension', 'spip_documents', 'id_document=' . sql_quote($id)) . ')',
'',
'',
'',
'',
$connect
)
) {
$r['mime'] = $mime;
}
return $r;
}
// analyse des raccourcis issus de [TITRE->RACCOURCInnn] et connexes
define('_RACCOURCI_URL', '/^\s*(\w*?)\s*(\d+)(\?(.*?))?(#([^\s]*))?\s*$/S');
// https://code.spip.net/@typer_raccourci
function typer_raccourci($lien) {
if (!preg_match(_RACCOURCI_URL, $lien, $match)) {
return [];
}
$f = $match[1];
// valeur par defaut et alias historiques
if (!$f) {
$f = 'article';
} else {
if ($f == 'art') {
$f = 'article';
} else {
if ($f == 'br') {
$f = 'breve';
} else {
if ($f == 'rub') {
$f = 'rubrique';
} else {
if ($f == 'aut') {
$f = 'auteur';
} else {
if ($f == 'doc' or $f == 'im' or $f == 'img' or $f == 'image' or $f == 'emb') {
$f = 'document';
} else {
if (preg_match('/^br..?ve$/S', $f)) {
$f = 'breve'; # accents :(
}
}
}
}
}
}
}
$match[0] = $f;
return $match;
}
/**
* Retourne le titre et la langue d'un objet éditorial
*
* @param int $id Identifiant de l'objet
* @param string $type Type d'objet
* @param string|null $connect Connecteur SQL utilisé
* @return array {
* @var string $titre Titre si présent, sinon ''
* @var string $lang Langue si présente, sinon ''
* }
**/
function traiter_raccourci_titre($id, $type, $connect = null) {
$trouver_table = charger_fonction('trouver_table', 'base');
$desc = $trouver_table(table_objet($type));
if (!($desc and $s = $desc['titre'])) {
return [];
}
$_id = $desc['key']['PRIMARY KEY'];
$r = sql_fetsel($s, $desc['table'], "$_id=$id", '', '', '', '', $connect);
if (!$r) {
return [];
}
$r['titre'] = supprimer_numero($r['titre']);
if (!$r['titre'] and !empty($r['surnom'])) {
$r['titre'] = $r['surnom'];
}
if (!isset($r['lang'])) {
$r['lang'] = '';
}
return $r;
}
// traite les modeles (dans la fonction typo), en remplacant
// le raccourci <modeleN|parametres> par la page calculee a
// partir du squelette modeles/modele.html
// Le nom du modele doit faire au moins trois caracteres (evite <h2>)
// Si $doublons==true, on repere les documents sans calculer les modeles
// mais on renvoie les params (pour l'indexation par le moteur de recherche)
// https://code.spip.net/@traiter_modeles
define(
'_PREG_MODELE',
'(<([a-z_-]{3,})' # <modele
. '\s*([0-9]*)\s*' # id
. '([|](?:<[^<>]*>|[^>])*?)?' # |arguments (y compris des tags <...>)
. '\s*/?' . '>)' # fin du modele >
);
define(
'_RACCOURCI_MODELE',
_PREG_MODELE
. '\s*(<\/a>)?' # eventuel </a>
);
define('_RACCOURCI_MODELE_DEBUT', '@^' . _RACCOURCI_MODELE . '@isS');
// https://code.spip.net/@traiter_modeles
function traiter_modeles($texte, $doublons = false, $echap = '', $connect = '', $liens = null, $env = []) {
// preserver la compatibilite : true = recherche des documents
if ($doublons === true) {
$doublons = ['documents' => ['doc', 'emb', 'img']];
}
// detecter les modeles (rapide)
if (
strpos($texte, '<') !== false
and preg_match_all('/<[a-z_-]{3,}\s*[0-9|]+/iS', $texte, $matches, PREG_SET_ORDER)
) {
include_spip('public/assembler');
$wrap_embed_html = charger_fonction('wrap_embed_html', 'inc', true);
// Recuperer l'appel complet (y compris un eventuel lien)
foreach ($matches as $match) {
$a = strpos($texte, $match[0]);
preg_match(_RACCOURCI_MODELE_DEBUT, substr($texte, $a), $regs);
// s'assurer qu'il y a toujours un 5e arg, eventuellement vide
while (count($regs) < 6) {
$regs[] = '';
}
list(, $mod, $type, $id, $params, $fin) = $regs;
if (
$fin
and preg_match('/<a\s[^<>]*>\s*$/i', substr($texte, 0, $a), $r)
) {
$lien = [
'href' => extraire_attribut($r[0], 'href'),
'class' => extraire_attribut($r[0], 'class'),
'mime' => extraire_attribut($r[0], 'type'),
'title' => extraire_attribut($r[0], 'title'),
'hreflang' => extraire_attribut($r[0], 'hreflang')
];
$n = strlen($r[0]);
$a -= $n;
$cherche = $n + strlen($regs[0]);
} else {
$lien = false;
$cherche = strlen($mod);
}
// calculer le modele
# hack indexation
if ($doublons) {
$texte .= preg_replace(',[|][^|=]*,s', ' ', $params);
} # version normale
else {
// si un tableau de liens a ete passe, reinjecter le contenu d'origine
// dans les parametres, plutot que les liens echappes
if (!is_null($liens)) {
$params = str_replace($liens[0], $liens[1], $params);
}
$modele = inclure_modele($type, $id, $params, $lien, $connect, $env);
// en cas d'echec,
// si l'objet demande a une url,
// creer un petit encadre vers elle
if ($modele === false) {
$modele = substr($texte, $a, $cherche);
if (!is_null($liens)) {
$modele = str_replace($liens[0], $liens[1], $modele);
}
$contexte = array_merge($env, ['id' => $id, 'type' => $type, 'modele' => $modele]);
if ($lien) {
# un eventuel guillemet (") sera reechappe par #ENV
$contexte['lien'] = str_replace('&quot;', '"', $lien['href']);
$contexte['lien_class'] = $lien['class'];
$contexte['lien_mime'] = $lien['mime'];
$contexte['lien_title'] = $lien['title'];
$contexte['lien_hreflang'] = $lien['hreflang'];
}
$modele = recuperer_fond('modeles/dist', $contexte, [], $connect);
}
// le remplacer dans le texte
if ($modele !== false) {
$modele = protege_js_modeles($modele);
if ($wrap_embed_html) {
$modele = $wrap_embed_html($mod, $modele);
}
$rempl = code_echappement($modele, $echap);
$texte = substr($texte, 0, $a)
. $rempl
. substr($texte, $a + $cherche);
}
}
// hack pour tout l'espace prive
if (((!_DIR_RESTREINT) or ($doublons)) and ($id)) {
foreach ($doublons ? $doublons : ['documents' => ['doc', 'emb', 'img']] as $quoi => $modeles) {
if (in_array(strtolower($type), $modeles)) {
$GLOBALS["doublons_{$quoi}_inclus"][] = $id;
}
}
}
}
}
return $texte;
}
//
// Raccourcis ancre [#ancre<-]
//
define('_RACCOURCI_ANCRE', '/\[#?([^][]*)<-\]/S');
// https://code.spip.net/@traiter_raccourci_ancre
function traiter_raccourci_ancre($letexte) {
if (preg_match_all(_RACCOURCI_ANCRE, $letexte, $m, PREG_SET_ORDER)) {
foreach ($m as $regs) {
$letexte = str_replace(
$regs[0],
'<a ' . (html5_permis() ? 'id' : 'name') . '="' . entites_html($regs[1]) . '"></a>',
$letexte
);
}
}
return $letexte;
}
//
// Raccourcis automatiques [?SPIP] vers un glossaire
// Wikipedia par defaut, avec ses contraintes techniques
// cf. http://fr.wikipedia.org/wiki/Wikip%C3%A9dia:Conventions_sur_les_titres
define('_RACCOURCI_GLOSSAIRE', '/\[\?+\s*([^][<>]+)\]/S');
define('_RACCOURCI_GLOSES', '/^([^|#{]*\w[^|#{]*)([^#]*)(#([^|{}]*))?(.*)$/S');
// https://code.spip.net/@traiter_raccourci_glossaire
function traiter_raccourci_glossaire($texte) {
if (!preg_match_all(_RACCOURCI_GLOSSAIRE, $texte, $matches, PREG_SET_ORDER)) {
return $texte;
}
include_spip('inc/charsets');
$lien = charger_fonction('lien', 'inc');
// Eviter les cas particulier genre "[?!?]"
// et isoler le lexeme a gloser de ses accessoires
// (#:url du glossaire, | bulle d'aide, {} hreflang)
// Transformation en pseudo-raccourci pour passer dans inc_lien
foreach ($matches as $regs) {
if (preg_match(_RACCOURCI_GLOSES, $regs[1], $r)) {
preg_match('/^(.*?)(\d*)$/', $r[4], $m);
$_n = intval($m[2]);
$gloss = $m[1] ? ('#' . $m[1]) : '';
$t = $r[1] . $r[2] . $r[5];
list($t, $bulle, $hlang) = traiter_raccourci_lien_atts($t);
if ($bulle === false) {
$bulle = $m[1];
}
$t = unicode2charset(charset2unicode($t), 'utf-8');
$ref = $lien("glose$_n$gloss", $t, 'spip_glossaire', $bulle, $hlang);
$texte = str_replace($regs[0], $ref, $texte);
}
}
return $texte;
}
// https://code.spip.net/@glossaire_std
function glossaire_std($terme) {
global $url_glossaire_externe;
static $pcre = null;
if ($pcre === null) {
$pcre = isset($GLOBALS['meta']['pcre_u']) ? $GLOBALS['meta']['pcre_u'] : '';
if (strpos($url_glossaire_externe, '%s') === false) {
$url_glossaire_externe .= '%s';
}
}
$glosateur = str_replace(
'@lang@',
$GLOBALS['spip_lang'],
$GLOBALS['url_glossaire_externe']
);
$terme = rawurlencode(preg_replace(',\s+,' . $pcre, '_', $terme));
return str_replace('%s', $terme, $glosateur);
}