From 12dfbb9dba44e5ef8ee415520ea481034e7429d4 Mon Sep 17 00:00:00 2001 From: Ludovic CHEVALIER Date: Tue, 21 Dec 2021 11:37:05 +0100 Subject: [PATCH 1/1] [SPIP] v3.2.11 -> v3.2.12 --- www/CHANGELOG.TXT | 58 + www/ecrire/action/editer_objet.php | 8 +- www/ecrire/balise/formulaire_.php | 10 + www/ecrire/base/connect_sql.php | 47 +- www/ecrire/genie/optimiser.php | 12 + www/ecrire/inc/cvt_autosave.php | 14 + www/ecrire/inc/cvt_multietapes.php | 23 +- www/ecrire/inc/distant.php | 23 +- www/ecrire/inc/documents.php | 13 + www/ecrire/inc/headers.php | 27 +- www/ecrire/inc/modifier.php | 4 +- www/ecrire/inc/queue.php | 12 +- www/ecrire/inc/rubriques.php | 37 +- www/ecrire/inc/utils.php | 2 +- www/ecrire/inc_version.php | 10 +- www/ecrire/iterateur/data.php | 4 +- www/ecrire/maj/svn10000.php | 58 +- www/ecrire/paquet.xml | 4 +- www/ecrire/public/aiguiller.php | 25 +- www/ecrire/public/balises.php | 2 + www/ecrire/public/interfaces.php | 26 +- www/ecrire/public/references.php | 16 + www/ecrire/req/mysql.php | 39 +- www/ecrire/req/sqlite_generique.php | 5 +- www/plugins-dist.json | 78 +- www/plugins-dist/aide/paquet.xml | 2 +- www/plugins-dist/archiviste/paquet.xml | 2 +- www/plugins-dist/breves/paquet.xml | 2 +- www/plugins-dist/compagnon/paquet.xml | 2 +- .../compresseur/inc/compresseur_embarquer.php | 2 +- www/plugins-dist/compresseur/paquet.xml | 2 +- www/plugins-dist/dump/paquet.xml | 2 +- .../filtres_images/images_fonctions.php | 1 + www/plugins-dist/filtres_images/paquet.xml | 2 +- www/plugins-dist/forum/paquet.xml | 2 +- www/plugins-dist/jquery_ui/paquet.xml | 2 +- .../mediabox/mediabox_pipelines.php | 2 +- www/plugins-dist/mediabox/paquet.xml | 2 +- .../medias/action/copier_local.php | 14 +- www/plugins-dist/medias/paquet.xml | 2 +- www/plugins-dist/mots/paquet.xml | 2 +- .../prive/squelettes/navigation/mots.html | 2 +- www/plugins-dist/organiseur/paquet.xml | 2 +- www/plugins-dist/petitions/paquet.xml | 2 +- www/plugins-dist/plan/paquet.xml | 2 +- www/plugins-dist/porte_plume/paquet.xml | 2 +- .../porte_plume/porte_plume_pipelines.php | 3 + www/plugins-dist/revisions/paquet.xml | 2 +- .../lib/safehtml/classes/HTMLSax3.php | 913 +++++++---- .../safehtml/classes/HTMLSax3/Decorators.php | 475 ++++-- .../lib/safehtml/classes/HTMLSax3/States.php | 465 +++--- .../lib/safehtml/classes/safehtml.php | 1415 +++++++++-------- .../safehtml/lib/safehtml/license.txt | 54 +- .../safehtml/lib/safehtml/readme.txt | 180 ++- www/plugins-dist/safehtml/paquet.xml | 5 +- www/plugins-dist/sites/paquet.xml | 2 +- .../squelettes_par_rubrique/paquet.xml | 2 +- www/plugins-dist/statistiques/paquet.xml | 2 +- www/plugins-dist/svp/paquet.xml | 2 +- www/plugins-dist/textwheel/paquet.xml | 2 +- www/plugins-dist/urls_etendues/paquet.xml | 2 +- www/plugins-dist/vertebres/paquet.xml | 2 +- www/prive/javascript/ajaxCallback.js | 26 +- www/prive/themes/spip/forms.css.html | 5 + www/squelettes-dist/paquet.xml | 2 +- www/squelettes-dist/robots.txt.html | 15 +- 66 files changed, 2624 insertions(+), 1560 deletions(-) diff --git a/www/CHANGELOG.TXT b/www/CHANGELOG.TXT index f69be25c..0759db53 100644 --- a/www/CHANGELOG.TXT +++ b/www/CHANGELOG.TXT @@ -1,3 +1,61 @@ +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) -------------------------------------------- diff --git a/www/ecrire/action/editer_objet.php b/www/ecrire/action/editer_objet.php index 1f8f1e09..16327464 100644 --- a/www/ecrire/action/editer_objet.php +++ b/www/ecrire/action/editer_objet.php @@ -489,6 +489,12 @@ function objet_editer_heritage($objet, $id, $id_rubrique, $statut, $champs, $con 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); } } diff --git a/www/ecrire/balise/formulaire_.php b/www/ecrire/balise/formulaire_.php index fa99b730..6cb7143c 100644 --- a/www/ecrire/balise/formulaire_.php +++ b/www/ecrire/balise/formulaire_.php @@ -250,6 +250,9 @@ function balise_FORMULAIRE__contexte($form, $args) { $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); @@ -267,6 +270,13 @@ function balise_FORMULAIRE__contexte($form, $args) { $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'; } diff --git a/www/ecrire/base/connect_sql.php b/www/ecrire/base/connect_sql.php index ba1fa377..6ea29352 100644 --- a/www/ecrire/base/connect_sql.php +++ b/www/ecrire/base/connect_sql.php @@ -426,10 +426,29 @@ function table_jointure($x, $y) { * @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: @@ -456,12 +475,18 @@ function query_echappe_textes($query) { $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]; } /** @@ -475,13 +500,9 @@ function query_echappe_textes($query) { * @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; diff --git a/www/ecrire/genie/optimiser.php b/www/ecrire/genie/optimiser.php index 455d969f..3a039d50 100644 --- a/www/ecrire/genie/optimiser.php +++ b/www/ecrire/genie/optimiser.php @@ -37,6 +37,7 @@ function genie_optimiser_dist($t) { 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 @@ -45,6 +46,17 @@ function genie_optimiser_dist($t) { 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 * diff --git a/www/ecrire/inc/cvt_autosave.php b/www/ecrire/inc/cvt_autosave.php index 108a79d4..22ca0091 100644 --- a/www/ecrire/inc/cvt_autosave.php +++ b/www/ecrire/inc/cvt_autosave.php @@ -63,6 +63,20 @@ function cvtautosave_formulaire_charger($flux) { } } + // 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 */ diff --git a/www/ecrire/inc/cvt_multietapes.php b/www/ecrire/inc/cvt_multietapes.php index ade7227e..4bd3d139 100644 --- a/www/ecrire/inc/cvt_multietapes.php +++ b/www/ecrire/inc/cvt_multietapes.php @@ -208,7 +208,7 @@ function cvtmulti_formulaire_verifier($flux) { /** * Verifier les etapes de saisie - * + * * @param array $args * @param $erreurs * @return array @@ -221,13 +221,15 @@ function cvtmulti_formulaire_verifier_etapes($args, $erreurs) { ) { // 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)) { @@ -239,6 +241,7 @@ function cvtmulti_formulaire_verifier_etapes($args, $erreurs) { } // 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( @@ -250,15 +253,21 @@ function cvtmulti_formulaire_verifier_etapes($args, $erreurs) { 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; @@ -271,7 +280,9 @@ function cvtmulti_formulaire_verifier_etapes($args, $erreurs) { $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'] = ""; } diff --git a/www/ecrire/inc/distant.php b/www/ecrire/inc/distant.php index cf35ca71..1428d18d 100644 --- a/www/ecrire/inc/distant.php +++ b/www/ecrire/inc/distant.php @@ -193,21 +193,28 @@ function valider_url_distante($url, $known_hosts = array()) { 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; } } diff --git a/www/ecrire/inc/documents.php b/www/ecrire/inc/documents.php index 53f4d6a5..73c346b9 100644 --- a/www/ecrire/inc/documents.php +++ b/www/ecrire/inc/documents.php @@ -139,6 +139,19 @@ function copier_document($ext, $orig, $source) { // 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; diff --git a/www/ecrire/inc/headers.php b/www/ecrire/inc/headers.php index 0146614a..8ef6e14d 100644 --- a/www/ecrire/inc/headers.php +++ b/www/ecrire/inc/headers.php @@ -186,35 +186,14 @@ function redirige_url_ecrire($script = '', $args = '', $equiv = '') { * * 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 diff --git a/www/ecrire/inc/modifier.php b/www/ecrire/inc/modifier.php index 95c4f73a..1700890b 100644 --- a/www/ecrire/inc/modifier.php +++ b/www/ecrire/inc/modifier.php @@ -232,7 +232,9 @@ function objet_modifier_champs($objet, $id_objet, $options, $c = null, $serveur 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]; diff --git a/www/ecrire/inc/queue.php b/www/ecrire/inc/queue.php index 5204c3d8..7f32e7b2 100644 --- a/www/ecrire/inc/queue.php +++ b/www/ecrire/inc/queue.php @@ -701,11 +701,13 @@ function queue_affichage_cron() { 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 = '' - . "" - . ""; + 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 = '' + . "" + . ""; + } return $texte; } diff --git a/www/ecrire/inc/rubriques.php b/www/ecrire/inc/rubriques.php index 49a05f16..d0d4879e 100644 --- a/www/ecrire/inc/rubriques.php +++ b/www/ecrire/inc/rubriques.php @@ -46,16 +46,43 @@ if (!defined('_ECRIRE_INC_VERSION')) { * 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()) @@ -69,7 +96,7 @@ function calculer_rubriques_if($id_rubrique, $modifs, $statut_ancien = '', $post } 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 diff --git a/www/ecrire/inc/utils.php b/www/ecrire/inc/utils.php index afc4fbc2..89243f12 100644 --- a/www/ecrire/inc/utils.php +++ b/www/ecrire/inc/utils.php @@ -905,7 +905,7 @@ function _L($text, $args = array(), $options = array()) { } if (($GLOBALS['test_i18n'] or (_request('var_mode') == 'traduction')) and is_null($options['class'])) { - return "$text"; + return "$text"; } else { return $text; } diff --git a/www/ecrire/inc_version.php b/www/ecrire/inc_version.php index a4f5006e..77ec9a64 100644 --- a/www/ecrire/inc_version.php +++ b/www/ecrire/inc_version.php @@ -374,18 +374,18 @@ $liste_des_authentifications = array( // 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; diff --git a/www/ecrire/iterateur/data.php b/www/ecrire/iterateur/data.php index 616bfc8a..42ad58f4 100644 --- a/www/ecrire/iterateur/data.php +++ b/www/ecrire/iterateur/data.php @@ -684,9 +684,7 @@ function inc_sql_to_array_dist($u) { * @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; } } diff --git a/www/ecrire/maj/svn10000.php b/www/ecrire/maj/svn10000.php index ae90fc7b..8f6454cb 100644 --- a/www/ecrire/maj/svn10000.php +++ b/www/ecrire/maj/svn10000.php @@ -670,7 +670,7 @@ $GLOBALS['maj'][21676] = array( /** * Ranger les images de local/cache-gd2 dans des sous-rep - * + * * http://core.spip.net/issues/3277 */ function ranger_cache_gd2() { @@ -704,3 +704,59 @@ $GLOBALS['maj'][21742] = array( $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 diff --git a/www/ecrire/paquet.xml b/www/ecrire/paquet.xml index b441cd09..9322829c 100644 --- a/www/ecrire/paquet.xml +++ b/www/ecrire/paquet.xml @@ -1,10 +1,10 @@ ' . '' . + '' . (!empty(\$Pile[0]['_hidden']) ? @\$Pile[0]['_hidden'] : '') . ''"; diff --git a/www/ecrire/public/interfaces.php b/www/ecrire/public/interfaces.php index 9f75f65d..b170b940 100644 --- a/www/ecrire/public/interfaces.php +++ b/www/ecrire/public/interfaces.php @@ -543,6 +543,16 @@ class Boucle { */ 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; @@ -943,11 +953,19 @@ function declarer_interfaces() { // $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)'; diff --git a/www/ecrire/public/references.php b/www/ecrire/public/references.php index 6a6116a8..a4250bbf 100644 --- a/www/ecrire/public/references.php +++ b/www/ecrire/public/references.php @@ -98,6 +98,9 @@ function index_pile( $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 @@ -123,6 +126,8 @@ function index_pile( 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); @@ -700,13 +705,21 @@ function champs_traitements($p) { 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" @@ -715,6 +728,9 @@ function champs_traitements($p) { } // 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]; diff --git a/www/ecrire/req/mysql.php b/www/ecrire/req/mysql.php index 4c78e1c6..ae9cdb34 100644 --- a/www/ecrire/req/mysql.php +++ b/www/ecrire/req/mysql.php @@ -524,9 +524,10 @@ define('_SQL_PREFIXE_TABLE_MYSQL', '/([,\s])spip_/S'); * @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 . '`.'; @@ -546,12 +547,22 @@ function _mysql_traite_query($query, $db = '', $prefixe = '') { // 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; @@ -710,9 +721,9 @@ function spip_mysql_create( /** * 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) { @@ -722,9 +733,17 @@ 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; } diff --git a/www/ecrire/req/sqlite_generique.php b/www/ecrire/req/sqlite_generique.php index 294df176..283157dc 100644 --- a/www/ecrire/req/sqlite_generique.php +++ b/www/ecrire/req/sqlite_generique.php @@ -2515,9 +2515,9 @@ function _sqlite_ref_fonctions() { /** - * $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 */ @@ -2531,6 +2531,7 @@ function _sqlite_remplacements_definitions_table($query, $autoinc = false) { '/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', diff --git a/www/plugins-dist.json b/www/plugins-dist.json index 68e7e009..ac4519f8 100644 --- a/www/plugins-dist.json +++ b/www/plugins-dist.json @@ -1,106 +1,132 @@ { "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 diff --git a/www/plugins-dist/aide/paquet.xml b/www/plugins-dist/aide/paquet.xml index 9fe2f4e3..aea1811c 100644 --- a/www/plugins-dist/aide/paquet.xml +++ b/www/plugins-dist/aide/paquet.xml @@ -1,7 +1,7 @@ $fichier, 'name' => basename($fichier)); @@ -84,6 +87,9 @@ function action_copier_local_post($id_document) { 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); diff --git a/www/plugins-dist/medias/paquet.xml b/www/plugins-dist/medias/paquet.xml index 5a184a02..8e30c1d8 100644 --- a/www/plugins-dist/medias/paquet.xml +++ b/www/plugins-dist/medias/paquet.xml @@ -1,7 +1,7 @@ [(#AUTORISER{voir,groupemots,#ID_GROUPE}|oui)
  • [(#RANG). ]#TITRE
  • ] diff --git a/www/plugins-dist/organiseur/paquet.xml b/www/plugins-dist/organiseur/paquet.xml index dd5fc915..7955e0e8 100644 --- a/www/plugins-dist/organiseur/paquet.xml +++ b/www/plugins-dist/organiseur/paquet.xml @@ -1,7 +1,7 @@ $hash)); diff --git a/www/plugins-dist/revisions/paquet.xml b/www/plugins-dist/revisions/paquet.xml index ca3f006c..7da4d01e 100644 --- a/www/plugins-dist/revisions/paquet.xml +++ b/www/plugins-dist/revisions/paquet.xml @@ -1,7 +1,7 @@ Original port from Python | -// | Authors: Harry Fuecks Port to PEAR + more | -// | Authors: Many @ Sitepointforums Advanced PHP Forums | -// +----------------------------------------------------------------------+ -// - -if (!defined('_ECRIRE_INC_VERSION')) return; - -if (!defined('XML_HTMLSAX3')) { - define('XML_HTMLSAX3', 'XML/'); -} -require_once(XML_HTMLSAX3 . 'HTMLSax3/States.php'); -require_once(XML_HTMLSAX3 . 'HTMLSax3/Decorators.php'); - -class XML_HTMLSax3_StateParser { - var $htmlsax; - var $handler_object_element; - var $handler_method_opening; - var $handler_method_closing; - var $handler_object_data; - var $handler_method_data; - var $handler_object_pi; - var $handler_method_pi; - var $handler_object_jasp; - var $handler_method_jasp; - var $handler_object_escape; - var $handler_method_escape; - var $handler_default; - var $parser_options = array(); - var $rawtext; - var $position; - var $length; - var $State = array(); - - 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(); - } - - function unscanCharacter() { - $this->position -= 1; - } - - function ignoreCharacter() { - $this->position += 1; - } - - function scanCharacter() { - if ($this->position < $this->length) { - return $this->rawtext[$this->position++]; - } - } - - 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); - } - - function scanUntilCharacters($string) {} - - function ignoreWhitespace() {} - - 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(); - } - - function _parse($state = XML_HTMLSAX3_STATE_START) { - do { - $state = $this->State[$state]->parse($this); - } while ($state != XML_HTMLSAX3_STATE_STOP && - $this->position < $this->length); - } -} - -class XML_HTMLSax3_StateParser_Lt430 extends XML_HTMLSax3_StateParser { - 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; - } - - function scanUntilCharacters($string) { - $startpos = $this->position; - while ($this->position < $this->length && strpos($string, $this->rawtext[$this->position]) === FALSE) { - $this->position++; - } - return substr($this->rawtext, $startpos, $this->position - $startpos); - } - - function ignoreWhitespace() { - while ($this->position < $this->length && - strpos(" \n\r\t", $this->rawtext[$this->position]) !== FALSE) { - $this->position++; - } - } - - function parse($data) { - parent::parse($data); - } -} - -class XML_HTMLSax3_StateParser_Gtet430 extends XML_HTMLSax3_StateParser { - 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; - } - function scanUntilCharacters($string) { - $startpos = $this->position; - $length = strcspn($this->rawtext, $string, $startpos); - $this->position += $length; - return substr($this->rawtext, $startpos, $length); - } - - function ignoreWhitespace() { - $this->position += strspn($this->rawtext, " \n\r\t", $this->position); - } - - function parse($data) { - parent::parse($data); - } -} - -class XML_HTMLSax3_NullHandler { - function DoNothing() { - } -} - -class XML_HTMLSax3 { - var $state_parser; - - function __construct() { - if (version_compare(phpversion(), '4.3', 'ge')) { - $this->state_parser = new XML_HTMLSax3_StateParser_Gtet430($this); - } else { - $this->state_parser = new XML_HTMLSax3_StateParser_Lt430($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'); - } - - 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'); - } - } - - 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'); - } - } - - 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; - } - - 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; - } - - 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; - } - - 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; - } - - 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; - } - - function get_current_position() { - return $this->state_parser->position; - } - - function get_length() { - return $this->state_parser->length; - } - - function parse($data) { - $this->state_parser->parse($data); - } -} -?> + Original port from Python | +// | Authors: Harry Fuecks 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
    + * Example: + *
    +	 * $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);
    +	 * 
    + * @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
    + * Available options: + *
      + *
    • XML_OPTION_TRIM_DATA_NODES: trim whitespace off the beginning + * and end of data passed to the data handler
    • + *
    • XML_OPTION_LINEFEED_BREAK: linefeeds result in additional data + * handler calls
    • + *
    • XML_OPTION_TAB_BREAK: tabs result in additional data handler + * calls
    • + *
    • XML_OPTION_ENTITIES_UNPARSED: XML entities are returned as + * seperate data handler calls in unparsed form
    • + *
    • 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
    • + *
    • XML_OPTION_STRIP_ESCAPES: strips out the -- -- comment markers + * or CDATA markup inside an XML escape, if found.
    • + *
    + * 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.
    + * 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. + *
    +	 * function myDataHander(& $parser,$data){}
    +	 * 
    + * @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 + *
    The open handler method must accept three arguments; the parser, + * the tag name and an array of attributes e.g. + *
    +	 * function myOpenHander(& $parser,$tagname,$attrs=array()){}
    +	 * 
    + * The close handler method must accept two arguments; the parser and + * the tag name e.g. + *
    +	 * function myCloseHander(& $parser,$tagname){}
    +	 * 
    + * @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
    + * The handler method must accept three arguments; the parser, the + * PI target and data inside the PI + *
    +	 * function myPIHander(& $parser,$target, $data){}
    +	 * 
    + * @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
    + * The handler method must accept two arguments; the parser and the + * contents of the escaped section + *
    +	 * function myEscapeHander(& $parser, $data){}
    +	 * 
    + * @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
    + * The handler method must accept two arguments; the parser and + * body of the JASP tag + *
    +	 * function myJaspHander(& $parser, $data){}
    +	 * 
    + * @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 + *
    Intended for use from within a user defined handler called + * via the $parser reference e.g. + *
    +	 * function myDataHandler(& $parser,$data) {
    +	 *     echo( 'Current position: '.$parser->get_current_position() );
    +	 * }
    +	 * 
    + * @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); + } +} diff --git a/www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3/Decorators.php b/www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3/Decorators.php index ab974518..5425677c 100644 --- a/www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3/Decorators.php +++ b/www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3/Decorators.php @@ -1,122 +1,353 @@ -orig_obj =& $orig_obj; - $this->orig_method = $orig_method; - } - function trimData(&$parser, $data) { - $data = trim($data); - if ($data != '') { - $this->orig_obj->{$this->orig_method}($parser, $data); - } - } -} -class XML_HTMLSax3_CaseFolding { - var $orig_obj; - var $orig_open_method; - var $orig_close_method; - 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; - } - function foldOpen(&$parser, $tag, $attrs = array(), $empty = FALSE) { - $this->orig_obj->{$this->orig_open_method}($parser, strtoupper($tag), $attrs, $empty); - } - function foldClose(&$parser, $tag, $empty = FALSE) { - $this->orig_obj->{$this->orig_close_method}($parser, strtoupper($tag), $empty); - } -} -class XML_HTMLSax3_Linefeed { - var $orig_obj; - var $orig_method; - function __construct(&$orig_obj, $orig_method) { - $this->orig_obj =& $orig_obj; - $this->orig_method = $orig_method; - } - function breakData(&$parser, $data) { - $data = explode("\n",$data); - foreach ( $data as $chunk ) { - $this->orig_obj->{$this->orig_method}($parser, $chunk); - } - } -} -class XML_HTMLSax3_Tab { - var $orig_obj; - var $orig_method; - function __construct(&$orig_obj, $orig_method) { - $this->orig_obj =& $orig_obj; - $this->orig_method = $orig_method; - } - function breakData(&$parser, $data) { - $data = explode("\t",$data); - foreach ( $data as $chunk ) { - $this->orig_obj->{$this->orig_method}($this, $chunk); - } - } -} -class XML_HTMLSax3_Entities_Parsed { - var $orig_obj; - var $orig_method; - function __construct(&$orig_obj, $orig_method) { - $this->orig_obj =& $orig_obj; - $this->orig_method = $orig_method; - } - 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); - $this->orig_obj->{$this->orig_method}($this, $chunk); - } - } -} -if (version_compare(phpversion(), '4.3', '<') && !function_exists('html_entity_decode') ) { - function html_entity_decode($str, $style = ENT_NOQUOTES) { - return strtr($str, - array_flip(get_html_translation_table(HTML_ENTITIES,$style))); - } -} -class XML_HTMLSax3_Entities_Unparsed { - var $orig_obj; - var $orig_method; - function __construct(&$orig_obj, $orig_method) { - $this->orig_obj =& $orig_obj; - $this->orig_method = $orig_method; - } - 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); - } - } -} - -class XML_HTMLSax3_Escape_Stripper { - var $orig_obj; - var $orig_method; - function __construct(&$orig_obj, $orig_method) { - $this->orig_obj =& $orig_obj; - $this->orig_method = $orig_method; - } - function strip(&$parser, $data) { - if ( substr($data,0,2) == '--' ) { - $patterns = array( - '/^\-\-/', // Opening comment: -- - '/\-\-$/', // Closing comment: -- - ); - $data = preg_replace($patterns,'',$data); - - } else if ( substr($data,0,1) == '[' ) { - $patterns = array( - '/^\[.*CDATA.*\[/s', // Opening CDATA - '/\].*\]$/s', // Closing CDATA - ); - $data = preg_replace($patterns,'',$data); - } - - $this->orig_obj->{$this->orig_method}($this, $data); - } -} -?> + Original port from Python | +// | Authors: Harry Fuecks 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
    + * 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
    + * @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.
    + * @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); + } +} diff --git a/www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3/States.php b/www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3/States.php index eb4a315d..9f16380e 100644 --- a/www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3/States.php +++ b/www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3/States.php @@ -1,179 +1,286 @@ -scanUntilString('<'); - if ($data != '') { - $context->handler_object_data-> - {$context->handler_method_data}($context->htmlsax, $data); - } - $context->IgnoreCharacter(); - return XML_HTMLSAX3_STATE_TAG; - } -} -class XML_HTMLSax3_TagState { - 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; - } - } -} -class XML_HTMLSax3_ClosingTagState { - 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; - } -} -class XML_HTMLSax3_OpeningTagState { - function parseAttributes(&$context) { - $Attributes = array(); - - $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; - } - - function parse(&$context) { - $tag = $context->scanUntilCharacters("/> \n\r\t"); - if ($tag != '') { - $this->attrs = array(); - $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; - } -} - -class XML_HTMLSax3_EscapeState { - 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; - } -} -class XML_HTMLSax3_JaspState { - 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; - } -} -class XML_HTMLSax3_PiState { - 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; - } -} -?> \ No newline at end of file + Original port from Python | +// | Authors: Harry Fuecks 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; + } +} diff --git a/www/plugins-dist/safehtml/lib/safehtml/classes/safehtml.php b/www/plugins-dist/safehtml/lib/safehtml/classes/safehtml.php index 6959b1cd..9bfeffaf 100644 --- a/www/plugins-dist/safehtml/lib/safehtml/classes/safehtml.php +++ b/www/plugins-dist/safehtml/lib/safehtml/classes/safehtml.php @@ -1,720 +1,755 @@ - * @author Miguel Vazquez Gocobachi - * @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 + * @author Miguel Vazquez Gocobachi + * @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: *
      *
    • 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", + *
    • 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 + * It also tries to convert code to XHTML valid, but htmltidy is far better * solution for this task. * * Example: *
    - * $parser =& new SafeHTML();
    + * $parser = new SafeHTML;
      * $result = $parser->parse($doc);
      * 
    - * - * @category HTML - * @package SafeHTML - * @author Roman Ivanov - * @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 ("") - * - * @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; $iprotoRegexps[] = $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
  • if
  • 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 .= ''; - } - - --$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: - *
    -     * $safe = new HTML_Safe;
    -     * $safe->setAllowTags(array('body'));
    -     * 
    - * - * @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 ("") + * + * @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
  • if
  • 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 .= ''; + } + + --$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: + *
    +	 * $safe = new SafeHTML;
    +	 * $safe->setAllowTags(['body']);
    +	 * 
    + * + * @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]), '=') . '-'; + } } + diff --git a/www/plugins-dist/safehtml/lib/safehtml/license.txt b/www/plugins-dist/safehtml/lib/safehtml/license.txt index a57f2f55..eff4b1b6 100644 --- a/www/plugins-dist/safehtml/lib/safehtml/license.txt +++ b/www/plugins-dist/safehtml/lib/safehtml/license.txt @@ -1,27 +1,27 @@ -(c) Miguel Vazquez Gocobachi, WackoWiki Team, 2005-2017 -(c) Roman Ivanov, 2004-2005 -(c) Pixel-Apes ( http://pixel-apes.com/ ), 2004-2005 -(c) JetStyle ( http://jetstyle.ru/ ), 2004-2005 -Maintainer -- Roman Ivanov - -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. +(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 + +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. diff --git a/www/plugins-dist/safehtml/lib/safehtml/readme.txt b/www/plugins-dist/safehtml/lib/safehtml/readme.txt index 7619497e..aa5a7367 100644 --- a/www/plugins-dist/safehtml/lib/safehtml/readme.txt +++ b/www/plugins-dist/safehtml/lib/safehtml/readme.txt @@ -1,87 +1,93 @@ -SafeHTML --------- -Version 1.3.10. -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.10. - * added HTML5 Block-level elements -1.3.9. - * Replaced preg_replace() e modifier with preg_replace_callback -1.3.8. - * UTF-7 XSS vulnerability fixed -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 standarts. - * 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 elemet, 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. - * 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: attack. - Thanks to shmel. -1.0.1. - Bug fix: safehtml hangs on code. - Thanks to lj user=electrocat. -1.0.0. - First public release +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. + * 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: attack. + Thanks to shmel. +1.0.1. + Bug fix: safehtml hangs on code. + Thanks to lj user=electrocat. +1.0.0. + First public release diff --git a/www/plugins-dist/safehtml/paquet.xml b/www/plugins-dist/safehtml/paquet.xml index 3b22460c..f6fb77e4 100644 --- a/www/plugins-dist/safehtml/paquet.xml +++ b/www/plugins-dist/safehtml/paquet.xml @@ -1,7 +1,7 @@ Roman Ivanov Pixel-Apes JetStyle + https://wackowiki.org/doc/Dev/Projects/SafeHTML GPL + + diff --git a/www/plugins-dist/sites/paquet.xml b/www/plugins-dist/sites/paquet.xml index 3708b432..0d060729 100644 --- a/www/plugins-dist/sites/paquet.xml +++ b/www/plugins-dist/sites/paquet.xml @@ -1,7 +1,7 @@