+SPIP-Core v3.2.11 -> v3.2.12 (14 December 2021)
+-----------------------------------------------
+
+19c3592b9 | cedric | 2021-12-07 | Ameliorer valider_url_distante() : on utilise filter_var plutot que des regexp et on ajoute un controle sur le TTL du ..
+685a2c0bd | cedric | 2021-11-03 | Le plugin mots et son formulaire editer_mot() contient encore du vieux code pas reformate, reactivons donc cette featu..
+28c2cd60b | cedric | 2021-10-21 | Lors de l'upload de documents, gerer le cas des fichiers avec multiples extensions : on ne laisse que celles qui sont ..
+aefb90d6a | cedric | 2021-10-21 | Il faut incrementer spip_version_code car tous les formulaires doivent etre recalcules
+299219036 | cedric | 2021-10-21 | Oups, erreur dans 1b8e4f404 il faut utiliser empty car on poste potentiellement une signature vide (empechait de se lo..
+361cc2608 | cedric | 2021-10-06 | Nom, nom_site et bio etant des champs librement modifiables par les utilisateurs, on les protege comme des forums, via..
+fea5b5b45 | cedric | 2021-10-06 | Balise #FORMULAIRE : nettoyer du code mort qui ne sert plus, ameliorer la securite en ajoutant une signature des argum..
+a4fdb3b8e | cedric | 2021-09-27 | Complement de 413ca3cc58 : _mysql_traite_query() s'appelle recursivement, elle ne doit echapper les textes qu'au premi..
+96e283e4a | cedric | 2021-09-17 | Simplifier la regexp, c'est pas plus mal (cfreal)
+fca83dc95 | cedric | 2021-09-06 | Fix/refactoring query_echappe_textes() qui ne detectait parfois pas completement et correctement les chaines On robust..
+1a3fda815 | cedric | 2021-07-07 | Une constante _HTML_BG_CRON_INHIB permet d'inhiber l'insertion du markup html pour lancer le cron via une image backgr..
+e2d9ac340 | pierretux | 2021-09-06 | Ticket #4878 : Mise à jour du code de http_status pour utiliser directement la function de php
+f3ddc3f10 | cedric | 2021-08-12 | Petit bug vicieux sur le bouton de vidage de cache quand on est en mode _CACHE_CONTEXTES_AJAX : - le bouton 'vider le ..
+8eecb049c | marcimat | 2021-07-08 | Ticket #4845 : on déclare la branche correspondante dans la liste des plugins-dist de cette distribution.
+a63f9e608 | marcimat | 2021-07-06 | Ticket #4842 : Renommage de source_champ en index_champ, déclaration dans la classe Boucle et phpdoc. Éventuellement s..
+ae4f817fc | cedric | 2021-07-06 | Fix #4842 : utiliser la meme boucle source pour le calcul des filtres d'une balise que celle utilisee pour la valeur d..
+50e30a4b5 | cedric | 2021-07-06 | coquille dans la typo, ca craint (vue via https://core.spip.net/issues/4513)
+7969d18f6 | maieul | 2020-10-16 | Permettre de surcharger les constantes de traitement typo sans provoquer de notice. Exemple de plugin qui utilise cela..
+c7091877a | marcimat | 2019-08-27 | Ticket #4353 : On adapte les champs déclarés 'TIMESTAMP' en mysql versions récentes (8 par exemple) afin qu’ils se com..
+ad29547ec | maieul | 2021-07-05 | des guillemets autour des attributs
+6c200052e | cedric | 2021-02-18 | Fix #3239 : maintenant qu'on sait gerer l'erreur cote js en cas de perte de contexte ajax, on peut purger les contexte..
+11821bec9 | cedric | 2021-02-18 | Quand un contexte ajax est invalide (corrompu ou trop long, ou on a vide le cache sur le disque), renvoyer une erreur ..
+ebe3911aa | cedric | 2021-02-18 | Fix #4374 : traduire a la volee le current_timestamp() introduit par MariaDB mais que SQlite ne connait pas (b_b et ma..
+f76082e16 | bruno | 2021-06-02 | report de 02f7548245985ad40d430d3e8f1f809960a2fcc4 & d07b859fbc7b92bf6d4d9140ced0bf601e2be8d2
+ec7a876a0 | cedric | 2021-05-27 | Fix un bug sur l'autosave qui faisait parfois revenir une valeur pourtant saisie en cas de post ajax et de fichiers se..
+3d9882412 | rastapopoulos | 2021-03-14 | Dans l'API générique pour tout objet : passer à calculer_rubrique_if aussi l'info de quel objet on vient de modifié… C..
+4d2ea673d | glopglop | 2021-04-21 | Gestion des alias de boucles dans le traitement des champs.
+de928fda2 | maieul | 2021-04-11 | Permettre à vérification d'une étape spécifique de mettre son propre message d'erreur global.
+82cf0ba8d | maieul | 2021-04-04 | CVT multiétape : permettre l'avance rapide à une autre étape, sans pour autant déclencher d'erreur à l'étape où l'on a..
+bcc3c3606 | maieul | 2021-04-03 | Pipeline saisies_verifier_etapes: passer aussi en argument - l'étape saisie - le nb total d'étapes - l'étape dem..
+240ca1577 | maieul | 2021-04-02 | CVT multiétape : déplacer la recherche de `aller_a_etape` après les vérifications de chacune des étapes passées, qui p..
+378975997 | cedric | 2021-03-22 | Fix #4699 : il faut indiquer une etape_demandee > que le nombre d'etapes pour aller directement a la validation finale..
+979babd7f | maieul | 2021-03-31 | Dans `objet_modifier_champs()` on a une sécurité qui vérifie qu'après la modification de la ligne via `sql_updateq()`,..
+
+
+
+SPIP-plugins-dist v3.2.11 -> v3.2.12 (14 December 2021)
+-------------------------------------------------------
+
+compresseur | 374fe22 | cedric | 2018-09-06 | coquille dans r111480 qui cassait les images de background
+filtres_images | 8005120 | cedric | 2021-10-04 | Inclusion faite par image_filtrer() pour les filtres images standard mais manquante ici (bennyb)
+mediabox | 94a80ae | maieul | 2021-04-04 | Comme pour la branche 3.3, éviter l'appel à une fonction match qui n'est pas toujours définie (et poserait des problèm..
+medias | 1a4b702 | cedric | 2021-12-07 | Utiliser valider_url_distante() en plus de tester_url_absolue() avant de faire une copie locale sur un document distan..
+mots | 3258f8f | nicod | 2021-04-09 | Quand on a beaucoup de groupes de mots clés, un clic sur le titre du groupe dans la colonne de gauche (navigation) ne ..
+porte_plume | c196f81 | rastapopoulos | 2020-12-10 | Tant qu'on n'utilise pas des loaders et classes bien propre, on doit toujours s'assurer que les fonctions qu'on utilis..
+porte_plume | 8ae9b48 | marcimat | 2021-06-15 | Ticket #4818 : il semble que les fonctions ne sont pas chargées parfois ici (real3t)
+safehtml | 036e2cf | cedric | 2021-05-12 | Fix https://core.spip.net/issues/4706 : les attributs HTML5 data-xx ne doivent pas etre supprimes par safehtml, on acc..
+safehtml | 9d9da26 | maieul | 2021-05-07 | SVP est sensible à l'odre des balises dans paquet.xml
+safehtml | d12f7fc | cedric | 2021-05-07 | Mise a jour du paquet avec credit/procure et increment de version
+safehtml | a63d837 | cedric | 2021-05-07 | Mise a jour des tests unitaires avec la v1.3.12 de safehtml
+safehtml | accba7a | cedric | 2021-05-07 | Mise a jour de SafeHTML en version 1.3.12 depuis https://bitbucket.org/wackowiki/wackowiki/src/master/wacko/lib/ Inclu..
+safehtml | 3e15768 | cedric | 2021-05-07 | Un test unitaire pour safehtml avec des string random et un jeu de test xss pour au moins verifier qu'on ne casse rien..
+squelettes-dist | bbf7446 | cedric | 2021-02-17 | Mise a jour des Disallow/Noindex pour permettres aux robots sociaux d'acceder aux images referencees dans les pages ht..
+
+
SPIP-Core v3.2.10 -> v3.2.11 (26 March 2021)
--------------------------------------------
include_spip('inc/rubriques');
//$postdate = ($GLOBALS['meta']["post_dates"] == "non" AND isset($champs['date']) AND (strtotime($champs['date']) < time()))?$champs['date']:false;
$postdate = false;
- calculer_rubriques_if($id_rubrique, $champs, $statut, $postdate);
+ // On rajoute les infos de l'objet
+ $infos = array(
+ 'objet' => $objet,
+ 'id_objet' => $id,
+ 'statut_ancien' => $statut,
+ );
+ calculer_rubriques_if($id_rubrique, $champs, $infos, $postdate);
}
}
$action = parametre_url($action, 'formulaire_action_args', '');
}
+ /**
+ * sert (encore :() pour poster sur les actions de type editer_xxx() qui ne prenaient pas d'argument autrement que par _request('arg') et pour lesquelles il fallait donc passer un hash valide
+ */
if (isset($valeurs['_action'])) {
$securiser_action = charger_fonction('securiser_action', 'inc');
$secu = $securiser_action(reset($valeurs['_action']), end($valeurs['_action']), '', -1);
$valeurs['action'] = $action;
$valeurs['form'] = $form;
+ $valeurs['formulaire_sign'] = '';
+ if (!empty($GLOBALS['visiteur_session']['id_auteur'])) {
+ $securiser_action = charger_fonction('securiser_action', 'inc');
+ $secu = $securiser_action($valeurs['form'], $valeurs['formulaire_args'], '', -1);
+ $valeurs['formulaire_sign'] = $secu['hash'];
+ }
+
if (!isset($valeurs['id'])) {
$valeurs['id'] = 'new';
}
* @param string $query
* @return array
*/
-function query_echappe_textes($query) {
- static $codeEchappements = array("''" => "\x1@##@\x1", "\'" => "\x2@##@\x2", "\\\"" => "\x3@##@\x3");
- $query = str_replace(array_keys($codeEchappements), array_values($codeEchappements), $query);
- if (preg_match_all("/((['])[^']*(\\2))|(([\"])[^\"]*(\\5))/S", $query, $textes)) {
+function query_echappe_textes($query, $uniqid=null) {
+ static $codeEchappements = null;
+ if (is_null($codeEchappements)) {
+ if (is_null($uniqid)) {
+ $uniqid = uniqid();
+ }
+ $uniqid = substr(md5($uniqid), 0, 4);
+ $codeEchappements = ["\\\\" => "\x1@#{$uniqid}#@\x1", "\\'" => "\x2@#{$uniqid}#@\x2", '\\"' => "\x3@#{$uniqid}#@\x3"];
+ }
+ if ($query === null) {
+ return $codeEchappements;
+ }
+
+ // si la query contient deja des codes d'echappement on va s'emmeler les pinceaux et donc on ne touche a rien
+ // ce n'est pas un cas legitime
+ foreach ($codeEchappements as $codeEchappement) {
+ if (strpos($query, $codeEchappement) !== false) {
+ return [$query, []];
+ }
+ }
+
+ $query_echappees = str_replace(array_keys($codeEchappements), array_values($codeEchappements), $query);
+ if (preg_match_all("/('[^']*')|(\"[^\"]*\")/S", $query_echappees, $textes)) {
$textes = reset($textes); // indice 0 du match
switch (count($textes)) {
case 0:
$replace = explode(',', $replace);
break;
}
- $query = str_replace($textes, $replace, $query);
+ $query_echappees = str_replace($textes, $replace, $query_echappees);
} else {
$textes = array();
}
- return array($query, $textes);
+ // si il reste des quotes simples ou doubles, c'est qu'on s'est emmelles les pinceaux
+ // dans le doute on ne touche a rien
+ if (strpbrk($query_echappees, "'\"") !== false) {
+ return [$query, []];
+ }
+
+ return [$query_echappees, $textes];
}
/**
* @return string
*/
function query_reinjecte_textes($query, $textes) {
- static $codeEchappements = array("''" => "\x1@##@\x1", "\'" => "\x2@##@\x2", "\\\"" => "\x3@##@\x3");
- # debug de la substitution
- #if (($c1=substr_count($query,"%"))!=($c2=count($textes))){
- # spip_log("$c1 ::". $query,"tradquery"._LOG_ERREUR);
- # spip_log("$c2 ::". var_export($textes,1),"tradquery"._LOG_ERREUR);
- # spip_log("ini ::". $qi,"tradquery"._LOG_ERREUR);
- #}
+ // recuperer les codes echappements
+ $codeEchappements = query_echappe_textes(null);
+
switch (count($textes)) {
case 0:
break;
optimiser_base_une_table();
optimiser_base();
+ optimiser_caches_contextes();
// la date souhaitee pour le tour suivant = apres-demain a 4h du mat ;
// sachant qu'on a un delai de 48h, on renvoie aujourd'hui a 4h du mat
return -(mktime(2, 0, 0) + rand(0, 3600 * 4));
}
+/**
+ * Vider les contextes ajax de plus de 48h
+ */
+function optimiser_caches_contextes() {
+ sous_repertoire(_DIR_CACHE, 'contextes');
+ if (is_dir( $d = _DIR_CACHE . 'contextes')) {
+ include_spip('inc/invalideur');
+ purger_repertoire($d, ['mtime' => time() - 48*24*3600, 'limit' => 10000]);
+ }
+}
+
/**
* Optimise la base de données
*
}
}
+ // si on est dans le charger() qui suit le traiter(), l'autosave a normalement ete vide
+ // mais si il y a plusieurs sessions il peut y avoir concurrence et un retour de l'autosave
+ if ($je_suis_poste and _request('autosave') === $cle_autosave and function_exists('terminer_actualiser_sessions')) {
+ terminer_actualiser_sessions();
+ // et verifions si jamais l'autosave a fait un come back, dans ce cas on le revide
+ if (isset($GLOBALS['visiteur_session']['session_autosave_' . $cle_autosave])) {
+ session_set('session_autosave_' . $cle_autosave, null);
+ // en court sleep pour etre certain que la concurrence est finie
+ sleep(1);
+ terminer_actualiser_sessions();
+ }
+ }
+
+
/**
* Envoyer le input hidden et le bout de js qui l'utilisera
*/
/**
* Verifier les etapes de saisie
- *
+ *
* @param array $args
* @param $erreurs
* @return array
) {
// recuperer l'etape saisie et le nombre d'etapes total
list($etape, $etapes) = $e;
- $etape_demandee = _request('aller_a_etape'); // possibilite de poster en entier dans aller_a_etape
+ $etape_demandee = intval(_request('aller_a_etape')); // possibilite de poster un entier dans aller_a_etape
+ $args['etape_saisie'] = $etape;
+ $args['etapes'] = $etapes;
// lancer les verifs pour chaque etape deja saisie de 1 a $etape
$erreurs_etapes = array();
$derniere_etape_ok = 0;
$e = 0;
- while ($e < $etape and $e < $etapes) {
+ while ($e < max($etape, $etape_demandee -1) and $e < $etapes) {
$e++;
$erreurs_etapes[$e] = array();
if ($verifier = charger_fonction("verifier_$e", "formulaires/$form/", true)) {
}
// et on appelle un pipeline dedie aux etapes, plus easy
$args['etape'] = $e;
+ $args['etape_demandee'] = $etape_demandee;
$erreurs_etapes[$e] = pipeline(
'formulaire_verifier_etape',
array(
if ($derniere_etape_ok == $e - 1 and !count($erreurs_etapes[$e])) {
$derniere_etape_ok = $e;
}
- // possibilite de poster dans _retour_etape_x
+ // possibilite de poster dans _retour_etape_x ou aller_a_etape
if (!is_null(_request("_retour_etape_$e"))) {
$etape_demandee = $e;
}
+ // Il se peut que les verifications ait décidé de faire sauter des étapes
+ if ($aller_a_etape = intval(_request('aller_a_etape'))) {
+ $etape_demandee = $aller_a_etape; // possibilite de poster un entier dans aller_a_etape
+ }
}
+
// si la derniere etape OK etait la derniere
// on renvoie le flux inchange et ca declenche traiter
- if ($derniere_etape_ok == $etapes and !$etape_demandee) {
+ if ($derniere_etape_ok == $etapes
+ and (!$etape_demandee or $etape_demandee>=$etapes)) {
return $erreurs;
} else {
$etape = $derniere_etape_ok + 1;
$erreurs = isset($erreurs_etapes[$etape]) ? $erreurs_etapes[$etape] : array();
// Ne pas se tromper dans le texte du message d'erreur : la clé '_etapes' n'est pas une erreur !
if ($erreurs) {
- $erreurs['message_erreur'] = singulier_ou_pluriel(count($erreurs), 'avis_1_erreur_saisie', 'avis_nb_erreurs_saisie');
+ if (!isset($erreurs['message_erreur'])) {
+ $erreurs['message_erreur'] = singulier_ou_pluriel(count($erreurs), 'avis_1_erreur_saisie', 'avis_nb_erreurs_saisie');
+ }
} else {
$erreurs['message_erreur'] = "";
}
if (!$is_known_host) {
$host = trim($parsed_url['host'], '.');
- if (preg_match('#^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $host)) {
- $ip = $host;
- } else {
+ if (! $ip = filter_var($host, FILTER_VALIDATE_IP)) {
$ip = gethostbyname($host);
if ($ip === $host) {
// Error condition for gethostbyname()
$ip = false;
}
+ if ($records = dns_get_record($host)) {
+ foreach ($records as $record) {
+ // il faut que le TTL soit suffisant afin d'etre certain que le copie_locale eventuel qui suit
+ // se fasse sur la meme IP
+ if ($record['ttl']<10) {
+ $ip = false;
+ break;
+ }
+ }
+ }
+ else {
+ $ip = false;
+ }
}
if ($ip) {
- $parts = array_map('intval', explode( '.', $ip ));
- if (127 === $parts[0] or 10 === $parts[0] or 0 === $parts[0]
- or ( 172 === $parts[0] and 16 <= $parts[1] and 31 >= $parts[1] )
- or ( 192 === $parts[0] && 168 === $parts[1] )
- ) {
+ if (! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
return false;
}
}
// pour les images transformees par rotation (action/documenter)
$dest = preg_replace(',-r(90|180|270)$,', '', $dest);
+ while (preg_match(",\.(\w+)$,", $dest, $m)) {
+ if (!function_exists('verifier_upload_autorise')
+ or !$r = verifier_upload_autorise($dest)
+ or $r['autozip']) {
+ $dest = substr($dest, 0, -strlen($m[0])) . '_' . $m[1];
+ break;
+ }
+ else {
+ $dest = substr($dest, 0, -strlen($m[0]));
+ $ext = $m[1] . "." . $ext;
+ }
+ }
+
// Si le document "source" est deja au bon endroit, ne rien faire
if ($source == ($dir . $dest . '.' . $ext)) {
return $source;
*
* Ainsi `http_status(301)` enverra le message `301 Moved Permanently`.
*
- * @link http://php.net/manual/fr/function.header.php Fonction header() de PHP utilisée ici
+ * @link https://www.php.net/manual/fr/function.http-response-code.php
+ * @uses http_response_code()
*
* @param int $status
* Code d'erreur
**/
function http_status($status) {
-
- static $status_string = array(
- 200 => '200 OK',
- 204 => '204 No Content',
- 301 => '301 Moved Permanently',
- 302 => '302 Found',
- 304 => '304 Not Modified',
- 401 => '401 Unauthorized',
- 403 => '403 Forbidden',
- 404 => '404 Not Found',
- 503 => '503 Service Unavailable'
- );
-
- if (!empty($GLOBALS['REDIRECT_STATUS']) && $GLOBALS['REDIRECT_STATUS'] == $status) {
- return;
- }
-
- $php_cgi = ($GLOBALS['flag_sapi_name'] and preg_match(",cgi,i", @php_sapi_name()));
- if ($php_cgi) {
- header("Status: " . $status_string[$status]);
- } else {
- header("HTTP/1.0 " . $status_string[$status]);
- }
+ http_response_code($status);
}
// Retourne ce qui va bien pour que le navigateur ne mette pas la page en cache
foreach ($moof as $k => $v) {
if ($v !== $champs[$k]
// ne pas alerter si le champ est numerique est que les valeurs sont equivalentes
- and (!is_numeric($v) or intval($v) != intval($champs[$k]))
+ and (!is_numeric($v) or intval($v) !== intval($champs[$k]))
+ // ne pas alerter si le champ est date, qu'on a envoye une valeur vide et qu'on recupere une date nulle
+ and (strlen($champs[$k]) or !in_array($v, ['0000-00-00 00:00:00', '0000-00-00']))
) {
$liste[] = $k;
$conflits[$k]['post'] = $champs[$k];
return $texte;
}
- // en derniere solution, on insere un appel xhr non bloquant ou une image background dans la page si pas de JS
- $url_cron = generer_url_action('cron');
- $texte = '<!-- SPIP-CRON -->'
- . "<script>setTimeout(function(){var xo = new XMLHttpRequest();xo.open('GET', '$url_cron', true);xo.send('');},100);</script>"
- . "<noscript><div style=\"background-image: url('$url_cron');\"></div></noscript>";
+ if (!defined('_HTML_BG_CRON_INHIB') or !_HTML_BG_CRON_INHIB) {
+ // en derniere solution, on insere un appel xhr non bloquant ou une image background dans la page si pas de JS
+ $url_cron = generer_url_action('cron');
+ $texte = '<!-- SPIP-CRON -->'
+ . "<script>setTimeout(function(){var xo = new XMLHttpRequest();xo.open('GET', '$url_cron', true);xo.send('');},100);</script>"
+ . "<noscript><div style=\"background-image: url('$url_cron');\"></div></noscript>";
+ }
return $texte;
}
* Peut avoir 2 index, 'statut' étant obligatoire :
* - statut : indique le nouveau statut de la rubrique
* - id_rubrique : indiquer la rubrique dans laquelle on déplace la rubrique (son nouveau parent donc)
- * @param string $statut_ancien
- * Ancien statut de la rubrique
+ * @param array $infos
+ * Infos sur l'objet modifié : statut_ancien, objet, id_objet…
* @param bool $postdate
* true pour recalculer aussi la date du prochain article post-daté
* @return bool
* true si le statut change effectivement
**/
-function calculer_rubriques_if($id_rubrique, $modifs, $statut_ancien = '', $postdate = false) {
+function calculer_rubriques_if($id_rubrique, $modifs, $infos = array(), $postdate = false) {
$neuf = false;
- if ($statut_ancien == 'publie') {
+
+ // Compat avec l'ancienne signature
+ if (is_string($infos)) {
+ $infos = array('statut_ancien' => $infos);
+ }
+ if (!isset($infos['statut_ancien'])) {
+ $infos['statut_ancien'] = '';
+ }
+
+ // On recherche quels statuts tester
+ if (
+ isset($infos['objet'])
+ and include_spip('inc/filtres')
+ and $declaration_statut = objet_info($infos['objet'], 'statut')
+ and is_array($declaration_statut)
+ ) {
+ foreach ($declaration_statut as $champ_statut) {
+ if ($champ_statut['champ'] == 'statut') {
+ $statuts_publies = array_map('trim', explode(',', $champ_statut['publie']));
+ break; // stop on a trouvé le bon champ
+ }
+ }
+ }
+ else {
+ $statuts_publies = array('publie');
+ }
+
+ if (in_array($infos['statut_ancien'], $statuts_publies)) {
if (isset($modifs['statut'])
or isset($modifs['id_rubrique'])
or ($postdate and strtotime($postdate) > time())
} elseif (isset($modifs['id_rubrique'])) {
$neuf |= publier_branche_rubrique($modifs['id_rubrique']);
}
- } elseif (isset($modifs['statut']) and $modifs['statut'] == 'publie') {
+ } elseif (isset($modifs['statut']) and in_array($modifs['statut'], $statuts_publies)) {
if ($postdate) {
calculer_prochain_postdate(true);
$neuf |= (strtotime($postdate) <= time()); // par securite
}
if (($GLOBALS['test_i18n'] or (_request('var_mode') == 'traduction')) and is_null($options['class'])) {
- return "<span class=debug-traduction-erreur>$text</span>";
+ return "<span class='debug-traduction-erreur'>$text</span>";
} else {
return $text;
}
// ex : 2.0.0, 2.0.0-dev, 2.0.0-beta, 2.0.0-beta2
// le _SPIP_VERSION_ID est un nombre entier représentant le numéro de version (2 chiffres pour chaque 03 + 02 + 06 = 30206
// le _SPIP_EXTRA_VERSION sert à repérer les version dev, beta etc. Pour une version stable il est vide.
-$spip_version_branche = "3.2.11";
-define('_SPIP_VERSION_ID', 30211);
+$spip_version_branche = "3.2.12";
+define('_SPIP_VERSION_ID', 30212);
define('_SPIP_EXTRA_VERSION', '');
// cette version dev accepte tous les plugins compatible avec la version ci-dessous
// a supprimer en phase beta/rc/release
#define('_DEV_VERSION_SPIP_COMPAT',"3.1.3");
// version des signatures de fonctions PHP
-// (= numero SVN de leur derniere modif cassant la compatibilite et/ou necessitant un recalcul des squelettes)
-$spip_version_code = 22653;
+// (= date de leur derniere modif cassant la compatibilite et/ou necessitant un recalcul des squelettes)
+$spip_version_code = 20211021;
// version de la base SQL (= numero SVN de sa derniere modif)
-$spip_version_base = 23375;
+$spip_version_base = 24379;
// version de l'interface a la base
$spip_sql_version = 1;
* @return array|bool
*/
function inc_json_to_array_dist($u) {
- if (is_array($json = json_decode($u))
- or is_object($json)
- ) {
+ if (is_array($json = json_decode($u, true))) {
return (array)$json;
}
}
/**
* Ranger les images de local/cache-gd2 dans des sous-rep
- *
+ *
* http://core.spip.net/issues/3277
*/
function ranger_cache_gd2() {
$GLOBALS['maj'][23375] = array(
array('sql_alter', "TABLE spip_auteurs CHANGE prefs prefs text"),
);
+
+// adaptation des timestamp mysql
+$GLOBALS['maj'][24379] = [['maj_timestamp_mysql']];
+
+/**
+ * Mise à jour des bdd Mysql pour réparer les timestamp auto-update absents
+ *
+ * @uses base_lister_toutes_tables()
+ * @uses _mysql_remplacements_definitions_table()
+ **/
+function maj_timestamp_mysql($tables = null) {
+
+ include_spip('base/dump');
+ if (is_null($tables)) {
+ $tables = base_lister_toutes_tables();
+ } elseif (is_string($tables)) {
+ $tables = [$tables];
+ } elseif (!is_array($tables)) {
+ return;
+ }
+
+ // rien a faire si base non mysql
+ if (strncmp($GLOBALS['connexions'][0]['type'], 'mysql', 5) !== 0) {
+ return;
+ }
+
+ $trouver_table = charger_fonction('trouver_table', 'base');
+ // forcer le vidage de cache
+ $trouver_table('');
+
+ foreach ($tables as $table) {
+ if (time() >= _TIME_OUT) {
+ return;
+ }
+ if ($desc = $trouver_table($table)) {
+ $fields_corrected = _mysql_remplacements_definitions_table($desc['field']);
+ $d = array_diff($desc['field'], $fields_corrected);
+ if ($d) {
+ spip_log("Table $table TIMESTAMP incorrect", "maj");
+ foreach ($desc['field'] as $field => $type) {
+ if ($desc['field'][$field] !== $fields_corrected[$field]) {
+ spip_log("Adaptation TIMESTAMP table $table", "maj." . _LOG_INFO_IMPORTANTE);
+ sql_alter("table $table change $field $field " . $fields_corrected[$field]);
+ $trouver_table('');
+ $new_desc = $trouver_table($table);
+ spip_log("Apres conversion $table : " . var_export($new_desc['field'], true),
+ "maj." . _LOG_INFO_IMPORTANTE);
+ }
+ }
+ }
+ }
+ }
+
+ // forcer le vidage de cache
+ $trouver_table('');
+}
\ No newline at end of file
<paquet
prefix="spip"
categorie="outil"
- version="3.2.11"
+ version="3.2.12"
etat="stable"
compatibilite="];["
- schema="23375"
+ schema="24379"
documentation="https://www.spip.net"
demonstration="https://demo.spip.net"
developpement="https://core.spip.net/projects/spip/"
}
} else {
include_spip('inc/headers');
- http_status(403);
+ http_status(400);
$texte = _L('signature ajax bloc incorrecte');
}
ajax_retour($texte, false);
return false;
} // le hit peut continuer normalement
+ // verifier que le post est licite (du meme auteur ou d'une session anonyme)
+ $sign = _request('formulaire_action_sign');
+ if (!empty($GLOBALS['visiteur_session']['id_auteur'])) {
+ if (empty($sign)) {
+ spip_log("signature ajax form incorrecte : $form (formulaire non signe mais on a une session)", 'formulaires' . _LOG_ERREUR);
+ return false;
+ }
+ $securiser_action = charger_fonction('securiser_action', 'inc');
+ $secu = $securiser_action($form, $args, '', -1);
+ if ($sign !== $secu['hash']) {
+ spip_log("signature ajax form incorrecte : $form (formulaire signe mais ne correspond pas a la session)", 'formulaires' . _LOG_ERREUR);
+ return false;
+ }
+ }
+ else {
+ if (!empty($sign)) {
+ spip_log("signature ajax form incorrecte : $form (formulaire signe mais pas de session)", 'formulaires' . _LOG_ERREUR);
+ return false;
+ }
+ }
+
include_spip('inc/filtres');
if (($args = decoder_contexte_ajax($args, $form)) === false) {
- spip_log("signature ajax form incorrecte : $form");
+ spip_log("signature ajax form incorrecte : $form (encodage corrompu)", 'formulaires' . _LOG_ERREUR);
return false; // continuons le hit comme si de rien etait
} else {
value=\'' . $_form . '\' />' .
'<input name=\'formulaire_action_args\' type=\'hidden\'
value=\'' . @\$Pile[0]['formulaire_args']. '\' />' .
+ '<input name=\'formulaire_action_sign\' type=\'hidden\'
+ value=\'' . @\$Pile[0]['formulaire_sign']. '\' />' .
(!empty(\$Pile[0]['_hidden']) ? @\$Pile[0]['_hidden'] : '') .
'</div>'";
*/
public $iterateur = ''; // type d'iterateur
+ /**
+ * Index de la boucle dont le champ présent dans cette boucle est originaire,
+ * notamment si le champ a été trouve dans une boucle parente
+ *
+ * Tableau nom du champ => index de boucle
+ *
+ * @var array $index_champ
+ */
+ public $index_champ = [];
+
// obsoletes, conserves provisoirement pour compatibilite
public $tout = false;
public $plat = false;
// $GLOBALS['exceptions_des_jointures']['titre_mot'] = array('spip_mots', 'titre'); // pour exemple
$GLOBALS['exceptions_des_jointures']['profondeur'] = array('spip_rubriques', 'profondeur');
- define('_TRAITEMENT_TYPO', 'typo(%s, "TYPO", $connect, $Pile[0])');
- define('_TRAITEMENT_RACCOURCIS', 'propre(%s, $connect, $Pile[0])');
- define('_TRAITEMENT_TYPO_SANS_NUMERO', 'supprimer_numero(typo(%s), "TYPO", $connect, $Pile[0])');
- $GLOBALS['table_des_traitements']['BIO'][] = _TRAITEMENT_RACCOURCIS;
+ if (!defined('_TRAITEMENT_TYPO')) {
+ define('_TRAITEMENT_TYPO', 'typo(%s, "TYPO", $connect, $Pile[0])');
+ }
+ if (!defined('_TRAITEMENT_RACCOURCIS')) {
+ define('_TRAITEMENT_RACCOURCIS', 'propre(%s, $connect, $Pile[0])');
+ }
+ if (!defined('_TRAITEMENT_TYPO_SANS_NUMERO')) {
+ define('_TRAITEMENT_TYPO_SANS_NUMERO', 'supprimer_numero(typo(%s, "TYPO", $connect, $Pile[0]))');
+ }
+ $GLOBALS['table_des_traitements']['BIO'][] = 'safehtml('._TRAITEMENT_RACCOURCIS.')';
+ $GLOBALS['table_des_traitements']['NOM_SITE']['spip_auteurs'] = 'entites_html(%s)';
+ $GLOBALS['table_des_traitements']['NOM']['spip_auteurs'] = 'safehtml(%s)';
$GLOBALS['table_des_traitements']['CHAPO'][] = _TRAITEMENT_RACCOURCIS;
$GLOBALS['table_des_traitements']['DATE'][] = 'normaliser_date(%s)';
$GLOBALS['table_des_traitements']['DATE_REDAC'][] = 'normaliser_date(%s)';
$defaut = '@$Pile[0][\'' . strtolower($nom_champ) . '\']';
}
+ $idb_origine = $idb;
+ $nom_champ_origine = $nom_champ;
+
$i = 0;
if (strlen($explicite)) {
// Recherche d'un champ dans un etage superieur
if ($select and !in_array($t, $boucles[$idb]->select)) {
$boucles[$idb]->select[] = $t;
}
+ // renseigner la boucle source de ce champ pour les traitements
+ $boucles[$idb_origine]->index_champ[$nom_champ_origine] = $idb;
$champ = '$Pile[$SP' . ($i ? "-$i" : "") . '][\'' . $c . '\']';
if (!$joker) {
return index_compose($conditionnel, $champ);
if (is_array($ps)) {
// Recuperer le type de boucle (articles, DATA) et la table SQL sur laquelle elle porte
$idb = index_boucle($p);
+ // si le champ a ete trouve dans une boucle parente sa source est renseignee ici
+ if (!empty($p->boucles[$idb]->index_champ[$p->nom_champ])) {
+ $idb = $p->boucles[$idb]->index_champ[$p->nom_champ];
+ }
+
// mais on peut aussi etre hors boucle. Se mefier.
$type_requete = isset($p->boucles[$idb]->type_requete) ? $p->boucles[$idb]->type_requete : false;
$table_sql = isset($p->boucles[$idb]->show['table_sql']) ? $p->boucles[$idb]->show['table_sql'] : false;
// bien prendre en compte les alias de boucles (hierarchie => rubrique, syndication => syncdic, etc.)
if ($type_requete and isset($GLOBALS['table_des_tables'][$type_requete])) {
+ $type_alias = $type_requete;
$type_requete = $GLOBALS['table_des_tables'][$type_requete];
+ } else {
+ $type_alias = false;
}
// le traitement peut n'etre defini que pour une table en particulier "spip_articles"
} // ou pour une boucle en particulier "DATA","articles"
elseif ($type_requete and isset($ps[$type_requete])) {
$ps = $ps[$type_requete];
+ } // ou pour une boucle utilisant un alias ("hierarchie")
+ elseif ($type_alias and isset($ps[$type_alias])) {
+ $ps = $ps[$type_alias];
} // ou pour indifféremment quelle que soit la boucle
elseif (isset($ps[0])) {
$ps = $ps[0];
* @param string $query Requête à préparer
* @param string $db Nom de la base de donnée
* @param string $prefixe Préfixe de tables à appliquer
+ * @param bool $echappe_textes Pour ne pas essayer de re-echapper une chaine deja echappee qu'on traite en recursif
* @return string Requête préparée
*/
-function _mysql_traite_query($query, $db = '', $prefixe = '') {
+function _mysql_traite_query($query, $db = '', $prefixe = '', $echappe_textes = true) {
if ($GLOBALS['mysql_rappel_nom_base'] and $db) {
$pref = '`' . $db . '`.';
// propager le prefixe en cas de requete imbriquee
// il faut alors echapper les chaine avant de le faire, pour ne pas risquer de
// modifier une requete qui est en fait juste du texte dans un champ
- if (stripos($suite, "SELECT") !== false) {
- list($suite, $textes) = query_echappe_textes($suite);
- if (preg_match('/^(.*?)([(]\s*SELECT\b.*)$/si', $suite, $r)) {
- $suite = $r[1] . _mysql_traite_query($r[2], $db, $prefixe);
+ if (stripos($suite, 'SELECT') !== false) {
+ if ($echappe_textes) {
+ list($suite_echap, $textes) = query_echappe_textes($suite);
+ }
+ else {
+ $suite_echap = $suite;
+ }
+ if (preg_match('/^(.*?)([(]\s*SELECT\b.*)$/si', $suite_echap, $r)) {
+ $suite_echap = $r[1] . _mysql_traite_query($r[2], $db, $prefixe, false);
+ if ($echappe_textes) {
+ $suite = query_reinjecte_textes($suite_echap, $textes);
+ }
+ else {
+ $suite = $suite_echap;
+ }
}
- $suite = query_reinjecte_textes($suite, $textes);
}
}
$r = preg_replace(_SQL_PREFIXE_TABLE_MYSQL, '\1' . $pref, $query) . $suite;
/**
* Adapte pour Mysql la déclaration SQL d'une colonne d'une table
*
- * @param string $query
- * Définition SQL d'un champ de table
- * @return string
+ * @param string|array $query
+ * Définition SQL d'un champ de table ou liste de déclarations
+ * @return string|array
* Définition SQL adaptée pour MySQL d'un champ de table
*/
function _mysql_remplacements_definitions_table($query) {
$remplace = array(
'/VARCHAR(\s*[^\s\(])/is' => 'VARCHAR(255)\\1',
+ '/^TIMESTAMP($| NULL DEFAULT NULL)/is' => 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP',
);
- $query = preg_replace(array_keys($remplace), $remplace, $query);
+ if (is_string($query)) {
+ $query = preg_replace(array_keys($remplace), $remplace, $query);
+ } elseif (is_array($query)) {
+ $keys = array_keys($remplace);
+ foreach ($query as $k => $q) {
+ $query[$k] = preg_replace($keys, $remplace, $q);
+ }
+ }
return $query;
}
/**
- * $query est une requete ou une liste de champs
+ * Adapte les déclarations des champs pour SQLite
*
- * @param $query
+ * @param string|array $query Déclaration d’un champ ou liste de déclarations de champs
* @param bool $autoinc
* @return mixed
*/
'/COLLATE \w+_bin/is' => 'COLLATE BINARY',
'/COLLATE \w+_ci/is' => 'COLLATE NOCASE',
'/auto_increment/is' => '',
+ '/current_timestamp\(\)/is' => 'CURRENT_TIMESTAMP', // Fix export depuis mariaDB #4374
'/(timestamp .* )ON .*$/is' => '\\1',
'/character set \w+/is' => '',
'/((big|small|medium|tiny)?int(eger)?)' . $num . '\s*unsigned/is' => '\\1 UNSIGNED',
{
"aide": {
"path": "plugins-dist/aide",
- "source": "https://git.spip.net/spip/aide.git"
+ "source": "https://git.spip.net/spip/aide.git",
+ "branch": "spip-3.2"
},
"archiviste": {
"path": "plugins-dist/archiviste",
- "source": "https://git.spip.net/spip/archiviste.git"
+ "source": "https://git.spip.net/spip/archiviste.git",
+ "branch": "spip-3.2"
},
"breves": {
"path": "plugins-dist/breves",
- "source": "https://git.spip.net/spip/breves.git"
+ "source": "https://git.spip.net/spip/breves.git",
+ "branch": "spip-3.2"
},
"compagnon": {
"path": "plugins-dist/compagnon",
- "source": "https://git.spip.net/spip/compagnon.git"
+ "source": "https://git.spip.net/spip/compagnon.git",
+ "branch": "spip-3.2"
},
"compresseur": {
"path": "plugins-dist/compresseur",
- "source": "https://git.spip.net/spip/compresseur.git"
+ "source": "https://git.spip.net/spip/compresseur.git",
+ "branch": "spip-3.2"
},
"dump": {
"path": "plugins-dist/dump",
- "source": "https://git.spip.net/spip/dump.git"
+ "source": "https://git.spip.net/spip/dump.git",
+ "branch": "spip-3.2"
},
"filtres_images": {
"path": "plugins-dist/filtres_images",
- "source": "https://git.spip.net/spip/filtres_images.git"
+ "source": "https://git.spip.net/spip/filtres_images.git",
+ "branch": "spip-3.2"
},
"forum": {
"path": "plugins-dist/forum",
- "source": "https://git.spip.net/spip/forum.git"
+ "source": "https://git.spip.net/spip/forum.git",
+ "branch": "spip-3.2"
},
"jquery_ui": {
"path": "plugins-dist/jquery_ui",
- "source": "https://git.spip.net/spip/jquery_ui.git"
+ "source": "https://git.spip.net/spip/jquery_ui.git",
+ "branch": "spip-3.2"
},
"mediabox": {
"path": "plugins-dist/mediabox",
- "source": "https://git.spip.net/spip/mediabox.git"
+ "source": "https://git.spip.net/spip/mediabox.git",
+ "branch": "spip-3.2"
},
"medias": {
"path": "plugins-dist/medias",
- "source": "https://git.spip.net/spip/medias.git"
+ "source": "https://git.spip.net/spip/medias.git",
+ "branch": "spip-3.2"
},
"mots": {
"path": "plugins-dist/mots",
- "source": "https://git.spip.net/spip/mots.git"
+ "source": "https://git.spip.net/spip/mots.git",
+ "branch": "spip-3.2"
},
"organiseur": {
"path": "plugins-dist/organiseur",
- "source": "https://git.spip.net/spip/organiseur.git"
+ "source": "https://git.spip.net/spip/organiseur.git",
+ "branch": "spip-3.2"
},
"petitions": {
"path": "plugins-dist/petitions",
- "source": "https://git.spip.net/spip/petitions.git"
+ "source": "https://git.spip.net/spip/petitions.git",
+ "branch": "spip-3.2"
},
"plan": {
"path": "plugins-dist/plan",
- "source": "https://git.spip.net/spip/plan.git"
+ "source": "https://git.spip.net/spip/plan.git",
+ "branch": "spip-3.2"
},
"porte_plume": {
"path": "plugins-dist/porte_plume",
- "source": "https://git.spip.net/spip/porte_plume.git"
+ "source": "https://git.spip.net/spip/porte_plume.git",
+ "branch": "spip-3.2"
},
"revisions": {
"path": "plugins-dist/revisions",
- "source": "https://git.spip.net/spip/revisions.git"
+ "source": "https://git.spip.net/spip/revisions.git",
+ "branch": "spip-3.2"
},
"safehtml": {
"path": "plugins-dist/safehtml",
- "source": "https://git.spip.net/spip/safehtml.git"
+ "source": "https://git.spip.net/spip/safehtml.git",
+ "branch": "spip-3.2"
},
"sites": {
"path": "plugins-dist/sites",
- "source": "https://git.spip.net/spip/sites.git"
+ "source": "https://git.spip.net/spip/sites.git",
+ "branch": "spip-3.2"
},
"squelettes_par_rubrique": {
"path": "plugins-dist/squelettes_par_rubrique",
- "source": "https://git.spip.net/spip/squelettes_par_rubrique.git"
+ "source": "https://git.spip.net/spip/squelettes_par_rubrique.git",
+ "branch": "spip-3.2"
},
"statistiques": {
"path": "plugins-dist/statistiques",
- "source": "https://git.spip.net/spip/statistiques.git"
+ "source": "https://git.spip.net/spip/statistiques.git",
+ "branch": "spip-3.2"
},
"svp": {
"path": "plugins-dist/svp",
- "source": "https://git.spip.net/spip/svp.git"
+ "source": "https://git.spip.net/spip/svp.git",
+ "branch": "spip-3.2"
},
"textwheel": {
"path": "plugins-dist/textwheel",
- "source": "https://git.spip.net/spip/textwheel.git"
+ "source": "https://git.spip.net/spip/textwheel.git",
+ "branch": "spip-3.2"
},
"urls_etendues": {
"path": "plugins-dist/urls_etendues",
- "source": "https://git.spip.net/spip/urls_etendues.git"
+ "source": "https://git.spip.net/spip/urls_etendues.git",
+ "branch": "spip-3.2"
},
"vertebres": {
"path": "plugins-dist/vertebres",
- "source": "https://git.spip.net/spip/vertebres.git"
+ "source": "https://git.spip.net/spip/vertebres.git",
+ "branch": "spip-3.2"
},
"dist": {
"path": "squelettes-dist",
- "source": "https://git.spip.net/spip/dist.git"
+ "source": "https://git.spip.net/spip/dist.git",
+ "branch": "spip-3.2"
}
}
\ No newline at end of file
<paquet
prefix="aide"
categorie="divers"
- version="1.0.0"
+ version="1.0.1"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="aide_logo-32.png"
<paquet
prefix="archiviste"
categorie="outil"
- version="0.2.2"
+ version="0.2.3"
etat="dev"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/archiviste-64.png"
<paquet
prefix="breves"
categorie="edition"
- version="1.4.1"
+ version="1.4.2"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/breve-32.png"
<paquet
prefix="compagnon"
categorie="divers"
- version="1.6.1"
+ version="1.6.2"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/compagnon-32.png"
return preg_replace_callback(
",url\s*\(\s*['\"]?([^'\"/][^:]*[.](png|gif|jpg))['\"]?\s*\),Uims",
function($x) use ($filtre_embarque_fichier, $base) {
- return "url(\"" . $filtre_embarque_fichier($x[1], $base, _CSS_EMBARQUE_FICHIER_MAX_SIZE) . "\");";
+ return "url(\"" . $filtre_embarque_fichier($x[1], $base, _CSS_EMBARQUE_FICHIER_MAX_SIZE) . "\")";
},
$contenu
);
<paquet
prefix="compresseur"
categorie="performance"
- version="1.12.10"
+ version="1.12.11"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="images/compresseur-32.png"
<paquet
prefix="dump"
categorie="maintenance"
- version="1.8.5"
+ version="1.8.6"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/base-backup-32.png"
* @return string
*/
function image_typo() {
+ include_spip('inc/filtres_images_mini.php');
include_spip('filtres/images_typo');
$tous = func_get_args();
return call_user_func_array('produire_image_typo', $tous);
<paquet
prefix="images"
categorie="multimedia"
- version="2.0.3"
+ version="2.0.4"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="images/image_filtre-32.png"
<paquet
prefix="forum"
categorie="communication"
- version="1.11.7"
+ version="1.11.8"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/forum-32.png"
<paquet
prefix="jqueryui"
categorie="outil"
- version="1.12.1"
+ version="1.12.2"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="images/jqueryui-128.png"
// Si c'est une image, on la chargera avec une redimentionnement automatique
// Sinon, chargement dans une iframe
$extension = pathinfo($config['splash_url'], PATHINFO_EXTENSION);
- if (match($extension, 'gif|png|jpg|jpeg')) {
+ if (in_array($extension, array('gif', 'png', 'jpg', 'jpeg'))) {
$configmediabox .= 'var box_settings_iframe = false;' . "\n";
} else {
$configmediabox .= 'var box_settings_splash_width = "' . mediabox_quote_js_param($config['splash_width']) . '";
<paquet
prefix="mediabox"
categorie="multimedia"
- version="1.1.5"
+ version="1.1.6"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/mediabox-32.png"
// si la source est bien un fichier distant
// sinon c'est une donnee moisie, on ne fait rien
- if (tester_url_absolue($source)) {
- include_spip('inc/distant'); // pour 'copie_locale'
+ include_spip('inc/distant');
+ if (tester_url_absolue($source)
+ and valider_url_distante($source)) {
$fichier = copie_locale($source);
- if ($fichier
- and tester_url_absolue($source)) {
+ if (
+ $fichier
+ and valider_url_distante($source)
+ ) {
$fichier = _DIR_RACINE . $fichier;
$files = array();
$files[] = array('tmp_name' => $fichier, 'name' => basename($fichier));
return true;
} else {
spip_log("echec copie locale $source", 'medias' . _LOG_ERREUR);
+ if ($fichier) {
+ @unlink(_DIR_RACINE . $fichier);
+ }
}
} else {
spip_log("echec copie locale $source n'est pas une URL distante", 'medias' . _LOG_ERREUR);
<paquet
prefix="medias"
categorie="multimedia"
- version="2.20.35"
+ version="2.20.36"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/portfolio-32.png"
<paquet
prefix="mots"
categorie="edition"
- version="2.8.9"
+ version="2.8.10"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/mot-32.png"
<ul class='liste-items'>
<BOUCLE_nav(GROUPES_MOTS){par num titre}{par multi titre}>[(#AUTORISER{voir,groupemots,#ID_GROUPE}|oui)
<li class="item"><a href='#groupe_mots-#ID_GROUPE'
- onclick='$(".groupe_mots").hide().filter("#groupe_mots-#ID_GROUPE").show();$(this).parent().addClass("on").siblings().removeClass("on").parent().siblings("a.tous").show();return false;'
+ onclick='$(".groupe_mots").hide().filter("#groupe_mots-#ID_GROUPE").show();$(this).parent().addClass("on").siblings().removeClass("on").parent().siblings("a.tous").show();'
>[(#RANG). ]#TITRE</a></li>
]</BOUCLE_nav>
</ul>
<paquet
prefix="organiseur"
categorie="date"
- version="1.2.5"
+ version="1.2.6"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/calendrier-32.png"
<paquet
prefix="petitions"
categorie="communication"
- version="1.6.1"
+ version="1.6.2"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/petition-32.png"
<paquet
prefix="plan"
categorie="navigation"
- version="2.2.5"
+ version="2.2.6"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/plan-64.png"
<paquet
prefix="porte_plume"
categorie="edition"
- version="1.18.4"
+ version="1.18.5"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="images/porte-plume-32.png"
* @return string Contenu du head complété
*/
function porte_plume_inserer_head($flux, $lang, $prive = false) {
+ include_spip('porte_plume_fonctions');
+
$markitup = timestamp(find_in_path('javascript/jquery.markitup_pour_spip.js'));
$js_previsu = timestamp(find_in_path('javascript/jquery.previsu_spip.js'));
}
$css = timestamp(direction_css(find_in_path('css/barre_outils.css'), lang_dir()));
+ include_spip('porte_plume_fonctions');
$hash = md5(barre_outils_css_icones());
$css_icones = produire_fond_statique('css/barre_outils_icones.css', array('hash' => $hash));
<paquet
prefix="revisions"
categorie="edition"
- version="1.9.4"
+ version="1.9.5"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/revision-32.png"
-<?php\r
-// +----------------------------------------------------------------------+\r
-// | Copyright (c) 1997-2002 The PHP Group |\r
-// +----------------------------------------------------------------------+\r
-// | This source file is subject to version 2.02 of the PHP license, |\r
-// | that is bundled with this package in the file LICENSE, and is |\r
-// | available at through the world-wide-web at |\r
-// | http://www.php.net/license/3_0.txt. |\r
-// | If you did not receive a copy of the PHP license and are unable to |\r
-// | obtain it through the world-wide-web, please send a note to |\r
-// | license@php.net so we can mail you a copy immediately. |\r
-// +----------------------------------------------------------------------+\r
-// | Authors: Alexander Zhukov <alex@veresk.ru> Original port from Python |\r
-// | Authors: Harry Fuecks <hfuecks@phppatterns.com> Port to PEAR + more |\r
-// | Authors: Many @ Sitepointforums Advanced PHP Forums |\r
-// +----------------------------------------------------------------------+\r
-//\r
-\r
-if (!defined('_ECRIRE_INC_VERSION')) return;\r
-\r
-if (!defined('XML_HTMLSAX3')) {\r
- define('XML_HTMLSAX3', 'XML/');\r
-}\r
-require_once(XML_HTMLSAX3 . 'HTMLSax3/States.php');\r
-require_once(XML_HTMLSAX3 . 'HTMLSax3/Decorators.php');\r
-\r
-class XML_HTMLSax3_StateParser {\r
- var $htmlsax;\r
- var $handler_object_element;\r
- var $handler_method_opening;\r
- var $handler_method_closing;\r
- var $handler_object_data;\r
- var $handler_method_data;\r
- var $handler_object_pi;\r
- var $handler_method_pi;\r
- var $handler_object_jasp;\r
- var $handler_method_jasp;\r
- var $handler_object_escape;\r
- var $handler_method_escape;\r
- var $handler_default;\r
- var $parser_options = array();\r
- var $rawtext;\r
- var $position;\r
- var $length;\r
- var $State = array();\r
-\r
- function __construct(& $htmlsax) {\r
- $this->htmlsax = & $htmlsax;\r
-\r
- $this->State[XML_HTMLSAX3_STATE_START] = new XML_HTMLSax3_StartingState();\r
-\r
- $this->State[XML_HTMLSAX3_STATE_CLOSING_TAG] = new XML_HTMLSax3_ClosingTagState();\r
- $this->State[XML_HTMLSAX3_STATE_TAG] = new XML_HTMLSax3_TagState();\r
- $this->State[XML_HTMLSAX3_STATE_OPENING_TAG] = new XML_HTMLSax3_OpeningTagState();\r
-\r
- $this->State[XML_HTMLSAX3_STATE_PI] = new XML_HTMLSax3_PiState();\r
- $this->State[XML_HTMLSAX3_STATE_JASP] = new XML_HTMLSax3_JaspState();\r
- $this->State[XML_HTMLSAX3_STATE_ESCAPE] = new XML_HTMLSax3_EscapeState();\r
- }\r
-\r
- function unscanCharacter() {\r
- $this->position -= 1;\r
- }\r
-\r
- function ignoreCharacter() {\r
- $this->position += 1;\r
- }\r
-\r
- function scanCharacter() {\r
- if ($this->position < $this->length) {\r
- return $this->rawtext[$this->position++];\r
- }\r
- }\r
-\r
- function scanUntilString($string) {\r
- $start = $this->position;\r
- $this->position = strpos($this->rawtext, $string, $start);\r
- if ($this->position === FALSE) {\r
- $this->position = $this->length;\r
- }\r
- return substr($this->rawtext, $start, $this->position - $start);\r
- }\r
-\r
- function scanUntilCharacters($string) {}\r
-\r
- function ignoreWhitespace() {}\r
-\r
- function parse($data) {\r
- if ($this->parser_options['XML_OPTION_TRIM_DATA_NODES']==1) {\r
- $decorator = new XML_HTMLSax3_Trim(\r
- $this->handler_object_data,\r
- $this->handler_method_data);\r
- $this->handler_object_data =& $decorator;\r
- $this->handler_method_data = 'trimData';\r
- }\r
- if ($this->parser_options['XML_OPTION_CASE_FOLDING']==1) {\r
- $open_decor = new XML_HTMLSax3_CaseFolding(\r
- $this->handler_object_element,\r
- $this->handler_method_opening,\r
- $this->handler_method_closing);\r
- $this->handler_object_element =& $open_decor;\r
- $this->handler_method_opening ='foldOpen';\r
- $this->handler_method_closing ='foldClose';\r
- }\r
- if ($this->parser_options['XML_OPTION_LINEFEED_BREAK']==1) {\r
- $decorator = new XML_HTMLSax3_Linefeed(\r
- $this->handler_object_data,\r
- $this->handler_method_data);\r
- $this->handler_object_data =& $decorator;\r
- $this->handler_method_data = 'breakData';\r
- }\r
- if ($this->parser_options['XML_OPTION_TAB_BREAK']==1) {\r
- $decorator = new XML_HTMLSax3_Tab(\r
- $this->handler_object_data,\r
- $this->handler_method_data);\r
- $this->handler_object_data =& $decorator;\r
- $this->handler_method_data = 'breakData';\r
- }\r
- if ($this->parser_options['XML_OPTION_ENTITIES_UNPARSED']==1) {\r
- $decorator = new XML_HTMLSax3_Entities_Unparsed(\r
- $this->handler_object_data,\r
- $this->handler_method_data);\r
- $this->handler_object_data =& $decorator;\r
- $this->handler_method_data = 'breakData';\r
- }\r
- if ($this->parser_options['XML_OPTION_ENTITIES_PARSED']==1) {\r
- $decorator = new XML_HTMLSax3_Entities_Parsed(\r
- $this->handler_object_data,\r
- $this->handler_method_data);\r
- $this->handler_object_data =& $decorator;\r
- $this->handler_method_data = 'breakData';\r
- }\r
- // Note switched on by default\r
- if ($this->parser_options['XML_OPTION_STRIP_ESCAPES']==1) {\r
- $decorator = new XML_HTMLSax3_Escape_Stripper(\r
- $this->handler_object_escape,\r
- $this->handler_method_escape);\r
- $this->handler_object_escape =& $decorator;\r
- $this->handler_method_escape = 'strip';\r
- }\r
- $this->rawtext = $data;\r
- $this->length = strlen($data);\r
- $this->position = 0;\r
- $this->_parse();\r
- }\r
-\r
- function _parse($state = XML_HTMLSAX3_STATE_START) {\r
- do {\r
- $state = $this->State[$state]->parse($this);\r
- } while ($state != XML_HTMLSAX3_STATE_STOP &&\r
- $this->position < $this->length);\r
- }\r
-}\r
-\r
-class XML_HTMLSax3_StateParser_Lt430 extends XML_HTMLSax3_StateParser {\r
- function __construct(& $htmlsax) {\r
- parent::__construct($htmlsax);\r
- $this->parser_options['XML_OPTION_TRIM_DATA_NODES'] = 0;\r
- $this->parser_options['XML_OPTION_CASE_FOLDING'] = 0;\r
- $this->parser_options['XML_OPTION_LINEFEED_BREAK'] = 0;\r
- $this->parser_options['XML_OPTION_TAB_BREAK'] = 0;\r
- $this->parser_options['XML_OPTION_ENTITIES_PARSED'] = 0;\r
- $this->parser_options['XML_OPTION_ENTITIES_UNPARSED'] = 0;\r
- $this->parser_options['XML_OPTION_STRIP_ESCAPES'] = 0;\r
- }\r
-\r
- function scanUntilCharacters($string) {\r
- $startpos = $this->position;\r
- while ($this->position < $this->length && strpos($string, $this->rawtext[$this->position]) === FALSE) {\r
- $this->position++;\r
- }\r
- return substr($this->rawtext, $startpos, $this->position - $startpos);\r
- }\r
-\r
- function ignoreWhitespace() {\r
- while ($this->position < $this->length && \r
- strpos(" \n\r\t", $this->rawtext[$this->position]) !== FALSE) {\r
- $this->position++;\r
- }\r
- }\r
-\r
- function parse($data) {\r
- parent::parse($data);\r
- }\r
-}\r
-\r
-class XML_HTMLSax3_StateParser_Gtet430 extends XML_HTMLSax3_StateParser {\r
- function __construct(& $htmlsax) {\r
- parent::__construct($htmlsax);\r
- $this->parser_options['XML_OPTION_TRIM_DATA_NODES'] = 0;\r
- $this->parser_options['XML_OPTION_CASE_FOLDING'] = 0;\r
- $this->parser_options['XML_OPTION_LINEFEED_BREAK'] = 0;\r
- $this->parser_options['XML_OPTION_TAB_BREAK'] = 0;\r
- $this->parser_options['XML_OPTION_ENTITIES_PARSED'] = 0;\r
- $this->parser_options['XML_OPTION_ENTITIES_UNPARSED'] = 0;\r
- $this->parser_options['XML_OPTION_STRIP_ESCAPES'] = 0;\r
- }\r
- function scanUntilCharacters($string) {\r
- $startpos = $this->position;\r
- $length = strcspn($this->rawtext, $string, $startpos);\r
- $this->position += $length;\r
- return substr($this->rawtext, $startpos, $length);\r
- }\r
-\r
- function ignoreWhitespace() {\r
- $this->position += strspn($this->rawtext, " \n\r\t", $this->position);\r
- }\r
-\r
- function parse($data) {\r
- parent::parse($data);\r
- }\r
-}\r
-\r
-class XML_HTMLSax3_NullHandler {\r
- function DoNothing() {\r
- }\r
-}\r
-\r
-class XML_HTMLSax3 {\r
- var $state_parser;\r
-\r
- function __construct() {\r
- if (version_compare(phpversion(), '4.3', 'ge')) {\r
- $this->state_parser = new XML_HTMLSax3_StateParser_Gtet430($this);\r
- } else {\r
- $this->state_parser = new XML_HTMLSax3_StateParser_Lt430($this);\r
- }\r
- $nullhandler = new XML_HTMLSax3_NullHandler();\r
- $this->set_object($nullhandler);\r
- $this->set_element_handler('DoNothing', 'DoNothing');\r
- $this->set_data_handler('DoNothing');\r
- $this->set_pi_handler('DoNothing');\r
- $this->set_jasp_handler('DoNothing');\r
- $this->set_escape_handler('DoNothing');\r
- }\r
-\r
- function set_object(&$object) {\r
- if ( is_object($object) ) {\r
- $this->state_parser->handler_default =& $object;\r
- return true;\r
- } else {\r
- require_once('PEAR.php');\r
- PEAR::raiseError('XML_HTMLSax3::set_object requires '.\r
- 'an object instance');\r
- }\r
- }\r
-\r
- function set_option($name, $value = 1) {\r
- if ( array_key_exists($name,$this->state_parser->parser_options) ) {\r
- $this->state_parser->parser_options[$name] = $value;\r
- return true;\r
- } else {\r
- require_once('PEAR.php');\r
- PEAR::raiseError('XML_HTMLSax3::set_option('.$name.') illegal');\r
- }\r
- }\r
-\r
- function set_data_handler($data_method) {\r
- $this->state_parser->handler_object_data =& $this->state_parser->handler_default;\r
- $this->state_parser->handler_method_data = $data_method;\r
- }\r
-\r
- function set_element_handler($opening_method, $closing_method) {\r
- $this->state_parser->handler_object_element =& $this->state_parser->handler_default;\r
- $this->state_parser->handler_method_opening = $opening_method;\r
- $this->state_parser->handler_method_closing = $closing_method;\r
- }\r
-\r
- function set_pi_handler($pi_method) {\r
- $this->state_parser->handler_object_pi =& $this->state_parser->handler_default;\r
- $this->state_parser->handler_method_pi = $pi_method;\r
- }\r
-\r
- function set_escape_handler($escape_method) {\r
- $this->state_parser->handler_object_escape =& $this->state_parser->handler_default;\r
- $this->state_parser->handler_method_escape = $escape_method;\r
- }\r
-\r
- function set_jasp_handler ($jasp_method) {\r
- $this->state_parser->handler_object_jasp =& $this->state_parser->handler_default;\r
- $this->state_parser->handler_method_jasp = $jasp_method;\r
- }\r
-\r
- function get_current_position() {\r
- return $this->state_parser->position;\r
- }\r
-\r
- function get_length() {\r
- return $this->state_parser->length;\r
- }\r
-\r
- function parse($data) {\r
- $this->state_parser->parse($data);\r
- }\r
-}\r
-?>\r
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+//
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2002 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject toversion 3.0 of the PHP license, |
+// | that is bundled with this package in the file LICENSE, and is |
+// | available at through the world-wide-web at |
+// | http://www.php.net/license/3_0.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Authors: Alexander Zhukov <alex@veresk.ru> Original port from Python |
+// | Authors: Harry Fuecks <hfuecks@phppatterns.com> Port to PEAR + more |
+// | Authors: Many @ Sitepointforums Advanced PHP Forums |
+// +----------------------------------------------------------------------+
+//
+// $Id: HTMLSax3.php,v 1.2 2007/10/29 21:41:34 hfuecks Exp $
+//
+/**
+ * Main parser components
+ * @package XML_HTMLSax3
+ * @version $Id: HTMLSax3.php,v 1.2 2007/10/29 21:41:34 hfuecks Exp $
+ */
+/**
+ * Required classes
+ */
+if (!defined('XML_HTMLSAX3')) {
+ define('XML_HTMLSAX3', 'XML/');
+}
+require_once(XML_HTMLSAX3 . 'HTMLSax3/States.php');
+require_once(XML_HTMLSAX3 . 'HTMLSax3/Decorators.php');
+
+/**
+ * Base State Parser
+ * @package XML_HTMLSax3
+ * @access protected
+ * @abstract
+ */
+class XML_HTMLSax3_StateParser {
+ /**
+ * Instance of user front end class to be passed to callbacks
+ * @var XML_HTMLSax3
+ * @access private
+ */
+ var $htmlsax;
+ /**
+ * User defined object for handling elements
+ * @var object
+ * @access private
+ */
+ var $handler_object_element;
+ /**
+ * User defined open tag handler method
+ * @var string
+ * @access private
+ */
+ var $handler_method_opening;
+ /**
+ * User defined close tag handler method
+ * @var string
+ * @access private
+ */
+ var $handler_method_closing;
+ /**
+ * User defined object for handling data in elements
+ * @var object
+ * @access private
+ */
+ var $handler_object_data;
+ /**
+ * User defined data handler method
+ * @var string
+ * @access private
+ */
+ var $handler_method_data;
+ /**
+ * User defined object for handling processing instructions
+ * @var object
+ * @access private
+ */
+ var $handler_object_pi;
+ /**
+ * User defined processing instruction handler method
+ * @var string
+ * @access private
+ */
+ var $handler_method_pi;
+ /**
+ * User defined object for handling JSP/ASP tags
+ * @var object
+ * @access private
+ */
+ var $handler_object_jasp;
+ /**
+ * User defined JSP/ASP handler method
+ * @var string
+ * @access private
+ */
+ var $handler_method_jasp;
+ /**
+ * User defined object for handling XML escapes
+ * @var object
+ * @access private
+ */
+ var $handler_object_escape;
+ /**
+ * User defined XML escape handler method
+ * @var string
+ * @access private
+ */
+ var $handler_method_escape;
+ /**
+ * User defined handler object or NullHandler
+ * @var object
+ * @access private
+ */
+ var $handler_default;
+ /**
+ * Parser options determining parsing behavior
+ * @var array
+ * @access private
+ */
+ var $parser_options = [];
+ /**
+ * XML document being parsed
+ * @var string
+ * @access private
+ */
+ var $rawtext;
+ /**
+ * Position in XML document relative to start (0)
+ * @var int
+ * @access private
+ */
+ var $position;
+ /**
+ * Length of the XML document in characters
+ * @var int
+ * @access private
+ */
+ var $length;
+ /**
+ * Array of state objects
+ * @var array
+ * @access private
+ */
+ var $State = [];
+
+ /**
+ * Constructs XML_HTMLSax3_StateParser setting up states
+ * @var XML_HTMLSax3 instance of user front end class
+ * @access protected
+ */
+ function __construct (& $htmlsax) {
+ $this->htmlsax = & $htmlsax;
+ $this->State[XML_HTMLSAX3_STATE_START] = new XML_HTMLSax3_StartingState();
+
+ $this->State[XML_HTMLSAX3_STATE_CLOSING_TAG] = new XML_HTMLSax3_ClosingTagState();
+ $this->State[XML_HTMLSAX3_STATE_TAG] = new XML_HTMLSax3_TagState();
+ $this->State[XML_HTMLSAX3_STATE_OPENING_TAG] = new XML_HTMLSax3_OpeningTagState();
+
+ $this->State[XML_HTMLSAX3_STATE_PI] = new XML_HTMLSax3_PiState();
+ $this->State[XML_HTMLSAX3_STATE_JASP] = new XML_HTMLSax3_JaspState();
+ $this->State[XML_HTMLSAX3_STATE_ESCAPE] = new XML_HTMLSax3_EscapeState();
+ }
+
+ /**
+ * Moves the position back one character
+ * @access protected
+ * @return void
+ */
+ function unscanCharacter() {
+ $this->position -= 1;
+ }
+
+ /**
+ * Moves the position forward one character
+ * @access protected
+ * @return void
+ */
+ function ignoreCharacter() {
+ $this->position += 1;
+ }
+
+ /**
+ * Returns the next character from the XML document or void if at end
+ * @access protected
+ * @return mixed
+ */
+ function scanCharacter() {
+ if ($this->position < $this->length) {
+ return $this->rawtext[$this->position++];
+ }
+ }
+
+ /**
+ * Returns a string from the current position to the next occurance
+ * of the supplied string
+ * @param string string to search until
+ * @access protected
+ * @return string
+ */
+ function scanUntilString($string) {
+ $start = $this->position;
+ $this->position = strpos($this->rawtext, $string, $start);
+ if ($this->position === FALSE) {
+ $this->position = $this->length;
+ }
+ return substr($this->rawtext, $start, $this->position - $start);
+ }
+
+ /**
+ * Returns a string from the current position until the first instance of
+ * one of the characters in the supplied string argument
+ * @param string string to search until
+ * @access protected
+ * @return string
+ * @abstract
+ */
+ function scanUntilCharacters($string) {}
+
+ /**
+ * Moves the position forward past any whitespace characters
+ * @access protected
+ * @return void
+ * @abstract
+ */
+ function ignoreWhitespace() {}
+
+ /**
+ * Begins the parsing operation, setting up any decorators, depending on
+ * parse options invoking _parse() to execute parsing
+ * @param string XML document to parse
+ * @access protected
+ * @return void
+ */
+ function parse($data) {
+ if ($this->parser_options['XML_OPTION_TRIM_DATA_NODES']==1) {
+ $decorator = new XML_HTMLSax3_Trim(
+ $this->handler_object_data,
+ $this->handler_method_data);
+ $this->handler_object_data =& $decorator;
+ $this->handler_method_data = 'trimData';
+ }
+ if ($this->parser_options['XML_OPTION_CASE_FOLDING']==1) {
+ $open_decor = new XML_HTMLSax3_CaseFolding(
+ $this->handler_object_element,
+ $this->handler_method_opening,
+ $this->handler_method_closing);
+ $this->handler_object_element =& $open_decor;
+ $this->handler_method_opening ='foldOpen';
+ $this->handler_method_closing ='foldClose';
+ }
+ if ($this->parser_options['XML_OPTION_LINEFEED_BREAK']==1) {
+ $decorator = new XML_HTMLSax3_Linefeed(
+ $this->handler_object_data,
+ $this->handler_method_data);
+ $this->handler_object_data =& $decorator;
+ $this->handler_method_data = 'breakData';
+ }
+ if ($this->parser_options['XML_OPTION_TAB_BREAK']==1) {
+ $decorator = new XML_HTMLSax3_Tab(
+ $this->handler_object_data,
+ $this->handler_method_data);
+ $this->handler_object_data =& $decorator;
+ $this->handler_method_data = 'breakData';
+ }
+ if ($this->parser_options['XML_OPTION_ENTITIES_UNPARSED']==1) {
+ $decorator = new XML_HTMLSax3_Entities_Unparsed(
+ $this->handler_object_data,
+ $this->handler_method_data);
+ $this->handler_object_data =& $decorator;
+ $this->handler_method_data = 'breakData';
+ }
+ if ($this->parser_options['XML_OPTION_ENTITIES_PARSED']==1) {
+ $decorator = new XML_HTMLSax3_Entities_Parsed(
+ $this->handler_object_data,
+ $this->handler_method_data);
+ $this->handler_object_data =& $decorator;
+ $this->handler_method_data = 'breakData';
+ }
+ // Note switched on by default
+ if ($this->parser_options['XML_OPTION_STRIP_ESCAPES']==1) {
+ $decorator = new XML_HTMLSax3_Escape_Stripper(
+ $this->handler_object_escape,
+ $this->handler_method_escape);
+ $this->handler_object_escape =& $decorator;
+ $this->handler_method_escape = 'strip';
+ }
+ $this->rawtext = $data;
+ $this->length = strlen($data);
+ $this->position = 0;
+ $this->_parse();
+ }
+
+ /**
+ * Performs the parsing itself, delegating calls to a specific parser
+ * state
+ * @param constant state object to parse with
+ * @access protected
+ * @return void
+ */
+ function _parse($state = XML_HTMLSAX3_STATE_START) {
+ do {
+ $state = $this->State[$state]->parse($this);
+ } while ($state != XML_HTMLSAX3_STATE_STOP &&
+ $this->position < $this->length);
+ }
+}
+
+/**
+ * Parser for PHP Versions equal to or greater than 4.3.0. Uses a faster
+ * parsing mechanism than the equivalent PHP < 4.3.0 subclass of StateParser
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_StateParser_Gtet430 extends XML_HTMLSax3_StateParser {
+ /**
+ * Constructs XML_HTMLSax3_StateParser_Gtet430 defining available
+ * parser options
+ * @var XML_HTMLSax3 instance of user front end class
+ * @access protected
+ */
+ function __construct(& $htmlsax) {
+ parent::__construct($htmlsax);
+ $this->parser_options['XML_OPTION_TRIM_DATA_NODES'] = 0;
+ $this->parser_options['XML_OPTION_CASE_FOLDING'] = 0;
+ $this->parser_options['XML_OPTION_LINEFEED_BREAK'] = 0;
+ $this->parser_options['XML_OPTION_TAB_BREAK'] = 0;
+ $this->parser_options['XML_OPTION_ENTITIES_PARSED'] = 0;
+ $this->parser_options['XML_OPTION_ENTITIES_UNPARSED'] = 0;
+ $this->parser_options['XML_OPTION_STRIP_ESCAPES'] = 0;
+ }
+ /**
+ * Returns a string from the current position until the first instance of
+ * one of the characters in the supplied string argument.
+ * @param string string to search until
+ * @access protected
+ * @return string
+ */
+ function scanUntilCharacters($string) {
+ $startpos = $this->position;
+ $length = strcspn($this->rawtext, $string, $startpos);
+ $this->position += $length;
+ return substr($this->rawtext, $startpos, $length);
+ }
+
+ /**
+ * Moves the position forward past any whitespace characters
+ * @access protected
+ * @return void
+ */
+ function ignoreWhitespace() {
+ $this->position += strspn($this->rawtext, " \n\r\t", $this->position);
+ }
+
+ /**
+ * Begins the parsing operation, setting up the parsed and unparsed
+ * XML entity decorators if necessary then delegating further work
+ * to parent
+ * @param string XML document to parse
+ * @access protected
+ * @return void
+ */
+ function parse($data) {
+ parent::parse($data);
+ }
+}
+
+/**
+ * Default NullHandler for methods which were not set by user
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_NullHandler {
+ /**
+ * Generic handler method which does nothing
+ * @access protected
+ * @return void
+ */
+ function DoNothing() {
+ }
+}
+
+/**
+ * User interface class. All user calls should only be made to this class
+ * @package XML_HTMLSax3
+ * @access public
+ */
+class XML_HTMLSax3 {
+ /**
+ * Instance of concrete subclass of XML_HTMLSax3_StateParser
+ * @var XML_HTMLSax3_StateParser
+ * @access private
+ */
+ var $state_parser;
+
+ /**
+ * Constructs XML_HTMLSax3 selecting concrete StateParser subclass
+ * depending on PHP version being used as well as setting the default
+ * NullHandler for all callbacks<br />
+ * <b>Example:</b>
+ * <pre>
+ * $myHandler = new MyHandler();
+ * $parser = new XML_HTMLSax3();
+ * $parser->set_object($myHandler);
+ * $parser->set_option('XML_OPTION_CASE_FOLDING');
+ * $parser->set_element_handler('myOpenHandler','myCloseHandler');
+ * $parser->set_data_handler('myDataHandler');
+ * $parser->parser($xml);
+ * </pre>
+ * @access public
+ */
+ function __construct() {
+ $this->state_parser = new XML_HTMLSax3_StateParser_Gtet430($this);
+ $nullhandler = new XML_HTMLSax3_NullHandler();
+ $this->set_object($nullhandler);
+ $this->set_element_handler('DoNothing', 'DoNothing');
+ $this->set_data_handler('DoNothing');
+ $this->set_pi_handler('DoNothing');
+ $this->set_jasp_handler('DoNothing');
+ $this->set_escape_handler('DoNothing');
+ }
+
+ /**
+ * Sets the user defined handler object. Returns a PEAR Error
+ * if supplied argument is not an object.
+ * @param object handler object containing SAX callback methods
+ * @access public
+ * @return mixed
+ */
+ function set_object(&$object) {
+ if ( is_object($object) ) {
+ $this->state_parser->handler_default =& $object;
+ return true;
+ } else {
+ require_once('PEAR.php');
+ PEAR::raiseError('XML_HTMLSax3::set_object requires '.
+ 'an object instance');
+ }
+ }
+
+ /**
+ * Sets a parser option. By default all options are switched off.
+ * Returns a PEAR Error if option is invalid<br />
+ * <b>Available options:</b>
+ * <ul>
+ * <li>XML_OPTION_TRIM_DATA_NODES: trim whitespace off the beginning
+ * and end of data passed to the data handler</li>
+ * <li>XML_OPTION_LINEFEED_BREAK: linefeeds result in additional data
+ * handler calls</li>
+ * <li>XML_OPTION_TAB_BREAK: tabs result in additional data handler
+ * calls</li>
+ * <li>XML_OPTION_ENTITIES_UNPARSED: XML entities are returned as
+ * seperate data handler calls in unparsed form</li>
+ * <li>XML_OPTION_ENTITIES_PARSED: (PHP 4.3.0+ only) XML entities are
+ * returned as seperate data handler calls and are parsed with
+ * PHP's html_entity_decode() function</li>
+ * <li>XML_OPTION_STRIP_ESCAPES: strips out the -- -- comment markers
+ * or CDATA markup inside an XML escape, if found.</li>
+ * </ul>
+ * To get HTMLSax to behave in the same way as the native PHP SAX parser,
+ * using it's default state, you need to switch on XML_OPTION_LINEFEED_BREAK,
+ * XML_OPTION_ENTITIES_PARSED and XML_OPTION_CASE_FOLDING
+ * @param string name of parser option
+ * @param int (optional) 1 to switch on, 0 for off
+ * @access public
+ * @return boolean
+ */
+ function set_option($name, $value=1) {
+ if ( array_key_exists($name,$this->state_parser->parser_options) ) {
+ $this->state_parser->parser_options[$name] = $value;
+ return true;
+ } else {
+ require_once('PEAR.php');
+ PEAR::raiseError('XML_HTMLSax3::set_option('.$name.') illegal');
+ }
+ }
+
+ /**
+ * Sets the data handler method which deals with the contents of XML
+ * elements.<br />
+ * The handler method must accept two arguments, the first being an
+ * instance of XML_HTMLSax3 and the second being the contents of an
+ * XML element e.g.
+ * <pre>
+ * function myDataHander(& $parser,$data){}
+ * </pre>
+ * @param string name of method
+ * @access public
+ * @return void
+ * @see set_object
+ */
+ function set_data_handler($data_method) {
+ $this->state_parser->handler_object_data =& $this->state_parser->handler_default;
+ $this->state_parser->handler_method_data = $data_method;
+ }
+
+ /**
+ * Sets the open and close tag handlers
+ * <br />The open handler method must accept three arguments; the parser,
+ * the tag name and an array of attributes e.g.
+ * <pre>
+ * function myOpenHander(& $parser,$tagname,$attrs=array()){}
+ * </pre>
+ * The close handler method must accept two arguments; the parser and
+ * the tag name e.g.
+ * <pre>
+ * function myCloseHander(& $parser,$tagname){}
+ * </pre>
+ * @param string name of open method
+ * @param string name of close method
+ * @access public
+ * @return void
+ * @see set_object
+ */
+ function set_element_handler($opening_method, $closing_method) {
+ $this->state_parser->handler_object_element =& $this->state_parser->handler_default;
+ $this->state_parser->handler_method_opening = $opening_method;
+ $this->state_parser->handler_method_closing = $closing_method;
+ }
+
+ /**
+ * Sets the processing instruction handler method e.g. for PHP open
+ * and close tags<br />
+ * The handler method must accept three arguments; the parser, the
+ * PI target and data inside the PI
+ * <pre>
+ * function myPIHander(& $parser,$target, $data){}
+ * </pre>
+ * @param string name of method
+ * @access public
+ * @return void
+ * @see set_object
+ */
+ function set_pi_handler($pi_method) {
+ $this->state_parser->handler_object_pi =& $this->state_parser->handler_default;
+ $this->state_parser->handler_method_pi = $pi_method;
+ }
+
+ /**
+ * Sets the XML escape handler method e.g. for comments and doctype
+ * declarations<br />
+ * The handler method must accept two arguments; the parser and the
+ * contents of the escaped section
+ * <pre>
+ * function myEscapeHander(& $parser, $data){}
+ * </pre>
+ * @param string name of method
+ * @access public
+ * @return void
+ * @see set_object
+ */
+ function set_escape_handler($escape_method) {
+ $this->state_parser->handler_object_escape =& $this->state_parser->handler_default;
+ $this->state_parser->handler_method_escape = $escape_method;
+ }
+
+ /**
+ * Sets the JSP/ASP markup handler<br />
+ * The handler method must accept two arguments; the parser and
+ * body of the JASP tag
+ * <pre>
+ * function myJaspHander(& $parser, $data){}
+ * </pre>
+ * @param string name of method
+ * @access public
+ * @return void
+ * @see set_object
+ */
+ function set_jasp_handler ($jasp_method) {
+ $this->state_parser->handler_object_jasp =& $this->state_parser->handler_default;
+ $this->state_parser->handler_method_jasp = $jasp_method;
+ }
+
+ /**
+ * Returns the current string position of the "cursor" inside the XML
+ * document
+ * <br />Intended for use from within a user defined handler called
+ * via the $parser reference e.g.
+ * <pre>
+ * function myDataHandler(& $parser,$data) {
+ * echo( 'Current position: '.$parser->get_current_position() );
+ * }
+ * </pre>
+ * @access public
+ * @return int
+ * @see get_length
+ */
+ function get_current_position() {
+ return $this->state_parser->position;
+ }
+
+ /**
+ * Returns the string length of the XML document being parsed
+ * @access public
+ * @return int
+ */
+ function get_length() {
+ return $this->state_parser->length;
+ }
+
+ /**
+ * Start parsing some XML
+ * @param string XML document
+ * @access public
+ * @return void
+ */
+ function parse($data) {
+ $this->state_parser->parse($data);
+ }
+}
-<?php\r
-class XML_HTMLSax3_Trim {\r
- var $orig_obj;\r
- var $orig_method;\r
- function __construct(&$orig_obj, $orig_method) {\r
- $this->orig_obj =& $orig_obj;\r
- $this->orig_method = $orig_method;\r
- }\r
- function trimData(&$parser, $data) {\r
- $data = trim($data);\r
- if ($data != '') {\r
- $this->orig_obj->{$this->orig_method}($parser, $data);\r
- }\r
- }\r
-}\r
-class XML_HTMLSax3_CaseFolding {\r
- var $orig_obj;\r
- var $orig_open_method;\r
- var $orig_close_method;\r
- function __construct(&$orig_obj, $orig_open_method, $orig_close_method) {\r
- $this->orig_obj =& $orig_obj;\r
- $this->orig_open_method = $orig_open_method;\r
- $this->orig_close_method = $orig_close_method;\r
- }\r
- function foldOpen(&$parser, $tag, $attrs = array(), $empty = FALSE) {\r
- $this->orig_obj->{$this->orig_open_method}($parser, strtoupper($tag), $attrs, $empty);\r
- }\r
- function foldClose(&$parser, $tag, $empty = FALSE) {\r
- $this->orig_obj->{$this->orig_close_method}($parser, strtoupper($tag), $empty);\r
- }\r
-}\r
-class XML_HTMLSax3_Linefeed {\r
- var $orig_obj;\r
- var $orig_method;\r
- function __construct(&$orig_obj, $orig_method) {\r
- $this->orig_obj =& $orig_obj;\r
- $this->orig_method = $orig_method;\r
- }\r
- function breakData(&$parser, $data) {\r
- $data = explode("\n",$data);\r
- foreach ( $data as $chunk ) {\r
- $this->orig_obj->{$this->orig_method}($parser, $chunk);\r
- }\r
- }\r
-}\r
-class XML_HTMLSax3_Tab {\r
- var $orig_obj;\r
- var $orig_method;\r
- function __construct(&$orig_obj, $orig_method) {\r
- $this->orig_obj =& $orig_obj;\r
- $this->orig_method = $orig_method;\r
- }\r
- function breakData(&$parser, $data) {\r
- $data = explode("\t",$data);\r
- foreach ( $data as $chunk ) {\r
- $this->orig_obj->{$this->orig_method}($this, $chunk);\r
- }\r
- }\r
-}\r
-class XML_HTMLSax3_Entities_Parsed {\r
- var $orig_obj;\r
- var $orig_method;\r
- function __construct(&$orig_obj, $orig_method) {\r
- $this->orig_obj =& $orig_obj;\r
- $this->orig_method = $orig_method;\r
- }\r
- function breakData(&$parser, $data) {\r
- $data = preg_split('/(&.+?;)/',$data,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);\r
- foreach ( $data as $chunk ) {\r
- $chunk = html_entity_decode($chunk,ENT_NOQUOTES);\r
- $this->orig_obj->{$this->orig_method}($this, $chunk);\r
- }\r
- }\r
-}\r
-if (version_compare(phpversion(), '4.3', '<') && !function_exists('html_entity_decode') ) {\r
- function html_entity_decode($str, $style = ENT_NOQUOTES) {\r
- return strtr($str,\r
- array_flip(get_html_translation_table(HTML_ENTITIES,$style)));\r
- }\r
-}\r
-class XML_HTMLSax3_Entities_Unparsed {\r
- var $orig_obj;\r
- var $orig_method;\r
- function __construct(&$orig_obj, $orig_method) {\r
- $this->orig_obj =& $orig_obj;\r
- $this->orig_method = $orig_method;\r
- }\r
- function breakData(&$parser, $data) {\r
- $data = preg_split('/(&.+?;)/',$data,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);\r
- foreach ( $data as $chunk ) {\r
- $this->orig_obj->{$this->orig_method}($this, $chunk);\r
- }\r
- }\r
-}\r
-\r
-class XML_HTMLSax3_Escape_Stripper {\r
- var $orig_obj;\r
- var $orig_method;\r
- function __construct(&$orig_obj, $orig_method) {\r
- $this->orig_obj =& $orig_obj;\r
- $this->orig_method = $orig_method;\r
- }\r
- function strip(&$parser, $data) {\r
- if ( substr($data,0,2) == '--' ) {\r
- $patterns = array(\r
- '/^\-\-/', // Opening comment: --\r
- '/\-\-$/', // Closing comment: --\r
- );\r
- $data = preg_replace($patterns,'',$data);\r
-\r
- } else if ( substr($data,0,1) == '[' ) {\r
- $patterns = array(\r
- '/^\[.*CDATA.*\[/s', // Opening CDATA\r
- '/\].*\]$/s', // Closing CDATA\r
- );\r
- $data = preg_replace($patterns,'',$data);\r
- }\r
-\r
- $this->orig_obj->{$this->orig_method}($this, $data);\r
- }\r
-}\r
-?>\r
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+//
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2002 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject toversion 3.0 of the PHP license, |
+// | that is bundled with this package in the file LICENSE, and is |
+// | available at through the world-wide-web at |
+// | http://www.php.net/license/3_0.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Authors: Alexander Zhukov <alex@veresk.ru> Original port from Python |
+// | Authors: Harry Fuecks <hfuecks@phppatterns.com> Port to PEAR + more |
+// | Authors: Many @ Sitepointforums Advanced PHP Forums |
+// +----------------------------------------------------------------------+
+//
+// $Id: Decorators.php,v 1.2 2007/10/29 21:41:35 hfuecks Exp $
+//
+/**
+ * Decorators for dealing with parser options
+ * @package XML_HTMLSax3
+ * @version $Id: Decorators.php,v 1.2 2007/10/29 21:41:35 hfuecks Exp $
+ * @see XML_HTMLSax3::set_option
+ */
+/**
+ * Trims the contents of element data from whitespace at start and end
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_Trim {
+ /**
+ * Original handler object
+ * @var object
+ * @access private
+ */
+ var $orig_obj;
+ /**
+ * Original handler method
+ * @var string
+ * @access private
+ */
+ var $orig_method;
+ /**
+ * Constructs XML_HTMLSax3_Trim
+ * @param object handler object being decorated
+ * @param string original handler method
+ * @access protected
+ */
+ function __construct(&$orig_obj, $orig_method) {
+ $this->orig_obj =& $orig_obj;
+ $this->orig_method = $orig_method;
+ }
+ /**
+ * Trims the data
+ * @param XML_HTMLSax3
+ * @param string element data
+ * @access protected
+ */
+ function trimData(&$parser, $data) {
+ $data = trim($data);
+ if ($data != '') {
+ $this->orig_obj->{$this->orig_method}($parser, $data);
+ }
+ }
+}
+/**
+ * Coverts tag names to upper case
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_CaseFolding {
+ /**
+ * Original handler object
+ * @var object
+ * @access private
+ */
+ var $orig_obj;
+ /**
+ * Original open handler method
+ * @var string
+ * @access private
+ */
+ var $orig_open_method;
+ /**
+ * Original close handler method
+ * @var string
+ * @access private
+ */
+ var $orig_close_method;
+ /**
+ * Constructs XML_HTMLSax3_CaseFolding
+ * @param object handler object being decorated
+ * @param string original open handler method
+ * @param string original close handler method
+ * @access protected
+ */
+ function __construct(&$orig_obj, $orig_open_method, $orig_close_method) {
+ $this->orig_obj =& $orig_obj;
+ $this->orig_open_method = $orig_open_method;
+ $this->orig_close_method = $orig_close_method;
+ }
+ /**
+ * Folds up open tag callbacks
+ * @param XML_HTMLSax3
+ * @param string tag name
+ * @param array tag attributes
+ * @access protected
+ */
+ function foldOpen(&$parser, $tag, $attrs=array(), $empty = FALSE) {
+ $this->orig_obj->{$this->orig_open_method}($parser, strtoupper($tag), $attrs, $empty);
+ }
+ /**
+ * Folds up close tag callbacks
+ * @param XML_HTMLSax3
+ * @param string tag name
+ * @access protected
+ */
+ function foldClose(&$parser, $tag, $empty = FALSE) {
+ $this->orig_obj->{$this->orig_close_method}($parser, strtoupper($tag), $empty);
+ }
+}
+/**
+ * Breaks up data by linefeed characters, resulting in additional
+ * calls to the data handler
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_Linefeed {
+ /**
+ * Original handler object
+ * @var object
+ * @access private
+ */
+ var $orig_obj;
+ /**
+ * Original handler method
+ * @var string
+ * @access private
+ */
+ var $orig_method;
+ /**
+ * Constructs XML_HTMLSax3_LineFeed
+ * @param object handler object being decorated
+ * @param string original handler method
+ * @access protected
+ */
+ function __construct(&$orig_obj, $orig_method) {
+ $this->orig_obj =& $orig_obj;
+ $this->orig_method = $orig_method;
+ }
+ /**
+ * Breaks the data up by linefeeds
+ * @param XML_HTMLSax3
+ * @param string element data
+ * @access protected
+ */
+ function breakData(&$parser, $data) {
+ $data = explode("\n",$data);
+ foreach ( $data as $chunk ) {
+ $this->orig_obj->{$this->orig_method}($parser, $chunk);
+ }
+ }
+}
+/**
+ * Breaks up data by tab characters, resulting in additional
+ * calls to the data handler
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_Tab {
+ /**
+ * Original handler object
+ * @var object
+ * @access private
+ */
+ var $orig_obj;
+ /**
+ * Original handler method
+ * @var string
+ * @access private
+ */
+ var $orig_method;
+ /**
+ * Constructs XML_HTMLSax3_Tab
+ * @param object handler object being decorated
+ * @param string original handler method
+ * @access protected
+ */
+ function __construct(&$orig_obj, $orig_method) {
+ $this->orig_obj =& $orig_obj;
+ $this->orig_method = $orig_method;
+ }
+ /**
+ * Breaks the data up by linefeeds
+ * @param XML_HTMLSax3
+ * @param string element data
+ * @access protected
+ */
+ function breakData(&$parser, $data) {
+ $data = explode("\t",$data);
+ foreach ( $data as $chunk ) {
+ $this->orig_obj->{$this->orig_method}($this, $chunk);
+ }
+ }
+}
+/**
+ * Breaks up data by XML entities and parses them with html_entity_decode(),
+ * resulting in additional calls to the data handler<br />
+ * Requires PHP 4.3.0+
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_Entities_Parsed {
+ /**
+ * Original handler object
+ * @var object
+ * @access private
+ */
+ var $orig_obj;
+ /**
+ * Original handler method
+ * @var string
+ * @access private
+ */
+ var $orig_method;
+ /**
+ * Constructs XML_HTMLSax3_Entities_Parsed
+ * @param object handler object being decorated
+ * @param string original handler method
+ * @access protected
+ */
+ function __construct(&$orig_obj, $orig_method) {
+ $this->orig_obj =& $orig_obj;
+ $this->orig_method = $orig_method;
+ }
+ /**
+ * Breaks the data up by XML entities
+ * @param XML_HTMLSax3
+ * @param string element data
+ * @access protected
+ */
+ function breakData(&$parser, $data) {
+ $data = preg_split('/(&.+?;)/',$data,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+ foreach ( $data as $chunk ) {
+ $chunk = html_entity_decode($chunk, ENT_NOQUOTES, HTML_ENTITIES_CHARSET);
+ $this->orig_obj->{$this->orig_method}($this, $chunk);
+ }
+ }
+}
+/**
+ * Breaks up data by XML entities but leaves them unparsed,
+ * resulting in additional calls to the data handler<br />
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_Entities_Unparsed {
+ /**
+ * Original handler object
+ * @var object
+ * @access private
+ */
+ var $orig_obj;
+ /**
+ * Original handler method
+ * @var string
+ * @access private
+ */
+ var $orig_method;
+ /**
+ * Constructs XML_HTMLSax3_Entities_Unparsed
+ * @param object handler object being decorated
+ * @param string original handler method
+ * @access protected
+ */
+ function __construct(&$orig_obj, $orig_method) {
+ $this->orig_obj =& $orig_obj;
+ $this->orig_method = $orig_method;
+ }
+ /**
+ * Breaks the data up by XML entities
+ * @param XML_HTMLSax3
+ * @param string element data
+ * @access protected
+ */
+ function breakData(&$parser, $data) {
+ $data = preg_split('/(&.+?;)/',$data,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+ foreach ( $data as $chunk ) {
+ $this->orig_obj->{$this->orig_method}($this, $chunk);
+ }
+ }
+}
+
+/**
+ * Strips the HTML comment markers or CDATA sections from an escape.
+ * If XML_OPTIONS_FULL_ESCAPES is on, this decorator is not used.<br />
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_Escape_Stripper {
+ /**
+ * Original handler object
+ * @var object
+ * @access private
+ */
+ var $orig_obj;
+ /**
+ * Original handler method
+ * @var string
+ * @access private
+ */
+ var $orig_method;
+ /**
+ * Constructs XML_HTMLSax3_Entities_Unparsed
+ * @param object handler object being decorated
+ * @param string original handler method
+ * @access protected
+ */
+ function __construct(&$orig_obj, $orig_method) {
+ $this->orig_obj =& $orig_obj;
+ $this->orig_method = $orig_method;
+ }
+ /**
+ * Breaks the data up by XML entities
+ * @param XML_HTMLSax3
+ * @param string element data
+ * @access protected
+ */
+ function strip(&$parser, $data) {
+ // Check for HTML comments first
+ if ( substr($data,0,2) == '--' ) {
+ $patterns = [
+ '/^\-\-/', // Opening comment: --
+ '/\-\-$/', // Closing comment: --
+ ];
+ $data = preg_replace($patterns,'',$data);
+
+ // Check for XML CDATA sections (note: don't do both!)
+ } else if ( substr($data,0,1) == '[' ) {
+ $patterns = [
+ '/^\[.*CDATA.*\[/s', // Opening CDATA
+ '/\].*\]$/s', // Closing CDATA
+ ];
+ $data = preg_replace($patterns,'',$data);
+ }
+
+ $this->orig_obj->{$this->orig_method}($this, $data);
+ }
+}
-<?php\r
-define('XML_HTMLSAX3_STATE_STOP', 0);\r
-define('XML_HTMLSAX3_STATE_START', 1);\r
-define('XML_HTMLSAX3_STATE_TAG', 2);\r
-define('XML_HTMLSAX3_STATE_OPENING_TAG', 3);\r
-define('XML_HTMLSAX3_STATE_CLOSING_TAG', 4);\r
-define('XML_HTMLSAX3_STATE_ESCAPE', 6);\r
-define('XML_HTMLSAX3_STATE_JASP', 7);\r
-define('XML_HTMLSAX3_STATE_PI', 8);\r
-class XML_HTMLSax3_StartingState {\r
- function parse(&$context) {\r
- $data = $context->scanUntilString('<');\r
- if ($data != '') {\r
- $context->handler_object_data->\r
- {$context->handler_method_data}($context->htmlsax, $data);\r
- }\r
- $context->IgnoreCharacter();\r
- return XML_HTMLSAX3_STATE_TAG;\r
- }\r
-}\r
-class XML_HTMLSax3_TagState {\r
- function parse(&$context) {\r
- switch($context->ScanCharacter()) {\r
- case '/':\r
- return XML_HTMLSAX3_STATE_CLOSING_TAG;\r
- break;\r
- case '?':\r
- return XML_HTMLSAX3_STATE_PI;\r
- break;\r
- case '%':\r
- return XML_HTMLSAX3_STATE_JASP;\r
- break;\r
- case '!':\r
- return XML_HTMLSAX3_STATE_ESCAPE;\r
- break;\r
- default:\r
- $context->unscanCharacter();\r
- return XML_HTMLSAX3_STATE_OPENING_TAG;\r
- }\r
- }\r
-}\r
-class XML_HTMLSax3_ClosingTagState {\r
- function parse(&$context) {\r
- $tag = $context->scanUntilCharacters('/>');\r
- if ($tag != '') {\r
- $char = $context->scanCharacter();\r
- if ($char == '/') {\r
- $char = $context->scanCharacter();\r
- if ($char != '>') {\r
- $context->unscanCharacter();\r
- }\r
- }\r
- $context->handler_object_element->\r
- {$context->handler_method_closing}($context->htmlsax, $tag, FALSE);\r
- }\r
- return XML_HTMLSAX3_STATE_START;\r
- }\r
-}\r
-class XML_HTMLSax3_OpeningTagState {\r
- function parseAttributes(&$context) {\r
- $Attributes = array();\r
- \r
- $context->ignoreWhitespace();\r
- $attributename = $context->scanUntilCharacters("=/> \n\r\t");\r
- while ($attributename != '') {\r
- $attributevalue = NULL;\r
- $context->ignoreWhitespace();\r
- $char = $context->scanCharacter();\r
- if ($char == '=') {\r
- $context->ignoreWhitespace();\r
- $char = $context->ScanCharacter();\r
- if ($char == '"') {\r
- $attributevalue= $context->scanUntilString('"');\r
- $context->IgnoreCharacter();\r
- } else if ($char == "'") {\r
- $attributevalue = $context->scanUntilString("'");\r
- $context->IgnoreCharacter();\r
- } else {\r
- $context->unscanCharacter();\r
- $attributevalue =\r
- $context->scanUntilCharacters("> \n\r\t");\r
- }\r
- } else if ($char !== NULL) {\r
- $attributevalue = NULL;\r
- $context->unscanCharacter();\r
- }\r
- $Attributes[$attributename] = $attributevalue;\r
- \r
- $context->ignoreWhitespace();\r
- $attributename = $context->scanUntilCharacters("=/> \n\r\t");\r
- }\r
- return $Attributes;\r
- }\r
-\r
- function parse(&$context) {\r
- $tag = $context->scanUntilCharacters("/> \n\r\t");\r
- if ($tag != '') {\r
- $this->attrs = array();\r
- $Attributes = $this->parseAttributes($context);\r
- $char = $context->scanCharacter();\r
- if ($char == '/') {\r
- $char = $context->scanCharacter();\r
- if ($char != '>') {\r
- $context->unscanCharacter();\r
- }\r
- $context->handler_object_element->\r
- {$context->handler_method_opening}($context->htmlsax, $tag, \r
- $Attributes, TRUE);\r
- $context->handler_object_element->\r
- {$context->handler_method_closing}($context->htmlsax, $tag, \r
- TRUE);\r
- } else {\r
- $context->handler_object_element->\r
- {$context->handler_method_opening}($context->htmlsax, $tag, \r
- $Attributes, FALSE);\r
- }\r
- }\r
- return XML_HTMLSAX3_STATE_START;\r
- }\r
-}\r
-\r
-class XML_HTMLSax3_EscapeState {\r
- function parse(&$context) {\r
- $char = $context->ScanCharacter();\r
- if ($char == '-') {\r
- $char = $context->ScanCharacter();\r
- if ($char == '-') {\r
- $context->unscanCharacter();\r
- $context->unscanCharacter();\r
- $text = $context->scanUntilString('-->');\r
- $text .= $context->scanCharacter();\r
- $text .= $context->scanCharacter();\r
- } else {\r
- $context->unscanCharacter();\r
- $text = $context->scanUntilString('>');\r
- }\r
- } else if ( $char == '[') {\r
- $context->unscanCharacter();\r
- $text = $context->scanUntilString(']>');\r
- $text.= $context->scanCharacter();\r
- } else {\r
- $context->unscanCharacter();\r
- $text = $context->scanUntilString('>');\r
- }\r
-\r
- $context->IgnoreCharacter();\r
- if ($text != '') {\r
- $context->handler_object_escape->\r
- {$context->handler_method_escape}($context->htmlsax, $text);\r
- }\r
- return XML_HTMLSAX3_STATE_START;\r
- }\r
-}\r
-class XML_HTMLSax3_JaspState {\r
- function parse(&$context) {\r
- $text = $context->scanUntilString('%>');\r
- if ($text != '') {\r
- $context->handler_object_jasp->\r
- {$context->handler_method_jasp}($context->htmlsax, $text);\r
- }\r
- $context->IgnoreCharacter();\r
- $context->IgnoreCharacter();\r
- return XML_HTMLSAX3_STATE_START;\r
- }\r
-}\r
-class XML_HTMLSax3_PiState {\r
- function parse(&$context) {\r
- $target = $context->scanUntilCharacters(" \n\r\t");\r
- $data = $context->scanUntilString('?>');\r
- if ($data != '') {\r
- $context->handler_object_pi->\r
- {$context->handler_method_pi}($context->htmlsax, $target, $data);\r
- }\r
- $context->IgnoreCharacter();\r
- $context->IgnoreCharacter();\r
- return XML_HTMLSAX3_STATE_START;\r
- }\r
-}\r
-?>
\ No newline at end of file
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+//
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2002 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject toversion 3.0 of the PHP license, |
+// | that is bundled with this package in the file LICENSE, and is |
+// | available at through the world-wide-web at |
+// | http://www.php.net/license/3_0.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Authors: Alexander Zhukov <alex@veresk.ru> Original port from Python |
+// | Authors: Harry Fuecks <hfuecks@phppatterns.com> Port to PEAR + more |
+// | Authors: Many @ Sitepointforums Advanced PHP Forums |
+// +----------------------------------------------------------------------+
+//
+// $Id: States.php,v 1.3 2007/10/29 21:41:35 hfuecks Exp $
+//
+/**
+ * Parsing states.
+ * @package XML_HTMLSax3
+ * @version $Id: States.php,v 1.3 2007/10/29 21:41:35 hfuecks Exp $
+ */
+/**
+ * Define parser states
+ */
+define('XML_HTMLSAX3_STATE_STOP', 0);
+define('XML_HTMLSAX3_STATE_START', 1);
+define('XML_HTMLSAX3_STATE_TAG', 2);
+define('XML_HTMLSAX3_STATE_OPENING_TAG', 3);
+define('XML_HTMLSAX3_STATE_CLOSING_TAG', 4);
+define('XML_HTMLSAX3_STATE_ESCAPE', 6);
+define('XML_HTMLSAX3_STATE_JASP', 7);
+define('XML_HTMLSAX3_STATE_PI', 8);
+/**
+ * StartingState searches for the start of any XML tag
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_StartingState {
+ /**
+ * @param XML_HTMLSax3_StateParser subclass
+ * @return constant XML_HTMLSAX3_STATE_TAG
+ * @access protected
+ */
+ function parse(&$context) {
+ $data = $context->scanUntilString('<');
+ if ($data != '') {
+ $context->handler_object_data->
+ {$context->handler_method_data}($context->htmlsax, $data);
+ }
+ $context->IgnoreCharacter();
+ return XML_HTMLSAX3_STATE_TAG;
+ }
+}
+/**
+ * Decides which state to move one from after StartingState
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_TagState {
+ /**
+ * @param XML_HTMLSax3_StateParser subclass
+ * @return constant the next state to move into
+ * @access protected
+ */
+ function parse(&$context) {
+ switch($context->ScanCharacter()) {
+ case '/':
+ return XML_HTMLSAX3_STATE_CLOSING_TAG;
+ break;
+ case '?':
+ return XML_HTMLSAX3_STATE_PI;
+ break;
+ case '%':
+ return XML_HTMLSAX3_STATE_JASP;
+ break;
+ case '!':
+ return XML_HTMLSAX3_STATE_ESCAPE;
+ break;
+ default:
+ $context->unscanCharacter();
+ return XML_HTMLSAX3_STATE_OPENING_TAG;
+ }
+ }
+}
+/**
+ * Dealing with closing XML tags
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_ClosingTagState {
+ /**
+ * @param XML_HTMLSax3_StateParser subclass
+ * @return constant XML_HTMLSAX3_STATE_START
+ * @access protected
+ */
+ function parse(&$context) {
+ $tag = $context->scanUntilCharacters('/>');
+ if ($tag != '') {
+ $char = $context->scanCharacter();
+ if ($char == '/') {
+ $char = $context->scanCharacter();
+ if ($char != '>') {
+ $context->unscanCharacter();
+ }
+ }
+ $context->handler_object_element->
+ {$context->handler_method_closing}($context->htmlsax, $tag, FALSE);
+ }
+ return XML_HTMLSAX3_STATE_START;
+ }
+}
+/**
+ * Dealing with opening XML tags
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_OpeningTagState {
+ /**
+ * Handles attributes
+ * @param string attribute name
+ * @param string attribute value
+ * @return void
+ * @access protected
+ * @see XML_HTMLSax3_AttributeStartState
+ */
+ function parseAttributes(&$context) {
+ $Attributes = [];
+
+ $context->ignoreWhitespace();
+ $attributename = $context->scanUntilCharacters("=/> \n\r\t");
+ while ($attributename != '') {
+ $attributevalue = null;
+ $context->ignoreWhitespace();
+ $char = $context->scanCharacter();
+ if ($char == '=') {
+ $context->ignoreWhitespace();
+ $char = $context->ScanCharacter();
+ if ($char == '"') {
+ $attributevalue= $context->scanUntilString('"');
+ $context->IgnoreCharacter();
+ } else if ($char == "'") {
+ $attributevalue = $context->scanUntilString("'");
+ $context->IgnoreCharacter();
+ } else {
+ $context->unscanCharacter();
+ $attributevalue =
+ $context->scanUntilCharacters("> \n\r\t");
+ }
+ } else if ($char !== null) {
+ $attributevalue = null;
+ $context->unscanCharacter();
+ }
+ $Attributes[$attributename] = $attributevalue;
+
+ $context->ignoreWhitespace();
+ $attributename = $context->scanUntilCharacters("=/> \n\r\t");
+ }
+ return $Attributes;
+ }
+
+ /**
+ * @param XML_HTMLSax3_StateParser subclass
+ * @return constant XML_HTMLSAX3_STATE_START
+ * @access protected
+ */
+ function parse(&$context) {
+ $tag = $context->scanUntilCharacters("/> \n\r\t");
+ if ($tag != '') {
+ $this->attrs = [];
+ $Attributes = $this->parseAttributes($context);
+ $char = $context->scanCharacter();
+ if ($char == '/') {
+ $char = $context->scanCharacter();
+ if ($char != '>') {
+ $context->unscanCharacter();
+ }
+ $context->handler_object_element->
+ {$context->handler_method_opening}($context->htmlsax, $tag,
+ $Attributes, TRUE);
+ $context->handler_object_element->
+ {$context->handler_method_closing}($context->htmlsax, $tag,
+ TRUE);
+ } else {
+ $context->handler_object_element->
+ {$context->handler_method_opening}($context->htmlsax, $tag,
+ $Attributes, FALSE);
+ }
+ }
+ return XML_HTMLSAX3_STATE_START;
+ }
+}
+
+/**
+ * Deals with XML escapes handling comments and CDATA correctly
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_EscapeState {
+ /**
+ * @param XML_HTMLSax3_StateParser subclass
+ * @return constant XML_HTMLSAX3_STATE_START
+ * @access protected
+ */
+ function parse(&$context) {
+ $char = $context->ScanCharacter();
+ if ($char == '-') {
+ $char = $context->ScanCharacter();
+ if ($char == '-') {
+ $context->unscanCharacter();
+ $context->unscanCharacter();
+ $text = $context->scanUntilString('-->');
+ $text .= $context->scanCharacter();
+ $text .= $context->scanCharacter();
+ } else {
+ $context->unscanCharacter();
+ $text = $context->scanUntilString('>');
+ }
+ } else if ( $char == '[') {
+ $context->unscanCharacter();
+ $text = $context->scanUntilString(']>');
+ $text.= $context->scanCharacter();
+ } else {
+ $context->unscanCharacter();
+ $text = $context->scanUntilString('>');
+ }
+
+ $context->IgnoreCharacter();
+ if ($text != '') {
+ $context->handler_object_escape->
+ {$context->handler_method_escape}($context->htmlsax, $text);
+ }
+ return XML_HTMLSAX3_STATE_START;
+ }
+}
+/**
+ * Deals with JASP/ASP markup
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_JaspState {
+ /**
+ * @param XML_HTMLSax3_StateParser subclass
+ * @return constant XML_HTMLSAX3_STATE_START
+ * @access protected
+ */
+ function parse(&$context) {
+ $text = $context->scanUntilString('%>');
+ if ($text != '') {
+ $context->handler_object_jasp->
+ {$context->handler_method_jasp}($context->htmlsax, $text);
+ }
+ $context->IgnoreCharacter();
+ $context->IgnoreCharacter();
+ return XML_HTMLSAX3_STATE_START;
+ }
+}
+/**
+ * Deals with XML processing instructions
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_PiState {
+ /**
+ * @param XML_HTMLSax3_StateParser subclass
+ * @return constant XML_HTMLSAX3_STATE_START
+ * @access protected
+ */
+ function parse(&$context) {
+ $target = $context->scanUntilCharacters(" \n\r\t");
+ $data = $context->scanUntilString('?>');
+ if ($data != '') {
+ $context->handler_object_pi->
+ {$context->handler_method_pi}($context->htmlsax, $target, $data);
+ }
+ $context->IgnoreCharacter();
+ $context->IgnoreCharacter();
+ return XML_HTMLSAX3_STATE_START;
+ }
+}
<?php
-
/**
* SafeHTML Parser
*
- * @note
- * Attention : Quelques modifications pour PHP 5.5 et 7
- *
- * @package SafeHTML
- * @author Roman Ivanov <thingol@mail.ru>
- * @author Miguel Vazquez Gocobachi <demrit@mx.gnu.org>
- * @copyright 2004-2009 Roman Ivanov, Miguel Vazquez Gocobachi
- * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
- * @version 1.3.10
- * @link https://wackowiki.org/doc/Dev/Projects/SafeHTML
+ * PHP version 7
+ *
+ * @category HTML
+ * @package SafeHTML
+ * @author Roman Ivanov <thingol@mail.ru>
+ * @author Miguel Vazquez Gocobachi <demrit@mx.gnu.org>
+ * @copyright 2004-2020 Roman Ivanov, Miguel Vazquez Gocobachi, WackoWiki Team
+ * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
+ * @version 1.3.12
+ * @link https://wackowiki.org/doc/Dev/Projects/SafeHTML
*/
-
-if (!defined('_ECRIRE_INC_VERSION')) return;
-
+/**
+ * This package requires HTMLSax3 package
+ */
require_once(XML_HTMLSAX3 . 'HTMLSax3.php');
/**
- *
- * SafeHTML Parser
+ * HTML_Safe Parser
*
* This parser strips down all potentially dangerous content within HTML:
* <ul>
* <li>opening tag without its closing tag</li>
* <li>closing tag without its opening tag</li>
- * <li>any of these tags: "base", "basefont", "head", "html", "body", "applet",
- * "object", "iframe", "frame", "frameset", "script", "layer", "ilayer", "embed",
+ * <li>any of these tags: "base", "basefont", "head", "html", "body", "applet",
+ * "object", "iframe", "frame", "frameset", "script", "layer", "ilayer", "embed",
* "bgsound", "link", "meta", "style", "title", "blink", "xml" etc.</li>
* <li>any of these attributes: on*, data*, dynsrc</li>
* <li>javascript:/vbscript:/about: etc. protocols</li>
* <li>expression/behavior etc. in styles</li>
* <li>any other active content</li>
* </ul>
- * It also tries to convert code to XHTML valid, but htmltidy is far better
+ * It also tries to convert code to XHTML valid, but htmltidy is far better
* solution for this task.
*
* <b>Example:</b>
* <pre>
- * $parser =& new SafeHTML();
+ * $parser = new SafeHTML;
* $result = $parser->parse($doc);
* </pre>
- *
- * @category HTML
- * @package SafeHTML
- * @author Roman Ivanov <thingol@mail.ru>
- * @copyright 1997-2005 Roman Ivanov
- * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
- * @version Release: @package_version@
- * @link http://pear.php.net/package/SafeHTML
*/
-class SafeHTML
+class SafeHTML
{
- /**
- * Storage for resulting HTML output
- *
- * @var string
- */
- protected $xhtml = '';
-
- /**
- * Array of counters for each tag
- *
- * @var array
- */
- protected $counter = array();
-
- /**
- * Stack of unclosed tags
- *
- * @var array
- */
- protected $stack = array();
-
- /**
- * Array of counters for tags that must be deleted with all content
- *
- * @var array
- */
- protected $dcCounter = array();
-
- /**
- * Stack of unclosed tags that must be deleted with all content
- *
- * @var array
- */
- protected $dcStack = array();
-
- /**
- * Stores level of list (ol/ul) nesting
- *
- * @var int
- */
- protected $listScope = 0;
-
- /**
- * Stack of unclosed list tags
- *
- * @var array
- */
- protected $liStack = array();
-
- /**
- * Array of prepared regular expressions for protocols (schemas) matching
- *
- * @var array
- */
- protected $protoRegexps = array();
-
- /**
- * Array of prepared regular expressions for CSS matching
- *
- * @var array
- */
- protected $cssRegexps = array();
-
- /**
- * Should we perform UTF7 repacking or not?
- *
- * This repacking might replace completely normal strings such as "+31-" by illegal sequences,
- * which cause the document to be truncated on saving to MySQL
- *
- * @var boolean
- * @access public
- */
- var $repackUTF7 = true;
-
- /**
- * Allowed tags
- *
- * @var array
- */
- protected $allowTags = array();
-
-
- /**
- * List of single tags ("<tag />")
- *
- * @var array
- */
- public $singleTags = array('area', 'br', 'img', 'input', 'hr', 'wbr', );
-
- /**
- * List of dangerous tags (such tags will be deleted)
- *
- * @var array
- */
- public $deleteTags = array(
- 'applet', 'base', 'basefont', 'bgsound', 'blink', 'body',
- 'embed', 'frame', 'frameset', 'head', 'html', 'ilayer',
- 'iframe', 'layer', 'link', 'meta', 'object', 'style',
- 'title', 'script',
- );
-
- /**
- * List of dangerous tags (such tags will be deleted, and all content
- * inside this tags will be also removed)
- *
- * @var array
- */
- public $deleteTagsContent = array('script', 'style', 'title', 'xml', );
-
- /**
- * Type of protocols filtering ('white' or 'black')
- *
- * @var string
- */
- public $protocolFiltering = 'white';
-
- /**
- * List of "dangerous" protocols (used for blacklist-filtering)
- *
- * @var array
- */
- public $blackProtocols = array(
- 'about', 'chrome', 'data', 'disk', 'hcp',
- 'help', 'javascript', 'livescript', 'lynxcgi', 'lynxexec',
- 'ms-help', 'ms-its', 'mhtml', 'mocha', 'opera',
- 'res', 'resource', 'shell', 'vbscript', 'view-source',
- 'vnd.ms.radio', 'wysiwyg',
- );
-
- /**
- * List of "safe" protocols (used for whitelist-filtering)
- *
- * @var array
- */
- public $whiteProtocols = array(
- 'ed2k', 'file', 'ftp', 'gopher', 'http', 'https',
- 'irc', 'mailto', 'news', 'nntp', 'telnet', 'webcal',
- 'xmpp', 'callto',
- );
-
- /**
- * List of attributes that can contain protocols
- *
- * @var array
- */
- public $protocolAttributes = array(
- 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc', 'src', 'formaction',
- );
-
- /**
- * List of dangerous CSS keywords
- *
- * Whole style="" attribute will be removed, if parser will find one of
- * these keywords
- *
- * @var array
- */
- public $cssKeywords = array(
- 'absolute', 'behavior', 'behaviour', 'content', 'expression',
- 'fixed', 'include-source', 'moz-binding',
- );
-
- /**
- * List of tags that can have no "closing tag"
- *
- * @var array
- * @deprecated XHTML does not allow such tags
- */
- public $noClose = array();
-
- /**
- * List of block-level tags that terminates paragraph
- *
- * Paragraph will be closed when this tags opened
- *
- * @var array
- */
- public $closeParagraph = array(
- 'address', 'article', 'aside', 'audio', 'blockquote', 'canvas',
- 'center', 'dd', 'dir', 'div', 'dl', 'dt',
- 'figure', 'figcaption', 'footer', 'h1', 'h2', 'h3',
- 'h4', 'h5', 'h6', 'header', 'hr', 'isindex',
- 'listing', 'main', 'marquee', 'menu', 'multicol', 'nav',
- 'ol', 'output', 'p', 'plaintext', 'pre', 'section',
- 'table', 'ul', 'video', 'xmp',
- );
-
- /**
- * List of table tags, all table tags outside a table will be removed
- *
- * @var array
- */
- public $tableTags = array(
- 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
- 'thead', 'tr',
- );
-
- /**
- * List of list tags
- *
- * @var array
- */
- public $listTags = array('dir', 'menu', 'ol', 'ul', 'dl', );
-
- /**
- * List of dangerous attributes
- *
- * @var array
- */
- public $attributes = array('dynsrc', 'id', 'name', );
-
- /**
- * List of allowed "namespaced" attributes
- *
- * @var array
- */
- public $attributesNS = array('xml:lang', );
-
- /**
- * Constructs class
- *
- * @access public
- */
- public function __construct()
- {
- //making regular expressions based on Proto & CSS arrays
- foreach ($this->blackProtocols as $proto) {
- $preg = "/[\s\x01-\x1F]*";
- for ($i=0; $i<strlen($proto); $i++) {
- $preg .= $proto[$i] . "[\s\x01-\x1F]*";
- }
- $preg .= ":/i";
- $this->protoRegexps[] = $preg;
- }
-
- foreach ($this->cssKeywords as $css) {
- $this->cssRegexps[] = '/' . $css . '/i';
- }
- return true;
- }
-
- /**
- * Handles the writing of attributes - called from $this->openHandler()
- *
- * @param array $attrs array of attributes $name => $value
- * @param string|null $tag
- * @return boolean
- */
- protected function writeAttrs ($attrs, $tag = null)
- {
- if (is_array($attrs)) {
- foreach ($attrs as $name => $value) {
- $name = strtolower($name);
-
- if (strpos($name, 'on') === 0) {
- continue;
- }
-
- if (strpos($name, 'data') === 0) {
- continue;
- }
-
- if ($tag != 'a' and in_array($name, $this->attributes)) {
- continue;
- }
-
- if (!preg_match('/^[a-z0-9]+$/i', $name)) {
- if (!in_array($name, $this->attributesNS)) {
- continue;
- }
- }
-
- if (($value === true) || (is_null($value))) {
- $value = $name;
- }
-
- if ($name == 'style') {
- // removes insignificant backslahes
- $value = str_replace("\\", '', $value);
-
- // removes CSS comments
- while (1) {
- $_value = preg_replace('!/\*.*?\*/!s', '', $value);
-
- if ($_value == $value) {
- break;
- }
-
- $value = $_value;
- }
-
- // replace all & to &
- $value = str_replace('&', '&', $value);
- $value = str_replace('&', '&', $value);
-
- foreach ($this->cssRegexps as $css) {
- if (preg_match($css, $value)) {
- continue 2;
- }
- }
-
- foreach ($this->protoRegexps as $proto) {
- if (preg_match($proto, $value)) {
- continue 2;
- }
- }
- }
-
- $tempval = preg_replace_callback('/&#(\d+);?/m', function ($matches) { return chr($matches[1]); }, $value); //"'
- $tempval = preg_replace_callback(
- '/&#x([0-9a-f]+);?/mi',
- function ($matches) { return chr(hexdec($matches[1])); },
- $tempval
- );
-
- if ((in_array($name, $this->protocolAttributes))
- && (strpos($tempval, ':') !== false)
- ) {
- if ($this->protocolFiltering == 'black') {
- foreach ($this->protoRegexps as $proto) {
- if (preg_match($proto, $tempval)) {
- continue 2;
- }
- }
- } else {
- $_tempval = explode(':', $tempval);
- $proto = $_tempval[0];
-
- if (!in_array($proto, $this->whiteProtocols)) {
- continue;
- }
- }
- }
-
- $value = str_replace("\"", '"', $value);
- $this->xhtml .= ' ' . $name . '="' . $value . '"';
- }
- }
-
- return true;
- }
-
- /**
- * Opening tag handler - called from HTMLSax
- *
- * @param object &$parser HTML Parser
- * @param string $name tag name
- * @param array $attrs tag attributes
- *
- * @return boolean
- */
- public function openHandler(&$parser, $name, $attrs)
- {
- $name = strtolower($name);
-
- if (in_array($name, $this->deleteTagsContent)) {
- array_push($this->dcStack, $name);
- $this->dcCounter[$name] = isset($this->dcCounter[$name])
- ? $this->dcCounter[$name]+1 : 1;
- }
- if (count($this->dcStack) != 0) {
- return true;
- }
-
- if (in_array($name, $this->deleteTags)
- && !in_array($name, $this->allowTags)
- ) {
- return true;
- }
-
- if (!preg_match('/^[a-z0-9]+$/i', $name)) {
- if (preg_match('!(?:\@|://)!i', $name)) {
- $this->xhtml .= '<' . $name . '>';
- }
- return true;
- }
-
- if (in_array($name, $this->singleTags)) {
- $this->xhtml .= '<' . $name;
- $this->writeAttrs($attrs, $name);
- $this->xhtml .= ' />';
- return true;
- }
-
- // TABLES: cannot open table elements when we are not inside table
- if ((isset($this->counter['table']))
- && ($this->counter['table'] <= 0)
- && (in_array($name, $this->tableTags))
- ) {
- return true;
- }
-
- // PARAGRAPHS: close paragraph when closeParagraph tags opening
- if ((in_array($name, $this->closeParagraph))
- && (in_array('p', $this->stack))
- ) {
- $this->closeHandler($parser, 'p');
- }
-
- // LISTS: we should close <li> if <li> of the same level opening
- if (($name == 'li') && count($this->liStack)
- && ($this->listScope == $this->liStack[count($this->liStack) - 1])
- ) {
- $this->closeHandler($parser, 'li');
- }
-
- // LISTS: we want to know on what nesting level of lists we are
- if (in_array($name, $this->listTags)) {
- ++$this->listScope;
- }
-
- if ($name == 'li') {
- array_push($this->liStack, $this->listScope);
- }
-
- $this->xhtml .= '<' . $name;
- $this->writeAttrs($attrs, $name);
- $this->xhtml .= '>';
- array_push($this->stack,$name);
- $this->counter[$name] = isset($this->counter[$name])
- ? ($this->counter[$name] + 1) : 1;
-
- return true;
- }
-
- /**
- * Closing tag handler - called from HTMLSax
- *
- * @param object &$parser HTML parser
- * @param string $name tag name
- *
- * @return boolean
- */
- public function closeHandler(&$parser, $name)
- {
- $name = strtolower($name);
-
- if (isset($this->dcCounter[$name])
- && ($this->dcCounter[$name] > 0)
- && (in_array($name, $this->deleteTagsContent))
- ) {
- while ($name != ($tag = array_pop($this->dcStack))) {
- --$this->dcCounter[$tag];
- }
-
- --$this->dcCounter[$name];
- }
-
- if (count($this->dcStack) != 0) {
- return true;
- }
-
- if ((isset($this->counter[$name])) && ($this->counter[$name] > 0)) {
- while ($name != ($tag = array_pop($this->stack))) {
- $this->closeTag($tag);
- }
-
- $this->closeTag($name);
- }
- return true;
- }
-
- /**
- * Closes tag
- *
- * @param string $tag tag name
- *
- * @return boolean
- */
- protected function closeTag($tag)
- {
- if (!in_array($tag, $this->noClose)) {
- $this->xhtml .= '</' . $tag . '>';
- }
-
- --$this->counter[$tag];
-
- if (in_array($tag, $this->listTags)) {
- --$this->listScope;
- }
-
- if ($tag == 'li') {
- array_pop($this->liStack);
- }
-
- return true;
- }
-
- /**
- * Character data handler - called from HTMLSax
- *
- * @param object &$parser HTML parser
- * @param string $data textual data
- *
- * @return boolean
- */
- public function dataHandler(&$parser, $data)
- {
- if (count($this->dcStack) == 0) {
- $this->xhtml .= $data;
- }
-
- return true;
- }
-
- /**
- * Escape handler - called from HTMLSax
- *
- * @param object &$parser HTML parser
- * @param string $data comments or other type of data
- *
- * @return boolean
- */
- public function escapeHandler(&$parser, $data)
- {
- return true;
- }
-
- /**
- * Allow tags
- *
- * Example:
- * <pre>
- * $safe = new HTML_Safe;
- * $safe->setAllowTags(array('body'));
- * </pre>
- *
- * @param array $tags Tags to allow
- *
- * @return void
- */
- public function setAllowTags($tags = array())
- {
- if (is_array($tags)) {
- $this->allowTags = $tags;
- }
- }
-
- /**
- * Returns the allowed tags
- *
- * @return array
- */
- public function getAllowTags()
- {
- return $this->allowTags;
- }
-
- /**
- * Reset the allowed tags
- *
- * @return void
- */
- public function resetAllowTags()
- {
- $this->allowTags = array();
- }
-
- /**
- * Returns the XHTML document
- *
- * @return string Processed (X)HTML document
- */
- public function getXHTML()
- {
- while ($tag = array_pop($this->stack)) {
- $this->closeTag($tag);
- }
-
- return $this->xhtml;
- }
-
- /**
- * Clears current document data
- *
- * @return boolean
- */
- public function clear()
- {
- $this->xhtml = '';
- return true;
- }
-
- /**
- * Main parsing fuction
- *
- * @param string $doc HTML document for processing
- *
- * @return string Processed (X)HTML document
- */
- public function parse($doc)
- {
- $result = '';
-
- // Save all '<' symbols
- $doc = preg_replace('/<(?=[^a-zA-Z\/\!\?\%])/', '<', $doc);
-
- // Web documents shouldn't contains \x00 symbol
- $doc = str_replace("\x00", '', $doc);
-
- // Opera6 bug workaround
- $doc = str_replace("\xC0\xBC", '<', $doc);
-
- if ($this->repackUTF7) {
- // UTF-7 encoding ASCII decode
- $doc = $this->repackUTF7($doc);
- }
-
- // Instantiate the parser
- $parser = new XML_HTMLSax3();
-
- // Set up the parser
- $parser->set_object($this);
-
- $parser->set_element_handler('openHandler', 'closeHandler');
- $parser->set_data_handler('dataHandler');
- $parser->set_escape_handler('escapeHandler');
-
- $parser->parse($doc);
-
- $result = $this->getXHTML();
-
- $this->clear();
-
- return $result;
- }
-
- /**
- * UTF-7 decoding fuction
- *
- * @param string $str HTML document for recode ASCII part of UTF-7 back to ASCII
- * @return string Decoded document
- */
- protected function repackUTF7($str)
- {
- return preg_replace_callback('!\+([0-9a-zA-Z/]+)\-!', array($this, 'repackUTF7Callback'), $str);
- }
-
- /**
- * Additional UTF-7 decoding fuction
- *
- * @param string $str String for recode ASCII part of UTF-7 back to ASCII
- * @return string Recoded string
- */
- protected function repackUTF7Callback($str)
- {
- $str = base64_decode($str[1]);
- $str = preg_replace_callback('/^((?:\x00.)*)((?:[^\x00].)+)/', array($this, 'repackUTF7Back'), $str);
- return preg_replace('/\x00(.)/', '$1', $str);
- }
-
- /**
- * Additional UTF-7 encoding fuction
- *
- * @param string $str String for recode ASCII part of UTF-7 back to ASCII
- * @return string Recoded string
- */
- protected function repackUTF7Back($str)
- {
- return $str[1].'+'.rtrim(base64_encode($str[2]), '=').'-';
- }
+ /**
+ * Storage for resulting HTML output
+ *
+ * @var string
+ */
+ protected $xhtml = '';
+
+ /**
+ * Array of counters for each tag
+ *
+ * @var array
+ */
+ protected $counter = [];
+
+ /**
+ * Stack of unclosed tags
+ *
+ * @var array
+ */
+ protected $stack = [];
+
+ /**
+ * Array of counters for tags that must be deleted with all content
+ *
+ * @var array
+ */
+ protected $dcCounter = [];
+
+ /**
+ * Stack of unclosed tags that must be deleted with all content
+ *
+ * @var array
+ */
+ protected $dcStack = [];
+
+ /**
+ * Stores level of list (ol/ul) nesting
+ *
+ * @var int
+ */
+ protected $listScope = 0;
+
+ /**
+ * Stack of unclosed list tags
+ *
+ * @var array
+ */
+ protected $liStack = [];
+
+ /**
+ * Array of prepared regular expressions for protocols (schemas) matching
+ *
+ * @var array
+ */
+ protected $protoRegexps = [];
+
+ /**
+ * Array of prepared regular expressions for CSS matching
+ *
+ * @var array
+ */
+ protected $cssRegexps = [];
+
+ /**
+ * Allowed tags
+ *
+ * @var array
+ */
+ protected $allowTags = [];
+
+
+ /**
+ * List of single tags ("<tag>")
+ *
+ * @var array
+ */
+ public $singleTags = ['area', 'br', 'img', 'input', 'hr', 'wbr', ];
+
+ /**
+ * List of dangerous tags (such tags will be deleted)
+ *
+ * @var array
+ */
+ public $deleteTags = [
+ 'applet', 'base', 'basefont', 'bgsound', 'blink', 'body',
+ 'embed', 'frame', 'frameset', 'head', 'html', 'ilayer',
+ 'iframe', 'layer', 'link', 'meta', 'object', 'style',
+ 'title', 'script',
+ ];
+
+ /**
+ * List of dangerous tags (such tags will be deleted, and all content
+ * inside this tags will be also removed)
+ *
+ * @var array
+ */
+ public $deleteTagsContent = ['script', 'style', 'title', 'xml', ];
+
+ /**
+ * Type of protocols filtering ('white' or 'black')
+ *
+ * @var string
+ */
+ public $protocolFiltering = 'white';
+
+ /**
+ * List of "dangerous" protocols (used for blacklist-filtering)
+ *
+ * @var array
+ */
+ public $blackProtocols = [
+ 'about', 'chrome', 'data', 'disk', 'hcp',
+ 'help', 'javascript', 'livescript', 'lynxcgi', 'lynxexec',
+ 'ms-help', 'ms-its', 'mhtml', 'mocha', 'opera',
+ 'res', 'resource', 'shell', 'vbscript', 'view-source',
+ 'vnd.ms.radio', 'wysiwyg',
+ ];
+
+ /**
+ * List of "safe" protocols (used for whitelist-filtering)
+ *
+ * @var array
+ */
+ public $whiteProtocols = [
+ 'ed2k', 'file', 'ftp', 'gopher', 'http', 'https',
+ 'irc', 'mailto', 'news', 'nntp', 'telnet', 'webcal',
+ 'xmpp', 'callto',
+ ];
+
+ /**
+ * List of attributes that can contain protocols
+ *
+ * @var array
+ */
+ public $protocolAttributes = [
+ 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc', 'src',
+ ];
+
+ /**
+ * List of dangerous CSS keywords
+ *
+ * Whole style="" attribute will be removed, if parser will find one of
+ * these keywords
+ *
+ * @var array
+ */
+ public $cssKeywords = [
+ 'absolute', 'behavior', 'behaviour', 'content', 'expression',
+ 'fixed', 'include-source', 'moz-binding',
+ ];
+
+ /**
+ * List of tags that can have no "closing tag"
+ *
+ * @var array
+ * @deprecated XHTML does not allow such tags
+ */
+ public $noClose = [];
+
+ /**
+ * List of block-level tags that terminates paragraph
+ *
+ * Paragraph will be closed when this tags opened
+ *
+ * @var array
+ */
+ public $closeParagraph = [
+ 'address', 'article', 'aside', 'blockquote', 'details', 'div',
+ 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form',
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
+ 'header', 'hgroup', 'hr', 'main', 'menu', 'nav',
+ 'ol', 'p', 'pre', 'section', 'table', 'ul',
+ ];
+
+ /**
+ * List of table tags, all table tags outside a table will be removed
+ *
+ * @var array
+ */
+ public $tableTags = [
+ 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
+ 'thead', 'tr',
+ ];
+
+ /**
+ * List of list tags
+ *
+ * @var array
+ */
+ public $listTags = ['menu', 'ol', 'ul', 'dl', ];
+
+ /**
+ * List of dangerous attributes
+ *
+ * @var array
+ */
+ public $attributes = ['dynsrc', 'id', 'name', ];
+
+ /**
+ * List of allowed "namespaced" attributes
+ *
+ * @var array
+ */
+ public $attributesNS = ['xml:lang', ];
+
+ /**
+ * Constructs class
+ *
+ * @access public
+ */
+ public function __construct()
+ {
+ //making regular expressions based on Proto & CSS arrays
+ foreach ($this->blackProtocols as $proto)
+ {
+ $preg = "/[\s\x01-\x1F]*";
+
+ for ($i = 0; $i < strlen($proto); $i++)
+ {
+ $preg .= $proto[$i] . "[\s\x01-\x1F]*";
+ }
+
+ $preg .= ":/i";
+ $this->protoRegexps[] = $preg;
+ }
+
+ foreach ($this->cssKeywords as $css)
+ {
+ $this->cssRegexps[] = '/' . $css . '/i';
+ }
+
+ return true;
+ }
+
+ /**
+ * Handles the writing of attributes - called from $this->openHandler()
+ *
+ * @param array $attrs array of attributes $name => $value
+ *
+ * @return boolean
+ */
+ protected function writeAttrs($attrs)
+ {
+ if (is_array($attrs))
+ {
+ foreach ($attrs as $name => $value)
+ {
+ $name = strtolower($name);
+
+ if (strpos($name, 'on') === 0)
+ {
+ continue;
+ }
+
+ // MODIF SPIP : ne pas supprimer les attributs html5 data-xx
+ if (in_array($name, $this->attributes))
+ {
+ continue;
+ }
+
+ // remove dataxx attributes but not the html5 data-xx one
+ if (strpos($name, 'data') === 0)
+ {
+ if (strpos($name, 'data-') !== 0 || (!preg_match('/^[a-z0-9-]+$/i', $name))) {
+ continue;
+ }
+ }
+ elseif (!preg_match('/^[a-z0-9]+$/i', $name))
+ {
+ if (!in_array($name, $this->attributesNS))
+ {
+ continue;
+ }
+ }
+ // FIN MODIF SPIP
+
+ if (($value === true) || (is_null($value)))
+ {
+ $value = $name;
+ }
+
+ if ($name == 'style')
+ {
+ // removes insignificant backslahes
+ $value = str_replace("\\", '', $value);
+
+ // removes CSS comments
+ while (1)
+ {
+ $_value = preg_replace('!/\*.*?\*/!s', '', $value);
+
+ if ($_value == $value)
+ {
+ break;
+ }
+
+ $value = $_value;
+ }
+
+ // replace all & to &
+ $value = str_replace('&', '&', $value);
+ $value = str_replace('&', '&', $value);
+
+ foreach ($this->cssRegexps as $css)
+ {
+ if (preg_match($css, $value))
+ {
+ continue 2;
+ }
+ }
+
+ foreach ($this->protoRegexps as $proto)
+ {
+ if (preg_match($proto, $value))
+ {
+ continue 2;
+ }
+ }
+ }
+
+ $tempval = preg_replace_callback('/&#(\d+);?/m', function ($matches) { return chr($matches[1]); }, $value); //"'
+ $tempval = preg_replace_callback(
+ '/&#x([0-9a-f]+);?/mi',
+ function ($matches) { return chr(hexdec($matches[1])); },
+ $tempval
+ );
+
+ if ((in_array($name, $this->protocolAttributes))
+ && (strpos($tempval, ':') !== false)
+ )
+ {
+ if ($this->protocolFiltering == 'black')
+ {
+ foreach ($this->protoRegexps as $proto)
+ {
+ if (preg_match($proto, $tempval))
+ {
+ continue 2;
+ }
+ }
+ }
+ else
+ {
+ $_tempval = explode(':', $tempval);
+ $proto = $_tempval[0];
+
+ if (!in_array($proto, $this->whiteProtocols))
+ {
+ continue;
+ }
+ }
+ }
+
+ $value = str_replace("\"", '"', $value);
+ $this->xhtml .= ' ' . $name . '="' . $value . '"';
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Opening tag handler - called from HTMLSax
+ *
+ * @param object &$parser HTML Parser
+ * @param string $name tag name
+ * @param array $attrs tag attributes
+ *
+ * @return boolean
+ */
+ public function openHandler(&$parser, $name, $attrs)
+ {
+ $name = strtolower($name);
+
+ if (in_array($name, $this->deleteTagsContent))
+ {
+ array_push($this->dcStack, $name);
+ $this->dcCounter[$name] = isset($this->dcCounter[$name])
+ ? $this->dcCounter[$name] + 1
+ : 1;
+ }
+
+ if (count($this->dcStack) != 0)
+ {
+ return true;
+ }
+
+ if (in_array($name, $this->deleteTags)
+ && !in_array($name, $this->allowTags)
+ )
+ {
+ return true;
+ }
+
+ if (!preg_match('/^[a-z0-9]+$/i', $name))
+ {
+ if (preg_match('!(?:\@|://)!i', $name))
+ {
+ $this->xhtml .= '<' . $name . '>';
+ }
+
+ return true;
+ }
+
+ if (in_array($name, $this->singleTags))
+ {
+ $this->xhtml .= '<' . $name;
+ $this->writeAttrs($attrs);
+ $this->xhtml .= ' />';
+
+ return true;
+ }
+
+ // TABLES: cannot open table elements when we are not inside table
+ if ((isset($this->counter['table']))
+ && ($this->counter['table'] <= 0)
+ && (in_array($name, $this->tableTags))
+ )
+ {
+ return true;
+ }
+
+ // PARAGRAPHS: close paragraph when closeParagraph tags opening
+ if ((in_array($name, $this->closeParagraph))
+ && (in_array('p', $this->stack))
+ )
+ {
+ $this->closeHandler($parser, 'p');
+ }
+
+ // LISTS: we should close <li> if <li> of the same level opening
+ if (($name == 'li') && count($this->liStack)
+ && ($this->listScope == $this->liStack[count($this->liStack) - 1])
+ )
+ {
+ $this->closeHandler($parser, 'li');
+ }
+
+ // LISTS: we want to know on what nesting level of lists we are
+ if (in_array($name, $this->listTags))
+ {
+ ++$this->listScope;
+ }
+
+ if ($name == 'li')
+ {
+ array_push($this->liStack, $this->listScope);
+ }
+
+ $this->xhtml .= '<' . $name;
+ $this->writeAttrs($attrs);
+ $this->xhtml .= '>';
+ array_push($this->stack, $name);
+ $this->counter[$name] = isset($this->counter[$name])
+ ? ($this->counter[$name] + 1)
+ : 1;
+
+ return true;
+ }
+
+ /**
+ * Closing tag handler - called from HTMLSax
+ *
+ * @param object &$parser HTML parser
+ * @param string $name tag name
+ *
+ * @return boolean
+ */
+ public function closeHandler(&$parser, $name)
+ {
+ $name = strtolower($name);
+
+ if (isset($this->dcCounter[$name])
+ && ($this->dcCounter[$name] > 0)
+ && (in_array($name, $this->deleteTagsContent))
+ )
+ {
+ while ($name != ($tag = array_pop($this->dcStack)))
+ {
+ --$this->dcCounter[$tag];
+ }
+
+ --$this->dcCounter[$name];
+ }
+
+ if (count($this->dcStack) != 0)
+ {
+ return true;
+ }
+
+ if ((isset($this->counter[$name])) && ($this->counter[$name] > 0))
+ {
+ while ($name != ($tag = array_pop($this->stack)))
+ {
+ $this->closeTag($tag);
+ }
+
+ $this->closeTag($name);
+ }
+
+ return true;
+ }
+
+ /**
+ * Closes tag
+ *
+ * @param string $tag tag name
+ *
+ * @return boolean
+ */
+ protected function closeTag($tag)
+ {
+ if (!in_array($tag, $this->noClose))
+ {
+ $this->xhtml .= '</' . $tag . '>';
+ }
+
+ --$this->counter[$tag];
+
+ if (in_array($tag, $this->listTags))
+ {
+ --$this->listScope;
+ }
+
+ if ($tag == 'li')
+ {
+ array_pop($this->liStack);
+ }
+
+ return true;
+ }
+
+ /**
+ * Character data handler - called from HTMLSax
+ *
+ * @param object &$parser HTML parser
+ * @param string $data textual data
+ *
+ * @return boolean
+ */
+ public function dataHandler(&$parser, $data)
+ {
+ if (count($this->dcStack) == 0)
+ {
+ $this->xhtml .= $data;
+ }
+
+ return true;
+ }
+
+ /**
+ * Escape handler - called from HTMLSax
+ *
+ * @param object &$parser HTML parser
+ * @param string $data comments or other type of data
+ *
+ * @return boolean
+ */
+ public function escapeHandler(&$parser, $data)
+ {
+ return true;
+ }
+
+ /**
+ * Allow tags
+ *
+ * Example:
+ * <pre>
+ * $safe = new SafeHTML;
+ * $safe->setAllowTags(['body']);
+ * </pre>
+ *
+ * @param array $tags Tags to allow
+ *
+ * @return void
+ */
+ public function setAllowTags($tags = [])
+ {
+ if (is_array($tags))
+ {
+ $this->allowTags = $tags;
+ }
+ }
+
+ /**
+ * Returns the allowed tags
+ *
+ * @return array
+ */
+ public function getAllowTags()
+ {
+ return $this->allowTags;
+ }
+
+ /**
+ * Reset the allowed tags
+ *
+ * @return void
+ */
+ public function resetAllowTags()
+ {
+ $this->allowTags = [];
+ }
+
+ /**
+ * Returns the XHTML document
+ *
+ * @return string Processed (X)HTML document
+ */
+ public function getXHTML()
+ {
+ while ($tag = array_pop($this->stack))
+ {
+ $this->closeTag($tag);
+ }
+
+ return $this->xhtml;
+ }
+
+ /**
+ * Clears current document data
+ *
+ * @return boolean
+ */
+ public function clear()
+ {
+ $this->xhtml = '';
+
+ return true;
+ }
+
+ /**
+ * Main parsing function
+ *
+ * @param string $doc HTML document for processing
+ *
+ * @return string Processed (X)HTML document
+ */
+ public function parse($doc)
+ {
+ $result = '';
+
+ // Save all '<' symbols
+ $doc = preg_replace('/<(?=[^a-zA-Z\/\!\?\%])/', '<', $doc);
+
+ // UTF7 pack
+ $doc = $this->repackUTF7($doc);
+
+ // Instantiate the parser
+ $parser = new XML_HTMLSax3;
+
+ // Set up the parser
+ $parser->set_object($this);
+
+ $parser->set_element_handler('openHandler', 'closeHandler');
+ $parser->set_data_handler('dataHandler');
+ $parser->set_escape_handler('escapeHandler');
+
+ $parser->parse($doc);
+
+ $result = $this->getXHTML();
+
+ $this->clear();
+
+ return $result;
+ }
+
+ /**
+ * UTF-7 decoding function
+ *
+ * @param string $str HTML document for recode ASCII part of UTF-7 back to ASCII
+ * @return string Decoded document
+ * @access private
+ */
+ function repackUTF7($str)
+ {
+ return preg_replace_callback('!\+([0-9a-zA-Z/]+)\-!', [$this, 'repackUTF7Callback'], $str);
+ }
+
+ /**
+ * Additional UTF-7 decoding function
+ *
+ * @param string $str String for recode ASCII part of UTF-7 back to ASCII
+ * @return string Recoded string
+ * @access private
+ */
+ function repackUTF7Callback($str)
+ {
+ $str = base64_decode($str[1]);
+ $str = preg_replace_callback('/^((?:\x00.)*)((?:[^\x00].)+)/', [$this, 'repackUTF7Back'], $str);
+
+ return preg_replace('/\x00(.)/', '$1', $str);
+ }
+
+ /**
+ * Additional UTF-7 encoding function
+ *
+ * @param string $str String for recode ASCII part of UTF-7 back to ASCII
+ * @return string Recoded string
+ * @access private
+ */
+ function repackUTF7Back($str)
+ {
+ return $str[1] . '+' . rtrim(base64_encode($str[2]), '=') . '-';
+ }
}
+
-(c) Miguel Vazquez Gocobachi, WackoWiki Team, 2005-2017\r
-(c) Roman Ivanov, 2004-2005\r
-(c) Pixel-Apes ( http://pixel-apes.com/ ), 2004-2005\r
-(c) JetStyle ( http://jetstyle.ru/ ), 2004-2005\r
-Maintainer -- Roman Ivanov <thingol@mail.ru>\r
-\r
-Redistribution and use in source and binary forms, with or without\r
-modification, are permitted provided that the following conditions\r
-are met:\r
-1. Redistributions of source code must retain the above copyright\r
- notice, this list of conditions and the following disclaimer.\r
-2. Redistributions in binary form must reproduce the above copyright\r
- notice, this list of conditions and the following disclaimer in the\r
- documentation and/or other materials provided with the distribution.\r
-3. The name of the author may not be used to endorse or promote products\r
- derived from this software without specific prior written permission.\r
-\r
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\r
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+(c) Miguel Vazquez Gocobachi, WackoWiki Team, 2006-2020
+(c) Roman Ivanov, 2004-2005
+(c) Pixel-Apes ( http://pixel-apes.com/ ), 2004-2005
+(c) JetStyle ( http://jetstyle.ru/ ), 2004-2005
+Maintainer -- Roman Ivanov <thingol@mail.ru>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-SafeHTML\r
---------\r
-Version 1.3.10.\r
-https://wackowiki.org/doc/Dev/Projects/SafeHTML\r
---------\r
-\r
-This parser strips down all potentially dangerous content within HTML:\r
- * opening tag without its closing tag\r
- * closing tag without its opening tag\r
- * any of these tags: "base", "basefont", "head", "html", "body", "applet", "object",\r
- "iframe", "frame", "frameset", "script", "layer", "ilayer", "embed", "bgsound",\r
- "link", "meta", "style", "title", "blink", "xml" etc.\r
- * any of these attributes: on*, data*, dynsrc\r
- * javascript:/vbscript:/about: etc. protocols\r
- * expression/behavior etc. in styles\r
- * any other active content\r
-It also tries to convert code to XHTML valid, but htmltidy is far better solution for this task.\r
-\r
-If you found any bugs in this parser, please file an issue -- https://wackowiki.org/bugs/\r
-\r
-Please, subscribe to https://wackowiki.org/doc/Dev/Projects/SafeHTML in order to receive notices\r
-when SAFEHTML will be updated.\r
-\r
--- Roman Ivanov.\r
--- Pixel-Apes ( http://pixel-apes.com ).\r
--- JetStyle ( http://jetstyle.ru/ ).\r
-\r
-\r
-\r
---------\r
-Version history:\r
---------\r
-1.3.10.\r
- * added HTML5 Block-level elements\r
-1.3.9.\r
- * Replaced preg_replace() e modifier with preg_replace_callback\r
-1.3.8.\r
- * UTF-7 XSS vulnerability fixed\r
-1.3.7.\r
- * Added 'dl' to the list of 'lists' tags.\r
- * Added 'callto' to the white list of protocols.\r
- * Added white list of "namespaced" attributes.\r
-1.3.6.\r
- * More accurate UTF-7 decoding.\r
-1.3.5.\r
- * Two serious security flaws fixed: UTF-7 XSS and CSS comments handling.\r
-1.3.2.\r
- * Security flaw (improper quotes handling in attributes' values) fixed. Big thanks to Nick Cleaton.\r
-1.3.1.\r
- * Dumb bug fixed (some closing tags were ignored).\r
-1.3.0.\r
- * Two holes (with decimal HTML entities and with \x00 symbol) fixed.\r
- * Class rewritten under PEAR coding standarts.\r
- * Class now uses unmodified HTMLSax3 from PEAR.\r
- * To the list of table tags added: "caption", "col", "colgroup".\r
-1.2.1.\r
- * It was possible to create XSS with hexadecimal HTML entities. Fixed. Big thanks to Christian Stocker.\r
-1.2.0.\r
- * "id" and "name" attributes added to dangerous attributes list, because malefactor can broke legal javascript by spoofing ID or NAME of some element.\r
- * New method parse() allows to do all parsing process in two lines of code. Examples also updated.\r
- * New array, closeParagraph, contains list of block-level elements. When we open such elemet, we should close paragraph before. . It allows SafeHTML to produce more XHTML compliant code.\r
- * Added "webcal" to white list of protocols for those who uses calendar programs (Mozilla/iCal/etc).\r
- * Now SafeHTML strips down table elements when we are not inside table.\r
- * Now SafeHTML correctly closes unclosed "li" tags: before opening "li" of the same nesting level.\r
-1.1.0.\r
- * New "dangerous" protocols: hcp, ms-help, help, disk, vnd.ms.radio, opera, res, resource, chrome, mocha, livescript.\r
- * <XML> tag was moved from "tags for deletion" to "tags for deletion with content".\r
- * New "dangerous" CSS instruction "include-source" (NN4 specific).\r
- * New array, Attributes, contains list of attributes for removal. If you need to remove "id" or "name" attribute, \r
- just add it to this array.\r
- * Now it is possible to choose between white-list and black-list filtering of protocols. Defaults are "white-list".\r
- This list is: "http", "https", "ftp", "telnet", "news", "nntp", "gopher", "mailto", "file".\r
- * For speed purposes, we now filter protocols only from these attributes: src, href, action, lowsrc, dynsrc, \r
- background, codebase.\r
- * Opera6 XSS bug ([\xC0][\xBC]script>alert(1)[\xC0][\xBC]/script> [UTF-8] workarounded.\r
-1.0.4.\r
- New "dangerous" tag: plaintext.\r
-1.0.3.\r
- Added array of elements that can have no closing tag.\r
-1.0.2.\r
- Bug fix: <img src="javascript:alert(1);"> attack.\r
- Thanks to shmel.\r
-1.0.1.\r
- Bug fix: safehtml hangs on <style></style></style> code.\r
- Thanks to lj user=electrocat.\r
-1.0.0.\r
- First public release\r
+SafeHTML
+--------
+Version 1.3.12.
+https://wackowiki.org/doc/Dev/Projects/SafeHTML
+--------
+
+This parser strips down all potentially dangerous content within HTML:
+ * opening tag without its closing tag
+ * closing tag without its opening tag
+ * any of these tags: "base", "basefont", "head", "html", "body", "applet", "object",
+ "iframe", "frame", "frameset", "script", "layer", "ilayer", "embed", "bgsound",
+ "link", "meta", "style", "title", "blink", "xml" etc.
+ * any of these attributes: on*, data*, dynsrc
+ * javascript:/vbscript:/about: etc. protocols
+ * expression/behavior etc. in styles
+ * any other active content
+It also tries to convert code to XHTML valid, but htmltidy is far better solution for this task.
+
+If you found any bugs in this parser, please file an issue -- https://wackowiki.org/bugs/
+
+Please, subscribe to https://wackowiki.org/doc/Dev/Projects/SafeHTML in order to receive notices
+when SAFEHTML will be updated.
+
+-- Roman Ivanov.
+-- Pixel-Apes ( http://pixel-apes.com ).
+-- JetStyle ( http://jetstyle.ru/ ).
+
+
+
+--------
+Version history:
+--------
+1.3.12
+ * added missing HTML5 tag terminators for paragraph
+ * removed obsolete and deprecated HTML elements
+1.3.11.
+ * added new HTML5 Block-level elements
+1.3.10.
+ * Replaced preg_replace() e modifier with preg_replace_callback
+1.3.9.
+ * UTF-7 XSS vulnerability fixed
+1.3.8.
+ * Allowed tags with setAllowTags() method.
+ * AllowTags can be disabled using resetAllowTags()
+1.3.7.
+ * Added 'dl' to the list of 'lists' tags.
+ * Added 'callto' to the white list of protocols.
+ * Added white list of "namespaced" attributes.
+1.3.6.
+ * More accurate UTF-7 decoding.
+1.3.5.
+ * Two serious security flaws fixed: UTF-7 XSS and CSS comments handling.
+1.3.2.
+ * Security flaw (improper quotes handling in attributes' values) fixed. Big thanks to Nick Cleaton.
+1.3.1.
+ * Dumb bug fixed (some closing tags were ignored).
+1.3.0.
+ * Two holes (with decimal HTML entities and with \x00 symbol) fixed.
+ * Class rewritten under PEAR coding standards.
+ * Class now uses unmodified HTMLSax3 from PEAR.
+ * To the list of table tags added: "caption", "col", "colgroup".
+1.2.1.
+ * It was possible to create XSS with hexadecimal HTML entities. Fixed. Big thanks to Christian Stocker.
+1.2.0.
+ * "id" and "name" attributes added to dangerous attributes list, because malefactor can broke legal javascript by spoofing ID or NAME of some element.
+ * New method parse() allows to do all parsing process in two lines of code. Examples also updated.
+ * New array, closeParagraph, contains list of block-level elements. When we open such element, we should close paragraph before. . It allows SafeHTML to produce more XHTML compliant code.
+ * Added "webcal" to white list of protocols for those who uses calendar programs (Mozilla/iCal/etc).
+ * Now SafeHTML strips down table elements when we are not inside table.
+ * Now SafeHTML correctly closes unclosed "li" tags: before opening "li" of the same nesting level.
+1.1.0.
+ * New "dangerous" protocols: hcp, ms-help, help, disk, vnd.ms.radio, opera, res, resource, chrome, mocha, livescript.
+ * <XML> tag was moved from "tags for deletion" to "tags for deletion with content".
+ * New "dangerous" CSS instruction "include-source" (NN4 specific).
+ * New array, Attributes, contains list of attributes for removal. If you need to remove "id" or "name" attribute,
+ just add it to this array.
+ * Now it is possible to choose between white-list and black-list filtering of protocols. Defaults are "white-list".
+ This list is: "http", "https", "ftp", "telnet", "news", "nntp", "gopher", "mailto", "file".
+ * For speed purposes, we now filter protocols only from these attributes: src, href, action, lowsrc, dynsrc,
+ background, codebase.
+ * Opera6 XSS bug ([\xC0][\xBC]script>alert(1)[\xC0][\xBC]/script> [UTF-8] workarounded.
+1.0.4.
+ New "dangerous" tag: plaintext.
+1.0.3.
+ Added array of elements that can have no closing tag.
+1.0.2.
+ Bug fix: <img src="javascript:alert(1);"> attack.
+ Thanks to shmel.
+1.0.1.
+ Bug fix: safehtml hangs on <style></style></style> code.
+ Thanks to lj user=electrocat.
+1.0.0.
+ First public release
<paquet
prefix="safehtml"
categorie="performance"
- version="1.5.2"
+ version="1.5.4"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="images/safehtml-32.png"
<credit>Roman Ivanov</credit>
<credit>Pixel-Apes</credit>
<credit>JetStyle</credit>
+ <credit lien="https://bitbucket.org/wackowiki/wackowiki/src/master/wacko/lib/">https://wackowiki.org/doc/Dev/Projects/SafeHTML</credit>
<licence lien="http://www.gnu.org/licenses/gpl-3.0.html">GPL</licence>
+
+ <procure nom="safehtml" version="1.3.12" />
</paquet>
<paquet
prefix="sites"
categorie="edition"
- version="1.10.6"
+ version="1.10.7"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/site-32.png"
<paquet
prefix="squelettes_par_rubrique"
categorie="outil"
- version="1.2.1"
+ version="1.2.2"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="squelettes_par_rubrique-32.png"
<paquet
prefix="stats"
categorie="statistique"
- version="1.1.11"
+ version="1.1.12"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/statistique-32.png"
<paquet
prefix="svp"
categorie="maintenance"
- version="1.3.12"
+ version="1.3.13"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="svp-64.png"
<paquet
prefix="tw"
categorie="edition"
- version="1.5.6"
+ version="1.5.7"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="textwheel-32.png"
<paquet
prefix="urls"
categorie="statistique"
- version="2.1.9"
+ version="2.1.10"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="prive/themes/spip/images/url-32.png"
<paquet
prefix="vertebres"
categorie="outil"
- version="1.3.2"
+ version="1.3.3"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="images/vertebres-32.png"
jQuery.spip.updateReaderBuffer();
}
+jQuery.spip.on_ajax_failed = function(blocfrag,statusCode,href,history) {
+ // marquer le bloc invalide
+ jQuery(blocfrag).addClass('invalid');
+ // si c'est une erreur 400 on a perdu la signature ajax
+ //console.log("AJAX Erreur");
+ //console.log(statusCode);
+ history = history || (history==null);
+ // quelle que soit l'erreur, on redirige si c'était la nouvelle URL principale de la page
+ if (history) {
+ //console.log("On redirige : " + href);
+ window.location.href = href;
+ }
+}
+
jQuery.spip.stateId=0;
jQuery.spip.setHistoryState = function(blocfrag){
if (!window.history.replaceState) return;
if (options.callback && typeof options.callback == "function")
options.callback.apply(blocfrag);
},
- error: function(){
+ error: function(e){
jQuery.spip.preloaded_urls[url]='';
+ jQuery.spip.on_ajax_failed(blocfrag,e.status,href,options.history);
}
});
}
success: function(c){
jQuery.spip.on_ajax_loaded(blocfrag,c);
jQuery.spip.preloaded_urls = {}; // on vide le cache des urls car on a fait une action en bdd
+ },
+ error: function(e){
+ jQuery.spip.preloaded_urls = {}; // on vide le cache des urls car on a fait une action en bdd
+ var href = parametre_url(url, 'redirect');
+ if (!href) {
+ href = window.location.href;
+ }
+ // si c'est une erreur 400 c'est un fragment ajax invalide, il faut rediriger vers href
+ jQuery.spip.on_ajax_failed(blocfrag,e.status,href,e.status === 400);
}/*,
iframe: jQuery.browser.msie*/
})
.formulaire_editer_logo .titrem,.formulaire_editer_logo .ajouter_survol {text-transform: uppercase;}
/* Date picker : passer par dessus des icones et du menu haut */
.ui-datepicker { z-index: 1001 !important;}
+
+/* Bloc ajax invalid apres reload */
+.ajaxbloc.invalid {
+ box-shadow: 0 0 var(--spip-alert-spacing-x) hsl(var(--spip-color-error--h), var(--spip-color-error--s), 50%);
+}
\ No newline at end of file
<paquet
prefix="dist"
categorie="squelette"
- version="3.2.3"
+ version="3.2.4"
etat="stable"
compatibilite="[3.2.0;3.2.*]"
logo="icon/skel.png"
User-agent: *
Allow: /local/cache-css/
Allow: /local/cache-js/
-Disallow: /local/
+Noindex: /local/
+Noindex: /plugins-dist/
+Noindex: /plugins/
+Noindex: /squelettes-dist/
+Noindex: /squelettes/
Disallow: /ecrire/
-Disallow: /plugins-dist/
Disallow: /lib/
-Disallow: /plugins/
Disallow: /prive/
-Disallow: /squelettes-dist/
-Disallow: /squelettes/
+Disallow: /spip.php?action=*
+Disallow: /spip.php?page=login*
+Disallow: /*.api/
Crawl-delay: 1
-Sitemap: #URL_SITE_SPIP/sitemap.xml
\ No newline at end of file
+Sitemap: #URL_SITE_SPIP/sitemap.xml