b7fcda555cf342b7bdad10499662b463c9236643
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
6 * Copyright (c) 2001-2017 *
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 * Gestion des textes et raccourcis SPIP
16 * @package SPIP\Core\Texte
19 if (!defined('_ECRIRE_INC_VERSION')) {
23 include_spip('inc/texte_mini');
24 include_spip('inc/lien');
26 /*************************************************************************************************************************
27 * Fonctions inutilisees en dehors de inc/texte
32 * Raccourcis dépendant du sens de la langue
34 * @return array Tablea ('','')
36 function definir_raccourcis_alineas() {
42 * Traitement des raccourcis de tableaux
44 * Ne fait rien ici. Voir plugin Textwheel.
49 function traiter_tableau($bloc) {
55 * Traitement des listes
57 * Ne fais rien. Voir Plugin Textwheel.
58 * (merci a Michael Parienti)
60 * @param string $texte
63 function traiter_listes($texte) {
68 * Nettoie un texte, traite les raccourcis autre qu'URL, la typo, etc.
70 * Ne fais rien ici. Voir plugin Textwheel.
72 * @pipeline_appel pre_propre
73 * @pipeline_appel post_propre
75 * @param string $letexte
78 function traiter_raccourcis($letexte) {
80 // Appeler les fonctions de pre_traitement
81 $letexte = pipeline('pre_propre', $letexte);
83 // APPELER ICI UN PIPELINE traiter_raccourcis ?
84 // $letexte = pipeline('traiter_raccourcis', $letexte);
86 // Appeler les fonctions de post-traitement
87 $letexte = pipeline('post_propre', $letexte);
92 /*************************************************************************************************************************
93 * Fonctions utilisees en dehors de inc/texte
98 * Échapper et affichier joliement les `<script` et `<iframe`...
101 * @param string $class Attributs HTML du conteneur à ajouter
104 function echappe_js($t, $class = ' class = "echappe-js"') {
105 foreach (array('script', 'iframe') as $tag) {
106 if (stripos($t, "<$tag") !== false
107 and preg_match_all(',<' . $tag . '.*?($|</' . $tag . '.),isS', $t, $r, PREG_SET_ORDER
)
109 foreach ($r as $regs) {
110 $t = str_replace($regs[0],
111 "<code$class>" . nl2br(spip_htmlspecialchars($regs[0])) . '</code>',
122 * Empêcher l'exécution de code PHP et JS
124 * Sécurité : empêcher l'exécution de code PHP, en le transformant en joli code
125 * dans l'espace privé. Cette fonction est aussi appelée par propre et typo.
127 * De la même manière, la fonction empêche l'exécution de JS mais selon le mode
128 * de protection passe en argument
130 * Il ne faut pas désactiver globalement la fonction dans l'espace privé car elle protège
131 * aussi les balises des squelettes qui ne passent pas forcement par propre ou typo après
132 * si elles sont appelées en direct
136 * @param int $mode_filtre
138 * -1 : protection dans l'espace privé et public
139 * 0 : protection dans l'espace public
140 * 1 : aucune protection
141 * utilise la valeur de la globale filtrer_javascript si non fourni
145 function interdire_scripts($arg, $mode_filtre=null) {
146 // on memorise le resultat sur les arguments non triviaux
147 static $dejavu = array();
149 // Attention, si ce n'est pas une chaine, laisser intact
150 if (!$arg or !is_string($arg) or !strstr($arg, '<')) {
154 if (is_null($mode_filtre) or !in_array($mode_filtre, array(-1, 0, 1))) {
155 $mode_filtre = $GLOBALS['filtrer_javascript'];
158 if (isset($dejavu[$mode_filtre][$arg])) {
159 return $dejavu[$mode_filtre][$arg];
162 // echapper les tags asp/php
163 $t = str_replace('<' . '%', '<%', $arg);
166 $t = str_replace('<' . '?', '<?', $t);
168 // echapper le < script language=php >
169 $t = preg_replace(',<(script\b[^>]+\blanguage\b[^\w>]+php\b),UimsS', '<\1', $t);
171 // Pour le js, trois modes : parano (-1), prive (0), ok (1)
172 switch ($mode_filtre) {
174 if (!_DIR_RESTREINT
) {
183 // pas de <base href /> svp !
184 $t = preg_replace(',<(base\b),iS', '<\1', $t);
186 // Reinserer les echappements des modeles
187 if (defined('_PROTEGE_JS_MODELES')) {
188 $t = echappe_retour($t, "javascript" . _PROTEGE_JS_MODELES
);
190 if (defined('_PROTEGE_PHP_MODELES')) {
191 $t = echappe_retour($t, "php" . _PROTEGE_PHP_MODELES
);
194 return $dejavu[$mode_filtre][$arg] = $t;
199 * Applique la typographie générale
201 * Effectue un traitement pour que les textes affichés suivent les règles
202 * de typographie. Fait une protection préalable des balises HTML et SPIP.
203 * Transforme les balises `<multi>`
206 * @uses traiter_modeles()
207 * @uses corriger_typo()
208 * @uses echapper_faux_tags()
211 * @param string $letexte
213 * @param bool $echapper
215 * @param string|null $connect
216 * Nom du connecteur à la bdd
218 * Environnement (pour les calculs de modèles)
222 function typo($letexte, $echapper = true, $connect = null, $env = array()) {
228 // les appels directs a cette fonction depuis le php de l'espace
229 // prive etant historiquement ecrit sans argment $connect
230 // on utilise la presence de celui-ci pour distinguer les cas
231 // ou il faut passer interdire_script explicitement
232 // les appels dans les squelettes (de l'espace prive) fournissant un $connect
233 // ne seront pas perturbes
234 $interdire_script = false;
235 if (is_null($connect)) {
237 $interdire_script = true;
238 $env['espace_prive'] = test_espace_prive();
241 // Echapper les codes <html> etc
243 $letexte = echappe_html($letexte, 'TYPO');
247 // Installer les modeles, notamment images et documents ;
249 // NOTE : propre() ne passe pas par ici mais directement par corriger_typo
252 $letexte = traiter_modeles($mem = $letexte, false, $echapper ?
'TYPO' : '', $connect, null, $env);
253 if ($letexte != $mem) {
258 $letexte = corriger_typo($letexte);
259 $letexte = echapper_faux_tags($letexte);
261 // reintegrer les echappements
263 $letexte = echappe_retour($letexte, 'TYPO');
266 // Dans les appels directs hors squelette, securiser ici aussi
267 if ($interdire_script) {
268 $letexte = interdire_scripts($letexte);
271 // Dans l'espace prive on se mefie de tout contenu dangereux
272 // https://core.spip.net/issues/3371
273 if (isset($env['espace_prive']) and $env['espace_prive']) {
274 $letexte = echapper_html_suspect($letexte);
280 // Correcteur typographique
281 define('_TYPO_PROTEGER', "!':;?~%-");
282 define('_TYPO_PROTECTEUR', "\x1\x2\x3\x4\x5\x6\x7\x8");
284 define('_TYPO_BALISE', ",</?[a-z!][^<>]*[" . preg_quote(_TYPO_PROTEGER
) . "][^<>]*>,imsS");
287 * Corrige la typographie
289 * Applique les corrections typographiques adaptées à la langue indiquée.
291 * @pipeline_appel pre_typo
292 * @pipeline_appel post_typo
293 * @uses corriger_caracteres()
294 * @uses corriger_caracteres()
296 * @param string $letexte Texte
297 * @param string $lang Langue
298 * @return string Texte
300 function corriger_typo($letexte, $lang = '') {
307 $letexte = pipeline('pre_typo', $letexte);
309 // Caracteres de controle "illegaux"
310 $letexte = corriger_caracteres($letexte);
312 // Proteger les caracteres typographiques a l'interieur des tags html
313 if (preg_match_all(_TYPO_BALISE
, $letexte, $regs, PREG_SET_ORDER
)) {
314 foreach ($regs as $reg) {
316 // hack: on transforme les caracteres a proteger en les remplacant
317 // par des caracteres "illegaux". (cf corriger_caracteres())
318 $insert = strtr($insert, _TYPO_PROTEGER
, _TYPO_PROTECTEUR
);
319 $letexte = str_replace($reg[0], $insert, $letexte);
323 // trouver les blocs idiomes et les traiter à part
324 $letexte = extraire_idiome($ei = $letexte, $lang, true);
325 $ei = ($ei !== $letexte);
327 // trouver les blocs multi et les traiter a part
328 $letexte = extraire_multi($em = $letexte, $lang, true);
329 $em = ($em !== $letexte);
331 // Charger & appliquer les fonctions de typographie
332 $typographie = charger_fonction(lang_typo($lang), 'typographie');
333 $letexte = $typographie($letexte);
335 // Les citations en une autre langue, s'il y a lieu
337 $letexte = echappe_retour($letexte, 'multi');
340 $letexte = echappe_retour($letexte, 'idiome');
343 // Retablir les caracteres proteges
344 $letexte = strtr($letexte, _TYPO_PROTECTEUR
, _TYPO_PROTEGER
);
347 $letexte = pipeline('post_typo', $letexte);
349 # un message pour abs_url - on est passe en mode texte
350 $GLOBALS['mode_abs_url'] = 'texte';
357 * Paragrapher seulement
359 * /!\ appelée dans inc/filtres et public/composer
361 * Ne fait rien ici. Voir plugin Textwheel
363 * @param string $letexte
364 * @param null $forcer
367 function paragrapher($letexte, $forcer = true) {
372 * Harmonise les retours chariots et mange les paragraphes HTML
376 * @param string $letexte Texte
377 * @return string Texte
379 function traiter_retours_chariots($letexte) {
380 $letexte = preg_replace(",\r\n?,S", "\n", $letexte);
381 $letexte = preg_replace(",<p[>[:space:]],iS", "\n\n\\0", $letexte);
382 $letexte = preg_replace(",</p[>[:space:]],iS", "\\0\n\n", $letexte);
389 * Transforme les raccourcis SPIP, liens et modèles d'un texte en code HTML
391 * Filtre à appliquer aux champs du type `#TEXTE*`
394 * @uses echappe_html()
395 * @uses expanser_liens()
396 * @uses traiter_raccourcis()
397 * @uses echappe_retour_modeles()
401 * Texte avec des raccourcis SPIP
402 * @param string|null $connect
403 * Nom du connecteur à la bdd
405 * Environnement (pour les calculs de modèles)
409 function propre($t, $connect = null, $env = array()) {
410 // les appels directs a cette fonction depuis le php de l'espace
411 // prive etant historiquement ecrits sans argment $connect
412 // on utilise la presence de celui-ci pour distinguer les cas
413 // ou il faut passer interdire_script explicitement
414 // les appels dans les squelettes (de l'espace prive) fournissant un $connect
415 // ne seront pas perturbes
416 $interdire_script = false;
417 if (is_null($connect)) {
419 $interdire_script = true;
426 $t = echappe_html($t);
427 $t = expanser_liens($t, $connect, $env);
428 $t = traiter_raccourcis($t);
429 $t = echappe_retour_modeles($t, $interdire_script);