|
|
|
@ -13,7 +13,8 @@
|
|
|
|
|
/** |
|
|
|
|
* Gestion des textes et raccourcis SPIP |
|
|
|
|
* |
|
|
|
|
* @package SPIP\Core\Texte |
|
|
|
|
* Surcharge de ecrire/inc/texte |
|
|
|
|
* |
|
|
|
|
**/ |
|
|
|
|
|
|
|
|
|
if (!defined('_ECRIRE_INC_VERSION')) { |
|
|
|
@ -23,101 +24,96 @@ if (!defined('_ECRIRE_INC_VERSION')) {
|
|
|
|
|
include_spip('inc/texte_mini'); |
|
|
|
|
include_spip('inc/lien'); |
|
|
|
|
|
|
|
|
|
/************************************************************************************************************************* |
|
|
|
|
* Fonctions inutilisees en dehors de inc/texte |
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
include_spip('inc/textwheel'); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Raccourcis dépendant du sens de la langue |
|
|
|
|
* |
|
|
|
|
* @return array Tablea ('','') |
|
|
|
|
*/ |
|
|
|
|
function definir_raccourcis_alineas() { |
|
|
|
|
return array('', ''); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
defined('_AUTOBR') || define('_AUTOBR', "<br class='autobr' />"); |
|
|
|
|
define('_AUTOBR_IGNORER', _AUTOBR ? "<!-- ig br -->" : ""); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Traitement des raccourcis de tableaux |
|
|
|
|
* |
|
|
|
|
* Ne fait rien ici. Voir plugin Textwheel. |
|
|
|
|
* |
|
|
|
|
* @param string $bloc |
|
|
|
|
* @return string |
|
|
|
|
*/ |
|
|
|
|
function traiter_tableau($bloc) { |
|
|
|
|
return $bloc; |
|
|
|
|
// Avec cette surcharge, cette globale n'est plus définie, et du coup ça plante dans les plugins qui font un foreach dessus comme ZPIP |
|
|
|
|
$GLOBALS['spip_raccourcis_typo'] = array(); |
|
|
|
|
if (!isset($GLOBALS['toujours_paragrapher'])) { |
|
|
|
|
$GLOBALS['toujours_paragrapher'] = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Traitement des listes |
|
|
|
|
* |
|
|
|
|
* Ne fais rien. Voir Plugin Textwheel. |
|
|
|
|
* (merci a Michael Parienti) |
|
|
|
|
* |
|
|
|
|
* @param string $texte |
|
|
|
|
* @return string |
|
|
|
|
*/ |
|
|
|
|
function traiter_listes($texte) { |
|
|
|
|
return $texte; |
|
|
|
|
// class_spip : savoir si on veut class="spip" sur p i strong & li |
|
|
|
|
// class_spip_plus : class="spip" sur les ul ol h3 hr quote table... |
|
|
|
|
// la difference c'est que des css specifiques existent pour les seconds |
|
|
|
|
// |
|
|
|
|
if (!isset($GLOBALS['class_spip'])) { |
|
|
|
|
$GLOBALS['class_spip'] = ''; |
|
|
|
|
} |
|
|
|
|
if (!isset($GLOBALS['class_spip_plus'])) { |
|
|
|
|
$GLOBALS['class_spip_plus'] = ' class="spip"'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Nettoie un texte, traite les raccourcis autre qu'URL, la typo, etc. |
|
|
|
|
* |
|
|
|
|
* Ne fais rien ici. Voir plugin Textwheel. |
|
|
|
|
* |
|
|
|
|
* @pipeline_appel pre_propre |
|
|
|
|
* @pipeline_appel post_propre |
|
|
|
|
* Échapper et affichier joliement les `<script` ... |
|
|
|
|
* |
|
|
|
|
* @param string $letexte |
|
|
|
|
* @param string $t |
|
|
|
|
* @return string |
|
|
|
|
*/ |
|
|
|
|
function traiter_raccourcis($letexte) { |
|
|
|
|
function echappe_js($t) { |
|
|
|
|
static $wheel = null; |
|
|
|
|
|
|
|
|
|
// Appeler les fonctions de pre_traitement |
|
|
|
|
$letexte = pipeline('pre_propre', $letexte); |
|
|
|
|
|
|
|
|
|
// APPELER ICI UN PIPELINE traiter_raccourcis ? |
|
|
|
|
// $letexte = pipeline('traiter_raccourcis', $letexte); |
|
|
|
|
if (!isset($wheel)) { |
|
|
|
|
$wheel = new TextWheel( |
|
|
|
|
SPIPTextWheelRuleset::loader($GLOBALS['spip_wheels']['echappe_js']) |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Appeler les fonctions de post-traitement |
|
|
|
|
$letexte = pipeline('post_propre', $letexte); |
|
|
|
|
try { |
|
|
|
|
$t = $wheel->text($t); |
|
|
|
|
} catch (Exception $e) { |
|
|
|
|
erreur_squelette($e->getMessage()); |
|
|
|
|
// sanitizer le contenu methode brute, puisqu'on a pas fait mieux |
|
|
|
|
$t = textebrut($t); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $letexte; |
|
|
|
|
return $t; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/************************************************************************************************************************* |
|
|
|
|
* Fonctions utilisees en dehors de inc/texte |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Échapper et affichier joliement les `<script` et `<iframe`... |
|
|
|
|
* Paragrapher seulement |
|
|
|
|
* |
|
|
|
|
* Fermer les paragraphes ; Essaie de préserver des paragraphes indiqués |
|
|
|
|
* à la main dans le texte (par ex: on ne modifie pas un `<p align='center'>`) |
|
|
|
|
* |
|
|
|
|
* @param string $t |
|
|
|
|
* @param string $class Attributs HTML du conteneur à ajouter |
|
|
|
|
* Le texte |
|
|
|
|
* @param null $toujours_paragrapher |
|
|
|
|
* true pour forcer les `<p>` même pour un seul paragraphe |
|
|
|
|
* @return string |
|
|
|
|
* Texte paragraphé |
|
|
|
|
*/ |
|
|
|
|
function echappe_js($t, $class = ' class = "echappe-js"') { |
|
|
|
|
foreach (array('script', 'iframe') as $tag) { |
|
|
|
|
if (stripos($t, "<$tag") !== false |
|
|
|
|
and preg_match_all(',<' . $tag . '.*?($|</' . $tag . '.),isS', $t, $r, PREG_SET_ORDER) |
|
|
|
|
function paragrapher($t, $toujours_paragrapher = null) { |
|
|
|
|
static $wheel = array(); |
|
|
|
|
if (is_null($toujours_paragrapher)) { |
|
|
|
|
$toujours_paragrapher = $GLOBALS['toujours_paragrapher']; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!isset($wheel[$toujours_paragrapher])) { |
|
|
|
|
$ruleset = SPIPTextWheelRuleset::loader($GLOBALS['spip_wheels']['paragrapher']); |
|
|
|
|
if (!$toujours_paragrapher |
|
|
|
|
and $rule = $ruleset->getRule('toujours-paragrapher') |
|
|
|
|
) { |
|
|
|
|
foreach ($r as $regs) { |
|
|
|
|
$t = str_replace($regs[0], |
|
|
|
|
"<code$class>" . nl2br(spip_htmlspecialchars($regs[0])) . '</code>', |
|
|
|
|
$t); |
|
|
|
|
} |
|
|
|
|
$rule->disabled = true; |
|
|
|
|
$ruleset->addRules(array('toujours-paragrapher' => $rule)); |
|
|
|
|
} |
|
|
|
|
$wheel[$toujours_paragrapher] = new TextWheel($ruleset); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
$t = $wheel[$toujours_paragrapher]->text($t); |
|
|
|
|
} catch (Exception $e) { |
|
|
|
|
erreur_squelette($e->getMessage()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $t; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Empêcher l'exécution de code PHP et JS |
|
|
|
|
* |
|
|
|
@ -145,43 +141,41 @@ function echappe_js($t, $class = ' class = "echappe-js"') {
|
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
static $wheel = array(); |
|
|
|
|
|
|
|
|
|
if (is_null($mode_filtre) or !in_array($mode_filtre, array(-1, 0, 1))) { |
|
|
|
|
$mode_filtre = $GLOBALS['filtrer_javascript']; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Attention, si ce n'est pas une chaine, laisser intact |
|
|
|
|
if (!$arg or !is_string($arg) or !strstr($arg, '<')) { |
|
|
|
|
return $arg; |
|
|
|
|
} |
|
|
|
|
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; |
|
|
|
|
if (!isset($wheel[$mode_filtre])) { |
|
|
|
|
$ruleset = SPIPTextWheelRuleset::loader( |
|
|
|
|
$GLOBALS['spip_wheels']['interdire_scripts'] |
|
|
|
|
); |
|
|
|
|
// Pour le js, trois modes : parano (-1), prive (0), ok (1) |
|
|
|
|
// desactiver la regle echappe-js si besoin |
|
|
|
|
if ($mode_filtre == 1 |
|
|
|
|
or ($mode_filtre == 0 and !test_espace_prive()) |
|
|
|
|
) { |
|
|
|
|
$ruleset->addRules(array('securite-js' => array('disabled' => true))); |
|
|
|
|
} |
|
|
|
|
$wheel[$mode_filtre] = new TextWheel($ruleset); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// pas de <base href /> svp ! |
|
|
|
|
$t = preg_replace(',<(base\b),iS', '<\1', $t); |
|
|
|
|
try { |
|
|
|
|
$t = $wheel[$mode_filtre]->text($arg); |
|
|
|
|
} catch (Exception $e) { |
|
|
|
|
erreur_squelette($e->getMessage()); |
|
|
|
|
// sanitizer le contenu methode brute, puisqu'on a pas fait mieux |
|
|
|
|
$t = textebrut($arg); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Reinserer les echappements des modeles |
|
|
|
|
if (defined('_PROTEGE_JS_MODELES')) { |
|
|
|
@ -238,9 +232,10 @@ function typo($letexte, $echapper = true, $connect = null, $env = array()) {
|
|
|
|
|
$env['espace_prive'] = test_espace_prive(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$echapper = ($echapper ? 'TYPO' : false); |
|
|
|
|
// Echapper les codes <html> etc |
|
|
|
|
if ($echapper) { |
|
|
|
|
$letexte = echappe_html($letexte, 'TYPO'); |
|
|
|
|
$letexte = echappe_html($letexte, $echapper); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// |
|
|
|
@ -249,9 +244,9 @@ function typo($letexte, $echapper = true, $connect = null, $env = array()) {
|
|
|
|
|
// 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; |
|
|
|
|
$letexte = traiter_modeles($mem = $letexte, false, $echapper ? $echapper : '', $connect, null, $env); |
|
|
|
|
if (!$echapper and $letexte != $mem) { |
|
|
|
|
$echapper = ''; |
|
|
|
|
} |
|
|
|
|
unset($mem); |
|
|
|
|
|
|
|
|
@ -259,8 +254,8 @@ function typo($letexte, $echapper = true, $connect = null, $env = array()) {
|
|
|
|
|
$letexte = echapper_faux_tags($letexte); |
|
|
|
|
|
|
|
|
|
// reintegrer les echappements |
|
|
|
|
if ($echapper) { |
|
|
|
|
$letexte = echappe_retour($letexte, 'TYPO'); |
|
|
|
|
if ($echapper !== false) { |
|
|
|
|
$letexte = echappe_retour($letexte, $echapper); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Dans les appels directs hors squelette, securiser ici aussi |
|
|
|
@ -281,6 +276,7 @@ function typo($letexte, $echapper = true, $connect = null, $env = array()) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Correcteur typographique |
|
|
|
|
|
|
|
|
|
define('_TYPO_PROTEGER', "!':;?~%-"); |
|
|
|
|
define('_TYPO_PROTECTEUR', "\x1\x2\x3\x4\x5\x6\x7\x8"); |
|
|
|
|
|
|
|
|
@ -296,95 +292,436 @@ define('_TYPO_BALISE', ",</?[a-z!][^<>]*[" . preg_quote(_TYPO_PROTEGER) . "][^<>
|
|
|
|
|
* @uses corriger_caracteres() |
|
|
|
|
* @uses corriger_caracteres() |
|
|
|
|
* |
|
|
|
|
* @param string $letexte Texte |
|
|
|
|
* @param string $t Texte |
|
|
|
|
* @param string $lang Langue |
|
|
|
|
* @return string Texte |
|
|
|
|
*/ |
|
|
|
|
function corriger_typo($letexte, $lang = '') { |
|
|
|
|
|
|
|
|
|
function corriger_typo($t, $lang = '') { |
|
|
|
|
static $typographie = array(); |
|
|
|
|
// Plus vite ! |
|
|
|
|
if (!$letexte) { |
|
|
|
|
return $letexte; |
|
|
|
|
if (!$t) { |
|
|
|
|
return $t; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$letexte = pipeline('pre_typo', $letexte); |
|
|
|
|
$t = pipeline('pre_typo', $t); |
|
|
|
|
|
|
|
|
|
// Caracteres de controle "illegaux" |
|
|
|
|
$letexte = corriger_caracteres($letexte); |
|
|
|
|
$t = corriger_caracteres($t); |
|
|
|
|
|
|
|
|
|
// Proteger les caracteres typographiques a l'interieur des tags html |
|
|
|
|
if (preg_match_all(_TYPO_BALISE, $letexte, $regs, PREG_SET_ORDER)) { |
|
|
|
|
if (preg_match_all(_TYPO_BALISE, $t, $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); |
|
|
|
|
$t = str_replace($reg[0], $insert, $t); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// trouver les blocs idiomes et les traiter à part |
|
|
|
|
$letexte = extraire_idiome($ei = $letexte, $lang, true); |
|
|
|
|
$ei = ($ei !== $letexte); |
|
|
|
|
$t = extraire_idiome($ei = $t, $lang, true); |
|
|
|
|
$ei = ($ei !== $t); |
|
|
|
|
|
|
|
|
|
// trouver les blocs multi et les traiter a part |
|
|
|
|
$letexte = extraire_multi($em = $letexte, $lang, true); |
|
|
|
|
$em = ($em !== $letexte); |
|
|
|
|
// trouver les blocs multi et les traiter à part |
|
|
|
|
$t = extraire_multi($em = $t, $lang, true); |
|
|
|
|
$em = ($em !== $t); |
|
|
|
|
|
|
|
|
|
// Charger & appliquer les fonctions de typographie |
|
|
|
|
$typographie = charger_fonction(lang_typo($lang), 'typographie'); |
|
|
|
|
$letexte = $typographie($letexte); |
|
|
|
|
$idxl = "$lang:" . (isset($GLOBALS['lang_objet']) ? $GLOBALS['lang_objet'] : $GLOBALS['spip_lang']); |
|
|
|
|
if (!isset($typographie[$idxl])) { |
|
|
|
|
$typographie[$idxl] = charger_fonction(lang_typo($lang), 'typographie'); |
|
|
|
|
} |
|
|
|
|
$t = $typographie[$idxl]($t); |
|
|
|
|
|
|
|
|
|
// 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'); |
|
|
|
|
$t = echappe_retour($t, 'idiome'); |
|
|
|
|
} |
|
|
|
|
if ($em) { |
|
|
|
|
$t = echappe_retour($t, 'multi'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Retablir les caracteres proteges |
|
|
|
|
$letexte = strtr($letexte, _TYPO_PROTECTEUR, _TYPO_PROTEGER); |
|
|
|
|
$t = strtr($t, _TYPO_PROTECTEUR, _TYPO_PROTEGER); |
|
|
|
|
|
|
|
|
|
// pipeline |
|
|
|
|
$letexte = pipeline('post_typo', $letexte); |
|
|
|
|
$t = pipeline('post_typo', $t); |
|
|
|
|
|
|
|
|
|
# un message pour abs_url - on est passe en mode texte |
|
|
|
|
$GLOBALS['mode_abs_url'] = 'texte'; |
|
|
|
|
|
|
|
|
|
return $letexte; |
|
|
|
|
return $t; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// |
|
|
|
|
// Tableaux |
|
|
|
|
// |
|
|
|
|
|
|
|
|
|
define('_RACCOURCI_TH_SPAN', '\s*(:?{{[^{}]+}}\s*)?|<'); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Paragrapher seulement |
|
|
|
|
* Traitement des raccourcis de tableaux |
|
|
|
|
* |
|
|
|
|
* /!\ appelée dans inc/filtres et public/composer |
|
|
|
|
* @param string $bloc |
|
|
|
|
* @return string |
|
|
|
|
*/ |
|
|
|
|
function traiter_tableau($bloc) { |
|
|
|
|
// id "unique" pour les id du tableau |
|
|
|
|
$tabid = substr(md5($bloc), 0, 4); |
|
|
|
|
|
|
|
|
|
// Decouper le tableau en lignes |
|
|
|
|
preg_match_all(',([|].*)[|]\n,UmsS', $bloc, $regs, PREG_PATTERN_ORDER); |
|
|
|
|
$lignes = array(); |
|
|
|
|
$debut_table = $summary = ''; |
|
|
|
|
$l = 0; |
|
|
|
|
|
|
|
|
|
// Traiter chaque ligne |
|
|
|
|
$reg_line1 = ',^(\|(' . _RACCOURCI_TH_SPAN . '))+$,sS'; |
|
|
|
|
$reg_line_all = ',^(' . _RACCOURCI_TH_SPAN . ')$,sS'; |
|
|
|
|
$hc = $hl = array(); |
|
|
|
|
foreach ($regs[1] as $ligne) { |
|
|
|
|
$l++; |
|
|
|
|
|
|
|
|
|
// Gestion de la premiere ligne : |
|
|
|
|
if ($l == 1) { |
|
|
|
|
// - <caption> et summary dans la premiere ligne : |
|
|
|
|
// || caption | summary || (|summary est optionnel) |
|
|
|
|
if (preg_match(',^\|\|([^|]*)(\|(.*))?$,sS', rtrim($ligne, '|'), $cap)) { |
|
|
|
|
$cap = array_pad($cap, 4, null); |
|
|
|
|
$l = 0; |
|
|
|
|
if ($caption = trim($cap[1])) { |
|
|
|
|
$debut_table .= "<caption>" . $caption . "</caption>\n"; |
|
|
|
|
} |
|
|
|
|
$summary = ' summary="' . entites_html(trim($cap[3])) . '"'; |
|
|
|
|
} |
|
|
|
|
// - <thead> sous la forme |{{titre}}|{{titre}}| |
|
|
|
|
// Attention thead oblige a avoir tbody |
|
|
|
|
else { |
|
|
|
|
if (preg_match($reg_line1, $ligne, $thead)) { |
|
|
|
|
preg_match_all('/\|([^|]*)/S', $ligne, $cols); |
|
|
|
|
$ligne = ''; |
|
|
|
|
$cols = $cols[1]; |
|
|
|
|
$colspan = 1; |
|
|
|
|
for ($c = count($cols) - 1; $c >= 0; $c--) { |
|
|
|
|
$attr = ''; |
|
|
|
|
if ($cols[$c] == '<') { |
|
|
|
|
$colspan++; |
|
|
|
|
} else { |
|
|
|
|
if ($colspan > 1) { |
|
|
|
|
$attr = " colspan='$colspan'"; |
|
|
|
|
$colspan = 1; |
|
|
|
|
} |
|
|
|
|
// inutile de garder le strong qui n'a servi que de marqueur |
|
|
|
|
$cols[$c] = str_replace(array('{', '}'), '', $cols[$c]); |
|
|
|
|
$ligne = "<th id='id{$tabid}_c$c'$attr>$cols[$c]</th>$ligne"; |
|
|
|
|
$hc[$c] = "id{$tabid}_c$c"; // pour mettre dans les headers des td |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$debut_table .= "<thead><tr class='row_first'>" . |
|
|
|
|
$ligne . "</tr></thead>\n"; |
|
|
|
|
$l = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Sinon ligne normale |
|
|
|
|
if ($l) { |
|
|
|
|
// Gerer les listes a puce dans les cellules |
|
|
|
|
// on declenche simplement sur \n- car il y a les |
|
|
|
|
// -* -# -? -! (qui produisent des - !) |
|
|
|
|
if (strpos($ligne, "\n-") !== false) { |
|
|
|
|
$ligne = traiter_listes($ligne); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// tout mettre dans un tableau 2d |
|
|
|
|
preg_match_all('/\|([^|]*)/S', $ligne, $cols); |
|
|
|
|
|
|
|
|
|
// Pas de paragraphes dans les cellules |
|
|
|
|
foreach ($cols[1] as &$col) { |
|
|
|
|
if (strlen($col = trim($col))) { |
|
|
|
|
$col = preg_replace("/\n{2,}/S", "<br /> <br />", $col); |
|
|
|
|
if (_AUTOBR) { |
|
|
|
|
$col = str_replace("\n", _AUTOBR . "\n", $col); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// assembler le tableau |
|
|
|
|
$lignes[] = $cols[1]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// maintenant qu'on a toutes les cellules |
|
|
|
|
// on prepare une liste de rowspan par defaut, a partir |
|
|
|
|
// du nombre de colonnes dans la premiere ligne. |
|
|
|
|
// Reperer egalement les colonnes numeriques pour les cadrer a droite |
|
|
|
|
$rowspans = $numeric = array(); |
|
|
|
|
$n = $lignes ? count($lignes[0]) : 0; |
|
|
|
|
$k = count($lignes); |
|
|
|
|
// distinguer les colonnes numeriques a point ou a virgule, |
|
|
|
|
// pour les alignements eventuels sur "," ou "." |
|
|
|
|
$numeric_class = array( |
|
|
|
|
'.' => 'point', |
|
|
|
|
',' => 'virgule', |
|
|
|
|
true => '' |
|
|
|
|
); |
|
|
|
|
for ($i = 0; $i < $n; $i++) { |
|
|
|
|
$align = true; |
|
|
|
|
for ($j = 0; $j < $k; $j++) { |
|
|
|
|
$rowspans[$j][$i] = 1; |
|
|
|
|
if ($align and preg_match('/^[{+-]*(?:\s|\d)*([.,]?)\d*[}]*$/', trim($lignes[$j][$i]), $r)) { |
|
|
|
|
if ($r[1]) { |
|
|
|
|
$align = $r[1]; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
$align = ''; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
$numeric[$i] = $align ? (" class='numeric " . $numeric_class[$align] . "'") : ''; |
|
|
|
|
} |
|
|
|
|
for ($j = 0; $j < $k; $j++) { |
|
|
|
|
if (preg_match($reg_line_all, $lignes[$j][0])) { |
|
|
|
|
$hl[$j] = "id{$tabid}_l$j"; // pour mettre dans les headers des td |
|
|
|
|
} else { |
|
|
|
|
unset($hl[0]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (!isset($hl[0])) { |
|
|
|
|
$hl = array(); |
|
|
|
|
} // toute la colonne ou rien |
|
|
|
|
|
|
|
|
|
// et on parcourt le tableau a l'envers pour ramasser les |
|
|
|
|
// colspan et rowspan en passant |
|
|
|
|
$html = ''; |
|
|
|
|
|
|
|
|
|
for ($l = count($lignes) - 1; $l >= 0; $l--) { |
|
|
|
|
$cols = $lignes[$l]; |
|
|
|
|
$colspan = 1; |
|
|
|
|
$ligne = ''; |
|
|
|
|
|
|
|
|
|
for ($c = count($cols) - 1; $c >= 0; $c--) { |
|
|
|
|
$attr = $numeric[$c]; |
|
|
|
|
$cell = trim($cols[$c]); |
|
|
|
|
if ($cell == '<') { |
|
|
|
|
$colspan++; |
|
|
|
|
|
|
|
|
|
} elseif ($cell == '^') { |
|
|
|
|
$rowspans[$l - 1][$c] += $rowspans[$l][$c]; |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
if ($colspan > 1) { |
|
|
|
|
$attr .= " colspan='$colspan'"; |
|
|
|
|
$colspan = 1; |
|
|
|
|
} |
|
|
|
|
if (($x = $rowspans[$l][$c]) > 1) { |
|
|
|
|
$attr .= " rowspan='$x'"; |
|
|
|
|
} |
|
|
|
|
$b = ($c == 0 and isset($hl[$l])) ? 'th' : 'td'; |
|
|
|
|
$h = (isset($hc[$c]) ? $hc[$c] : '') . ' ' . (($b == 'td' and isset($hl[$l])) ? $hl[$l] : ''); |
|
|
|
|
if ($h = trim($h)) { |
|
|
|
|
$attr .= " headers='$h'"; |
|
|
|
|
} |
|
|
|
|
// inutile de garder le strong qui n'a servi que de marqueur |
|
|
|
|
if ($b == 'th') { |
|
|
|
|
$attr .= " id='" . $hl[$l] . "'"; |
|
|
|
|
$cols[$c] = str_replace(array('{', '}'), '', $cols[$c]); |
|
|
|
|
} |
|
|
|
|
$ligne = "\n<$b" . $attr . '>' . $cols[$c] . "</$b>" . $ligne; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ligne complete |
|
|
|
|
$class = alterner($l + 1, 'odd', 'even'); |
|
|
|
|
$html = "<tr class='row_$class $class'>$ligne</tr>\n$html"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return "\n\n<table" . $GLOBALS['class_spip_plus'] . $summary . ">\n" |
|
|
|
|
. $debut_table |
|
|
|
|
. "<tbody>\n" |
|
|
|
|
. $html |
|
|
|
|
. "</tbody>\n" |
|
|
|
|
. "</table>\n\n"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Traitement des listes |
|
|
|
|
* |
|
|
|
|
* Ne fait rien ici. Voir plugin Textwheel |
|
|
|
|
* On utilise la wheel correspondante |
|
|
|
|
* |
|
|
|
|
* @param string $letexte |
|
|
|
|
* @param null $forcer |
|
|
|
|
* @param string $t |
|
|
|
|
* @return string |
|
|
|
|
*/ |
|
|
|
|
function paragrapher($letexte, $forcer = true) { |
|
|
|
|
return $letexte; |
|
|
|
|
function traiter_listes($t) { |
|
|
|
|
static $wheel = null; |
|
|
|
|
|
|
|
|
|
if (!isset($wheel)) { |
|
|
|
|
$wheel = new TextWheel( |
|
|
|
|
SPIPTextWheelRuleset::loader($GLOBALS['spip_wheels']['listes']) |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
$t = $wheel->text($t); |
|
|
|
|
} catch (Exception $e) { |
|
|
|
|
erreur_squelette($e->getMessage()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $t; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Ces deux constantes permettent de proteger certains caracteres |
|
|
|
|
// en les remplacanat par des caracteres "illegaux". (cf corriger_caracteres) |
|
|
|
|
|
|
|
|
|
define('_RACCOURCI_PROTEGER', "{}_-"); |
|
|
|
|
define('_RACCOURCI_PROTECTEUR', "\x1\x2\x3\x4"); |
|
|
|
|
|
|
|
|
|
define('_RACCOURCI_BALISE', ",</?[a-z!][^<>]*[" . preg_quote(_RACCOURCI_PROTEGER) . "][^<>]*>,imsS"); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Harmonise les retours chariots et mange les paragraphes HTML |
|
|
|
|
* mais d'abord, une callback de reconfiguration des raccourcis |
|
|
|
|
* a partir de globales (est-ce old-style ? on conserve quand meme |
|
|
|
|
* par souci de compat ascendante) |
|
|
|
|
* |
|
|
|
|
* Ne sert plus |
|
|
|
|
* @param $ruleset |
|
|
|
|
* @return string |
|
|
|
|
*/ |
|
|
|
|
function personnaliser_raccourcis(&$ruleset) { |
|
|
|
|
if ($ruleset) { |
|
|
|
|
if (isset($GLOBALS['debut_intertitre']) and $rule = $ruleset->getRule('intertitres')) { |
|
|
|
|
$rule->replace[0] = preg_replace(',<[^>]*>,Uims', $GLOBALS['debut_intertitre'], $rule->replace[0]); |
|
|
|
|
$rule->replace[1] = preg_replace(',<[^>]*>,Uims', $GLOBALS['fin_intertitre'], $rule->replace[1]); |
|
|
|
|
$ruleset->addRules(array('intertitres' => $rule)); |
|
|
|
|
} |
|
|
|
|
if (isset($GLOBALS['debut_gras']) and $rule = $ruleset->getRule('gras')) { |
|
|
|
|
$rule->replace[0] = preg_replace(',<[^>]*>,Uims', $GLOBALS['debut_gras'], $rule->replace[0]); |
|
|
|
|
$rule->replace[1] = preg_replace(',<[^>]*>,Uims', $GLOBALS['fin_gras'], $rule->replace[1]); |
|
|
|
|
$ruleset->addRules(array('gras' => $rule)); |
|
|
|
|
} |
|
|
|
|
if (isset($GLOBALS['debut_italique']) and $rule = $ruleset->getRule('italiques')) { |
|
|
|
|
$rule->replace[0] = preg_replace(',<[^>]*>,Uims', $GLOBALS['debut_italique'], $rule->replace[0]); |
|
|
|
|
$rule->replace[1] = preg_replace(',<[^>]*>,Uims', $GLOBALS['fin_italique'], $rule->replace[1]); |
|
|
|
|
$ruleset->addRules(array('italiques' => $rule)); |
|
|
|
|
} |
|
|
|
|
if (isset($GLOBALS['ligne_horizontale']) and $rule = $ruleset->getRule('ligne-horizontale')) { |
|
|
|
|
$rule->replace = preg_replace(',<[^>]*>,Uims', $GLOBALS['ligne_horizontale'], $rule->replace); |
|
|
|
|
$ruleset->addRules(array('ligne-horizontale' => $rule)); |
|
|
|
|
} |
|
|
|
|
if (isset($GLOBALS['toujours_paragrapher']) and !$GLOBALS['toujours_paragrapher'] |
|
|
|
|
and $rule = $ruleset->getRule('toujours-paragrapher') |
|
|
|
|
) { |
|
|
|
|
$rule->disabled = true; |
|
|
|
|
$ruleset->addRules(array('toujours-paragrapher' => $rule)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// retourner une signature de l'etat de la fonction, pour la mise en cache |
|
|
|
|
return implode("/", |
|
|
|
|
array( |
|
|
|
|
isset($GLOBALS['debut_intertitre']) ? $GLOBALS['debut_intertitre'] : "", |
|
|
|
|
isset($GLOBALS['debut_gras']) ? $GLOBALS['debut_gras'] : "", |
|
|
|
|
isset($GLOBALS['debut_italique']) ? $GLOBALS['debut_italique'] : "", |
|
|
|
|
isset($GLOBALS['ligne_horizontale']) ? $GLOBALS['ligne_horizontale'] : "", |
|
|
|
|
isset($GLOBALS['toujours_paragrapher']) ? $GLOBALS['toujours_paragrapher'] : 1, |
|
|
|
|
) |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Nettoie un texte, traite les raccourcis autre qu'URL, la typo, etc. |
|
|
|
|
* |
|
|
|
|
* @param string $letexte Texte |
|
|
|
|
* @return string Texte |
|
|
|
|
**/ |
|
|
|
|
function traiter_retours_chariots($letexte) { |
|
|
|
|
$letexte = preg_replace(",\r\n?,S", "\n", $letexte); |
|
|
|
|
$letexte = preg_replace(",<p[>[:space:]],iS", "\n\n\\0", $letexte); |
|
|
|
|
$letexte = preg_replace(",</p[>[:space:]],iS", "\\0\n\n", $letexte); |
|
|
|
|
* @pipeline_appel pre_propre |
|
|
|
|
* @pipeline_appel post_propre |
|
|
|
|
* |
|
|
|
|
* @param string $t |
|
|
|
|
* @param bool $show_autobr |
|
|
|
|
* @return string |
|
|
|
|
*/ |
|
|
|
|
function traiter_raccourcis($t, $show_autobr = false) { |
|
|
|
|
static $wheel = array(), $notes; |
|
|
|
|
static $img_br_auto, $img_br_manuel, $img_br_no; |
|
|
|
|
global $spip_lang, $spip_lang_rtl; |
|
|
|
|
|
|
|
|
|
// hack1: respecter le tag ignore br |
|
|
|
|
if (_AUTOBR_IGNORER |
|
|
|
|
and strncmp($t, _AUTOBR_IGNORER, strlen(_AUTOBR_IGNORER)) == 0 |
|
|
|
|
) { |
|
|
|
|
$ignorer_autobr = true; |
|
|
|
|
$t = substr($t, strlen(_AUTOBR_IGNORER)); |
|
|
|
|
} else { |
|
|
|
|
$ignorer_autobr = false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $letexte; |
|
|
|
|
// Appeler les fonctions de pre_traitement |
|
|
|
|
$t = pipeline('pre_propre', $t); |
|
|
|
|
|
|
|
|
|
$key = ""; |
|
|
|
|
$key = personnaliser_raccourcis($key); |
|
|
|
|
if (!isset($wheel[$key])) { |
|
|
|
|
$ruleset = SPIPTextWheelRuleset::loader( |
|
|
|
|
$GLOBALS['spip_wheels']['raccourcis'], 'personnaliser_raccourcis' |
|
|
|
|
); |
|
|
|
|
$wheel[$key] = new TextWheel($ruleset); |
|
|
|
|
|
|
|
|
|
if (_request('var_mode') == 'wheel' |
|
|
|
|
and autoriser('debug') |
|
|
|
|
) { |
|
|
|
|
$f = $wheel->compile(); |
|
|
|
|
echo "<pre>\n" . spip_htmlspecialchars($f) . "</pre>\n"; |
|
|
|
|
exit; |
|
|
|
|
} |
|
|
|
|
$notes = charger_fonction('notes', 'inc'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Gerer les notes (ne passe pas dans le pipeline) |
|
|
|
|
list($t, $mes_notes) = $notes($t); |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
$t = $wheel[$key]->text($t); |
|
|
|
|
} catch (Exception $e) { |
|
|
|
|
erreur_squelette($e->getMessage()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Appeler les fonctions de post-traitement |
|
|
|
|
$t = pipeline('post_propre', $t); |
|
|
|
|
|
|
|
|
|
if ($mes_notes) { |
|
|
|
|
$notes($mes_notes, 'traiter', $ignorer_autobr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (_AUTOBR and !function_exists('aide_lang_dir')) { |
|
|
|
|
include_spip('inc/lang'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// hack2: wrap des autobr dans l'espace prive, pour affichage css |
|
|
|
|
// car en css on ne sait pas styler l'element BR |
|
|
|
|
if ($ignorer_autobr and _AUTOBR) { |
|
|
|
|
if (is_null($img_br_no)) { |
|
|
|
|
$img_br_no = ($show_autobr ? http_img_pack("br-no" . aide_lang_dir($spip_lang, $spip_lang_rtl) . "-10.png", |
|
|
|
|
_T("tw:retour_ligne_ignore"), "class='br-no'", _T("tw:retour_ligne_ignore")) : ""); |
|
|
|
|
} |
|
|
|
|
$t = str_replace(_AUTOBR, $img_br_no, $t); |
|
|
|
|
} |
|
|
|
|
if ($show_autobr and _AUTOBR) { |
|
|
|
|
if (is_null($img_br_manuel)) { |
|
|
|
|
$img_br_manuel = http_img_pack("br-manuel" . aide_lang_dir($spip_lang, $spip_lang_rtl) . "-10.png", |
|
|
|
|
_T("tw:retour_ligne_manuel"), "class='br-manuel'", _T("tw:retour_ligne_manuel")); |
|
|
|
|
} |
|
|
|
|
if (is_null($img_br_auto)) { |
|
|
|
|
$img_br_auto = http_img_pack("br-auto" . aide_lang_dir($spip_lang, $spip_lang_rtl) . "-10.png", |
|
|
|
|
_T("tw:retour_ligne_auto"), "class='br-auto'", _T("tw:retour_ligne_auto")); |
|
|
|
|
} |
|
|
|
|
if (false !== strpos(strtolower($t), '<br')) { |
|
|
|
|
$t = preg_replace("/<br\b.*>/UiS", "$img_br_manuel\\0", $t); |
|
|
|
|
$t = str_replace($img_br_manuel . _AUTOBR, $img_br_auto . _AUTOBR, $t); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $t; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -416,8 +753,9 @@ function propre($t, $connect = null, $env = array()) {
|
|
|
|
|
// 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)) { |
|
|
|
|
|
|
|
|
|
$interdire_script = ( empty($env) and $GLOBALS['filtrer_javascript'] == -1); |
|
|
|
|
if (is_null($connect) and test_espace_prive()) { |
|
|
|
|
$connect = ''; |
|
|
|
|
$interdire_script = true; |
|
|
|
|
} |
|
|
|
@ -426,6 +764,11 @@ function propre($t, $connect = null, $env = array()) {
|
|
|
|
|
return strval($t); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$t = pipeline('pre_echappe_html_propre', $t); |
|
|
|
|
$t = echappe_html($t); |
|
|
|
|
$t = expanser_liens($t, $connect, $env); |
|
|
|
|
|
|
|
|
|
$t = traiter_raccourcis($t, (isset($env['wysiwyg']) and $env['wysiwyg']) ? true : false); |
|
|
|
|
// Dans l'espace prive on se mefie de tout contenu dangereux |
|
|
|
|
// avant echappement des balises <html> |
|
|
|
|
// https://core.spip.net/issues/3371 |
|
|
|
@ -437,10 +780,10 @@ function propre($t, $connect = null, $env = array()) {
|
|
|
|
|
or (isset($env['wysiwyg']) and $env['wysiwyg'] and $GLOBALS['filtrer_javascript']<=0)) { |
|
|
|
|
$t = echapper_html_suspect($t, false); |
|
|
|
|
} |
|
|
|
|
$t = echappe_html($t); |
|
|
|
|
$t = expanser_liens($t, $connect, $env); |
|
|
|
|
$t = traiter_raccourcis($t); |
|
|
|
|
|
|
|
|
|
$t = echappe_retour_modeles($t, $interdire_script); |
|
|
|
|
|
|
|
|
|
$t = pipeline('post_echappe_html_propre', $t); |
|
|
|
|
|
|
|
|
|
return $t; |
|
|
|
|
} |
|
|
|
|