X-Git-Url: http://git.cyclocoop.org/?p=velocampus%2Fweb%2Fwww.git;a=blobdiff_plain;f=www%2Fecrire%2Finc%2Flien.php;fp=www%2Fecrire%2Finc%2Flien.php;h=0c169f634dc73f929a60be6de96467b833e40f6f;hp=0000000000000000000000000000000000000000;hb=80b4d3e85f78d402ed2e73f8f5d1bf4c19962eed;hpb=aaf970bf4cdaf76689ecc10609048e18d073820c diff --git a/www/ecrire/inc/lien.php b/www/ecrire/inc/lien.php new file mode 100644 index 0000000..0c169f6 --- /dev/null +++ b/www/ecrire/inc/lien.php @@ -0,0 +1,580 @@ +url] etc. +// Note : complique car c'est ici qu'on applique typo(), +// et en plus on veut pouvoir les passer en pipeline +// + +// http://doc.spip.org/@traiter_raccourci_lien_lang +function inc_lien_dist($lien, $texte='', $class='', $title='', $hlang='', $rel='', $connect='') +{ + // 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 + if ($hlang + AND $match = typer_raccourci($lien)) { + @list($type,,$id,,$args,,$ancre) = $match; + if ($id_trad = sql_getfetsel('id_trad', 'spip_articles', "id_article=$id") + AND $id_dest = sql_getfetsel('id_article', 'spip_articles', + "id_trad=$id_trad AND statut<>'refuse' AND lang=" . sql_quote($hlang)) + ) + $lien = "$type$id_dest"; + else + $hlang = ''; + } + + $mode = ($texte AND $class) ? 'url' : 'tout'; + $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']; + } + if (substr($lien,0,1) == '#') # ancres pures (internes a la page) + $class = 'spip_ancre'; + elseif (preg_match('/^\s*mailto:/',$lien)) # pseudo URL de mail + $class = "spip_mail"; + elseif (preg_match('/^/',$texte)) # cf traiter_lien_explicite + $class = "spip_url spip_out"; + elseif (!$class) $class = "spip_out"; # si pas spip_in|spip_glossaire + + // Si l'objet n'est pas de la langue courante, on ajoute hreflang + if (!$hlang AND $lang!==$GLOBALS['spip_lang']) + $hlang = $lang; + + $lang = ($hlang ? " hreflang='$hlang'" : ''); + + if ($title) $title = ' title="'.texte_backend($title).'"'; + + // rel=external pour les liens externes + if (preg_match(',^https?://,S', $lien) + AND false === strpos("$lien/", url_de_base())) + $rel = trim("$rel external"); + if ($rel) $rel = " rel='$rel'"; + + $lien = "$texte"; + + # 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 [->URL], qui exige typo('...') + return typo($lien, true, $connect); +} + +// 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', "/\[([^][]*?([[]\w*[]][^][]*)*)->(>?)([^]]*)\]/msS"); + +// http://doc.spip.org/@expanser_liens +function expanser_liens($texte, $connect='') +{ + $texte = pipeline('pre_liens', $texte); + $sources = $inserts = $regs = array(); + if (preg_match_all(_RACCOURCI_LIEN, $texte, $regs, PREG_SET_ORDER)) { + $lien = charger_fonction('lien', 'inc'); + foreach ($regs as $k => $reg) { + + $inserts[$k] = '@@SPIP_ECHAPPE_LIEN_' . $k . '@@'; + $sources[$k] = $reg[0]; + $texte = str_replace($sources[$k], $inserts[$k], $texte); + + list($titre, $bulle, $hlang) = traiter_raccourci_lien_atts($reg[1]); + $r = $reg[count($reg)-1]; + // la mise en lien automatique est passee par la a tort ! + // corrigeons pour eviter d'avoir un dans un href... + if (strncmp($r,'...] +// la langue et la bulle eventuelles + +define('_RACCOURCI_ATTRIBUTS', '/^(.*?)([|]([^<>]*?))?([{]([a-z_]*)[}])?$/'); + +// http://doc.spip.org/@traiter_raccourci_lien_atts +function traiter_raccourci_lien_atts($texte) { + + $bulle = $hlang = ''; + // title et hreflang donnes par le raccourci ? + if (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 + } else { + $m[1] .= $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]; + } + + return array(trim($texte), $bulle, $hlang); +} + +define('_EXTRAIRE_DOMAINE', '/^(?:[^\W_]((?:[^\W_]|-){0,61}[^\W_,])?\.)+[a-z]{2,6}\b/Si'); + +// callback pour la fonction traiter_raccourci_liens() +// http://doc.spip.org/@autoliens_callback +function traiter_autoliens($r) { + if (count($r)<2) return reset($r); + list($tout, $l) = $r; + if (!$l) return $tout; + // reperer le protocole + if (preg_match(',^(https?):/*,S', $l, $m)) { + $l = substr($l, strlen($m[0])); + $protocol = $m[1]; + } else $protocol = 'http'; + // valider le nom de domaine + if (!preg_match(_EXTRAIRE_DOMAINE, $l)) return $tout; + // supprimer les ponctuations a la fin d'une URL + preg_match('/^(.*?)([,.;?]?)$/', $l, $k); + $url = $protocol.'://'.$k[1]; + $lien = charger_fonction('lien', 'inc'); + $r = $lien($url,'','','','','nofollow') . $k[2]; + // si l'original ne contenait pas le 'http:' on le supprime du clic + return $m ? $r : str_replace('>http://', '>', $r); +} + +define('_EXTRAIRE_LIENS', ',' . '\[[^\[\]]*(?:<-|->).*?\]' . '|' . '|((?:https?:/|www\.)[^"\'\s\[\]\}\)<>]*)' .',imsS'); + +// Les URLs brutes sont converties en url +// http://doc.spip.org/@traiter_raccourci_liens +function traiter_raccourci_liens($t) { + return preg_replace_callback(_EXTRAIRE_LIENS, 'traiter_autoliens', $t); +} + + +define('_RACCOURCI_CHAPO', '/^(\W*)(\W*)(\w*\d+([?#].*)?)$/'); +/** + * Fonction pour les champs chapo commencant par =, redirection qui peut etre: + * 1. un raccourci Spip habituel (premier If) [texte->TYPEnnn] + * 2. un ultra raccourci TYPEnnn voire nnn (article) (deuxieme If) + * 3. une URL std + * + * renvoie l'url reelle de redirection si le $url=true, + * l'url brute contenue dans le chapo sinon + * + * http://doc.spip.org/@chapo_redirige + * + * @param string $chapo + * @param bool $url + * @return string + */ +function chapo_redirige($chapo, $url=false) +{ + if (!preg_match(_RACCOURCI_LIEN, $chapo, $m)) + if (!preg_match(_RACCOURCI_CHAPO, $chapo, $m)) + return $chapo; + + return !$url ? $m[3] : traiter_lien_implicite($m[3]); +} + +// Ne pas afficher le chapo si article virtuel +// http://doc.spip.org/@nettoyer_chapo +function nettoyer_chapo($chapo){ + return (substr($chapo,0,1) == "=") ? '' : $chapo; +} + +// http://doc.spip.org/@chapo_redirigetil +function chapo_redirigetil($chapo) { return $chapo && $chapo[0] == '=';} + +// 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 T) +// 'titre': seulement T ci-dessus (i.e. le TITRE ci-dessus ou dans table SQL) +// 'url': seulement U (i.e. generer_url_RACCOURCI) + +// http://doc.spip.org/@calculer_url +function calculer_url ($ref, $texte='', $pour='url', $connect='') { + $r = traiter_lien_implicite($ref, $texte, $pour, $connect); + return $r ? $r : traiter_lien_explicite($ref, $texte, $pour, $connect); +} + +define('_EXTRAIRE_LIEN', ",^\s*(http:?/?/?|mailto:?)\s*$,iS"); + +// http://doc.spip.org/@traiter_lien_explicite +function traiter_lien_explicite ($ref, $texte='', $pour='url', $connect='') +{ + if (preg_match(_EXTRAIRE_LIEN, $ref)) + return ($pour != 'tout') ? '' : array('','','',''); + + $lien = entites_html(trim($ref)); + + // Liens explicites + if (!$texte) { + $texte = str_replace('"', '', $lien); + // evite l'affichage de trops longues urls. + $lien_court = charger_fonction('lien_court', 'inc'); + $texte = $lien_court($texte); + $texte = "".quote_amp($texte).""; + } + + // 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 array('url' => $lien, 'titre' => $texte); +} + +// http://doc.spip.org/@traiter_lien_implicite +function traiter_lien_implicite ($ref, $texte='', $pour='url', $connect='') +{ + 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 + if ($type == 'site') + $url = sql_getfetsel('url_site', 'spip_syndic', "id_syndic=$id",'','','','',$connect); + elseif ($type == 'glose') { + if (function_exists($f = 'glossaire_' . $ancre)) + $url = $f($texte, $id); + else $url = glossaire_std($texte); + } else $url = generer_url_entite($id,$type,$args,$ancre,$connect ? $connect : NULL); + if (!$url) return false; + if (is_array($url)) { + @list($type,$id) = $url; + $url = generer_url_entite($id,$type,$args,$ancre,$connect ? $connect : NULL); + } + 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 (SELECT extension FROM spip_documents where 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'); + +// http://doc.spip.org/@typer_raccourci +function typer_raccourci ($lien) { + if (!preg_match(_RACCOURCI_URL, $lien, $match)) return array(); + $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 champ textuel associe a une cle primaire, et sa langue +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 array(); + $_id = $desc['key']['PRIMARY KEY']; + $r = sql_fetsel($s, $desc['table'], "$_id=$id", '','','','',$connect); + if (!$r) return array(); + $r['titre'] = supprimer_numero($r['titre']); + if (!$r['titre']) $r['titre'] = $r['surnom']; + if (!isset($r['lang'])) $r['lang'] = ''; + return $r; +} + +// traite les modeles (dans la fonction typo), en remplacant +// le raccourci par la page calculee a +// partir du squelette modeles/modele.html +// Le nom du modele doit faire au moins trois caracteres (evite

) +// Si $doublons==true, on repere les documents sans calculer les modeles +// mais on renvoie les params (pour l'indexation par le moteur de recherche) +// http://doc.spip.org/@traiter_modeles + +define('_RACCOURCI_MODELE', + '(<([a-z_-]{3,})' # ]*>|[^>])*?)?' # |arguments (y compris des tags <...>) + .'\s*/?'.'>)' # fin du modele > + .'\s*(<\/a>)?' # eventuel + ); + +define('_RACCOURCI_MODELE_DEBUT', '@^' . _RACCOURCI_MODELE .'@isS'); + +// http://doc.spip.org/@traiter_modeles +function traiter_modeles($texte, $doublons=false, $echap='', $connect='', $liens = null) { + // preserver la compatibilite : true = recherche des documents + if ($doublons===true) + $doublons = array('documents'=>array('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'); + foreach ($matches as $match) { + // Recuperer l'appel complet (y compris un eventuel lien) + + $a = strpos($texte,$match[0]); + preg_match(_RACCOURCI_MODELE_DEBUT, + substr($texte, $a), $regs); + $regs[]=""; // s'assurer qu'il y a toujours un 5e arg, eventuellement vide + list(,$mod, $type, $id, $params, $fin) = $regs; + if ($fin AND + preg_match('/]*>\s*$/i', + substr($texte, 0, $a), $r)) { + $lien = array( + 'href' => extraire_attribut($r[0],'href'), + 'class' => extraire_attribut($r[0],'class'), + 'mime' => extraire_attribut($r[0],'type') + ); + $n = strlen($r[0]); + $a -= $n; + $cherche = $n + strlen($regs[0]); + } else { + $lien = false; + $cherche = strlen($mod); + } + + // calculer le modele + # hack articles_edit, breves_edit, 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); + // en cas d'echec, + // si l'objet demande a une url, + // creer un petit encadre vers elle + if ($modele === false) { + if (!$lien) + $lien = traiter_lien_implicite("$type$id", '', 'tout', $connect); + if ($lien) + $modele = '' + .sinon($lien['titre'], _T('ecrire:info_sans_titre')) + .""; + else { + $modele = ""; + if (test_espace_prive()) { + $modele = entites_html(substr($texte,$a,$cherche)); + if (!is_null($liens)) + $modele = "
".str_replace($liens[0], $liens[1], $modele)."
"; + } + } + } + // le remplacer dans le texte + if ($modele !== false) { + $modele = protege_js_modeles($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:array('documents'=>array('doc','emb','img')) as $quoi=>$modeles) + if (in_array($type,$modeles)) + $GLOBALS["doublons_{$quoi}_inclus"][] = $id; + } + } + } + + return $texte; +} + +// +// Raccourcis ancre [#ancre<-] +// + +define('_RACCOURCI_ANCRE', "/\[#?([^][]*)<-\]/S"); + +// http://doc.spip.org/@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], + '', $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'); + +// http://doc.spip.org/@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'); + + foreach ($matches as $regs) { + // 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 + 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); + $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; +} + +// http://doc.spip.org/@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); +} + +?>