" . nl2br(spip_htmlspecialchars($regs[0])) . '', $t); } } } return $t; } /** * Empêcher l'exécution de code PHP et JS * * Sécurité : empêcher l'exécution de code PHP, en le transformant en joli code * dans l'espace privé. Cette fonction est aussi appelée par propre et typo. * * De la même manière, la fonction empêche l'exécution de JS mais selon le mode * de protection passe en argument * * Il ne faut pas désactiver globalement la fonction dans l'espace privé car elle protège * aussi les balises des squelettes qui ne passent pas forcement par propre ou typo après * si elles sont appelées en direct * * @param string $arg * Code à protéger * @param int $mode_filtre * Mode de protection * -1 : protection dans l'espace privé et public * 0 : protection dans l'espace public * 1 : aucune protection * utilise la valeur de la globale filtrer_javascript si non fourni * @return string * Code protégé **/ function interdire_scripts($arg, $mode_filtre=null) { // on memorise le resultat sur les arguments non triviaux static $dejavu = array(); // Attention, si ce n'est pas une chaine, laisser intact if (!$arg or !is_string($arg) or !strstr($arg, '<')) { return $arg; } if (is_null($mode_filtre) or !in_array($mode_filtre, array(-1, 0, 1))) { $mode_filtre = $GLOBALS['filtrer_javascript']; } if (isset($dejavu[$mode_filtre][$arg])) { return $dejavu[$mode_filtre][$arg]; } // echapper les tags asp/php $t = str_replace('<' . '%', '<%', $arg); // echapper le php $t = str_replace('<' . '?', '<?', $t); // echapper le < script language=php > $t = preg_replace(',<(script\b[^>]+\blanguage\b[^\w>]+php\b),UimsS', '<\1', $t); // Pour le js, trois modes : parano (-1), prive (0), ok (1) switch ($mode_filtre) { case 0: if (!_DIR_RESTREINT) { $t = echappe_js($t); } break; case -1: $t = echappe_js($t); break; } // pas de svp ! $t = preg_replace(',<(base\b),iS', '<\1', $t); // Reinserer les echappements des modeles if (defined('_PROTEGE_JS_MODELES')) { $t = echappe_retour($t, "javascript" . _PROTEGE_JS_MODELES); } if (defined('_PROTEGE_PHP_MODELES')) { $t = echappe_retour($t, "php" . _PROTEGE_PHP_MODELES); } return $dejavu[$mode_filtre][$arg] = $t; } /** * Applique la typographie générale * * Effectue un traitement pour que les textes affichés suivent les règles * de typographie. Fait une protection préalable des balises HTML et SPIP. * Transforme les balises `` * * @filtre * @uses traiter_modeles() * @uses corriger_typo() * @uses echapper_faux_tags() * @see propre() * * @param string $letexte * Texte d'origine * @param bool $echapper * Échapper ? * @param string|null $connect * Nom du connecteur à la bdd * @param array $env * Environnement (pour les calculs de modèles) * @return string $t * Texte transformé **/ function typo($letexte, $echapper = true, $connect = null, $env = array()) { // Plus vite ! if (!$letexte) { return $letexte; } // les appels directs a cette fonction depuis le php de l'espace // prive etant historiquement ecrit sans argment $connect // on utilise la presence de celui-ci pour distinguer les cas // ou il faut passer interdire_script explicitement // les appels dans les squelettes (de l'espace prive) fournissant un $connect // ne seront pas perturbes $interdire_script = false; if (is_null($connect)) { $connect = ''; $interdire_script = true; $env['espace_prive'] = test_espace_prive(); } // Echapper les codes etc if ($echapper) { $letexte = echappe_html($letexte, 'TYPO'); } // // Installer les modeles, notamment images et documents ; // // NOTE : propre() ne passe pas par ici mais directement par corriger_typo // cf. inc/lien $letexte = traiter_modeles($mem = $letexte, false, $echapper ? 'TYPO' : '', $connect, null, $env); if ($letexte != $mem) { $echapper = true; } unset($mem); $letexte = corriger_typo($letexte); $letexte = echapper_faux_tags($letexte); // reintegrer les echappements if ($echapper) { $letexte = echappe_retour($letexte, 'TYPO'); } // Dans les appels directs hors squelette, securiser ici aussi if ($interdire_script) { $letexte = interdire_scripts($letexte); } // Dans l'espace prive on se mefie de tout contenu dangereux // https://core.spip.net/issues/3371 if (isset($env['espace_prive']) and $env['espace_prive']) { $letexte = echapper_html_suspect($letexte); } return $letexte; } // Correcteur typographique define('_TYPO_PROTEGER', "!':;?~%-"); define('_TYPO_PROTECTEUR', "\x1\x2\x3\x4\x5\x6\x7\x8"); define('_TYPO_BALISE', ",]*[" . preg_quote(_TYPO_PROTEGER) . "][^<>]*>,imsS"); /** * Corrige la typographie * * Applique les corrections typographiques adaptées à la langue indiquée. * * @pipeline_appel pre_typo * @pipeline_appel post_typo * @uses corriger_caracteres() * @uses corriger_caracteres() * * @param string $letexte Texte * @param string $lang Langue * @return string Texte */ function corriger_typo($letexte, $lang = '') { // Plus vite ! if (!$letexte) { return $letexte; } $letexte = pipeline('pre_typo', $letexte); // Caracteres de controle "illegaux" $letexte = corriger_caracteres($letexte); // Proteger les caracteres typographiques a l'interieur des tags html if (preg_match_all(_TYPO_BALISE, $letexte, $regs, PREG_SET_ORDER)) { foreach ($regs as $reg) { $insert = $reg[0]; // hack: on transforme les caracteres a proteger en les remplacant // par des caracteres "illegaux". (cf corriger_caracteres()) $insert = strtr($insert, _TYPO_PROTEGER, _TYPO_PROTECTEUR); $letexte = str_replace($reg[0], $insert, $letexte); } } // trouver les blocs idiomes et les traiter à part $letexte = extraire_idiome($ei = $letexte, $lang, true); $ei = ($ei !== $letexte); // trouver les blocs multi et les traiter a part $letexte = extraire_multi($em = $letexte, $lang, true); $em = ($em !== $letexte); // Charger & appliquer les fonctions de typographie $typographie = charger_fonction(lang_typo($lang), 'typographie'); $letexte = $typographie($letexte); // Les citations en une autre langue, s'il y a lieu if ($em) { $letexte = echappe_retour($letexte, 'multi'); } if ($ei) { $letexte = echappe_retour($letexte, 'idiome'); } // Retablir les caracteres proteges $letexte = strtr($letexte, _TYPO_PROTECTEUR, _TYPO_PROTEGER); // pipeline $letexte = pipeline('post_typo', $letexte); # un message pour abs_url - on est passe en mode texte $GLOBALS['mode_abs_url'] = 'texte'; return $letexte; } /** * Paragrapher seulement * * /!\ appelée dans inc/filtres et public/composer * * Ne fait rien ici. Voir plugin Textwheel * * @param string $letexte * @param null $forcer * @return string */ function paragrapher($letexte, $forcer = true) { return $letexte; } /** * Harmonise les retours chariots et mange les paragraphes HTML * * Ne sert plus * * @param string $letexte Texte * @return string Texte **/ function traiter_retours_chariots($letexte) { $letexte = preg_replace(",\r\n?,S", "\n", $letexte); $letexte = preg_replace(",[:space:]],iS", "\n\n\\0", $letexte); $letexte = preg_replace(",[:space:]],iS", "\\0\n\n", $letexte); return $letexte; } /** * Transforme les raccourcis SPIP, liens et modèles d'un texte en code HTML * * Filtre à appliquer aux champs du type `#TEXTE*` * * @filtre * @uses echappe_html() * @uses expanser_liens() * @uses traiter_raccourcis() * @uses echappe_retour_modeles() * @see typo() * * @param string $t * Texte avec des raccourcis SPIP * @param string|null $connect * Nom du connecteur à la bdd * @param array $env * Environnement (pour les calculs de modèles) * @return string $t * Texte transformé **/ function propre($t, $connect = null, $env = array()) { // les appels directs a cette fonction depuis le php de l'espace // prive etant historiquement ecrits sans argment $connect // on utilise la presence de celui-ci pour distinguer les cas // ou il faut passer interdire_script explicitement // les appels dans les squelettes (de l'espace prive) fournissant un $connect // ne seront pas perturbes $interdire_script = false; if (is_null($connect)) { $connect = ''; $interdire_script = true; } if (!$t) { return strval($t); } $t = echappe_html($t); $t = expanser_liens($t, $connect, $env); $t = traiter_raccourcis($t); $t = echappe_retour_modeles($t, $interdire_script); return $t; }