Skip to content
Commits on Source (65)
......@@ -2,47 +2,34 @@
## Unreleased
### Security
- #5552 Appliquer l’option `httponly` sur la plupart des cookies internes à SPIP
- #5552 Appliquer l’option `secure` sur les cookies lorsqu’on est en HTTPS
- spip-team/securite#4840 Éviter `unserialize` dans l’écran de sécurité
- spip-team/securite#4840 Limiter la profondeur de recursion de `protege_champ`
- spip-team/securite#4840 Inclure l’écran de sécurité avant l’autoloader
- spip-team/securite#4841 Limiter l’usage de `#ENV**` dans les formulaires.
### Added
- #5565 Critère `{collate}` (remplace `{collecte}`)
- #5565 Critères `{groupby}` et `{groupby_supprimer}` (remplace `{fusion}` et `{fusion_supprimer}`)
- #5565 Critère `{having}`
- #5586 Attributs `data-objet`, `data-id_objet` et `data-objet-source` sur le formulaire d’édition de liens, pour usage en JS à toutes fins utiles.
- #5535 Log des dépréciations, via la fonction `trigger_deprecation` (de symfony/deprecations-contracts).
- Les plugins-dist et le squelettes-dist s'intallent avec composer
- #5301 Permettre de fournir le nom de l’attachement à `spip_livrer_fichier()`
### Changed
- Refactor de `echappe_html()` avec un collecteur
- #5552 Signature de `spip_setcookie` (reprend la signature de php `setcookie`)
- Mise à jour de Sortable.js (1.14.0 => 1.15.0)
- #5542 Refacto page de contrôle et boîtes des tâches de fond
- #5540 Les fonctions `extraire_balise` et `extraire_balises` peuvent gérer des balises imbriquées
- Les logos historiques (migrés en documents à partir de SPIP 4.0) ne sont plus utilisés s’il en restait.
- Nécessite PHP 8.1 minimum
### Fixed
- #5563 Filtre `couper` erroné dans certains cas avec des caractères utf8 multi bytes.
- Formulaire de configuration du multilinguisme (suite à spip-team/securite#4841)
- #5584 Présentation de l’input de recherche dans l’ajout d’auteurs liés
- #5580 Recherche et navigation dans le sélecteur de rubriques dépliant
- #5496 Typage en entrée de certains paramètres des fonctions `generer_*` lorsque l’objet n’existe pas.
- #5571 Retrouver correctement les anciens itérateurs
- #5341 Éviter une fatale sur le retour non booléen des fonctions `autoriser()` pour aider à nettoyer le code
- #5342 Éviter un warning dans ecrire
- #4697 Quand une URL de redirection contient une querystring avec des crochets, les encoder pour générer l'URL affichée
- #5240 Tester la variable plus tôt pour éviter un warning
- #5451 Lien vers l'URL/mail de suivi éditorial suivant le format
- #5446 Inconsistance dans l'UX et le label de l'adresse d'inscription au suivi éditorial
- #5528 Éviter des collisions avec les noms de cache des fichiers distants
- #5615 Ne pas considérer un texte malicieux s’il a simplement une entité html
- #5570 Inclusion manquante sur charger_fonction() en échec
- #5576 Rétablir l'insertion du script de protection sandbox sur la prévisu d'un objet
- #5543 Indiquer la bonne fonction dans le message d'erreur de `_imagecreatefrom_func`
- #5317 Animation plus douce des formulaires resoumis hors ajax
- #5485 Correction d’erreurs des traitements d’image si la balise `img` n’a pas d’attribut `src`
- #5426 Correction des filtres de date lorsque l’entrée ne précise pas le jour tel qu’avec `2023-03`
- #5541 Notices PHP en moins sur la page de contrôle des tâches de fond
### Deprecated
......
This diff is collapsed.
......@@ -218,7 +218,7 @@ function generer_url_api_low_sec(string $script, string $format, string $fond, s
$cle = afficher_low_sec($id_auteur, "$script/$format $fond $args");
$path = "$id_auteur/$cle/$format/$fond" . ($path ? "/$path" : '');
return generer_url_api($script, $path, $args, $no_entities = false, $public);
return generer_url_api($script, $path, $args, $no_entities, $public);
}
/**
......
......@@ -228,6 +228,11 @@ function autoriser_dist(string $faire, ?string $type = '', $id = null, $qui = nu
'autoriser' . _LOG_DEBUG
);
if (!is_bool($a)) {
trigger_error(sprintf("Function %s should returns a boolean instead of %s (casts as boolean). This will trigger fatal error in future versions.", $f, gettype($a)), \E_USER_DEPRECATED);
$a = (bool) $a;
}
return $a;
}
......
......@@ -262,15 +262,15 @@ function html2unicode($texte, $secure = false) {
}
}
if ($secure) {
return str_replace(array_keys($trans), array_values($trans), $texte);
} else {
return str_replace(
$texte = str_replace(array_keys($trans), array_values($trans), $texte);
if (!$secure) {
$texte = str_replace(
['&', '"', '<', '>'],
['&', '"', '<', '>'],
str_replace(array_keys($trans), array_values($trans), $texte)
$texte
);
}
return $texte;
}
......
......@@ -30,27 +30,25 @@ if (!defined('_ECRIRE_INC_VERSION')) {
* Nom du cookie
* @param string $value
* Valeur à stocker
* @param array{expires: int, path: string, domain: string, secure: bool, samesite: string} $options
* @param int|array{expires: int, path: string, domain: string, secure: bool, samesite: string} $expires_or_options
* int: Date d'expiration du cookie (timestamp)
* Tableau clé => valeur de l’option
* - expires = 0 : Date d'expiration du cookie (timestamp)
* - path = 'AUTO' : Chemin sur lequel le cookie sera disponible
* - domain = '' : Domaine à partir duquel le cookie est disponible
* - secure = false : cookie sécurisé ou non ?
* - samesite = 'Lax' : valeur samesite (Lax, Strict ou None)
* @param string $path
* Chemin sur lequel le cookie sera disponible (SPIP < 4.0: $path = 'AUTO')
* @param string $domain
* Domaine à partir duquel le cookie est disponible
* @param bool $secure
* Indique si le cookie doit être envoyé par le navigateur uniquement en connexion HTTPS (true) ou systématiquement (false)
* @param bool $httponly
* Indique si le cookie doit être accessible en Javascript (false) ou non (true)
* @return bool
* true si le cookie a été posé, false sinon.
*
* @note Anciens paramètres (à la place de $options) (pour rétrocompatibilité)
* param int $expire
* Date d'expiration du cookie (timestamp)
* param string $path
* Chemin sur lequel le cookie sera disponible
* param string $domain
* Domaine à partir duquel le cookie est disponible
* param bool $secure
* cookie sécurisé ou non ?
**/
// function spip_setcookie($name = '', $value = '', $options = []) {
function spip_setcookie(
string $name = '',
string $value = '',
......
......@@ -857,17 +857,31 @@ function nom_fichier_copie_locale($source, $extension) {
$d = creer_repertoire_documents('distant'); # IMG/distant/
$d = sous_repertoire($d, $extension); # IMG/distant/pdf/
// on se place tout le temps comme si on etait a la racine
// on se place tout le temps comme si on était a la racine
if (_DIR_RACINE) {
$d = preg_replace(',^' . preg_quote((string) _DIR_RACINE, ',') . ',', '', (string) $d);
}
$m = md5($source);
return $d
. substr(preg_replace(',[^\w-],', '', basename($source)) . '-' . $m, 0, 12)
. substr($m, 0, 4)
. ".$extension";
$filename =
$d
. substr(preg_replace(',[^\w-],', '', basename($source, $extension)), 0, 16)
. '-' . substr($m, 0, 8)
. ".$extension";
// ancien nommage des fichiers distants : renommer le fichier a la volee si besoin pour eviter de dupliquer les caches
$legacy_filename =
$d
. substr(preg_replace(',[^\w-],', '', basename($source)) . '-' . $m, 0, 12)
. substr($m, 0, 4)
. ".$extension";
if (file_exists(_DIR_RACINE . $legacy_filename)) {
@rename(_DIR_RACINE . $legacy_filename, $filename);
}
return $filename;
}
/**
......
<?php
use Spip\Texte\Collecteur\HtmlTag;
use Spip\Texte\Collecteur\Idiomes;
use Spip\Texte\Collecteur\Modeles;
use Spip\Texte\Collecteur\Multis;
use Spip\Texte\Collecteur\HtmlTag as CollecteurHtmlTag;
use Spip\Texte\Collecteur\Idiomes as CollecteurIdiomes;
use Spip\Texte\Collecteur\Modeles as CollecteurModeles;
use Spip\Texte\Collecteur\Multis as CollecteurMultis;
/***************************************************************************\
* SPIP, Système de publication pour l'internet *
......@@ -811,7 +811,9 @@ function entites_html($texte, $tout = false, $quote = true) {
include_spip('inc/texte');
$flags = ($quote ? ENT_QUOTES : ENT_NOQUOTES);
$flags |= ENT_HTML401;
$texte = spip_htmlspecialchars(echappe_retour(echappe_html($texte, '', true), '', 'proteger_amp'), $flags);
$texte = CollecteurHtmlTag::proteger_balisesHtml($texte);
$texte = CollecteurHtmlTag::retablir_depuisHtmlBase64($texte, '', 'proteger_amp');
$texte = spip_htmlspecialchars($texte, $flags);
if ($tout) {
return corriger_toutes_entites_html($texte);
} else {
......@@ -1560,12 +1562,12 @@ function post_autobr($texte, $delim = "\n_ ") {
$fin = '';
}
$texte = echappe_html($texte, '', true);
$texte = CollecteurHtmlTag::proteger_balisesHtml($texte);
// echapper les modeles
$collecteurModeles = null;
if (str_contains($texte, '<')) {
$collecteurModeles = new Modeles();
$collecteurModeles = new CollecteurModeles();
$texte = $collecteurModeles->echapper($texte);
}
......@@ -1595,7 +1597,7 @@ function post_autobr($texte, $delim = "\n_ ") {
$texte = $collecteurModeles->retablir($texte);
}
$texte = echappe_retour($texte);
$texte = CollecteurHtmlTag::retablir_depuisHtmlBase64($texte);
return $texte . $fin;
}
......@@ -1612,8 +1614,6 @@ function post_autobr($texte, $delim = "\n_ ") {
*
* @filtre
* @uses inc_traduire_dist()
* @uses code_echappement()
* @uses echappe_retour()
*
* @param string $letexte
* @param string $lang
......@@ -1645,7 +1645,7 @@ function extraire_idiome($letexte, $lang = null, $options = []) {
}
$options['lang'] = $lang;
$collecteurIdiomes = new Idiomes();
$collecteurIdiomes = new CollecteurIdiomes();
$letexte = $collecteurIdiomes->traiter($letexte, $options);
}
......@@ -1704,7 +1704,7 @@ function extraire_multi($letexte, $lang = null, $options = []) {
}
$options['lang'] = $lang;
$collecteurMultis = new Multis();
$collecteurMultis = new CollecteurMultis();
$letexte = $collecteurMultis->traiter($letexte, $options);
}
......@@ -2494,7 +2494,7 @@ function extraire_balises($texte, $tag = 'a', $options = []) {
return $texte;
}
$htmlTagCollecteur = new HtmlTag($tag);
$htmlTagCollecteur = new CollecteurHtmlTag($tag);
$collection = $htmlTagCollecteur->collecter($texte, $options);
if (!empty($collection)) {
return array_column($collection, 'raw');
......
......@@ -422,7 +422,20 @@ function lien_article_virtuel($virtuel) {
return '';
}
return propre('[->' . $virtuel . ']');
$joli = $virtuel;
$parts = parse_url($virtuel);
if (!empty($parts['query']) and str_contains($parts['query'], ']')) {
$query = str_replace(['[', ']'], [urlencode('['), urlencode(']')], $parts['query']);
$virtuel = str_replace("?" . $parts['query'], "?$query", $virtuel);
}
if ($virtuel !== $joli) {
$joli = propre('[' . $joli . ' -> ' . $virtuel . ']');
}
else {
$joli = propre('[->' . $virtuel . ']');
}
return $joli;
}
......
......@@ -38,6 +38,10 @@ if (!defined('_ECRIRE_INC_VERSION')) {
**/
function changer_langue($lang, $liste_langues = null) {
if (empty($lang)) {
return false;
}
if (is_null($liste_langues)) {
$liste_langues = ($GLOBALS['meta']['langues_proposees'] ?? '') . ',' . ($GLOBALS['meta']['langues_multilingue'] ?? '');
} else {
......@@ -50,9 +54,6 @@ function changer_langue($lang, $liste_langues = null) {
// Si la langue demandee n'existe pas, on essaie d'autres variantes
// Exemple : 'pt-br' => 'pt_br' => 'pt'
$lang = str_replace('-', '_', trim($lang));
if (!$lang) {
return false;
}
if (
str_contains($liste_langues, (string) ",$lang,")
......
<?php
use Spip\Texte\Collecteur\HtmlTag as CollecteurHtmlTag;
/***************************************************************************\
* SPIP, Système de publication pour l'internet *
* *
......@@ -100,52 +102,38 @@ function produire_image_math($tex) {
*/
function traiter_math($letexte, $source = '', $defaire_amp = false) {
$texte_a_voir = $letexte;
while (($debut = strpos($texte_a_voir, '<math>')) !== false) {
if (!$fin = strpos($texte_a_voir, '</math>')) {
$fin = strlen($texte_a_voir);
}
$texte_debut = substr($texte_a_voir, 0, $debut);
$texte_milieu = substr(
$texte_a_voir,
$debut + strlen('<math>'),
$fin - $debut - strlen('<math>')
);
$texte_fin = substr(
$texte_a_voir,
$fin + strlen('</math>'),
strlen($texte_a_voir)
);
// Les doubles $$x^2$$ en mode 'div'
while ((preg_match(',[$][$]([^$]+)[$][$],', $texte_milieu, $regs))) {
$expression = $regs[1];
if ($defaire_amp) {
$expression = str_replace('&amp;', '&', $expression);
}
$echap = "\n<p class=\"spip\" style=\"text-align: center;\">" . produire_image_math($expression) . "</p>\n";
$pos = strpos($texte_milieu, (string) $regs[0]);
$texte_milieu = substr($texte_milieu, 0, $pos)
. code_echappement($echap, $source)
. substr($texte_milieu, $pos + strlen($regs[0]));
}
// Les simples $x^2$ en mode 'span'
while ((preg_match(',[$]([^$]+)[$],', $texte_milieu, $regs))) {
$expression = $regs[1];
if ($defaire_amp) {
$expression = str_replace('&amp;', '&', $expression);
$collecteurMath = new CollecteurHtmlTag('math', '@<math>(.*)(</math>|$)@iUsS', '');
$collection = $collecteurMath->collecter($letexte);
$collection = array_reverse($collection);
foreach ($collection as $c) {
$texte_milieu = $c['match'][1];
$traitements = [
// Les doubles $$x^2$$ en mode 'div'
['str' => '$$', 'preg' => ',[$][$]([^$]+)[$][$],', 'pre' => "\n<p class=\"spip\" style=\"text-align: center;\">", "post" => "</p>\n"],
// Les simples $x^2$ en mode 'span'
['str' => '$', 'preg' => ',[$]([^$]+)[$],'],
];
foreach ($traitements as $t) {
while (
strpos($texte_milieu, $t['str']) !== false
and (preg_match($t['preg'], $texte_milieu, $regs))) {
$expression = $regs[1];
if ($defaire_amp) {
$expression = str_replace('&amp;', '&', $expression);
}
$echap = produire_image_math($expression);
$echap = ($t['pre'] ?? '') . $echap . ($t['post'] ?? '');
$echap = CollecteurHtmlTag::echappementHtmlBase64($echap, $source);
$pos = strpos($texte_milieu, (string) $regs[0]);
$texte_milieu = substr_replace($texte_milieu, $echap, $pos, strlen($regs[0]));
}
$echap = produire_image_math($expression);
$pos = strpos($texte_milieu, (string) $regs[0]);
$texte_milieu = substr($texte_milieu, 0, $pos)
. code_echappement($echap, $source)
. substr($texte_milieu, $pos + strlen($regs[0]));
}
$texte_a_voir = $texte_debut . $texte_milieu . $texte_fin;
$letexte = substr_replace($letexte, $texte_milieu, $c['pos'], $c['length']);
}
return $texte_a_voir;
return $letexte;
}
<?php
use Spip\Texte\Collecteur\HtmlTag as CollecteurHtmlTag;
/***************************************************************************\
* SPIP, Système de publication pour l'internet *
* *
......@@ -242,7 +244,7 @@ function typo($letexte, $echapper = true, $connect = null, $env = []) {
// Echapper les codes <html> etc
if ($echapper) {
$letexte = echappe_html($letexte, 'TYPO');
$letexte = CollecteurHtmlTag::proteger_balisesHtml($letexte, 'TYPO');
}
//
......@@ -262,7 +264,7 @@ function typo($letexte, $echapper = true, $connect = null, $env = []) {
// reintegrer les echappements
if ($echapper) {
$letexte = echappe_retour($letexte, 'TYPO');
$letexte = CollecteurHtmlTag::retablir_depuisHtmlBase64($letexte, 'TYPO');
}
// Dans les appels directs hors squelette, securiser ici aussi
......
<?php
use Spip\Texte\Collecteur\Idiomes;
use Spip\Texte\Collecteur\Liens;
use Spip\Texte\Collecteur\Modeles;
use Spip\Texte\Collecteur\Multis;
use Spip\Texte\Collecteur\Idiomes as CollecteurIdiomes;
use Spip\Texte\Collecteur\Liens as CollecteurLiens;
use Spip\Texte\Collecteur\Modeles as CollecteurModeles;
use Spip\Texte\Collecteur\Multis as CollecteurMultis;
use Spip\Texte\Collecteur\HtmlTag as CollecteurHtmlTag;
/***************************************************************************\
* SPIP, Système de publication pour l'internet *
......@@ -101,70 +102,49 @@ function spip_balisage_code(string $corps, bool $bloc = false, string $attributs
// XHTML - Preserver les balises-bloc : on liste ici tous les elements
// dont on souhaite qu'ils provoquent un saut de paragraphe
defined('_BALISES_BLOCS') || define('_BALISES_BLOCS', implode('|', CollecteurHtmlTag::$listeBalisesBloc));
defined('_BALISES_BLOCS_REGEXP') || define('_BALISES_BLOCS_REGEXP', ',</?(' . _BALISES_BLOCS . ')[>[:space:]],iS');
if (!defined('_BALISES_BLOCS')) {
define(
'_BALISES_BLOCS',
'address|applet|article|aside|blockquote|button|center|d[ltd]|div|fieldset|fig(ure|caption)|footer|form|h[1-6r]|hgroup|head|header|iframe|li|map|marquee|nav|noscript|object|ol|pre|section|t(able|[rdh]|body|foot|extarea)|ul|script|style'
);
}
if (!defined('_BALISES_BLOCS_REGEXP')) {
define('_BALISES_BLOCS_REGEXP', ',</?(' . _BALISES_BLOCS . ')[>[:space:]],iS');
}
//
// Echapper les elements perilleux en les passant en base64
//
// Creer un bloc base64 correspondant a $rempl ; au besoin en marquant
// une $source differente ; le script detecte automagiquement si ce qu'on
// echappe est un div ou un span
/**
* Echapper les elements perilleux en les passant en base64
*
* Creer un bloc base64 correspondant a $rempl ; au besoin en marquant
* une $source differente ; le script detecte automagiquement si ce qu'on
* echappe est un div ou un span
*
* @param $rempl
* @param $source
* @param $no_transform
* @param $mode
* @return string
*/
function code_echappement($rempl, $source = '', $no_transform = false, $mode = null) {
if (!strlen($rempl)) {
if (!is_string($rempl) or !strlen($rempl)) {
return '';
}
// Tester si on echappe en span ou en div
if (is_null($mode) or !in_array($mode, ['div', 'span'])) {
$mode = preg_match(',</?(' . _BALISES_BLOCS . ')[>[:space:]],iS', $rempl) ? 'div' : 'span';
}
// Decouper en morceaux, base64 a des probleme selon la taille de la pile
$taille = 30000;
$return = '';
for ($i = 0; $i < strlen($rempl); $i += $taille) {
// Convertir en base64 et cacher dans un attribut
// utiliser les " pour eviter le re-encodage de ' et &#8217
$base64 = base64_encode(substr($rempl, $i, $taille));
$return .= "<$mode class=\"base64$source\" title=\"$base64\"></$mode>";
}
return $return;
return CollecteurHtmlTag::echappementHtmlBase64((string)$rempl, (string)$source, in_array($mode, ['div', 'span']) ? $mode === 'div' : null);
}
// Echapper les <html>...</ html>
function traiter_echap_html_dist($regs, $options = []) {
return $regs[3];
return $regs['innerHtml'];
}
// Echapper les <pre>...</ pre>
function traiter_echap_pre_dist($regs, $options = []) {
// echapper les <code> dans <pre>
$pre = $regs[3];
$pre = $regs['innerHtml'];
// echapper les < dans <code>
// on utilise _PROTEGE_BLOCS pour simplifier le code et la maintenance, mais on est interesse que par <code>
if (
strpos($pre, '<') !== false
and preg_match_all(_PROTEGE_BLOCS, $pre, $matches, PREG_SET_ORDER)
) {
foreach ($matches as $m) {
if ($m[1] === 'code') {
$code = '<code' . $m[2] . '>' . spip_htmlspecialchars($m[3]) . '</code>';
$pre = str_replace($m[0], $code, $pre);
}
if (strpos($pre, '<') !== false) {
$collecteurCode = new CollecteurHtmlTag('code');
$collections = $collecteurCode->collecter($pre);
$collections = array_reverse($collections);
foreach ($collections as $c) {
$code = $c['opening'] . spip_htmlspecialchars($c['innerHtml']) . $c['closing'];
$pre = substr_replace($pre, $code, $c['pos'], $c['length']);
}
}
return "<pre>$pre</pre>";
......@@ -172,7 +152,8 @@ function traiter_echap_pre_dist($regs, $options = []) {
// Echapper les <code>...</ code>
function traiter_echap_code_dist($regs, $options = []) {
[, , $att, $corps] = $regs;
$corps = $regs['innerHtml'];
$att = $regs['attributs'];
// ne pas mettre le <div...> s'il n'y a qu'une ligne
if (strpos($corps, "\n") !== false) {
......@@ -190,7 +171,7 @@ function traiter_echap_code_dist($regs, $options = []) {
// Echapper les <cadre>...</ cadre> aka <frame>...</ frame>
function traiter_echap_cadre_dist($regs, $options = []) {
$echap = trim(entites_html($regs[3]));
$echap = trim(entites_html($regs['innerHtml']));
// compter les lignes un peu plus finement qu'avec les \n
$lignes = explode("\n", trim($echap));
$n = 0;
......@@ -209,25 +190,25 @@ function traiter_echap_frame_dist($regs, $options = []) {
function traiter_echap_script_dist($regs, $options = []) {
// rendre joli (et inactif) si c'est un script language=php
if (preg_match(',<script\b[^>]+php,ims', $regs[0])) {
return highlight_string($regs[0], true);
if (strpos($regs['opening'], 'php')) {
return highlight_string($regs['raw'], true);
}
// Cas normal : le script passe tel quel
return $regs[0];
return $regs['raw'];
}
define('_PROTEGE_BLOCS', ',<(html|pre|code|cadre|frame|script|style)(\b[^>]*)?>(.*)</\1>,UimsS');
defined('_PROTEGE_BLOCS') || define('_PROTEGE_BLOCS', ',<('.implode('|', CollecteurHtmlTag::$listeBalisesAProteger).')(\b[^>]*)?>(.*)</\1>,UimsS');
/**
* pour $source voir commentaire infra (echappe_retour)
* pour $no_transform voir le filtre post_autobr dans inc/filtres
* @see post_autobr()
*
* @param string $letexte
* @param string $source
* @param bool $no_transform
* @param string $preg
* déprécié, cet argument ne doit plus être utilisé, utiliser directement Spip\Texte\Collecteur\HtmlTag::proteger_balisesHtml dans ce cas
* @param ?array $html_tags
* le passage d'une preg au format string est déprécié
* @param string $callback_prefix
* @param array $callback_options
* @return string|string[]
......@@ -236,7 +217,7 @@ function echappe_html(
$letexte,
$source = '',
$no_transform = false,
$preg = '',
$html_tags = null,
$callback_prefix = '',
$callback_options = []
) {
......@@ -244,35 +225,44 @@ function echappe_html(
return $letexte;
}
if (
($preg or str_contains($letexte, '<'))
and preg_match_all($preg ?: _PROTEGE_BLOCS, $letexte, $matches, PREG_SET_ORDER)
) {
foreach ($matches as $regs) {
$echap = '';
// echappements tels quels ?
if ($no_transform) {
$echap = $regs[0];
} else {
// sinon les traiter selon le cas
$callback_secure_prefix = ($callback_options['secure_prefix'] ?? '');
if (
function_exists($f = $callback_prefix . $callback_secure_prefix . 'traiter_echap_' . strtolower($regs[1]))
if ($no_transform !== false) {
trigger_deprecation('spip', '5.0', 'Using "%s" arg is deprecated, use directly "%s" instead.', '$no_transform', 'Spip\Texte\Collecteur\HtmlTag::proteger_balisesHtml', __FUNCTION__);
}
// appels legacy avec un ''
if (empty($html_tags)) {
$html_tags = null;
}
// legacy : les appels fournissaient une preg pour repérer les balises HTML
if ($html_tags and !is_array($html_tags)) {
trigger_deprecation('spip', '5.0', 'Using a preg for "%s" arg is deprecated, use a tag array instead.', '$html_tags', __FUNCTION__);
$t = explode(')', $html_tags, 2);
$t = reset($t);
$t = explode('(', $t, 2);
$t = end($t);
$html_tags = explode('|', $t);
}
$callbacks = [];
if (!$no_transform) {
$callback_secure_prefix = ($callback_options['secure_prefix'] ?? '');
foreach ($html_tags ?: CollecteurHtmlTag::$listeBalisesAProteger as $tag) {
if (
function_exists($f = $callback_prefix . $callback_secure_prefix . 'traiter_echap_' . $tag)
or function_exists($f = $f . '_dist')
or ($callback_secure_prefix and (
function_exists($f = $callback_prefix . 'traiter_echap_' . $tag)
or function_exists($f = $f . '_dist')
or ($callback_secure_prefix and (
function_exists($f = $callback_prefix . 'traiter_echap_' . strtolower($regs[1]))
or function_exists($f = $f . '_dist')
))
) {
$echap = $f($regs, $callback_options);
}
))
) {
$callbacks[$tag] = $f;
}
$p = strpos($letexte, (string) $regs[0]);
$letexte = substr_replace($letexte, code_echappement($echap, $source, $no_transform), $p, strlen($regs[0]));
}
}
$letexte = CollecteurHtmlTag::proteger_balisesHtml($letexte, $source, $html_tags, $callbacks, $callback_options);
if ($no_transform) {
return $letexte;
}
......@@ -280,80 +270,42 @@ function echappe_html(
// Echapper le php pour faire joli (ici, c'est pas pour la securite)
// seulement si on a echappe les <script>
// (derogatoire car on ne peut pas faire passer < ? ... ? >
// dans une callback autonommee
if (strpos($preg ?: _PROTEGE_BLOCS, 'script') !== false) {
if (
strpos($letexte, '<' . '?') !== false and preg_match_all(
',<[?].*($|[?]>),UisS',
$letexte,
$matches,
PREG_SET_ORDER
)
) {
foreach ($matches as $regs) {
$letexte = str_replace(
$regs[0],
code_echappement(highlight_string($regs[0], true), $source),
$letexte
);
}
}
// dans une callback autonommee + la preg pour collecter est un peu spécifique
if (in_array('script', $html_tags ?: CollecteurHtmlTag::$listeBalisesAProteger)) {
$htmlTagCollecteur = new CollecteurHtmlTag('?', '@<[?].*($|[?]>)@UsS', '');
$letexte = $htmlTagCollecteur->echapper_enHtmlBase64($letexte, $source, function ($c, $o) { return highlight_string($c['raw'], true);});
}
return $letexte;
}
//
// Traitement final des echappements
// Rq: $source sert a faire des echappements "a soi" qui ne sont pas nettoyes
// par propre() : exemple dans multi et dans typo()
/**
* Traitement final des echappements
* Rq: $source sert a faire des echappements "a soi" qui ne sont pas nettoyes
* par propre() : exemple dans multi et dans typo()
*
* @param string $letexte
* @param string $source
* @param string $filtre
* @return array|mixed|string|string[]
*/
function echappe_retour($letexte, $source = '', $filtre = '') {
if (strpos($letexte, (string) "base64$source")) {
# spip_log(spip_htmlspecialchars($letexte)); ## pour les curieux
$max_prof = 5;
while (
strpos($letexte, '<') !== false
and
preg_match_all(
',<(span|div)\sclass=[\'"]base64' . $source . '[\'"]\s(.*)>\s*</\1>,UmsS',
$letexte,
$regs,
PREG_SET_ORDER
)
and $max_prof--
) {
foreach ($regs as $reg) {
$rempl = base64_decode(extraire_attribut($reg[0], 'title'));
// recherche d'attributs supplementaires
$at = [];
foreach (['lang', 'dir'] as $attr) {
if ($a = extraire_attribut($reg[0], $attr)) {
$at[$attr] = $a;
}
}
if ($at) {
$rempl = '<' . $reg[1] . '>' . $rempl . '</' . $reg[1] . '>';
foreach ($at as $attr => $a) {
$rempl = inserer_attribut($rempl, $attr, $a);
}
}
if ($filtre) {
$rempl = $filtre($rempl);
}
$letexte = str_replace($reg[0], $rempl, $letexte);
}
}
if (!is_string($letexte) or !strlen($letexte)) {
return $letexte;
}
return $letexte;
return CollecteurHtmlTag::retablir_depuisHtmlBase64((string)$letexte, (string)$source, (string)$filtre);
}
// Reinserer le javascript de confiance (venant des modeles)
function echappe_retour_modeles($letexte, $interdire_scripts = false) {
$letexte = echappe_retour($letexte);
if (!is_string($letexte) or !strlen($letexte)) {
return $letexte;
}
$letexte = CollecteurHtmlTag::retablir_depuisHtmlBase64((string)$letexte);
// Dans les appels directs hors squelette, securiser aussi ici
// c'est interdire_scripts() qui rétablit les scripts des modeles echappés avec _PROTEGE_JS_MODELES et _PROTEGE_PHP_MODELES
if ($interdire_scripts) {
$letexte = interdire_scripts($letexte);
}
......@@ -473,29 +425,24 @@ function couper($texte, $taille = 50, $suite = null) {
}
function protege_js_modeles($t) {
if (isset($GLOBALS['visiteur_session'])) {
if (preg_match_all(',<script.*?($|</script.),isS', $t, $r, PREG_SET_ORDER)) {
if (!defined('_PROTEGE_JS_MODELES')) {
include_spip('inc/acces');
define('_PROTEGE_JS_MODELES', creer_uniqid());
}
foreach ($r as $regs) {
$t = str_replace($regs[0], code_echappement($regs[0], 'javascript' . _PROTEGE_JS_MODELES), $t);
}
}
if (preg_match_all(',<\?php.*?($|\?' . '>),isS', $t, $r, PREG_SET_ORDER)) {
if (!defined('_PROTEGE_PHP_MODELES')) {
include_spip('inc/acces');
define('_PROTEGE_PHP_MODELES', creer_uniqid());
}
foreach ($r as $regs) {
$t = str_replace($regs[0], code_echappement($regs[0], 'php' . _PROTEGE_PHP_MODELES), $t);
function protege_js_modeles($texte) {
if (isset($GLOBALS['visiteur_session']) and strpos($texte, '<') !== false) {
$tags = [
'javascript' => ['tag' => 'script', 'preg' => ',<script.*?($|</script.),isS', 'c' => '_PROTEGE_JS_MODELES'],
'php' => ['tag' => '?php', 'preg' => ',<\?php.*?($|\?' . '>),isS', 'c' => '_PROTEGE_PHP_MODELES'],
];
foreach ($tags as $k => $t) {
if (stripos($texte, '<' . $t['tag']) !== false) {
if (!defined($t['c'])) {
include_spip('inc/acces');
define($t['c'], creer_uniqid());
}
$collecteurHtmlTag = new CollecteurHtmlTag($t['tag'], $t['preg'], '');
$texte = $collecteurHtmlTag->echapper_enHtmlBase64($texte, $k . constant($t['c']));
}
}
}
return $t;
return $texte;
}
......@@ -582,7 +529,7 @@ function echapper_html_suspect($texte, $options = [], $connect = null, $env = []
return $texte;
}
$collecteurModeles = new Modeles();
$collecteurModeles = new CollecteurModeles();
$texte = $collecteurModeles->echapper($texte);
$texte = echappe_js($texte);
......@@ -619,10 +566,10 @@ function echapper_html_suspect($texte, $options = [], $connect = null, $env = []
$texte = expanser_liens($texte, $env['connect'] ?? '', $env['env'] ?? []);
}
else {
$collecteurLiens = new Liens();
$collecteurLiens = new CollecteurLiens();
$texte = $collecteurLiens->echapper($texte, ['sanitize_callback' => 'safehtml']);
$collecteurModeles = new Modeles();
$collecteurModeles = new CollecteurModeles();
$texte = $collecteurModeles->echapper($texte);
}
$texte = safehtml($texte);
......@@ -667,12 +614,12 @@ function safehtml($t) {
$collecteurIdiomes = null;
if (stripos($t, '<:') !== false) {
$collecteurIdiomes = new Idiomes();
$collecteurIdiomes = new CollecteurIdiomes();
$t = $collecteurIdiomes->echapper($t);
}
$collecteurMultis = null;
if (stripos($t, '<multi') !== false) {
$collecteurMultis = new Multis();
$collecteurMultis = new CollecteurMultis();
$t = $collecteurMultis->echapper($t, ['sanitize_callback' => 'safehtml']);
}
......@@ -712,8 +659,12 @@ function is_html_safe(string $texte): bool {
$texte = str_replace("\r\n", "\n", $texte);
// safehtml reduit aussi potentiellement les &nbsp;
$texte = str_replace('&nbsp;', ' ', $texte);
// safehtml remplace les entités html
if (str_contains($texte, '&') && str_contains($texte, ';')) {
$texte = html2unicode($texte, true);
}
// safehtml remplace les entités numériques
if (strpos($texte, '&#') !== false) {
if (str_contains($texte, '&#')) {
$texte = unicode2charset($texte);
}
......
......@@ -101,6 +101,7 @@ function charger_fonction($nom, $dossier = 'exec', $continue = false) {
($inc ? '' : " (fichier $d absent de $dossier)"));
include_spip('inc/minipres');
include_spip('inc/filtres_mini');
echo minipres(
_T('forum_titre_erreur'),
$inc ?
......@@ -1903,7 +1904,7 @@ function generer_objet_url($id, string $entite, string $args = '', string $ancre
}
// On a ete gentil mais la ....
spip_log("generer_objet_url: entite $entite ($f) inconnue $type $public $connect", _LOG_ERREUR);
spip_log("generer_objet_url: entite $entite " . ($public ? "($f)" : '') . " inconnue $type $public $connect", _LOG_ERREUR);
return '';
}
......@@ -2451,7 +2452,7 @@ function generer_url_action($script, $args = '', $no_entities = false, $public =
*/
function generer_url_api(string $script, string $path, string $args, bool $no_entities = false, ?bool $public = null) {
if (is_null($public)) {
$public = (_DIR_RACINE ? false : '');
$public = (_DIR_RACINE ? false : true);
}
if (substr($script, -4) !== '.api') {
$script .= '.api';
......
This diff is collapsed.
......@@ -232,6 +232,7 @@ $GLOBALS[$GLOBALS['idx_lang']] = array(
'info_administrer_rubrique' => 'Vous pouvez administrer cette rubrique',
'info_adresse' => 'à l’adresse :',
'info_adresse_desinscription' => 'Adresse de désinscription :',
'info_adresse_inscription' => 'Adresse d’inscription :',
'info_adresse_url' => 'Adresse (URL) du site public',
'info_afficher_par_nb' => 'Afficher par',
'info_aide_en_ligne' => 'Aide en ligne SPIP',
......
......@@ -733,14 +733,20 @@ dans une couleur qui indique leur état :',
'protocole_ldap' => 'Version du protocole :',
// Q
'queue_args_fonction_label' => 'Arguments passés à la fonction @fonction@',
'queue_args_voir' => 'Voir les arguments',
'queue_executer_maintenant' => 'Exécuter maintenant',
'queue_fonction_label' => 'Fonction',
'queue_info_purger' => 'Tu peux supprimer toutes les tâches de fond en attente et réinitialiser la liste avec les tâches périodiques',
'queue_liens_label' => 'Liens',
'queue_nb_jobs_in_queue' => '@nb@ tâches en attente',
'queue_next_job_in_nb_sec' => 'Prochaine tâche dans @nb@ s',
'queue_next_job_scheduled' => 'Prochaine tâche',
'queue_no_job_in_queue' => 'Aucune tâche en attente',
'queue_one_job_in_queue' => '1 tâche en attente',
'queue_priorite_tache' => 'priorité',
'queue_purger_queue' => 'Réinitialiser la liste des tâches',
'queue_statut_en_cours' => 'En cours',
'queue_titre' => 'Tâches de fond',
// R
......
......@@ -50,7 +50,7 @@
<langue code="en_hx" url="https://trad.spip.net/tradlang_module/public?lang_cible=en_hx" total="83" traduits="64" relire="1" modifs="3" nouveaux="15" pourcent="77.11">
<traducteur nom="kent1" lien="https://trad.spip.net/auteur/kent1" />
</langue>
<langue code="eo" url="https://trad.spip.net/tradlang_module/public?lang_cible=eo" total="83" traduits="78" relire="0" modifs="0" nouveaux="5" pourcent="93.98">
<langue code="eo" url="https://trad.spip.net/tradlang_module/public?lang_cible=eo" total="83" traduits="81" relire="0" modifs="0" nouveaux="2" pourcent="97.59">
<traducteur nom="Matthieu Marcillaud" lien="https://trad.spip.net/auteur/matthieu-marcillaud" />
</langue>
<langue code="es" url="https://trad.spip.net/tradlang_module/public?lang_cible=es" total="83" traduits="83" relire="0" modifs="0" nouveaux="0" pourcent="100.00">
......
......@@ -96,6 +96,9 @@ $GLOBALS[$GLOBALS['idx_lang']] = array(
'repondre_breve' => 'Respondi al tiu fulm-informo',
'resultats_recherche' => 'Serĉo-rezultoj',
'retour_debut_forums' => 'Reen al forumoj-komenco',
'rss_abonnement_titre' => 'Abonu',
'rss_abonnement_titre_page' => 'Aboni al',
'rss_explication_titre' => 'Kio estas RSS-fluo ?',
'rubrique' => 'Rubriko',
'rubriques' => 'Rubrikoj',
......
......@@ -98,6 +98,7 @@
<pipeline nom="libeller_logo" action="" />
<pipeline nom="nettoyer_raccourcis_typo" action="" />
<pipeline nom="notifications" action="" />
<pipeline nom="notifications_destinataires" action="" />
<pipeline nom="notifications_envoyer_mails" action="" />
<pipeline nom="objet_compte_enfants" action="" />
<pipeline nom="optimiser_base_disparus" action="" />
......