[SPIP] v3.2.11 -> v3.2.12
authorLudovic CHEVALIER <lchevalier@araignee.local>
Tue, 21 Dec 2021 10:37:05 +0000 (11:37 +0100)
committerLudovic CHEVALIER <ludovic@beurresarrasin.net>
Tue, 21 Dec 2021 10:37:45 +0000 (11:37 +0100)
66 files changed:
www/CHANGELOG.TXT
www/ecrire/action/editer_objet.php
www/ecrire/balise/formulaire_.php
www/ecrire/base/connect_sql.php
www/ecrire/genie/optimiser.php
www/ecrire/inc/cvt_autosave.php
www/ecrire/inc/cvt_multietapes.php
www/ecrire/inc/distant.php
www/ecrire/inc/documents.php
www/ecrire/inc/headers.php
www/ecrire/inc/modifier.php
www/ecrire/inc/queue.php
www/ecrire/inc/rubriques.php
www/ecrire/inc/utils.php
www/ecrire/inc_version.php
www/ecrire/iterateur/data.php
www/ecrire/maj/svn10000.php
www/ecrire/paquet.xml
www/ecrire/public/aiguiller.php
www/ecrire/public/balises.php
www/ecrire/public/interfaces.php
www/ecrire/public/references.php
www/ecrire/req/mysql.php
www/ecrire/req/sqlite_generique.php
www/plugins-dist.json
www/plugins-dist/aide/paquet.xml
www/plugins-dist/archiviste/paquet.xml
www/plugins-dist/breves/paquet.xml
www/plugins-dist/compagnon/paquet.xml
www/plugins-dist/compresseur/inc/compresseur_embarquer.php
www/plugins-dist/compresseur/paquet.xml
www/plugins-dist/dump/paquet.xml
www/plugins-dist/filtres_images/images_fonctions.php
www/plugins-dist/filtres_images/paquet.xml
www/plugins-dist/forum/paquet.xml
www/plugins-dist/jquery_ui/paquet.xml
www/plugins-dist/mediabox/mediabox_pipelines.php
www/plugins-dist/mediabox/paquet.xml
www/plugins-dist/medias/action/copier_local.php
www/plugins-dist/medias/paquet.xml
www/plugins-dist/mots/paquet.xml
www/plugins-dist/mots/prive/squelettes/navigation/mots.html
www/plugins-dist/organiseur/paquet.xml
www/plugins-dist/petitions/paquet.xml
www/plugins-dist/plan/paquet.xml
www/plugins-dist/porte_plume/paquet.xml
www/plugins-dist/porte_plume/porte_plume_pipelines.php
www/plugins-dist/revisions/paquet.xml
www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3.php
www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3/Decorators.php
www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3/States.php
www/plugins-dist/safehtml/lib/safehtml/classes/safehtml.php
www/plugins-dist/safehtml/lib/safehtml/license.txt
www/plugins-dist/safehtml/lib/safehtml/readme.txt
www/plugins-dist/safehtml/paquet.xml
www/plugins-dist/sites/paquet.xml
www/plugins-dist/squelettes_par_rubrique/paquet.xml
www/plugins-dist/statistiques/paquet.xml
www/plugins-dist/svp/paquet.xml
www/plugins-dist/textwheel/paquet.xml
www/plugins-dist/urls_etendues/paquet.xml
www/plugins-dist/vertebres/paquet.xml
www/prive/javascript/ajaxCallback.js
www/prive/themes/spip/forms.css.html
www/squelettes-dist/paquet.xml
www/squelettes-dist/robots.txt.html

index f69be25..0759db5 100644 (file)
@@ -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)
 --------------------------------------------
 
index 1f8f1e0..1632746 100644 (file)
@@ -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);
        }
 }
index fa99b73..6cb7143 100644 (file)
@@ -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';
        }
index ba1fa37..6ea2935 100644 (file)
@@ -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;
index 455d969..3a039d5 100644 (file)
@@ -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
  *
index 108a79d..22ca009 100644 (file)
@@ -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
                 */
index ade7227..4bd3d13 100644 (file)
@@ -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'] = "";
                        }
index cf35ca7..1428d18 100644 (file)
@@ -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;
                        }
                }
index 53f4d6a..73c346b 100644 (file)
@@ -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;
index 0146614..8ef6e14 100644 (file)
@@ -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
index 95c4f73..1700890 100644 (file)
@@ -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];
index 5204c3d..7f32e7b 100644 (file)
@@ -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 = '<!-- SPIP-CRON -->'
-         . "<script>setTimeout(function(){var xo = new XMLHttpRequest();xo.open('GET', '$url_cron', true);xo.send('');},100);</script>"
-         . "<noscript><div style=\"background-image: url('$url_cron');\"></div></noscript>";
+       if (!defined('_HTML_BG_CRON_INHIB') or !_HTML_BG_CRON_INHIB) {
+               // en derniere solution, on insere un appel xhr non bloquant ou une image background dans la page si pas de JS
+               $url_cron = generer_url_action('cron');
+               $texte = '<!-- SPIP-CRON -->'
+                 . "<script>setTimeout(function(){var xo = new XMLHttpRequest();xo.open('GET', '$url_cron', true);xo.send('');},100);</script>"
+                 . "<noscript><div style=\"background-image: url('$url_cron');\"></div></noscript>";
+       }
 
        return $texte;
 }
index 49a05f1..d0d4879 100644 (file)
@@ -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
index afc4fbc..89243f1 100644 (file)
@@ -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 "<span class=debug-traduction-erreur>$text</span>";
+               return "<span class='debug-traduction-erreur'>$text</span>";
        } else {
                return $text;
        }
index a4f5006..77ec9a6 100644 (file)
@@ -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;
index 616bfc8..42ad58f 100644 (file)
@@ -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;
        }
 }
index ae90fc7..8f6454c 100644 (file)
@@ -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
index b441cd0..9322829 100644 (file)
@@ -1,10 +1,10 @@
 <paquet
        prefix="spip"
        categorie="outil"
-       version="3.2.11"
+       version="3.2.12"
        etat="stable"
        compatibilite="];["
-       schema="23375"
+       schema="24379"
        documentation="https://www.spip.net"
        demonstration="https://demo.spip.net"
        developpement="https://core.spip.net/projects/spip/"
index 44629a1..1c74a79 100644 (file)
@@ -149,7 +149,7 @@ function traiter_appels_inclusions_ajax() {
                        }
                } else {
                        include_spip('inc/headers');
-                       http_status(403);
+                       http_status(400);
                        $texte = _L('signature ajax bloc incorrecte');
                }
                ajax_retour($texte, false);
@@ -183,9 +183,30 @@ function traiter_formulaires_dynamiques($get = false) {
                return false;
        } // le hit peut continuer normalement
 
+       // verifier que le post est licite (du meme auteur ou d'une session anonyme)
+       $sign = _request('formulaire_action_sign');
+       if (!empty($GLOBALS['visiteur_session']['id_auteur'])) {
+               if (empty($sign)) {
+                       spip_log("signature ajax form incorrecte : $form (formulaire non signe mais on a une session)", 'formulaires' . _LOG_ERREUR);
+                       return false;
+               }
+               $securiser_action = charger_fonction('securiser_action', 'inc');
+               $secu = $securiser_action($form, $args, '', -1);
+               if ($sign !== $secu['hash']) {
+                       spip_log("signature ajax form incorrecte : $form (formulaire signe mais ne correspond pas a la session)", 'formulaires' . _LOG_ERREUR);
+                       return false;
+               }
+       }
+       else {
+               if (!empty($sign)) {
+                       spip_log("signature ajax form incorrecte : $form (formulaire signe mais pas de session)", 'formulaires' . _LOG_ERREUR);
+                       return false;
+               }
+       }
+
        include_spip('inc/filtres');
        if (($args = decoder_contexte_ajax($args, $form)) === false) {
-               spip_log("signature ajax form incorrecte : $form");
+               spip_log("signature ajax form incorrecte : $form (encodage corrompu)", 'formulaires' . _LOG_ERREUR);
 
                return false; // continuons le hit comme si de rien etait
        } else {
index 9e80959..2710297 100644 (file)
@@ -2562,6 +2562,8 @@ function balise_ACTION_FORMULAIRE($p) {
                value=\'' . $_form . '\' />' .
        '<input name=\'formulaire_action_args\' type=\'hidden\'
                value=\'' . @\$Pile[0]['formulaire_args']. '\' />' .
+       '<input name=\'formulaire_action_sign\' type=\'hidden\'
+               value=\'' . @\$Pile[0]['formulaire_sign']. '\' />' .
        (!empty(\$Pile[0]['_hidden']) ? @\$Pile[0]['_hidden'] : '') .
        '</div>'";
 
index 9f75f65..b170b94 100644 (file)
@@ -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)';
index 6a6116a..a4250bb 100644 (file)
@@ -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];
index 4c78e1c..ae9cdb3 100644 (file)
@@ -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;
 }
index 294df17..283157d 100644 (file)
@@ -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',
index 68e7e00..ac4519f 100644 (file)
 {
     "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
index 9fe2f4e..aea1811 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="aide"
        categorie="divers"
-       version="1.0.0"
+       version="1.0.1"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="aide_logo-32.png"
index f62ec83..08c48a2 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="archiviste"
        categorie="outil"
-       version="0.2.2"
+       version="0.2.3"
        etat="dev"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/archiviste-64.png"
index 8dea4ab..f3d9a1e 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="breves"
        categorie="edition"
-       version="1.4.1"
+       version="1.4.2"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/breve-32.png"
index 231e2f2..ceb9deb 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="compagnon"
        categorie="divers"
-       version="1.6.1"
+       version="1.6.2"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/compagnon-32.png"
index 891c7b8..153d4e1 100644 (file)
@@ -48,7 +48,7 @@ function compresseur_embarquer_images_css($contenu, $source, $source_file = null
        return preg_replace_callback(
                ",url\s*\(\s*['\"]?([^'\"/][^:]*[.](png|gif|jpg))['\"]?\s*\),Uims",
                function($x) use ($filtre_embarque_fichier, $base) {
-                       return "url(\"" . $filtre_embarque_fichier($x[1], $base, _CSS_EMBARQUE_FICHIER_MAX_SIZE) . "\");";
+                       return "url(\"" . $filtre_embarque_fichier($x[1], $base, _CSS_EMBARQUE_FICHIER_MAX_SIZE) . "\")";
                },
                $contenu
        );
index 36eea2e..6b0cd61 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="compresseur"
        categorie="performance"
-       version="1.12.10"
+       version="1.12.11"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="images/compresseur-32.png"
index dbee178..5658894 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="dump"
        categorie="maintenance"
-       version="1.8.5"
+       version="1.8.6"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/base-backup-32.png"
index 1fcba3f..c373c4d 100644 (file)
@@ -74,6 +74,7 @@ $GLOBALS['spip_matrice']['_image_decale_composante_127'] = 'filtres/images_lib.p
  * @return string
  */
 function image_typo() {
+       include_spip('inc/filtres_images_mini.php');
        include_spip('filtres/images_typo');
        $tous = func_get_args();
        return call_user_func_array('produire_image_typo', $tous);
index fdc189f..c30597f 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="images"
        categorie="multimedia"
-       version="2.0.3"
+       version="2.0.4"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="images/image_filtre-32.png"
index ebc962d..df655ce 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="forum"
        categorie="communication"
-       version="1.11.7"
+       version="1.11.8"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/forum-32.png"
index 4641a47..26193f5 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="jqueryui"
        categorie="outil"
-       version="1.12.1"
+       version="1.12.2"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="images/jqueryui-128.png"
index 31599af..c938b2f 100644 (file)
@@ -89,7 +89,7 @@ var box_settings = {tt_img:' . ($config['traiter_toutes_images'] == 'oui' ? 'tru
                // Si c'est une image, on la chargera avec une redimentionnement automatique
                // Sinon, chargement dans une iframe
                $extension = pathinfo($config['splash_url'], PATHINFO_EXTENSION);
-               if (match($extension, 'gif|png|jpg|jpeg')) {
+               if (in_array($extension, array('gif', 'png', 'jpg', 'jpeg'))) {
                        $configmediabox .= 'var box_settings_iframe = false;' . "\n";
                } else {
                        $configmediabox .= 'var box_settings_splash_width = "' . mediabox_quote_js_param($config['splash_width']) . '";
index 07fcde9..d7f5418 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="mediabox"
        categorie="multimedia"
-       version="1.1.5"
+       version="1.1.6"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/mediabox-32.png"
index bef04af..06a4b86 100644 (file)
@@ -59,11 +59,14 @@ function action_copier_local_post($id_document) {
 
        // si la source est bien un fichier distant
        // sinon c'est une donnee moisie, on ne fait rien
-       if (tester_url_absolue($source)) {
-               include_spip('inc/distant'); // pour 'copie_locale'
+       include_spip('inc/distant');
+       if (tester_url_absolue($source)
+               and valider_url_distante($source)) {
                $fichier = copie_locale($source);
-               if ($fichier
-                       and tester_url_absolue($source)) {
+               if (
+                       $fichier
+                       and valider_url_distante($source)
+               ) {
                        $fichier = _DIR_RACINE . $fichier;
                        $files = array();
                        $files[] = array('tmp_name' => $fichier, 'name' => basename($fichier));
@@ -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);
index 5a184a0..8e30c1d 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="medias"
        categorie="multimedia"
-       version="2.20.35"
+       version="2.20.36"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/portfolio-32.png"
index 987cf9e..5391edf 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="mots"
        categorie="edition"
-       version="2.8.9"
+       version="2.8.10"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/mot-32.png"
index af9e1cb..92317be 100644 (file)
@@ -5,7 +5,7 @@
                <ul class='liste-items'>
                <BOUCLE_nav(GROUPES_MOTS){par num titre}{par multi titre}>[(#AUTORISER{voir,groupemots,#ID_GROUPE}|oui)
                <li class="item"><a href='#groupe_mots-#ID_GROUPE'
-                                        onclick='$(".groupe_mots").hide().filter("#groupe_mots-#ID_GROUPE").show();$(this).parent().addClass("on").siblings().removeClass("on").parent().siblings("a.tous").show();return false;'
+                                        onclick='$(".groupe_mots").hide().filter("#groupe_mots-#ID_GROUPE").show();$(this).parent().addClass("on").siblings().removeClass("on").parent().siblings("a.tous").show();'
                                >[(#RANG). ]#TITRE</a></li>
                ]</BOUCLE_nav>
                </ul>
index dd5fc91..7955e0e 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="organiseur"
        categorie="date"
-       version="1.2.5"
+       version="1.2.6"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/calendrier-32.png"
index febd31f..41dedd6 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="petitions"
        categorie="communication"
-       version="1.6.1"
+       version="1.6.2"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/petition-32.png"
index 2740b78..4b7be70 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="plan"
        categorie="navigation"
-       version="2.2.5"
+       version="2.2.6"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/plan-64.png"
index 3baf8c5..c8abb03 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="porte_plume"
        categorie="edition"
-       version="1.18.4"
+       version="1.18.5"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="images/porte-plume-32.png"
index e5289b8..47b7662 100644 (file)
@@ -125,6 +125,8 @@ function porte_plume_insert_head_prive($flux) {
  * @return string Contenu du head complété
  */
 function porte_plume_inserer_head($flux, $lang, $prive = false) {
+       include_spip('porte_plume_fonctions');
+       
        $markitup = timestamp(find_in_path('javascript/jquery.markitup_pour_spip.js'));
        $js_previsu = timestamp(find_in_path('javascript/jquery.previsu_spip.js'));
 
@@ -170,6 +172,7 @@ function porte_plume_insert_head_css($flux = '', $prive = false) {
                }
                $css = timestamp(direction_css(find_in_path('css/barre_outils.css'), lang_dir()));
 
+               include_spip('porte_plume_fonctions');
                $hash = md5(barre_outils_css_icones());
                $css_icones = produire_fond_statique('css/barre_outils_icones.css', array('hash' => $hash));
 
index ca3f006..7da4d01 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="revisions"
        categorie="edition"
-       version="1.9.4"
+       version="1.9.5"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/revision-32.png"
index 2b71148..12c50e3 100644 (file)
-<?php\r
-// +----------------------------------------------------------------------+\r
-// | Copyright (c) 1997-2002 The PHP Group                                |\r
-// +----------------------------------------------------------------------+\r
-// | This source file is subject to version 2.02 of the PHP license,      |\r
-// | that is bundled with this package in the file LICENSE, and is        |\r
-// | available at through the world-wide-web at                           |\r
-// | http://www.php.net/license/3_0.txt.                                  |\r
-// | If you did not receive a copy of the PHP license and are unable to   |\r
-// | obtain it through the world-wide-web, please send a note to          |\r
-// | license@php.net so we can mail you a copy immediately.               |\r
-// +----------------------------------------------------------------------+\r
-// | Authors: Alexander Zhukov <alex@veresk.ru> Original port from Python |\r
-// | Authors: Harry Fuecks <hfuecks@phppatterns.com> Port to PEAR + more  |\r
-// | Authors: Many @ Sitepointforums Advanced PHP Forums                  |\r
-// +----------------------------------------------------------------------+\r
-//\r
-\r
-if (!defined('_ECRIRE_INC_VERSION')) return;\r
-\r
-if (!defined('XML_HTMLSAX3')) {\r
- define('XML_HTMLSAX3', 'XML/');\r
-}\r
-require_once(XML_HTMLSAX3 . 'HTMLSax3/States.php');\r
-require_once(XML_HTMLSAX3 . 'HTMLSax3/Decorators.php');\r
-\r
-class XML_HTMLSax3_StateParser {\r
- var $htmlsax;\r
- var $handler_object_element;\r
- var $handler_method_opening;\r
- var $handler_method_closing;\r
- var $handler_object_data;\r
- var $handler_method_data;\r
- var $handler_object_pi;\r
- var $handler_method_pi;\r
- var $handler_object_jasp;\r
- var $handler_method_jasp;\r
- var $handler_object_escape;\r
- var $handler_method_escape;\r
- var $handler_default;\r
- var $parser_options = array();\r
- var $rawtext;\r
- var $position;\r
- var $length;\r
- var $State = array();\r
-\r
- function __construct(& $htmlsax) {\r
-  $this->htmlsax = & $htmlsax;\r
-\r
-  $this->State[XML_HTMLSAX3_STATE_START] = new XML_HTMLSax3_StartingState();\r
-\r
-  $this->State[XML_HTMLSAX3_STATE_CLOSING_TAG] = new XML_HTMLSax3_ClosingTagState();\r
-  $this->State[XML_HTMLSAX3_STATE_TAG] = new XML_HTMLSax3_TagState();\r
-  $this->State[XML_HTMLSAX3_STATE_OPENING_TAG] = new XML_HTMLSax3_OpeningTagState();\r
-\r
-  $this->State[XML_HTMLSAX3_STATE_PI] = new XML_HTMLSax3_PiState();\r
-  $this->State[XML_HTMLSAX3_STATE_JASP] = new XML_HTMLSax3_JaspState();\r
-  $this->State[XML_HTMLSAX3_STATE_ESCAPE] = new XML_HTMLSax3_EscapeState();\r
- }\r
-\r
- function unscanCharacter() {\r
-  $this->position -= 1;\r
- }\r
-\r
- function ignoreCharacter() {\r
-  $this->position += 1;\r
- }\r
-\r
- function scanCharacter() {\r
-  if ($this->position < $this->length) {\r
-   return $this->rawtext[$this->position++];\r
-  }\r
- }\r
-\r
- function scanUntilString($string) {\r
-  $start = $this->position;\r
-  $this->position = strpos($this->rawtext, $string, $start);\r
-  if ($this->position === FALSE) {\r
-   $this->position = $this->length;\r
-  }\r
-  return substr($this->rawtext, $start, $this->position - $start);\r
- }\r
-\r
- function scanUntilCharacters($string) {}\r
-\r
- function ignoreWhitespace() {}\r
-\r
- function parse($data) {\r
-  if ($this->parser_options['XML_OPTION_TRIM_DATA_NODES']==1) {\r
-   $decorator = new XML_HTMLSax3_Trim(\r
-    $this->handler_object_data,\r
-    $this->handler_method_data);\r
-   $this->handler_object_data =& $decorator;\r
-   $this->handler_method_data = 'trimData';\r
-  }\r
-  if ($this->parser_options['XML_OPTION_CASE_FOLDING']==1) {\r
-   $open_decor = new XML_HTMLSax3_CaseFolding(\r
-    $this->handler_object_element,\r
-    $this->handler_method_opening,\r
-    $this->handler_method_closing);\r
-   $this->handler_object_element =& $open_decor;\r
-   $this->handler_method_opening ='foldOpen';\r
-   $this->handler_method_closing ='foldClose';\r
-  }\r
-  if ($this->parser_options['XML_OPTION_LINEFEED_BREAK']==1) {\r
-   $decorator = new XML_HTMLSax3_Linefeed(\r
-    $this->handler_object_data,\r
-    $this->handler_method_data);\r
-   $this->handler_object_data =& $decorator;\r
-   $this->handler_method_data = 'breakData';\r
-  }\r
-  if ($this->parser_options['XML_OPTION_TAB_BREAK']==1) {\r
-   $decorator = new XML_HTMLSax3_Tab(\r
-    $this->handler_object_data,\r
-    $this->handler_method_data);\r
-   $this->handler_object_data =& $decorator;\r
-   $this->handler_method_data = 'breakData';\r
-  }\r
-  if ($this->parser_options['XML_OPTION_ENTITIES_UNPARSED']==1) {\r
-   $decorator = new XML_HTMLSax3_Entities_Unparsed(\r
-    $this->handler_object_data,\r
-    $this->handler_method_data);\r
-   $this->handler_object_data =& $decorator;\r
-   $this->handler_method_data = 'breakData';\r
-  }\r
-  if ($this->parser_options['XML_OPTION_ENTITIES_PARSED']==1) {\r
-   $decorator = new XML_HTMLSax3_Entities_Parsed(\r
-    $this->handler_object_data,\r
-    $this->handler_method_data);\r
-   $this->handler_object_data =& $decorator;\r
-   $this->handler_method_data = 'breakData';\r
-  }\r
-  // Note switched on by default\r
-  if ($this->parser_options['XML_OPTION_STRIP_ESCAPES']==1) {\r
-   $decorator = new XML_HTMLSax3_Escape_Stripper(\r
-    $this->handler_object_escape,\r
-    $this->handler_method_escape);\r
-   $this->handler_object_escape =& $decorator;\r
-   $this->handler_method_escape = 'strip';\r
-  }\r
-  $this->rawtext = $data;\r
-  $this->length = strlen($data);\r
-  $this->position = 0;\r
-  $this->_parse();\r
- }\r
-\r
- function _parse($state = XML_HTMLSAX3_STATE_START) {\r
-  do {\r
-   $state = $this->State[$state]->parse($this);\r
-  } while ($state != XML_HTMLSAX3_STATE_STOP &&\r
-     $this->position < $this->length);\r
- }\r
-}\r
-\r
-class XML_HTMLSax3_StateParser_Lt430 extends XML_HTMLSax3_StateParser {\r
- function __construct(& $htmlsax) {\r
-  parent::__construct($htmlsax);\r
-  $this->parser_options['XML_OPTION_TRIM_DATA_NODES'] = 0;\r
-  $this->parser_options['XML_OPTION_CASE_FOLDING'] = 0;\r
-  $this->parser_options['XML_OPTION_LINEFEED_BREAK'] = 0;\r
-  $this->parser_options['XML_OPTION_TAB_BREAK'] = 0;\r
-  $this->parser_options['XML_OPTION_ENTITIES_PARSED'] = 0;\r
-  $this->parser_options['XML_OPTION_ENTITIES_UNPARSED'] = 0;\r
-  $this->parser_options['XML_OPTION_STRIP_ESCAPES'] = 0;\r
- }\r
-\r
- function scanUntilCharacters($string) {\r
-  $startpos = $this->position;\r
-  while ($this->position < $this->length && strpos($string, $this->rawtext[$this->position]) === FALSE) {\r
-   $this->position++;\r
-  }\r
-  return substr($this->rawtext, $startpos, $this->position - $startpos);\r
- }\r
-\r
- function ignoreWhitespace() {\r
-  while ($this->position < $this->length && \r
-   strpos(" \n\r\t", $this->rawtext[$this->position]) !== FALSE) {\r
-   $this->position++;\r
-  }\r
- }\r
-\r
- function parse($data) {\r
-  parent::parse($data);\r
- }\r
-}\r
-\r
-class XML_HTMLSax3_StateParser_Gtet430 extends XML_HTMLSax3_StateParser {\r
- function __construct(& $htmlsax) {\r
-  parent::__construct($htmlsax);\r
-  $this->parser_options['XML_OPTION_TRIM_DATA_NODES'] = 0;\r
-  $this->parser_options['XML_OPTION_CASE_FOLDING'] = 0;\r
-  $this->parser_options['XML_OPTION_LINEFEED_BREAK'] = 0;\r
-  $this->parser_options['XML_OPTION_TAB_BREAK'] = 0;\r
-  $this->parser_options['XML_OPTION_ENTITIES_PARSED'] = 0;\r
-  $this->parser_options['XML_OPTION_ENTITIES_UNPARSED'] = 0;\r
-  $this->parser_options['XML_OPTION_STRIP_ESCAPES'] = 0;\r
- }\r
- function scanUntilCharacters($string) {\r
-  $startpos = $this->position;\r
-  $length = strcspn($this->rawtext, $string, $startpos);\r
-  $this->position += $length;\r
-  return substr($this->rawtext, $startpos, $length);\r
- }\r
-\r
- function ignoreWhitespace() {\r
-  $this->position += strspn($this->rawtext, " \n\r\t", $this->position);\r
- }\r
-\r
- function parse($data) {\r
-  parent::parse($data);\r
- }\r
-}\r
-\r
-class XML_HTMLSax3_NullHandler {\r
- function DoNothing() {\r
- }\r
-}\r
-\r
-class XML_HTMLSax3 {\r
- var $state_parser;\r
-\r
- function __construct() {\r
-  if (version_compare(phpversion(), '4.3', 'ge')) {\r
-   $this->state_parser = new XML_HTMLSax3_StateParser_Gtet430($this);\r
-  } else {\r
-   $this->state_parser = new XML_HTMLSax3_StateParser_Lt430($this);\r
-  }\r
-  $nullhandler = new XML_HTMLSax3_NullHandler();\r
-  $this->set_object($nullhandler);\r
-  $this->set_element_handler('DoNothing', 'DoNothing');\r
-  $this->set_data_handler('DoNothing');\r
-  $this->set_pi_handler('DoNothing');\r
-  $this->set_jasp_handler('DoNothing');\r
-  $this->set_escape_handler('DoNothing');\r
- }\r
-\r
- function set_object(&$object) {\r
-  if ( is_object($object) ) {\r
-   $this->state_parser->handler_default =& $object;\r
-   return true;\r
-  } else {\r
-   require_once('PEAR.php');\r
-   PEAR::raiseError('XML_HTMLSax3::set_object requires '.\r
-    'an object instance');\r
-  }\r
- }\r
-\r
- function set_option($name, $value = 1) {\r
-  if ( array_key_exists($name,$this->state_parser->parser_options) ) {\r
-   $this->state_parser->parser_options[$name] = $value;\r
-   return true;\r
-  } else {\r
-   require_once('PEAR.php');\r
-   PEAR::raiseError('XML_HTMLSax3::set_option('.$name.') illegal');\r
-  }\r
- }\r
-\r
- function set_data_handler($data_method) {\r
-  $this->state_parser->handler_object_data =& $this->state_parser->handler_default;\r
-  $this->state_parser->handler_method_data = $data_method;\r
- }\r
-\r
- function set_element_handler($opening_method, $closing_method) {\r
-  $this->state_parser->handler_object_element =& $this->state_parser->handler_default;\r
-  $this->state_parser->handler_method_opening = $opening_method;\r
-  $this->state_parser->handler_method_closing = $closing_method;\r
- }\r
-\r
- function set_pi_handler($pi_method) {\r
-  $this->state_parser->handler_object_pi =& $this->state_parser->handler_default;\r
-  $this->state_parser->handler_method_pi = $pi_method;\r
- }\r
-\r
- function set_escape_handler($escape_method) {\r
-  $this->state_parser->handler_object_escape =& $this->state_parser->handler_default;\r
-  $this->state_parser->handler_method_escape = $escape_method;\r
- }\r
-\r
- function set_jasp_handler ($jasp_method) {\r
-  $this->state_parser->handler_object_jasp =& $this->state_parser->handler_default;\r
-  $this->state_parser->handler_method_jasp = $jasp_method;\r
- }\r
-\r
- function get_current_position() {\r
-  return $this->state_parser->position;\r
- }\r
-\r
- function get_length() {\r
-  return $this->state_parser->length;\r
- }\r
-\r
- function parse($data) {\r
-  $this->state_parser->parse($data);\r
- }\r
-}\r
-?>\r
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+//
+// +----------------------------------------------------------------------+
+// | PHP Version 4                                                        |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2002 The PHP Group                                |
+// +----------------------------------------------------------------------+
+// | This source file is subject toversion 3.0 of the PHP license,      |
+// | that is bundled with this package in the file LICENSE, and is        |
+// | available at through the world-wide-web at                           |
+// | http://www.php.net/license/3_0.txt.                                  |
+// | If you did not receive a copy of the PHP license and are unable to   |
+// | obtain it through the world-wide-web, please send a note to          |
+// | license@php.net so we can mail you a copy immediately.               |
+// +----------------------------------------------------------------------+
+// | Authors: Alexander Zhukov <alex@veresk.ru> Original port from Python |
+// | Authors: Harry Fuecks <hfuecks@phppatterns.com> Port to PEAR + more  |
+// | Authors: Many @ Sitepointforums Advanced PHP Forums                  |
+// +----------------------------------------------------------------------+
+//
+// $Id: HTMLSax3.php,v 1.2 2007/10/29 21:41:34 hfuecks Exp $
+//
+/**
+ * Main parser components
+ * @package XML_HTMLSax3
+ * @version $Id: HTMLSax3.php,v 1.2 2007/10/29 21:41:34 hfuecks Exp $
+ */
+/**
+ * Required classes
+ */
+if (!defined('XML_HTMLSAX3')) {
+       define('XML_HTMLSAX3', 'XML/');
+}
+require_once(XML_HTMLSAX3 . 'HTMLSax3/States.php');
+require_once(XML_HTMLSAX3 . 'HTMLSax3/Decorators.php');
+
+/**
+ * Base State Parser
+ * @package XML_HTMLSax3
+ * @access protected
+ * @abstract
+ */
+class XML_HTMLSax3_StateParser {
+       /**
+        * Instance of user front end class to be passed to callbacks
+        * @var XML_HTMLSax3
+        * @access private
+        */
+       var $htmlsax;
+       /**
+        * User defined object for handling elements
+        * @var object
+        * @access private
+        */
+       var $handler_object_element;
+       /**
+        * User defined open tag handler method
+        * @var string
+        * @access private
+        */
+       var $handler_method_opening;
+       /**
+        * User defined close tag handler method
+        * @var string
+        * @access private
+        */
+       var $handler_method_closing;
+       /**
+        * User defined object for handling data in elements
+        * @var object
+        * @access private
+        */
+       var $handler_object_data;
+       /**
+        * User defined data handler method
+        * @var string
+        * @access private
+        */
+       var $handler_method_data;
+       /**
+        * User defined object for handling processing instructions
+        * @var object
+        * @access private
+        */
+       var $handler_object_pi;
+       /**
+        * User defined processing instruction handler method
+        * @var string
+        * @access private
+        */
+       var $handler_method_pi;
+       /**
+        * User defined object for handling JSP/ASP tags
+        * @var object
+        * @access private
+        */
+       var $handler_object_jasp;
+       /**
+        * User defined JSP/ASP handler method
+        * @var string
+        * @access private
+        */
+       var $handler_method_jasp;
+       /**
+        * User defined object for handling XML escapes
+        * @var object
+        * @access private
+        */
+       var $handler_object_escape;
+       /**
+        * User defined XML escape handler method
+        * @var string
+        * @access private
+        */
+       var $handler_method_escape;
+       /**
+        * User defined handler object or NullHandler
+        * @var object
+        * @access private
+        */
+       var $handler_default;
+       /**
+        * Parser options determining parsing behavior
+        * @var array
+        * @access private
+        */
+       var $parser_options = [];
+       /**
+        * XML document being parsed
+        * @var string
+        * @access private
+        */
+       var $rawtext;
+       /**
+        * Position in XML document relative to start (0)
+        * @var int
+        * @access private
+        */
+       var $position;
+       /**
+        * Length of the XML document in characters
+        * @var int
+        * @access private
+        */
+       var $length;
+       /**
+        * Array of state objects
+        * @var array
+        * @access private
+        */
+       var $State = [];
+
+       /**
+        * Constructs XML_HTMLSax3_StateParser setting up states
+        * @var XML_HTMLSax3 instance of user front end class
+        * @access protected
+        */
+       function __construct (& $htmlsax) {
+               $this->htmlsax = & $htmlsax;
+               $this->State[XML_HTMLSAX3_STATE_START] = new XML_HTMLSax3_StartingState();
+
+               $this->State[XML_HTMLSAX3_STATE_CLOSING_TAG] = new XML_HTMLSax3_ClosingTagState();
+               $this->State[XML_HTMLSAX3_STATE_TAG] = new XML_HTMLSax3_TagState();
+               $this->State[XML_HTMLSAX3_STATE_OPENING_TAG] = new XML_HTMLSax3_OpeningTagState();
+
+               $this->State[XML_HTMLSAX3_STATE_PI] = new XML_HTMLSax3_PiState();
+               $this->State[XML_HTMLSAX3_STATE_JASP] = new XML_HTMLSax3_JaspState();
+               $this->State[XML_HTMLSAX3_STATE_ESCAPE] = new XML_HTMLSax3_EscapeState();
+       }
+
+       /**
+        * Moves the position back one character
+        * @access protected
+        * @return void
+        */
+       function unscanCharacter() {
+               $this->position -= 1;
+       }
+
+       /**
+        * Moves the position forward one character
+        * @access protected
+        * @return void
+        */
+       function ignoreCharacter() {
+               $this->position += 1;
+       }
+
+       /**
+        * Returns the next character from the XML document or void if at end
+        * @access protected
+        * @return mixed
+        */
+       function scanCharacter() {
+               if ($this->position < $this->length) {
+                       return $this->rawtext[$this->position++];
+               }
+       }
+
+       /**
+        * Returns a string from the current position to the next occurance
+        * of the supplied string
+        * @param string string to search until
+        * @access protected
+        * @return string
+        */
+       function scanUntilString($string) {
+               $start = $this->position;
+               $this->position = strpos($this->rawtext, $string, $start);
+               if ($this->position === FALSE) {
+                       $this->position = $this->length;
+               }
+               return substr($this->rawtext, $start, $this->position - $start);
+       }
+
+       /**
+        * Returns a string from the current position until the first instance of
+        * one of the characters in the supplied string argument
+        * @param string string to search until
+        * @access protected
+        * @return string
+        * @abstract
+        */
+       function scanUntilCharacters($string) {}
+
+       /**
+        * Moves the position forward past any whitespace characters
+        * @access protected
+        * @return void
+        * @abstract
+        */
+       function ignoreWhitespace() {}
+
+       /**
+        * Begins the parsing operation, setting up any decorators, depending on
+        * parse options invoking _parse() to execute parsing
+        * @param string XML document to parse
+        * @access protected
+        * @return void
+        */
+       function parse($data) {
+               if ($this->parser_options['XML_OPTION_TRIM_DATA_NODES']==1) {
+                       $decorator = new XML_HTMLSax3_Trim(
+                       $this->handler_object_data,
+                       $this->handler_method_data);
+                       $this->handler_object_data =& $decorator;
+                       $this->handler_method_data = 'trimData';
+               }
+               if ($this->parser_options['XML_OPTION_CASE_FOLDING']==1) {
+                       $open_decor = new XML_HTMLSax3_CaseFolding(
+                       $this->handler_object_element,
+                       $this->handler_method_opening,
+                       $this->handler_method_closing);
+                       $this->handler_object_element =& $open_decor;
+                       $this->handler_method_opening ='foldOpen';
+                       $this->handler_method_closing ='foldClose';
+               }
+               if ($this->parser_options['XML_OPTION_LINEFEED_BREAK']==1) {
+                       $decorator = new XML_HTMLSax3_Linefeed(
+                       $this->handler_object_data,
+                       $this->handler_method_data);
+                       $this->handler_object_data =& $decorator;
+                       $this->handler_method_data = 'breakData';
+               }
+               if ($this->parser_options['XML_OPTION_TAB_BREAK']==1) {
+                       $decorator = new XML_HTMLSax3_Tab(
+                       $this->handler_object_data,
+                       $this->handler_method_data);
+                       $this->handler_object_data =& $decorator;
+                       $this->handler_method_data = 'breakData';
+               }
+               if ($this->parser_options['XML_OPTION_ENTITIES_UNPARSED']==1) {
+                       $decorator = new XML_HTMLSax3_Entities_Unparsed(
+                       $this->handler_object_data,
+                       $this->handler_method_data);
+                       $this->handler_object_data =& $decorator;
+                       $this->handler_method_data = 'breakData';
+               }
+               if ($this->parser_options['XML_OPTION_ENTITIES_PARSED']==1) {
+                       $decorator = new XML_HTMLSax3_Entities_Parsed(
+                       $this->handler_object_data,
+                       $this->handler_method_data);
+                       $this->handler_object_data =& $decorator;
+                       $this->handler_method_data = 'breakData';
+               }
+               // Note switched on by default
+               if ($this->parser_options['XML_OPTION_STRIP_ESCAPES']==1) {
+                       $decorator = new XML_HTMLSax3_Escape_Stripper(
+                       $this->handler_object_escape,
+                       $this->handler_method_escape);
+                       $this->handler_object_escape =& $decorator;
+                       $this->handler_method_escape = 'strip';
+               }
+               $this->rawtext = $data;
+               $this->length = strlen($data);
+               $this->position = 0;
+               $this->_parse();
+       }
+
+       /**
+        * Performs the parsing itself, delegating calls to a specific parser
+        * state
+        * @param constant state object to parse with
+        * @access protected
+        * @return void
+        */
+       function _parse($state = XML_HTMLSAX3_STATE_START) {
+               do {
+                       $state = $this->State[$state]->parse($this);
+               } while ($state != XML_HTMLSAX3_STATE_STOP &&
+               $this->position < $this->length);
+       }
+}
+
+/**
+ * Parser for PHP Versions equal to or greater than 4.3.0. Uses a faster
+ * parsing mechanism than the equivalent PHP < 4.3.0 subclass of StateParser
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_StateParser_Gtet430 extends XML_HTMLSax3_StateParser {
+       /**
+        * Constructs XML_HTMLSax3_StateParser_Gtet430 defining available
+        * parser options
+        * @var XML_HTMLSax3 instance of user front end class
+        * @access protected
+        */
+       function __construct(& $htmlsax) {
+               parent::__construct($htmlsax);
+               $this->parser_options['XML_OPTION_TRIM_DATA_NODES'] = 0;
+               $this->parser_options['XML_OPTION_CASE_FOLDING'] = 0;
+               $this->parser_options['XML_OPTION_LINEFEED_BREAK'] = 0;
+               $this->parser_options['XML_OPTION_TAB_BREAK'] = 0;
+               $this->parser_options['XML_OPTION_ENTITIES_PARSED'] = 0;
+               $this->parser_options['XML_OPTION_ENTITIES_UNPARSED'] = 0;
+               $this->parser_options['XML_OPTION_STRIP_ESCAPES'] = 0;
+       }
+       /**
+        * Returns a string from the current position until the first instance of
+        * one of the characters in the supplied string argument.
+        * @param string string to search until
+        * @access protected
+        * @return string
+        */
+       function scanUntilCharacters($string) {
+               $startpos = $this->position;
+               $length = strcspn($this->rawtext, $string, $startpos);
+               $this->position += $length;
+               return substr($this->rawtext, $startpos, $length);
+       }
+
+       /**
+        * Moves the position forward past any whitespace characters
+        * @access protected
+        * @return void
+        */
+       function ignoreWhitespace() {
+               $this->position += strspn($this->rawtext, " \n\r\t", $this->position);
+       }
+
+       /**
+        * Begins the parsing operation, setting up the parsed and unparsed
+        * XML entity decorators if necessary then delegating further work
+        * to parent
+        * @param string XML document to parse
+        * @access protected
+        * @return void
+        */
+       function parse($data) {
+               parent::parse($data);
+       }
+}
+
+/**
+ * Default NullHandler for methods which were not set by user
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_NullHandler {
+       /**
+        * Generic handler method which does nothing
+        * @access protected
+        * @return void
+        */
+       function DoNothing() {
+       }
+}
+
+/**
+ * User interface class. All user calls should only be made to this class
+ * @package XML_HTMLSax3
+ * @access public
+ */
+class XML_HTMLSax3 {
+       /**
+        * Instance of concrete subclass of XML_HTMLSax3_StateParser
+        * @var XML_HTMLSax3_StateParser
+        * @access private
+        */
+       var $state_parser;
+
+       /**
+        * Constructs XML_HTMLSax3 selecting concrete StateParser subclass
+        * depending on PHP version being used as well as setting the default
+        * NullHandler for all callbacks<br />
+        * <b>Example:</b>
+        * <pre>
+        * $myHandler = new MyHandler();
+        * $parser = new XML_HTMLSax3();
+        * $parser->set_object($myHandler);
+        * $parser->set_option('XML_OPTION_CASE_FOLDING');
+        * $parser->set_element_handler('myOpenHandler','myCloseHandler');
+        * $parser->set_data_handler('myDataHandler');
+        * $parser->parser($xml);
+        * </pre>
+        * @access public
+        */
+       function __construct() {
+               $this->state_parser = new XML_HTMLSax3_StateParser_Gtet430($this);
+               $nullhandler = new XML_HTMLSax3_NullHandler();
+               $this->set_object($nullhandler);
+               $this->set_element_handler('DoNothing', 'DoNothing');
+               $this->set_data_handler('DoNothing');
+               $this->set_pi_handler('DoNothing');
+               $this->set_jasp_handler('DoNothing');
+               $this->set_escape_handler('DoNothing');
+       }
+
+       /**
+        * Sets the user defined handler object. Returns a PEAR Error
+        * if supplied argument is not an object.
+        * @param object handler object containing SAX callback methods
+        * @access public
+        * @return mixed
+        */
+       function set_object(&$object) {
+               if ( is_object($object) ) {
+                       $this->state_parser->handler_default =& $object;
+                       return true;
+               } else {
+                       require_once('PEAR.php');
+                       PEAR::raiseError('XML_HTMLSax3::set_object requires '.
+                               'an object instance');
+               }
+       }
+
+       /**
+        * Sets a parser option. By default all options are switched off.
+        * Returns a PEAR Error if option is invalid<br />
+        * <b>Available options:</b>
+        * <ul>
+        * <li>XML_OPTION_TRIM_DATA_NODES: trim whitespace off the beginning
+        * and end of data passed to the data handler</li>
+        * <li>XML_OPTION_LINEFEED_BREAK: linefeeds result in additional data
+        * handler calls</li>
+        * <li>XML_OPTION_TAB_BREAK: tabs result in additional data handler
+        * calls</li>
+        * <li>XML_OPTION_ENTITIES_UNPARSED: XML entities are returned as
+        * seperate data handler calls in unparsed form</li>
+        * <li>XML_OPTION_ENTITIES_PARSED: (PHP 4.3.0+ only) XML entities are
+        * returned as seperate data handler calls and are parsed with
+        * PHP's html_entity_decode() function</li>
+        * <li>XML_OPTION_STRIP_ESCAPES: strips out the -- -- comment markers
+        * or CDATA markup inside an XML escape, if found.</li>
+        * </ul>
+        * To get HTMLSax to behave in the same way as the native PHP SAX parser,
+        * using it's default state, you need to switch on XML_OPTION_LINEFEED_BREAK,
+        * XML_OPTION_ENTITIES_PARSED and XML_OPTION_CASE_FOLDING
+        * @param string name of parser option
+        * @param int (optional) 1 to switch on, 0 for off
+        * @access public
+        * @return boolean
+        */
+       function set_option($name, $value=1) {
+               if ( array_key_exists($name,$this->state_parser->parser_options) ) {
+                       $this->state_parser->parser_options[$name] = $value;
+                       return true;
+               } else {
+                       require_once('PEAR.php');
+                       PEAR::raiseError('XML_HTMLSax3::set_option('.$name.') illegal');
+               }
+       }
+
+       /**
+        * Sets the data handler method which deals with the contents of XML
+        * elements.<br />
+        * The handler method must accept two arguments, the first being an
+        * instance of XML_HTMLSax3 and the second being the contents of an
+        * XML element e.g.
+        * <pre>
+        * function myDataHander(& $parser,$data){}
+        * </pre>
+        * @param string name of method
+        * @access public
+        * @return void
+        * @see set_object
+        */
+       function set_data_handler($data_method) {
+               $this->state_parser->handler_object_data =& $this->state_parser->handler_default;
+               $this->state_parser->handler_method_data = $data_method;
+       }
+
+       /**
+        * Sets the open and close tag handlers
+        * <br />The open handler method must accept three arguments; the parser,
+        * the tag name and an array of attributes e.g.
+        * <pre>
+        * function myOpenHander(& $parser,$tagname,$attrs=array()){}
+        * </pre>
+        * The close handler method must accept two arguments; the parser and
+        * the tag name e.g.
+        * <pre>
+        * function myCloseHander(& $parser,$tagname){}
+        * </pre>
+        * @param string name of open method
+        * @param string name of close method
+        * @access public
+        * @return void
+        * @see set_object
+        */
+       function set_element_handler($opening_method, $closing_method) {
+               $this->state_parser->handler_object_element =& $this->state_parser->handler_default;
+               $this->state_parser->handler_method_opening = $opening_method;
+               $this->state_parser->handler_method_closing = $closing_method;
+       }
+
+       /**
+        * Sets the processing instruction handler method e.g. for PHP open
+        * and close tags<br />
+        * The handler method must accept three arguments; the parser, the
+        * PI target and data inside the PI
+        * <pre>
+        * function myPIHander(& $parser,$target, $data){}
+        * </pre>
+        * @param string name of method
+        * @access public
+        * @return void
+        * @see set_object
+        */
+       function set_pi_handler($pi_method) {
+               $this->state_parser->handler_object_pi =& $this->state_parser->handler_default;
+               $this->state_parser->handler_method_pi = $pi_method;
+       }
+
+       /**
+        * Sets the XML escape handler method e.g. for comments and doctype
+        * declarations<br />
+        * The handler method must accept two arguments; the parser and the
+        * contents of the escaped section
+        * <pre>
+        * function myEscapeHander(& $parser, $data){}
+        * </pre>
+        * @param string name of method
+        * @access public
+        * @return void
+        * @see set_object
+        */
+       function set_escape_handler($escape_method) {
+               $this->state_parser->handler_object_escape =& $this->state_parser->handler_default;
+               $this->state_parser->handler_method_escape = $escape_method;
+       }
+
+       /**
+        * Sets the JSP/ASP markup handler<br />
+        * The handler method must accept two arguments; the parser and
+        * body of the JASP tag
+        * <pre>
+        * function myJaspHander(& $parser, $data){}
+        * </pre>
+        * @param string name of method
+        * @access public
+        * @return void
+        * @see set_object
+        */
+       function set_jasp_handler ($jasp_method) {
+               $this->state_parser->handler_object_jasp =& $this->state_parser->handler_default;
+               $this->state_parser->handler_method_jasp = $jasp_method;
+       }
+
+       /**
+        * Returns the current string position of the "cursor" inside the XML
+        * document
+        * <br />Intended for use from within a user defined handler called
+        * via the $parser reference e.g.
+        * <pre>
+        * function myDataHandler(& $parser,$data) {
+        *     echo( 'Current position: '.$parser->get_current_position() );
+        * }
+        * </pre>
+        * @access public
+        * @return int
+        * @see get_length
+        */
+       function get_current_position() {
+               return $this->state_parser->position;
+       }
+
+       /**
+        * Returns the string length of the XML document being parsed
+        * @access public
+        * @return int
+        */
+       function get_length() {
+               return $this->state_parser->length;
+       }
+
+       /**
+        * Start parsing some XML
+        * @param string XML document
+        * @access public
+        * @return void
+        */
+       function parse($data) {
+               $this->state_parser->parse($data);
+       }
+}
index ab97451..5425677 100644 (file)
-<?php\r
-class XML_HTMLSax3_Trim {\r
- var $orig_obj;\r
- var $orig_method;\r
- function __construct(&$orig_obj, $orig_method) {\r
-  $this->orig_obj =& $orig_obj;\r
-  $this->orig_method = $orig_method;\r
- }\r
- function trimData(&$parser, $data) {\r
-  $data = trim($data);\r
-  if ($data != '') {\r
-   $this->orig_obj->{$this->orig_method}($parser, $data);\r
-  }\r
- }\r
-}\r
-class XML_HTMLSax3_CaseFolding {\r
- var $orig_obj;\r
- var $orig_open_method;\r
- var $orig_close_method;\r
- function __construct(&$orig_obj, $orig_open_method, $orig_close_method) {\r
-  $this->orig_obj =& $orig_obj;\r
-  $this->orig_open_method = $orig_open_method;\r
-  $this->orig_close_method = $orig_close_method;\r
- }\r
- function foldOpen(&$parser, $tag, $attrs = array(), $empty = FALSE) {\r
-  $this->orig_obj->{$this->orig_open_method}($parser, strtoupper($tag), $attrs, $empty);\r
- }\r
- function foldClose(&$parser, $tag, $empty = FALSE) {\r
-  $this->orig_obj->{$this->orig_close_method}($parser, strtoupper($tag), $empty);\r
- }\r
-}\r
-class XML_HTMLSax3_Linefeed {\r
- var $orig_obj;\r
- var $orig_method;\r
- function __construct(&$orig_obj, $orig_method) {\r
-  $this->orig_obj =& $orig_obj;\r
-  $this->orig_method = $orig_method;\r
- }\r
- function breakData(&$parser, $data) {\r
-  $data = explode("\n",$data);\r
-  foreach ( $data as $chunk ) {\r
-   $this->orig_obj->{$this->orig_method}($parser, $chunk);\r
-  }\r
- }\r
-}\r
-class XML_HTMLSax3_Tab {\r
- var $orig_obj;\r
- var $orig_method;\r
- function __construct(&$orig_obj, $orig_method) {\r
-  $this->orig_obj =& $orig_obj;\r
-  $this->orig_method = $orig_method;\r
- }\r
- function breakData(&$parser, $data) {\r
-  $data = explode("\t",$data);\r
-  foreach ( $data as $chunk ) {\r
-   $this->orig_obj->{$this->orig_method}($this, $chunk);\r
-  }\r
- }\r
-}\r
-class XML_HTMLSax3_Entities_Parsed {\r
- var $orig_obj;\r
- var $orig_method;\r
- function __construct(&$orig_obj, $orig_method) {\r
-  $this->orig_obj =& $orig_obj;\r
-  $this->orig_method = $orig_method;\r
- }\r
- function breakData(&$parser, $data) {\r
-  $data = preg_split('/(&.+?;)/',$data,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);\r
-  foreach ( $data as $chunk ) {\r
-   $chunk = html_entity_decode($chunk,ENT_NOQUOTES);\r
-   $this->orig_obj->{$this->orig_method}($this, $chunk);\r
-  }\r
- }\r
-}\r
-if (version_compare(phpversion(), '4.3', '<') && !function_exists('html_entity_decode') ) {\r
- function html_entity_decode($str, $style = ENT_NOQUOTES) {\r
-  return strtr($str,\r
-   array_flip(get_html_translation_table(HTML_ENTITIES,$style)));\r
- }\r
-}\r
-class XML_HTMLSax3_Entities_Unparsed {\r
- var $orig_obj;\r
- var $orig_method;\r
- function __construct(&$orig_obj, $orig_method) {\r
-  $this->orig_obj =& $orig_obj;\r
-  $this->orig_method = $orig_method;\r
- }\r
- function breakData(&$parser, $data) {\r
-  $data = preg_split('/(&.+?;)/',$data,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);\r
-  foreach ( $data as $chunk ) {\r
-   $this->orig_obj->{$this->orig_method}($this, $chunk);\r
-  }\r
- }\r
-}\r
-\r
-class XML_HTMLSax3_Escape_Stripper {\r
- var $orig_obj;\r
- var $orig_method;\r
- function __construct(&$orig_obj, $orig_method) {\r
-  $this->orig_obj =& $orig_obj;\r
-  $this->orig_method = $orig_method;\r
- }\r
- function strip(&$parser, $data) {\r
-  if ( substr($data,0,2) == '--' ) {\r
-   $patterns = array(\r
-    '/^\-\-/',    // Opening comment: --\r
-    '/\-\-$/',    // Closing comment: --\r
-   );\r
-   $data = preg_replace($patterns,'',$data);\r
-\r
-  } else if ( substr($data,0,1) == '[' ) {\r
-   $patterns = array(\r
-    '/^\[.*CDATA.*\[/s', // Opening CDATA\r
-    '/\].*\]$/s',    // Closing CDATA\r
-    );\r
-   $data = preg_replace($patterns,'',$data);\r
-  }\r
-\r
-  $this->orig_obj->{$this->orig_method}($this, $data);\r
- }\r
-}\r
-?>\r
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+//
+// +----------------------------------------------------------------------+
+// | PHP Version 4                                                        |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2002 The PHP Group                                |
+// +----------------------------------------------------------------------+
+// | This source file is subject toversion 3.0 of the PHP license,      |
+// | that is bundled with this package in the file LICENSE, and is        |
+// | available at through the world-wide-web at                           |
+// | http://www.php.net/license/3_0.txt.                                  |
+// | If you did not receive a copy of the PHP license and are unable to   |
+// | obtain it through the world-wide-web, please send a note to          |
+// | license@php.net so we can mail you a copy immediately.               |
+// +----------------------------------------------------------------------+
+// | Authors: Alexander Zhukov <alex@veresk.ru> Original port from Python |
+// | Authors: Harry Fuecks <hfuecks@phppatterns.com> Port to PEAR + more  |
+// | Authors: Many @ Sitepointforums Advanced PHP Forums                  |
+// +----------------------------------------------------------------------+
+//
+// $Id: Decorators.php,v 1.2 2007/10/29 21:41:35 hfuecks Exp $
+//
+/**
+ * Decorators for dealing with parser options
+ * @package XML_HTMLSax3
+ * @version $Id: Decorators.php,v 1.2 2007/10/29 21:41:35 hfuecks Exp $
+ * @see XML_HTMLSax3::set_option
+ */
+/**
+ * Trims the contents of element data from whitespace at start and end
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_Trim {
+       /**
+        * Original handler object
+        * @var object
+        * @access private
+        */
+       var $orig_obj;
+       /**
+        * Original handler method
+        * @var string
+        * @access private
+        */
+       var $orig_method;
+       /**
+        * Constructs XML_HTMLSax3_Trim
+        * @param object handler object being decorated
+        * @param string original handler method
+        * @access protected
+        */
+       function __construct(&$orig_obj, $orig_method) {
+               $this->orig_obj =& $orig_obj;
+               $this->orig_method = $orig_method;
+       }
+       /**
+        * Trims the data
+        * @param XML_HTMLSax3
+        * @param string element data
+        * @access protected
+        */
+       function trimData(&$parser, $data) {
+               $data = trim($data);
+               if ($data != '') {
+                       $this->orig_obj->{$this->orig_method}($parser, $data);
+               }
+       }
+}
+/**
+ * Coverts tag names to upper case
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_CaseFolding {
+       /**
+        * Original handler object
+        * @var object
+        * @access private
+        */
+       var $orig_obj;
+       /**
+        * Original open handler method
+        * @var string
+        * @access private
+        */
+       var $orig_open_method;
+       /**
+        * Original close handler method
+        * @var string
+        * @access private
+        */
+       var $orig_close_method;
+       /**
+        * Constructs XML_HTMLSax3_CaseFolding
+        * @param object handler object being decorated
+        * @param string original open handler method
+        * @param string original close handler method
+        * @access protected
+        */
+       function __construct(&$orig_obj, $orig_open_method, $orig_close_method) {
+               $this->orig_obj =& $orig_obj;
+               $this->orig_open_method = $orig_open_method;
+               $this->orig_close_method = $orig_close_method;
+       }
+       /**
+        * Folds up open tag callbacks
+        * @param XML_HTMLSax3
+        * @param string tag name
+        * @param array tag attributes
+        * @access protected
+        */
+       function foldOpen(&$parser, $tag, $attrs=array(), $empty = FALSE) {
+               $this->orig_obj->{$this->orig_open_method}($parser, strtoupper($tag), $attrs, $empty);
+       }
+       /**
+        * Folds up close tag callbacks
+        * @param XML_HTMLSax3
+        * @param string tag name
+        * @access protected
+        */
+       function foldClose(&$parser, $tag, $empty = FALSE) {
+               $this->orig_obj->{$this->orig_close_method}($parser, strtoupper($tag), $empty);
+       }
+}
+/**
+ * Breaks up data by linefeed characters, resulting in additional
+ * calls to the data handler
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_Linefeed {
+       /**
+        * Original handler object
+        * @var object
+        * @access private
+        */
+       var $orig_obj;
+       /**
+        * Original handler method
+        * @var string
+        * @access private
+        */
+       var $orig_method;
+       /**
+        * Constructs XML_HTMLSax3_LineFeed
+        * @param object handler object being decorated
+        * @param string original handler method
+        * @access protected
+        */
+       function __construct(&$orig_obj, $orig_method) {
+               $this->orig_obj =& $orig_obj;
+               $this->orig_method = $orig_method;
+       }
+       /**
+        * Breaks the data up by linefeeds
+        * @param XML_HTMLSax3
+        * @param string element data
+        * @access protected
+        */
+       function breakData(&$parser, $data) {
+               $data = explode("\n",$data);
+               foreach ( $data as $chunk ) {
+                       $this->orig_obj->{$this->orig_method}($parser, $chunk);
+               }
+       }
+}
+/**
+ * Breaks up data by tab characters, resulting in additional
+ * calls to the data handler
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_Tab {
+       /**
+        * Original handler object
+        * @var object
+        * @access private
+        */
+       var $orig_obj;
+       /**
+        * Original handler method
+        * @var string
+        * @access private
+        */
+       var $orig_method;
+       /**
+        * Constructs XML_HTMLSax3_Tab
+        * @param object handler object being decorated
+        * @param string original handler method
+        * @access protected
+        */
+       function __construct(&$orig_obj, $orig_method) {
+               $this->orig_obj =& $orig_obj;
+               $this->orig_method = $orig_method;
+       }
+       /**
+        * Breaks the data up by linefeeds
+        * @param XML_HTMLSax3
+        * @param string element data
+        * @access protected
+        */
+       function breakData(&$parser, $data) {
+               $data = explode("\t",$data);
+               foreach ( $data as $chunk ) {
+                       $this->orig_obj->{$this->orig_method}($this, $chunk);
+               }
+       }
+}
+/**
+ * Breaks up data by XML entities and parses them with html_entity_decode(),
+ * resulting in additional calls to the data handler<br />
+ * Requires PHP 4.3.0+
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_Entities_Parsed {
+       /**
+        * Original handler object
+        * @var object
+        * @access private
+        */
+       var $orig_obj;
+       /**
+        * Original handler method
+        * @var string
+        * @access private
+        */
+       var $orig_method;
+       /**
+        * Constructs XML_HTMLSax3_Entities_Parsed
+        * @param object handler object being decorated
+        * @param string original handler method
+        * @access protected
+        */
+       function __construct(&$orig_obj, $orig_method) {
+               $this->orig_obj =& $orig_obj;
+               $this->orig_method = $orig_method;
+       }
+       /**
+        * Breaks the data up by XML entities
+        * @param XML_HTMLSax3
+        * @param string element data
+        * @access protected
+        */
+       function breakData(&$parser, $data) {
+               $data = preg_split('/(&.+?;)/',$data,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+               foreach ( $data as $chunk ) {
+                       $chunk = html_entity_decode($chunk, ENT_NOQUOTES, HTML_ENTITIES_CHARSET);
+                       $this->orig_obj->{$this->orig_method}($this, $chunk);
+               }
+       }
+}
+/**
+ * Breaks up data by XML entities but leaves them unparsed,
+ * resulting in additional calls to the data handler<br />
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_Entities_Unparsed {
+       /**
+        * Original handler object
+        * @var object
+        * @access private
+        */
+       var $orig_obj;
+       /**
+        * Original handler method
+        * @var string
+        * @access private
+        */
+       var $orig_method;
+       /**
+        * Constructs XML_HTMLSax3_Entities_Unparsed
+        * @param object handler object being decorated
+        * @param string original handler method
+        * @access protected
+        */
+       function __construct(&$orig_obj, $orig_method) {
+               $this->orig_obj =& $orig_obj;
+               $this->orig_method = $orig_method;
+       }
+       /**
+        * Breaks the data up by XML entities
+        * @param XML_HTMLSax3
+        * @param string element data
+        * @access protected
+        */
+       function breakData(&$parser, $data) {
+               $data = preg_split('/(&.+?;)/',$data,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+               foreach ( $data as $chunk ) {
+                       $this->orig_obj->{$this->orig_method}($this, $chunk);
+               }
+       }
+}
+
+/**
+ * Strips the HTML comment markers or CDATA sections from an escape.
+ * If XML_OPTIONS_FULL_ESCAPES is on, this decorator is not used.<br />
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_Escape_Stripper {
+       /**
+        * Original handler object
+        * @var object
+        * @access private
+        */
+       var $orig_obj;
+       /**
+        * Original handler method
+        * @var string
+        * @access private
+        */
+       var $orig_method;
+       /**
+        * Constructs XML_HTMLSax3_Entities_Unparsed
+        * @param object handler object being decorated
+        * @param string original handler method
+        * @access protected
+        */
+       function __construct(&$orig_obj, $orig_method) {
+               $this->orig_obj =& $orig_obj;
+               $this->orig_method = $orig_method;
+       }
+       /**
+        * Breaks the data up by XML entities
+        * @param XML_HTMLSax3
+        * @param string element data
+        * @access protected
+        */
+       function strip(&$parser, $data) {
+               // Check for HTML comments first
+               if ( substr($data,0,2) == '--' ) {
+                       $patterns = [
+                               '/^\-\-/',                              // Opening comment: --
+                               '/\-\-$/',                              // Closing comment: --
+                       ];
+                       $data = preg_replace($patterns,'',$data);
+
+                       // Check for XML CDATA sections (note: don't do both!)
+               } else if ( substr($data,0,1) == '[' ) {
+                       $patterns = [
+                               '/^\[.*CDATA.*\[/s',    // Opening CDATA
+                               '/\].*\]$/s',                   // Closing CDATA
+                       ];
+                       $data = preg_replace($patterns,'',$data);
+               }
+
+               $this->orig_obj->{$this->orig_method}($this, $data);
+       }
+}
index eb4a315..9f16380 100644 (file)
-<?php\r
-define('XML_HTMLSAX3_STATE_STOP', 0);\r
-define('XML_HTMLSAX3_STATE_START', 1);\r
-define('XML_HTMLSAX3_STATE_TAG', 2);\r
-define('XML_HTMLSAX3_STATE_OPENING_TAG', 3);\r
-define('XML_HTMLSAX3_STATE_CLOSING_TAG', 4);\r
-define('XML_HTMLSAX3_STATE_ESCAPE', 6);\r
-define('XML_HTMLSAX3_STATE_JASP', 7);\r
-define('XML_HTMLSAX3_STATE_PI', 8);\r
-class XML_HTMLSax3_StartingState  {\r
- function parse(&$context) {\r
-  $data = $context->scanUntilString('<');\r
-  if ($data != '') {\r
-   $context->handler_object_data->\r
-    {$context->handler_method_data}($context->htmlsax, $data);\r
-  }\r
-  $context->IgnoreCharacter();\r
-  return XML_HTMLSAX3_STATE_TAG;\r
- }\r
-}\r
-class XML_HTMLSax3_TagState {\r
- function parse(&$context) {\r
-  switch($context->ScanCharacter()) {\r
-  case '/':\r
-   return XML_HTMLSAX3_STATE_CLOSING_TAG;\r
-   break;\r
-  case '?':\r
-   return XML_HTMLSAX3_STATE_PI;\r
-   break;\r
-  case '%':\r
-   return XML_HTMLSAX3_STATE_JASP;\r
-   break;\r
-  case '!':\r
-   return XML_HTMLSAX3_STATE_ESCAPE;\r
-   break;\r
-  default:\r
-   $context->unscanCharacter();\r
-   return XML_HTMLSAX3_STATE_OPENING_TAG;\r
-  }\r
- }\r
-}\r
-class XML_HTMLSax3_ClosingTagState {\r
- function parse(&$context) {\r
-  $tag = $context->scanUntilCharacters('/>');\r
-  if ($tag != '') {\r
-   $char = $context->scanCharacter();\r
-   if ($char == '/') {\r
-    $char = $context->scanCharacter();\r
-    if ($char != '>') {\r
-     $context->unscanCharacter();\r
-    }\r
-   }\r
-   $context->handler_object_element->\r
-    {$context->handler_method_closing}($context->htmlsax, $tag, FALSE);\r
-  }\r
-  return XML_HTMLSAX3_STATE_START;\r
- }\r
-}\r
-class XML_HTMLSax3_OpeningTagState {\r
- function parseAttributes(&$context) {\r
-  $Attributes = array();\r
\r
-  $context->ignoreWhitespace();\r
-  $attributename = $context->scanUntilCharacters("=/> \n\r\t");\r
-  while ($attributename != '') {\r
-   $attributevalue = NULL;\r
-   $context->ignoreWhitespace();\r
-   $char = $context->scanCharacter();\r
-   if ($char == '=') {\r
-    $context->ignoreWhitespace();\r
-    $char = $context->ScanCharacter();\r
-    if ($char == '"') {\r
-     $attributevalue= $context->scanUntilString('"');\r
-     $context->IgnoreCharacter();\r
-    } else if ($char == "'") {\r
-     $attributevalue = $context->scanUntilString("'");\r
-     $context->IgnoreCharacter();\r
-    } else {\r
-     $context->unscanCharacter();\r
-     $attributevalue =\r
-      $context->scanUntilCharacters("> \n\r\t");\r
-    }\r
-   } else if ($char !== NULL) {\r
-    $attributevalue = NULL;\r
-    $context->unscanCharacter();\r
-   }\r
-   $Attributes[$attributename] = $attributevalue;\r
-   \r
-   $context->ignoreWhitespace();\r
-   $attributename = $context->scanUntilCharacters("=/> \n\r\t");\r
-  }\r
-  return $Attributes;\r
- }\r
-\r
- function parse(&$context) {\r
-  $tag = $context->scanUntilCharacters("/> \n\r\t");\r
-  if ($tag != '') {\r
-   $this->attrs = array();\r
-   $Attributes = $this->parseAttributes($context);\r
-   $char = $context->scanCharacter();\r
-   if ($char == '/') {\r
-    $char = $context->scanCharacter();\r
-    if ($char != '>') {\r
-     $context->unscanCharacter();\r
-    }\r
-    $context->handler_object_element->\r
-     {$context->handler_method_opening}($context->htmlsax, $tag, \r
-     $Attributes, TRUE);\r
-    $context->handler_object_element->\r
-     {$context->handler_method_closing}($context->htmlsax, $tag, \r
-     TRUE);\r
-   } else {\r
-    $context->handler_object_element->\r
-     {$context->handler_method_opening}($context->htmlsax, $tag, \r
-     $Attributes, FALSE);\r
-   }\r
-  }\r
-  return XML_HTMLSAX3_STATE_START;\r
- }\r
-}\r
-\r
-class XML_HTMLSax3_EscapeState {\r
- function parse(&$context) {\r
-  $char = $context->ScanCharacter();\r
-  if ($char == '-') {\r
-   $char = $context->ScanCharacter();\r
-   if ($char == '-') {\r
-    $context->unscanCharacter();\r
-    $context->unscanCharacter();\r
-    $text = $context->scanUntilString('-->');\r
-    $text .= $context->scanCharacter();\r
-    $text .= $context->scanCharacter();\r
-   } else {\r
-    $context->unscanCharacter();\r
-    $text = $context->scanUntilString('>');\r
-   }\r
-  } else if ( $char == '[') {\r
-   $context->unscanCharacter();\r
-   $text = $context->scanUntilString(']>');\r
-   $text.= $context->scanCharacter();\r
-  } else {\r
-   $context->unscanCharacter();\r
-   $text = $context->scanUntilString('>');\r
-  }\r
-\r
-  $context->IgnoreCharacter();\r
-  if ($text != '') {\r
-   $context->handler_object_escape->\r
-   {$context->handler_method_escape}($context->htmlsax, $text);\r
-  }\r
-  return XML_HTMLSAX3_STATE_START;\r
- }\r
-}\r
-class XML_HTMLSax3_JaspState {\r
- function parse(&$context) {\r
-  $text = $context->scanUntilString('%>');\r
-  if ($text != '') {\r
-   $context->handler_object_jasp->\r
-    {$context->handler_method_jasp}($context->htmlsax, $text);\r
-  }\r
-  $context->IgnoreCharacter();\r
-  $context->IgnoreCharacter();\r
-  return XML_HTMLSAX3_STATE_START;\r
- }\r
-}\r
-class XML_HTMLSax3_PiState {\r
- function parse(&$context) {\r
-  $target = $context->scanUntilCharacters(" \n\r\t");\r
-  $data = $context->scanUntilString('?>');\r
-  if ($data != '') {\r
-   $context->handler_object_pi->\r
-   {$context->handler_method_pi}($context->htmlsax, $target, $data);\r
-  }\r
-  $context->IgnoreCharacter();\r
-  $context->IgnoreCharacter();\r
-  return XML_HTMLSAX3_STATE_START;\r
- }\r
-}\r
-?>
\ No newline at end of file
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+//
+// +----------------------------------------------------------------------+
+// | PHP Version 4                                                        |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2002 The PHP Group                                |
+// +----------------------------------------------------------------------+
+// | This source file is subject toversion 3.0 of the PHP license,      |
+// | that is bundled with this package in the file LICENSE, and is        |
+// | available at through the world-wide-web at                           |
+// | http://www.php.net/license/3_0.txt.                                  |
+// | If you did not receive a copy of the PHP license and are unable to   |
+// | obtain it through the world-wide-web, please send a note to          |
+// | license@php.net so we can mail you a copy immediately.               |
+// +----------------------------------------------------------------------+
+// | Authors: Alexander Zhukov <alex@veresk.ru> Original port from Python |
+// | Authors: Harry Fuecks <hfuecks@phppatterns.com> Port to PEAR + more  |
+// | Authors: Many @ Sitepointforums Advanced PHP Forums                  |
+// +----------------------------------------------------------------------+
+//
+// $Id: States.php,v 1.3 2007/10/29 21:41:35 hfuecks Exp $
+//
+/**
+ * Parsing states.
+ * @package XML_HTMLSax3
+ * @version $Id: States.php,v 1.3 2007/10/29 21:41:35 hfuecks Exp $
+ */
+/**
+ * Define parser states
+ */
+define('XML_HTMLSAX3_STATE_STOP', 0);
+define('XML_HTMLSAX3_STATE_START', 1);
+define('XML_HTMLSAX3_STATE_TAG', 2);
+define('XML_HTMLSAX3_STATE_OPENING_TAG', 3);
+define('XML_HTMLSAX3_STATE_CLOSING_TAG', 4);
+define('XML_HTMLSAX3_STATE_ESCAPE', 6);
+define('XML_HTMLSAX3_STATE_JASP', 7);
+define('XML_HTMLSAX3_STATE_PI', 8);
+/**
+ * StartingState searches for the start of any XML tag
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_StartingState  {
+       /**
+        * @param XML_HTMLSax3_StateParser subclass
+        * @return constant XML_HTMLSAX3_STATE_TAG
+        * @access protected
+        */
+       function parse(&$context) {
+               $data = $context->scanUntilString('<');
+               if ($data != '') {
+                       $context->handler_object_data->
+                       {$context->handler_method_data}($context->htmlsax, $data);
+               }
+               $context->IgnoreCharacter();
+               return XML_HTMLSAX3_STATE_TAG;
+       }
+}
+/**
+ * Decides which state to move one from after StartingState
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_TagState {
+       /**
+        * @param XML_HTMLSax3_StateParser subclass
+        * @return constant the next state to move into
+        * @access protected
+        */
+       function parse(&$context) {
+               switch($context->ScanCharacter()) {
+                       case '/':
+                               return XML_HTMLSAX3_STATE_CLOSING_TAG;
+                               break;
+                       case '?':
+                               return XML_HTMLSAX3_STATE_PI;
+                               break;
+                       case '%':
+                               return XML_HTMLSAX3_STATE_JASP;
+                               break;
+                       case '!':
+                               return XML_HTMLSAX3_STATE_ESCAPE;
+                               break;
+                       default:
+                               $context->unscanCharacter();
+                               return XML_HTMLSAX3_STATE_OPENING_TAG;
+               }
+       }
+}
+/**
+ * Dealing with closing XML tags
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_ClosingTagState {
+       /**
+        * @param XML_HTMLSax3_StateParser subclass
+        * @return constant XML_HTMLSAX3_STATE_START
+        * @access protected
+        */
+       function parse(&$context) {
+               $tag = $context->scanUntilCharacters('/>');
+               if ($tag != '') {
+                       $char = $context->scanCharacter();
+                       if ($char == '/') {
+                               $char = $context->scanCharacter();
+                               if ($char != '>') {
+                                       $context->unscanCharacter();
+                               }
+                       }
+                       $context->handler_object_element->
+                       {$context->handler_method_closing}($context->htmlsax, $tag, FALSE);
+               }
+               return XML_HTMLSAX3_STATE_START;
+       }
+}
+/**
+ * Dealing with opening XML tags
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_OpeningTagState {
+       /**
+        * Handles attributes
+        * @param string attribute name
+        * @param string attribute value
+        * @return void
+        * @access protected
+        * @see XML_HTMLSax3_AttributeStartState
+        */
+       function parseAttributes(&$context) {
+               $Attributes = [];
+
+               $context->ignoreWhitespace();
+               $attributename = $context->scanUntilCharacters("=/> \n\r\t");
+               while ($attributename != '') {
+                       $attributevalue = null;
+                       $context->ignoreWhitespace();
+                       $char = $context->scanCharacter();
+                       if ($char == '=') {
+                               $context->ignoreWhitespace();
+                               $char = $context->ScanCharacter();
+                               if ($char == '"') {
+                                       $attributevalue= $context->scanUntilString('"');
+                                       $context->IgnoreCharacter();
+                               } else if ($char == "'") {
+                                       $attributevalue = $context->scanUntilString("'");
+                                       $context->IgnoreCharacter();
+                               } else {
+                                       $context->unscanCharacter();
+                                       $attributevalue =
+                                       $context->scanUntilCharacters("> \n\r\t");
+                               }
+                       } else if ($char !== null) {
+                               $attributevalue = null;
+                               $context->unscanCharacter();
+                       }
+                       $Attributes[$attributename] = $attributevalue;
+
+                       $context->ignoreWhitespace();
+                       $attributename = $context->scanUntilCharacters("=/> \n\r\t");
+               }
+               return $Attributes;
+       }
+
+       /**
+        * @param XML_HTMLSax3_StateParser subclass
+        * @return constant XML_HTMLSAX3_STATE_START
+        * @access protected
+        */
+       function parse(&$context) {
+               $tag = $context->scanUntilCharacters("/> \n\r\t");
+               if ($tag != '') {
+                       $this->attrs = [];
+                       $Attributes = $this->parseAttributes($context);
+                       $char = $context->scanCharacter();
+                       if ($char == '/') {
+                               $char = $context->scanCharacter();
+                               if ($char != '>') {
+                                       $context->unscanCharacter();
+                               }
+                               $context->handler_object_element->
+                               {$context->handler_method_opening}($context->htmlsax, $tag,
+                               $Attributes, TRUE);
+                               $context->handler_object_element->
+                               {$context->handler_method_closing}($context->htmlsax, $tag,
+                               TRUE);
+                       } else {
+                               $context->handler_object_element->
+                               {$context->handler_method_opening}($context->htmlsax, $tag,
+                               $Attributes, FALSE);
+                       }
+               }
+               return XML_HTMLSAX3_STATE_START;
+       }
+}
+
+/**
+ * Deals with XML escapes handling comments and CDATA correctly
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_EscapeState {
+       /**
+        * @param XML_HTMLSax3_StateParser subclass
+        * @return constant XML_HTMLSAX3_STATE_START
+        * @access protected
+        */
+       function parse(&$context) {
+               $char = $context->ScanCharacter();
+               if ($char == '-') {
+                       $char = $context->ScanCharacter();
+                       if ($char == '-') {
+                               $context->unscanCharacter();
+                               $context->unscanCharacter();
+                               $text = $context->scanUntilString('-->');
+                               $text .= $context->scanCharacter();
+                               $text .= $context->scanCharacter();
+                       } else {
+                               $context->unscanCharacter();
+                               $text = $context->scanUntilString('>');
+                       }
+               } else if ( $char == '[') {
+                       $context->unscanCharacter();
+                       $text = $context->scanUntilString(']>');
+                       $text.= $context->scanCharacter();
+               } else {
+                       $context->unscanCharacter();
+                       $text = $context->scanUntilString('>');
+               }
+
+               $context->IgnoreCharacter();
+               if ($text != '') {
+                       $context->handler_object_escape->
+                       {$context->handler_method_escape}($context->htmlsax, $text);
+               }
+               return XML_HTMLSAX3_STATE_START;
+       }
+}
+/**
+ * Deals with JASP/ASP markup
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_JaspState {
+       /**
+        * @param XML_HTMLSax3_StateParser subclass
+        * @return constant XML_HTMLSAX3_STATE_START
+        * @access protected
+        */
+       function parse(&$context) {
+               $text = $context->scanUntilString('%>');
+               if ($text != '') {
+                       $context->handler_object_jasp->
+                       {$context->handler_method_jasp}($context->htmlsax, $text);
+               }
+               $context->IgnoreCharacter();
+               $context->IgnoreCharacter();
+               return XML_HTMLSAX3_STATE_START;
+       }
+}
+/**
+ * Deals with XML processing instructions
+ * @package XML_HTMLSax3
+ * @access protected
+ */
+class XML_HTMLSax3_PiState {
+       /**
+        * @param XML_HTMLSax3_StateParser subclass
+        * @return constant XML_HTMLSAX3_STATE_START
+        * @access protected
+        */
+       function parse(&$context) {
+               $target = $context->scanUntilCharacters(" \n\r\t");
+               $data = $context->scanUntilString('?>');
+               if ($data != '') {
+                       $context->handler_object_pi->
+                       {$context->handler_method_pi}($context->htmlsax, $target, $data);
+               }
+               $context->IgnoreCharacter();
+               $context->IgnoreCharacter();
+               return XML_HTMLSAX3_STATE_START;
+       }
+}
index 6959b1c..9bfeffa 100644 (file)
 <?php
-
 /**
  * SafeHTML Parser
  *
- * @note
- *     Attention : Quelques modifications pour PHP 5.5 et 7
- * 
- * @package    SafeHTML
- * @author     Roman Ivanov <thingol@mail.ru>
- * @author     Miguel Vazquez Gocobachi <demrit@mx.gnu.org>
- * @copyright  2004-2009 Roman Ivanov, Miguel Vazquez Gocobachi
- * @license    http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
- * @version    1.3.10
- * @link       https://wackowiki.org/doc/Dev/Projects/SafeHTML
+ * PHP version 7
+ *
+ * @category   HTML
+ * @package            SafeHTML
+ * @author             Roman Ivanov <thingol@mail.ru>
+ * @author             Miguel Vazquez Gocobachi <demrit@mx.gnu.org>
+ * @copyright  2004-2020 Roman Ivanov, Miguel Vazquez Gocobachi, WackoWiki Team
+ * @license            http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
+ * @version            1.3.12
+ * @link               https://wackowiki.org/doc/Dev/Projects/SafeHTML
  */
 
-
-if (!defined('_ECRIRE_INC_VERSION')) return;
-
+/**
+ * This package requires HTMLSax3 package
+ */
 require_once(XML_HTMLSAX3 . 'HTMLSax3.php');
 
 /**
- *
- * SafeHTML Parser
+ * HTML_Safe Parser
  *
  * This parser strips down all potentially dangerous content within HTML:
  * <ul>
  * <li>opening tag without its closing tag</li>
  * <li>closing tag without its opening tag</li>
- * <li>any of these tags: "base", "basefont", "head", "html", "body", "applet", 
- * "object", "iframe", "frame", "frameset", "script", "layer", "ilayer", "embed", 
+ * <li>any of these tags: "base", "basefont", "head", "html", "body", "applet",
+ * "object", "iframe", "frame", "frameset", "script", "layer", "ilayer", "embed",
  * "bgsound", "link", "meta", "style", "title", "blink", "xml" etc.</li>
  * <li>any of these attributes: on*, data*, dynsrc</li>
  * <li>javascript:/vbscript:/about: etc. protocols</li>
  * <li>expression/behavior etc. in styles</li>
  * <li>any other active content</li>
  * </ul>
- * It also tries to convert code to XHTML valid, but htmltidy is far better 
+ * It also tries to convert code to XHTML valid, but htmltidy is far better
  * solution for this task.
  *
  * <b>Example:</b>
  * <pre>
- * $parser =& new SafeHTML();
+ * $parser = new SafeHTML;
  * $result = $parser->parse($doc);
  * </pre>
- *
- * @category   HTML
- * @package    SafeHTML
- * @author     Roman Ivanov <thingol@mail.ru>
- * @copyright  1997-2005 Roman Ivanov
- * @license    http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
- * @version    Release: @package_version@
- * @link       http://pear.php.net/package/SafeHTML
  */
 
-class SafeHTML 
+class SafeHTML
 {
-    /**
-     * Storage for resulting HTML output
-     *
-     * @var string
-     */
-    protected $xhtml = '';
-    
-    /**
-     * Array of counters for each tag
-     *
-     * @var array
-     */
-    protected $counter = array();
-    
-    /**
-     * Stack of unclosed tags
-     *
-     * @var array
-     */
-    protected $stack = array();
-    
-    /**
-     * Array of counters for tags that must be deleted with all content
-     *
-     * @var array
-     */
-    protected $dcCounter = array();
-    
-    /**
-     * Stack of unclosed tags that must be deleted with all content
-     *
-     * @var array
-     */
-    protected $dcStack = array();
-    
-    /**
-     * Stores level of list (ol/ul) nesting
-     *
-     * @var int
-     */
-    protected $listScope = 0;
-    
-    /**
-     * Stack of unclosed list tags 
-     *
-     * @var array
-     */
-    protected $liStack = array();
-
-    /**
-     * Array of prepared regular expressions for protocols (schemas) matching
-     *
-     * @var array
-     */
-    protected $protoRegexps = array();
-    
-    /**
-     * Array of prepared regular expressions for CSS matching
-     *
-     * @var array
-     */
-    protected $cssRegexps = array();
-
-    /**
-     * Should we perform UTF7 repacking or not?
-     *
-     * This repacking might replace completely normal strings such as "+31-" by illegal sequences,
-     * which cause the document to be truncated on saving to MySQL
-     *
-     * @var boolean
-     * @access public
-     */
-    var $repackUTF7 = true;
-
-    /**
-     * Allowed tags
-     *
-     * @var array
-     */
-    protected $allowTags = array();
-
-
-    /**
-     * List of single tags ("<tag />")
-     *
-     * @var array
-     */
-    public $singleTags = array('area', 'br', 'img', 'input', 'hr', 'wbr', );
-
-    /**
-     * List of dangerous tags (such tags will be deleted)
-     *
-     * @var array
-     */
-    public $deleteTags = array(
-        'applet', 'base',   'basefont', 'bgsound', 'blink',  'body', 
-        'embed',  'frame',  'frameset', 'head',    'html',   'ilayer', 
-        'iframe', 'layer',  'link',     'meta',    'object', 'style', 
-        'title',  'script', 
-        );
-
-    /**
-     * List of dangerous tags (such tags will be deleted, and all content 
-     * inside this tags will be also removed)
-     *
-     * @var array
-     */
-    public $deleteTagsContent = array('script', 'style', 'title', 'xml', );
-
-    /**
-     * Type of protocols filtering ('white' or 'black')
-     *
-     * @var string
-     */
-    public $protocolFiltering = 'white';
-
-    /**
-     * List of "dangerous" protocols (used for blacklist-filtering)
-     *
-     * @var array
-     */
-    public $blackProtocols = array(
-        'about',   'chrome',     'data',       'disk',     'hcp',     
-        'help',    'javascript', 'livescript', 'lynxcgi',  'lynxexec', 
-        'ms-help', 'ms-its',     'mhtml',      'mocha',    'opera',   
-        'res',     'resource',   'shell',      'vbscript', 'view-source', 
-        'vnd.ms.radio',          'wysiwyg', 
-        );
-
-    /**
-     * List of "safe" protocols (used for whitelist-filtering)
-     *
-     * @var array
-     */
-    public $whiteProtocols = array(
-        'ed2k',   'file', 'ftp',  'gopher', 'http',  'https', 
-        'irc',    'mailto', 'news', 'nntp', 'telnet', 'webcal', 
-        'xmpp',   'callto',
-        );
-
-    /**
-     * List of attributes that can contain protocols
-     *
-     * @var array
-     */
-    public $protocolAttributes = array(
-        'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc', 'src', 'formaction',
-        );
-
-    /**
-     * List of dangerous CSS keywords
-     *
-     * Whole style="" attribute will be removed, if parser will find one of 
-     * these keywords
-     *
-     * @var array
-     */
-    public $cssKeywords = array(
-        'absolute', 'behavior',       'behaviour',   'content', 'expression', 
-        'fixed',    'include-source', 'moz-binding',
-        );
-
-    /**
-     * List of tags that can have no "closing tag"
-     *
-     * @var array
-     * @deprecated XHTML does not allow such tags
-     */
-    public $noClose = array();
-
-    /**
-     * List of block-level tags that terminates paragraph
-     *
-     * Paragraph will be closed when this tags opened
-     *
-     * @var array
-     */
-    public $closeParagraph = array(
-        'address', 'article',    'aside',     'audio',    'blockquote', 'canvas',
-        'center',  'dd',         'dir',       'div',      'dl',         'dt',
-        'figure',  'figcaption', 'footer',    'h1',       'h2',         'h3',
-        'h4',      'h5',         'h6',        'header',   'hr',         'isindex',
-        'listing', 'main',       'marquee',   'menu',      'multicol',  'nav',
-        'ol',      'output',     'p',         'plaintext', 'pre',       'section',
-        'table',   'ul',         'video',     'xmp',
-        );
-
-    /**
-     * List of table tags, all table tags outside a table will be removed
-     *
-     * @var array
-     */
-    public $tableTags = array(
-        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
-        'thead',   'tr', 
-        );
-
-    /**
-     * List of list tags
-     *
-     * @var array
-     */
-    public $listTags = array('dir', 'menu', 'ol', 'ul', 'dl', );
-
-    /**
-     * List of dangerous attributes
-     *
-     * @var array
-     */
-    public $attributes = array('dynsrc', 'id', 'name', );
-
-    /**
-     * List of allowed "namespaced" attributes
-     *
-     * @var array
-     */
-    public $attributesNS = array('xml:lang', );
-
-    /**
-     * Constructs class
-     *
-     * @access public
-     */
-    public function __construct()
-    {
-        //making regular expressions based on Proto & CSS arrays
-        foreach ($this->blackProtocols as $proto) {
-            $preg = "/[\s\x01-\x1F]*";
-            for ($i=0; $i<strlen($proto); $i++) {
-                $preg .= $proto[$i] . "[\s\x01-\x1F]*";
-            }
-            $preg .= ":/i";
-            $this->protoRegexps[] = $preg;
-        }
-
-        foreach ($this->cssKeywords as $css) {
-            $this->cssRegexps[] = '/' . $css . '/i';
-        }
-        return true;
-    }
-
-    /**
-     * Handles the writing of attributes - called from $this->openHandler()
-     *
-     * @param array $attrs array of attributes $name => $value
-     * @param string|null $tag
-     * @return boolean
-     */
-    protected function writeAttrs ($attrs, $tag = null)
-    {
-        if (is_array($attrs)) {
-            foreach ($attrs as $name => $value) {
-                $name = strtolower($name);
-
-                if (strpos($name, 'on') === 0) {
-                    continue;
-                }
-
-                if (strpos($name, 'data') === 0) {
-                    continue;
-                }
-
-                if ($tag != 'a' and in_array($name, $this->attributes)) {
-                    continue;
-                }
-
-                if (!preg_match('/^[a-z0-9]+$/i', $name)) {
-                    if (!in_array($name, $this->attributesNS)) {
-                        continue;
-                    }
-                }
-
-                if (($value === true) || (is_null($value))) {
-                    $value = $name;
-                }
-
-                if ($name == 'style') {
-                   // removes insignificant backslahes
-                   $value = str_replace("\\", '', $value);
-
-                   // removes CSS comments
-                   while (1) {
-                     $_value = preg_replace('!/\*.*?\*/!s', '', $value);
-
-                     if ($_value == $value) {
-                         break;
-                     }
-
-                     $value = $_value;
-                   }
-                   
-                   // replace all & to &amp;
-                   $value = str_replace('&amp;', '&', $value);
-                   $value = str_replace('&', '&amp;', $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("\"", '&quot;', $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 .= '&lt;' . $name . '&gt;';
-            }
-            return true;
-        }
-
-        if (in_array($name, $this->singleTags)) {
-            $this->xhtml .= '<' . $name;
-            $this->writeAttrs($attrs, $name);
-            $this->xhtml .= ' />';
-            return true;
-        }
-
-        // TABLES: cannot open table elements when we are not inside table
-        if ((isset($this->counter['table']))
-            && ($this->counter['table'] <= 0)
-            && (in_array($name, $this->tableTags))
-        ) {
-            return true;
-        }
-
-        // PARAGRAPHS: close paragraph when closeParagraph tags opening
-        if ((in_array($name, $this->closeParagraph))
-            && (in_array('p', $this->stack))
-        ) {
-            $this->closeHandler($parser, 'p');
-        }
-
-        // LISTS: we should close <li> if <li> of the same level opening
-        if (($name == 'li') && count($this->liStack)
-            && ($this->listScope == $this->liStack[count($this->liStack) - 1])
-        ) {
-            $this->closeHandler($parser, 'li');
-        }
-
-        // LISTS: we want to know on what nesting level of lists we are
-        if (in_array($name, $this->listTags)) {
-            ++$this->listScope;
-        }
-
-        if ($name == 'li') {
-            array_push($this->liStack, $this->listScope);
-        }
-            
-        $this->xhtml .= '<' . $name;
-        $this->writeAttrs($attrs, $name);
-        $this->xhtml .= '>';
-        array_push($this->stack,$name);
-        $this->counter[$name] = isset($this->counter[$name])
-            ? ($this->counter[$name] + 1) : 1;
-
-        return true;
-    }
-
-    /**
-     * Closing tag handler - called from HTMLSax
-     *
-     * @param object &$parser HTML parser
-     * @param string $name    tag name
-     *
-     * @return boolean
-     */
-    public function closeHandler(&$parser, $name)
-    {
-        $name = strtolower($name);
-
-        if (isset($this->dcCounter[$name])
-            && ($this->dcCounter[$name] > 0)
-            && (in_array($name, $this->deleteTagsContent))
-        ) {
-           while ($name != ($tag = array_pop($this->dcStack))) {
-                --$this->dcCounter[$tag];
-           }
-
-            --$this->dcCounter[$name];
-        }
-
-        if (count($this->dcStack) != 0) {
-            return true;
-        }
-
-        if ((isset($this->counter[$name])) && ($this->counter[$name] > 0)) {
-           while ($name != ($tag = array_pop($this->stack))) {
-                $this->closeTag($tag);
-           }
-
-            $this->closeTag($name);
-        }
-        return true;
-    }
-
-    /**
-     * Closes tag 
-     *
-     * @param string $tag tag name
-     *
-     * @return boolean
-     */
-    protected function closeTag($tag)
-    {
-        if (!in_array($tag, $this->noClose)) {
-            $this->xhtml .= '</' . $tag . '>';
-        }
-
-        --$this->counter[$tag];
-
-        if (in_array($tag, $this->listTags)) {
-            --$this->listScope;
-        }
-
-        if ($tag == 'li') {
-            array_pop($this->liStack);
-        }
-
-        return true;
-    }
-
-    /**
-     * Character data handler - called from HTMLSax
-     *
-     * @param object &$parser HTML parser
-     * @param string $data   textual data
-     *
-     * @return boolean
-     */
-    public function dataHandler(&$parser, $data)
-    {
-        if (count($this->dcStack) == 0) {
-            $this->xhtml .= $data;
-        }
-
-        return true;
-    }
-
-    /**
-     * Escape handler - called from HTMLSax
-     *
-     * @param object &$parser HTML parser
-     * @param string $data   comments or other type of data
-     *
-     * @return boolean
-     */
-    public function escapeHandler(&$parser, $data)
-    {
-        return true;
-    }
-
-    /**
-     * Allow tags
-     *
-     * Example:
-     * <pre>
-     * $safe = new HTML_Safe;
-     * $safe->setAllowTags(array('body'));
-     * </pre>
-     *
-     * @param array $tags Tags to allow
-     *
-     * @return void
-     */
-    public function setAllowTags($tags = array())
-    {
-        if (is_array($tags)) {
-            $this->allowTags = $tags;
-        }
-    }
-
-    /**
-     * Returns the allowed tags
-     *
-     * @return array
-     */
-    public function getAllowTags()
-    {
-        return $this->allowTags;
-    }
-
-    /**
-     * Reset the allowed tags
-     *
-     * @return void
-     */
-    public function resetAllowTags()
-    {
-        $this->allowTags = array();
-    }
-
-    /**
-     * Returns the XHTML document
-     *
-     * @return string Processed (X)HTML document
-     */
-    public function getXHTML()
-    {
-        while ($tag = array_pop($this->stack)) {
-            $this->closeTag($tag);
-        }
-        
-        return $this->xhtml;
-    }
-
-    /**
-     * Clears current document data
-     *
-     * @return boolean
-     */
-    public function clear()
-    {
-        $this->xhtml = '';
-        return true;
-    }
-
-    /**
-     * Main parsing fuction
-     *
-     * @param string $doc HTML document for processing
-     *
-     * @return string Processed (X)HTML document
-     */
-    public function parse($doc)
-    {
-       $result = '';
-
-       // Save all '<' symbols
-       $doc = preg_replace('/<(?=[^a-zA-Z\/\!\?\%])/', '&lt;', $doc);
-
-       // Web documents shouldn't contains \x00 symbol
-       $doc = str_replace("\x00", '', $doc);
-
-       // Opera6 bug workaround
-       $doc = str_replace("\xC0\xBC", '&lt;', $doc);
-
-       if ($this->repackUTF7) {
-           // UTF-7 encoding ASCII decode
-           $doc = $this->repackUTF7($doc);
-       }
-
-       // Instantiate the parser
-       $parser = new XML_HTMLSax3();
-
-       // Set up the parser
-       $parser->set_object($this);
-
-       $parser->set_element_handler('openHandler', 'closeHandler');
-       $parser->set_data_handler('dataHandler');
-       $parser->set_escape_handler('escapeHandler');
-
-       $parser->parse($doc);
-
-       $result = $this->getXHTML();
-
-       $this->clear();
-
-       return $result;
-    }
-
-    /**
-     * UTF-7 decoding fuction
-     *
-     * @param string $str HTML document for recode ASCII part of UTF-7 back to ASCII
-     * @return string Decoded document
-     */
-    protected function repackUTF7($str)
-    {
-       return preg_replace_callback('!\+([0-9a-zA-Z/]+)\-!', array($this, 'repackUTF7Callback'), $str);
-    }
-
-    /**
-     * Additional UTF-7 decoding fuction
-     *
-     * @param string $str String for recode ASCII part of UTF-7 back to ASCII
-     * @return string Recoded string
-     */
-    protected function repackUTF7Callback($str)
-    {
-       $str = base64_decode($str[1]);
-       $str = preg_replace_callback('/^((?:\x00.)*)((?:[^\x00].)+)/', array($this, 'repackUTF7Back'), $str);
-       return preg_replace('/\x00(.)/', '$1', $str);
-    }
-
-    /**
-     * Additional UTF-7 encoding fuction
-     *
-     * @param string $str String for recode ASCII part of UTF-7 back to ASCII
-     * @return string Recoded string
-     */
-    protected function repackUTF7Back($str)
-    {
-       return $str[1].'+'.rtrim(base64_encode($str[2]), '=').'-';
-    }
+       /**
+        * Storage for resulting HTML output
+        *
+        * @var string
+        */
+       protected $xhtml = '';
+
+       /**
+        * Array of counters for each tag
+        *
+        * @var array
+        */
+       protected $counter = [];
+
+       /**
+        * Stack of unclosed tags
+        *
+        * @var array
+        */
+       protected $stack = [];
+
+       /**
+        * Array of counters for tags that must be deleted with all content
+        *
+        * @var array
+        */
+       protected $dcCounter = [];
+
+       /**
+        * Stack of unclosed tags that must be deleted with all content
+        *
+        * @var array
+        */
+       protected $dcStack = [];
+
+       /**
+        * Stores level of list (ol/ul) nesting
+        *
+        * @var int
+        */
+       protected $listScope = 0;
+
+       /**
+        * Stack of unclosed list tags
+        *
+        * @var array
+        */
+       protected $liStack = [];
+
+       /**
+        * Array of prepared regular expressions for protocols (schemas) matching
+        *
+        * @var array
+        */
+       protected $protoRegexps = [];
+
+       /**
+        * Array of prepared regular expressions for CSS matching
+        *
+        * @var array
+        */
+       protected $cssRegexps = [];
+
+       /**
+        * Allowed tags
+        *
+        * @var array
+        */
+       protected $allowTags = [];
+
+
+       /**
+        * List of single tags ("<tag>")
+        *
+        * @var array
+        */
+       public $singleTags = ['area', 'br', 'img', 'input', 'hr', 'wbr', ];
+
+       /**
+        * List of dangerous tags (such tags will be deleted)
+        *
+        * @var array
+        */
+       public $deleteTags = [
+               'applet', 'base',   'basefont', 'bgsound', 'blink',  'body',
+               'embed',  'frame',  'frameset', 'head',    'html',   'ilayer',
+               'iframe', 'layer',  'link',     'meta',    'object', 'style',
+               'title',  'script',
+       ];
+
+       /**
+        * List of dangerous tags (such tags will be deleted, and all content
+        * inside this tags will be also removed)
+        *
+        * @var array
+        */
+       public $deleteTagsContent = ['script', 'style', 'title', 'xml', ];
+
+       /**
+        * Type of protocols filtering ('white' or 'black')
+        *
+        * @var string
+        */
+       public $protocolFiltering = 'white';
+
+       /**
+        * List of "dangerous" protocols (used for blacklist-filtering)
+        *
+        * @var array
+        */
+       public $blackProtocols = [
+               'about',   'chrome',     'data',       'disk',     'hcp',
+               'help',    'javascript', 'livescript', 'lynxcgi',  'lynxexec',
+               'ms-help', 'ms-its',     'mhtml',      'mocha',    'opera',
+               'res',     'resource',   'shell',      'vbscript', 'view-source',
+               'vnd.ms.radio',          'wysiwyg',
+       ];
+
+       /**
+        * List of "safe" protocols (used for whitelist-filtering)
+        *
+        * @var array
+        */
+       public $whiteProtocols = [
+               'ed2k',   'file', 'ftp',  'gopher', 'http',   'https',
+               'irc',    'mailto', 'news', 'nntp', 'telnet', 'webcal',
+               'xmpp',   'callto',
+       ];
+
+       /**
+        * List of attributes that can contain protocols
+        *
+        * @var array
+        */
+       public $protocolAttributes = [
+               'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc', 'src',
+       ];
+
+       /**
+        * List of dangerous CSS keywords
+        *
+        * Whole style="" attribute will be removed, if parser will find one of
+        * these keywords
+        *
+        * @var array
+        */
+       public $cssKeywords = [
+               'absolute', 'behavior',       'behaviour',   'content', 'expression',
+               'fixed',    'include-source', 'moz-binding',
+       ];
+
+       /**
+        * List of tags that can have no "closing tag"
+        *
+        * @var array
+        * @deprecated XHTML does not allow such tags
+        */
+       public $noClose = [];
+
+       /**
+        * List of block-level tags that terminates paragraph
+        *
+        * Paragraph will be closed when this tags opened
+        *
+        * @var array
+        */
+       public $closeParagraph = [
+               'address',      'article',      'aside',                'blockquote',   'details',      'div',
+               'dl',           'fieldset',     'figcaption',   'figure',               'footer',       'form',
+               'h1',           'h2',           'h3',                   'h4',                   'h5',           'h6',
+               'header',       'hgroup',       'hr',                   'main',                 'menu',         'nav',
+               'ol',           'p',            'pre',                  'section',              'table',        'ul',
+       ];
+
+       /**
+        * List of table tags, all table tags outside a table will be removed
+        *
+        * @var array
+        */
+       public $tableTags = [
+               'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
+               'thead',   'tr',
+       ];
+
+       /**
+        * List of list tags
+        *
+        * @var array
+        */
+       public $listTags = ['menu', 'ol', 'ul', 'dl', ];
+
+       /**
+        * List of dangerous attributes
+        *
+        * @var array
+        */
+       public $attributes = ['dynsrc', 'id', 'name', ];
+
+       /**
+        * List of allowed "namespaced" attributes
+        *
+        * @var array
+        */
+       public $attributesNS = ['xml:lang', ];
+
+       /**
+        * Constructs class
+        *
+        * @access public
+        */
+       public function __construct()
+       {
+               //making regular expressions based on Proto & CSS arrays
+               foreach ($this->blackProtocols as $proto)
+               {
+                       $preg = "/[\s\x01-\x1F]*";
+
+                       for ($i = 0; $i < strlen($proto); $i++)
+                       {
+                               $preg .= $proto[$i] . "[\s\x01-\x1F]*";
+                       }
+
+                       $preg .= ":/i";
+                       $this->protoRegexps[] = $preg;
+               }
+
+               foreach ($this->cssKeywords as $css)
+               {
+                       $this->cssRegexps[] = '/' . $css . '/i';
+               }
+
+               return true;
+       }
+
+       /**
+        * Handles the writing of attributes - called from $this->openHandler()
+        *
+        * @param array $attrs array of attributes $name => $value
+        *
+        * @return boolean
+        */
+       protected function writeAttrs($attrs)
+       {
+               if (is_array($attrs))
+               {
+                       foreach ($attrs as $name => $value)
+                       {
+                               $name = strtolower($name);
+
+                               if (strpos($name, 'on') === 0)
+                               {
+                                       continue;
+                               }
+
+                               // MODIF SPIP : ne pas supprimer les attributs html5 data-xx
+                               if (in_array($name, $this->attributes))
+                               {
+                                       continue;
+                               }
+
+                               // remove dataxx attributes but not the html5 data-xx one
+                               if (strpos($name, 'data') === 0)
+                               {
+                                       if (strpos($name, 'data-') !== 0 || (!preg_match('/^[a-z0-9-]+$/i', $name))) {
+                                               continue;
+                                       }
+                               }
+                               elseif (!preg_match('/^[a-z0-9]+$/i', $name))
+                               {
+                                       if (!in_array($name, $this->attributesNS))
+                                       {
+                                               continue;
+                                       }
+                               }
+                               // FIN MODIF SPIP
+
+                               if (($value === true) || (is_null($value)))
+                               {
+                                       $value = $name;
+                               }
+
+                               if ($name == 'style')
+                               {
+                                       // removes insignificant backslahes
+                                       $value = str_replace("\\", '', $value);
+
+                                       // removes CSS comments
+                                       while (1)
+                                       {
+                                               $_value = preg_replace('!/\*.*?\*/!s', '', $value);
+
+                                               if ($_value == $value)
+                                               {
+                                                       break;
+                                               }
+
+                                               $value = $_value;
+                                       }
+
+                                       // replace all & to &amp;
+                                       $value = str_replace('&amp;', '&', $value);
+                                       $value = str_replace('&', '&amp;', $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("\"", '&quot;', $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 .= '&lt;' . $name . '&gt;';
+                       }
+
+                       return true;
+               }
+
+               if (in_array($name, $this->singleTags))
+               {
+                       $this->xhtml .= '<' . $name;
+                       $this->writeAttrs($attrs);
+                       $this->xhtml .= ' />';
+
+                       return true;
+               }
+
+               // TABLES: cannot open table elements when we are not inside table
+               if ((isset($this->counter['table']))
+                       && ($this->counter['table'] <= 0)
+                       && (in_array($name, $this->tableTags))
+               )
+               {
+                       return true;
+               }
+
+               // PARAGRAPHS: close paragraph when closeParagraph tags opening
+               if ((in_array($name, $this->closeParagraph))
+                       && (in_array('p', $this->stack))
+               )
+               {
+                       $this->closeHandler($parser, 'p');
+               }
+
+               // LISTS: we should close <li> if <li> of the same level opening
+               if (($name == 'li') && count($this->liStack)
+                       && ($this->listScope == $this->liStack[count($this->liStack) - 1])
+               )
+               {
+                       $this->closeHandler($parser, 'li');
+               }
+
+               // LISTS: we want to know on what nesting level of lists we are
+               if (in_array($name, $this->listTags))
+               {
+                       ++$this->listScope;
+               }
+
+               if ($name == 'li')
+               {
+                       array_push($this->liStack, $this->listScope);
+               }
+
+               $this->xhtml .= '<' . $name;
+               $this->writeAttrs($attrs);
+               $this->xhtml .= '>';
+               array_push($this->stack, $name);
+               $this->counter[$name] = isset($this->counter[$name])
+                       ? ($this->counter[$name] + 1)
+                       : 1;
+
+               return true;
+       }
+
+       /**
+        * Closing tag handler - called from HTMLSax
+        *
+        * @param object &$parser HTML parser
+        * @param string $name  tag name
+        *
+        * @return boolean
+        */
+       public function closeHandler(&$parser, $name)
+       {
+               $name = strtolower($name);
+
+               if (isset($this->dcCounter[$name])
+                       && ($this->dcCounter[$name] > 0)
+                       && (in_array($name, $this->deleteTagsContent))
+               )
+               {
+                       while ($name != ($tag = array_pop($this->dcStack)))
+                       {
+                               --$this->dcCounter[$tag];
+                       }
+
+                       --$this->dcCounter[$name];
+               }
+
+               if (count($this->dcStack) != 0)
+               {
+                       return true;
+               }
+
+               if ((isset($this->counter[$name])) && ($this->counter[$name] > 0))
+               {
+                       while ($name != ($tag = array_pop($this->stack)))
+                       {
+                               $this->closeTag($tag);
+                       }
+
+                       $this->closeTag($name);
+               }
+
+               return true;
+       }
+
+       /**
+        * Closes tag
+        *
+        * @param string $tag tag name
+        *
+        * @return boolean
+        */
+       protected function closeTag($tag)
+       {
+               if (!in_array($tag, $this->noClose))
+               {
+                       $this->xhtml .= '</' . $tag . '>';
+               }
+
+               --$this->counter[$tag];
+
+               if (in_array($tag, $this->listTags))
+               {
+                       --$this->listScope;
+               }
+
+               if ($tag == 'li')
+               {
+                       array_pop($this->liStack);
+               }
+
+               return true;
+       }
+
+       /**
+        * Character data handler - called from HTMLSax
+        *
+        * @param object &$parser HTML parser
+        * @param string $data  textual data
+        *
+        * @return boolean
+        */
+       public function dataHandler(&$parser, $data)
+       {
+               if (count($this->dcStack) == 0)
+               {
+                       $this->xhtml .= $data;
+               }
+
+               return true;
+       }
+
+       /**
+        * Escape handler - called from HTMLSax
+        *
+        * @param object &$parser HTML parser
+        * @param string $data  comments or other type of data
+        *
+        * @return boolean
+        */
+       public function escapeHandler(&$parser, $data)
+       {
+               return true;
+       }
+
+       /**
+        * Allow tags
+        *
+        * Example:
+        * <pre>
+        * $safe = new SafeHTML;
+        * $safe->setAllowTags(['body']);
+        * </pre>
+        *
+        * @param array $tags Tags to allow
+        *
+        * @return void
+        */
+       public function setAllowTags($tags = [])
+       {
+               if (is_array($tags))
+               {
+                       $this->allowTags = $tags;
+               }
+       }
+
+       /**
+        * Returns the allowed tags
+        *
+        * @return array
+        */
+       public function getAllowTags()
+       {
+               return $this->allowTags;
+       }
+
+       /**
+        * Reset the allowed tags
+        *
+        * @return void
+        */
+       public function resetAllowTags()
+       {
+               $this->allowTags = [];
+       }
+
+       /**
+        * Returns the XHTML document
+        *
+        * @return string Processed (X)HTML document
+        */
+       public function getXHTML()
+       {
+               while ($tag = array_pop($this->stack))
+               {
+                       $this->closeTag($tag);
+               }
+
+               return $this->xhtml;
+       }
+
+       /**
+        * Clears current document data
+        *
+        * @return boolean
+        */
+       public function clear()
+       {
+               $this->xhtml = '';
+
+               return true;
+       }
+
+       /**
+        * Main parsing function
+        *
+        * @param string $doc HTML document for processing
+        *
+        * @return string Processed (X)HTML document
+        */
+       public function parse($doc)
+       {
+               $result = '';
+
+               // Save all '<' symbols
+               $doc = preg_replace('/<(?=[^a-zA-Z\/\!\?\%])/', '&lt;', $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]), '=') . '-';
+       }
 }
+
index a57f2f5..eff4b1b 100644 (file)
@@ -1,27 +1,27 @@
-(c) Miguel Vazquez Gocobachi, WackoWiki Team, 2005-2017\r
-(c) Roman Ivanov, 2004-2005\r
-(c) Pixel-Apes ( http://pixel-apes.com/ ), 2004-2005\r
-(c) JetStyle   ( http://jetstyle.ru/    ), 2004-2005\r
-Maintainer -- Roman Ivanov <thingol@mail.ru>\r
-\r
-Redistribution and use in source and binary forms, with or without\r
-modification, are permitted provided that the following conditions\r
-are met:\r
-1. Redistributions of source code must retain the above copyright\r
-   notice, this list of conditions and the following disclaimer.\r
-2. Redistributions in binary form must reproduce the above copyright\r
-   notice, this list of conditions and the following disclaimer in the\r
-   documentation and/or other materials provided with the distribution.\r
-3. The name of the author may not be used to endorse or promote products\r
-   derived from this software without specific prior written permission.\r
-\r
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\r
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\r
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+(c) Miguel Vazquez Gocobachi, WackoWiki Team, 2006-2020
+(c) Roman Ivanov, 2004-2005
+(c) Pixel-Apes ( http://pixel-apes.com/ ), 2004-2005
+(c) JetStyle   ( http://jetstyle.ru/    ), 2004-2005
+Maintainer -- Roman Ivanov <thingol@mail.ru>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
index 7619497..aa5a736 100644 (file)
@@ -1,87 +1,93 @@
-SafeHTML\r
---------\r
-Version 1.3.10.\r
-https://wackowiki.org/doc/Dev/Projects/SafeHTML\r
---------\r
-\r
-This parser strips down all potentially dangerous content within HTML:\r
-  * opening tag without its closing tag\r
-  * closing tag without its opening tag\r
-  * any of these tags: "base", "basefont", "head", "html", "body", "applet", "object",\r
-    "iframe", "frame", "frameset", "script", "layer", "ilayer", "embed", "bgsound",\r
-    "link", "meta", "style", "title", "blink", "xml" etc.\r
-  * any of these attributes: on*, data*, dynsrc\r
-  * javascript:/vbscript:/about: etc. protocols\r
-  * expression/behavior etc. in styles\r
-  * any other active content\r
-It also tries to convert code to XHTML valid, but htmltidy is far better solution for this task.\r
-\r
-If you found any bugs in this parser, please file an issue -- https://wackowiki.org/bugs/\r
-\r
-Please, subscribe to https://wackowiki.org/doc/Dev/Projects/SafeHTML in order to receive notices\r
-when SAFEHTML will be updated.\r
-\r
--- Roman Ivanov.\r
--- Pixel-Apes ( http://pixel-apes.com ).\r
--- JetStyle ( http://jetstyle.ru/ ).\r
-\r
-\r
-\r
---------\r
-Version history:\r
---------\r
-1.3.10.\r
- * added HTML5 Block-level elements\r
-1.3.9.\r
- * Replaced preg_replace() e modifier with preg_replace_callback\r
-1.3.8.\r
- * UTF-7 XSS vulnerability fixed\r
-1.3.7.\r
- * Added 'dl' to the list of 'lists' tags.\r
- * Added 'callto' to the white list of protocols.\r
- * Added white list of "namespaced" attributes.\r
-1.3.6.\r
- * More accurate UTF-7 decoding.\r
-1.3.5.\r
- * Two serious security flaws fixed: UTF-7 XSS and CSS comments handling.\r
-1.3.2.\r
- * Security flaw (improper quotes handling in attributes' values) fixed. Big thanks to Nick Cleaton.\r
-1.3.1.\r
- * Dumb bug fixed (some closing tags were ignored).\r
-1.3.0.\r
- * Two holes (with decimal HTML entities and with \x00 symbol) fixed.\r
- * Class rewritten under PEAR coding standarts.\r
- * Class now uses unmodified HTMLSax3 from PEAR.\r
- * To the list of table tags added: "caption", "col", "colgroup".\r
-1.2.1.\r
- * It was possible to create XSS with hexadecimal HTML entities. Fixed. Big thanks to Christian Stocker.\r
-1.2.0.\r
- * "id" and "name" attributes added to dangerous attributes list, because malefactor can broke legal javascript by spoofing ID or NAME of some element.\r
- * New method parse() allows to do all parsing process in two lines of code. Examples also updated.\r
- * New array, closeParagraph, contains list of block-level elements. When we open such elemet, we should close paragraph before. . It allows SafeHTML to produce more XHTML compliant code.\r
- * Added "webcal" to white list of protocols for those who uses calendar programs (Mozilla/iCal/etc).\r
- * Now SafeHTML strips down table elements when we are not inside table.\r
- * Now SafeHTML correctly closes unclosed "li" tags: before opening "li" of the same nesting level.\r
-1.1.0.\r
- * New "dangerous" protocols: hcp, ms-help, help, disk, vnd.ms.radio, opera, res, resource, chrome, mocha, livescript.\r
- * <XML> tag was moved from "tags for deletion" to "tags for deletion with content".\r
- * New "dangerous" CSS instruction "include-source" (NN4 specific).\r
- * New array, Attributes, contains list of attributes for removal. If you need to remove "id" or "name" attribute, \r
- just add it to this array.\r
- * Now it is possible to choose between white-list and black-list filtering of protocols. Defaults are "white-list".\r
- This list is: "http", "https", "ftp", "telnet", "news", "nntp", "gopher", "mailto", "file".\r
- * For speed purposes, we now filter protocols only from these attributes: src, href, action, lowsrc, dynsrc, \r
- background, codebase.\r
- * Opera6 XSS bug ([\xC0][\xBC]script>alert(1)[\xC0][\xBC]/script> [UTF-8] workarounded.\r
-1.0.4.\r
- New "dangerous" tag: plaintext.\r
-1.0.3.\r
- Added array of elements that can have no closing tag.\r
-1.0.2.\r
- Bug fix: <img src="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;alert(1);"> attack.\r
- Thanks to shmel.\r
-1.0.1.\r
- Bug fix: safehtml hangs on <style></style></style> code.\r
- Thanks to lj user=electrocat.\r
-1.0.0.\r
- First public release\r
+SafeHTML
+--------
+Version 1.3.12.
+https://wackowiki.org/doc/Dev/Projects/SafeHTML
+--------
+
+This parser strips down all potentially dangerous content within HTML:
+  * opening tag without its closing tag
+  * closing tag without its opening tag
+  * any of these tags: "base", "basefont", "head", "html", "body", "applet", "object", 
+    "iframe", "frame", "frameset", "script", "layer", "ilayer", "embed", "bgsound", 
+    "link", "meta", "style", "title", "blink", "xml" etc.
+  * any of these attributes: on*, data*, dynsrc
+  * javascript:/vbscript:/about: etc. protocols
+  * expression/behavior etc. in styles
+  * any other active content
+It also tries to convert code to XHTML valid, but htmltidy is far better solution for this task.
+
+If you found any bugs in this parser, please file an issue -- https://wackowiki.org/bugs/
+
+Please, subscribe to https://wackowiki.org/doc/Dev/Projects/SafeHTML in order to receive notices 
+when SAFEHTML will be updated.
+
+-- Roman Ivanov.
+-- Pixel-Apes ( http://pixel-apes.com ).
+-- JetStyle ( http://jetstyle.ru/ ).
+
+
+
+--------
+Version history:
+--------
+1.3.12
+ * added missing HTML5 tag terminators for paragraph
+ * removed obsolete and deprecated HTML elements
+1.3.11.
+ * added new HTML5 Block-level elements
+1.3.10.
+ * Replaced preg_replace() e modifier with preg_replace_callback
+1.3.9.
+ * UTF-7 XSS vulnerability fixed
+1.3.8.
+ * Allowed tags with setAllowTags() method.
+ * AllowTags can be disabled using resetAllowTags()
+1.3.7.
+ * Added 'dl' to the list of 'lists' tags.
+ * Added 'callto' to the white list of protocols.
+ * Added white list of "namespaced" attributes.
+1.3.6.
+ * More accurate UTF-7 decoding.
+1.3.5.
+ * Two serious security flaws fixed: UTF-7 XSS and CSS comments handling.
+1.3.2.
+ * Security flaw (improper quotes handling in attributes' values) fixed. Big thanks to Nick Cleaton.
+1.3.1.
+ * Dumb bug fixed (some closing tags were ignored).
+1.3.0.
+ * Two holes (with decimal HTML entities and with \x00 symbol) fixed.
+ * Class rewritten under PEAR coding standards.
+ * Class now uses unmodified HTMLSax3 from PEAR.
+ * To the list of table tags added: "caption", "col", "colgroup".
+1.2.1.
+ * It was possible to create XSS with hexadecimal HTML entities. Fixed. Big thanks to Christian Stocker.
+1.2.0.
+ * "id" and "name" attributes added to dangerous attributes list, because malefactor can broke legal javascript by spoofing ID or NAME of some element.
+ * New method parse() allows to do all parsing process in two lines of code. Examples also updated.
+ * New array, closeParagraph, contains list of block-level elements. When we open such element, we should close paragraph before. . It allows SafeHTML to produce more XHTML compliant code.
+ * Added "webcal" to white list of protocols for those who uses calendar programs (Mozilla/iCal/etc).
+ * Now SafeHTML strips down table elements when we are not inside table.
+ * Now SafeHTML correctly closes unclosed "li" tags: before opening "li" of the same nesting level.
+1.1.0.
+ * New "dangerous" protocols: hcp, ms-help, help, disk, vnd.ms.radio, opera, res, resource, chrome, mocha, livescript.
+ * <XML> tag was moved from "tags for deletion" to "tags for deletion with content".
+ * New "dangerous" CSS instruction "include-source" (NN4 specific).
+ * New array, Attributes, contains list of attributes for removal. If you need to remove "id" or "name" attribute, 
+ just add it to this array.
+ * Now it is possible to choose between white-list and black-list filtering of protocols. Defaults are "white-list".
+ This list is: "http", "https", "ftp", "telnet", "news", "nntp", "gopher", "mailto", "file".
+ * For speed purposes, we now filter protocols only from these attributes: src, href, action, lowsrc, dynsrc, 
+ background, codebase.
+ * Opera6 XSS bug ([\xC0][\xBC]script>alert(1)[\xC0][\xBC]/script> [UTF-8] workarounded.
+1.0.4.
+ New "dangerous" tag: plaintext.
+1.0.3.
+ Added array of elements that can have no closing tag.
+1.0.2.
+ Bug fix: <img src="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;alert(1);"> attack.
+ Thanks to shmel.
+1.0.1.
+ Bug fix: safehtml hangs on <style></style></style> code.
+ Thanks to lj user=electrocat.
+1.0.0.
+ First public release
index 3b22460..f6fb77e 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="safehtml"
        categorie="performance"
-       version="1.5.2"
+       version="1.5.4"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="images/safehtml-32.png"
@@ -15,6 +15,9 @@
        <credit>Roman Ivanov</credit>
        <credit>Pixel-Apes</credit>
        <credit>JetStyle</credit>
+       <credit lien="https://bitbucket.org/wackowiki/wackowiki/src/master/wacko/lib/">https://wackowiki.org/doc/Dev/Projects/SafeHTML</credit>
 
        <licence lien="http://www.gnu.org/licenses/gpl-3.0.html">GPL</licence>
+
+       <procure nom="safehtml" version="1.3.12" />
 </paquet>
index 3708b43..0d06072 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="sites"
        categorie="edition"
-       version="1.10.6"
+       version="1.10.7"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/site-32.png"
index 0908024..379756e 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="squelettes_par_rubrique"
        categorie="outil"
-       version="1.2.1"
+       version="1.2.2"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="squelettes_par_rubrique-32.png"
index 92070fd..e62de8b 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="stats"
        categorie="statistique"
-       version="1.1.11"
+       version="1.1.12"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/statistique-32.png"
index 332f7e8..e7fb1ed 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="svp"
        categorie="maintenance"
-       version="1.3.12"
+       version="1.3.13"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="svp-64.png"
index 40d79d9..2668d20 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="tw"
        categorie="edition"
-       version="1.5.6"
+       version="1.5.7"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="textwheel-32.png"
index c4e495a..67f4366 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="urls"
        categorie="statistique"
-       version="2.1.9"
+       version="2.1.10"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="prive/themes/spip/images/url-32.png"
index 3255d73..221d84b 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="vertebres"
        categorie="outil"
-       version="1.3.2"
+       version="1.3.3"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="images/vertebres-32.png"
index 777a0cb..dd774d3 100644 (file)
@@ -502,6 +502,20 @@ jQuery.spip.on_ajax_loaded = function(blocfrag,c,href,history) {
        jQuery.spip.updateReaderBuffer();
 }
 
+jQuery.spip.on_ajax_failed = function(blocfrag,statusCode,href,history) {
+       // marquer le bloc invalide
+       jQuery(blocfrag).addClass('invalid');
+       // si c'est une erreur 400 on a perdu la signature ajax
+       //console.log("AJAX Erreur");
+       //console.log(statusCode);
+       history = history || (history==null);
+       // quelle que soit l'erreur, on redirige si c'était la nouvelle URL principale de la page
+       if (history) {
+               //console.log("On redirige : " + href);
+               window.location.href = href;
+       }
+}
+
 jQuery.spip.stateId=0;
 jQuery.spip.setHistoryState = function(blocfrag){
        if (!window.history.replaceState) return;
@@ -595,8 +609,9 @@ jQuery.spip.loadAjax = function(blocfrag,url, href, options){
                                if (options.callback && typeof options.callback == "function")
                                        options.callback.apply(blocfrag);
                        },
-                       error: function(){
+                       error: function(e){
                                jQuery.spip.preloaded_urls[url]='';
+                               jQuery.spip.on_ajax_failed(blocfrag,e.status,href,options.history);
                        }
                });
        }
@@ -765,6 +780,15 @@ jQuery.fn.ajaxbloc = function() {
                                success: function(c){
                                        jQuery.spip.on_ajax_loaded(blocfrag,c);
                                        jQuery.spip.preloaded_urls = {}; // on vide le cache des urls car on a fait une action en bdd
+                               },
+                               error: function(e){
+                                       jQuery.spip.preloaded_urls = {}; // on vide le cache des urls car on a fait une action en bdd
+                                       var href = parametre_url(url, 'redirect');
+                                       if (!href) {
+                                               href = window.location.href;
+                                       }
+                                       // si c'est une erreur 400 c'est un fragment ajax invalide, il faut rediriger vers href
+                                       jQuery.spip.on_ajax_failed(blocfrag,e.status,href,e.status === 400);
                                }/*,
                                iframe: jQuery.browser.msie*/
                        })
index fef70f7..bd87159 100644 (file)
@@ -340,3 +340,8 @@ form.bouton_action_post.link button.submit:hover, .formulaire_spip .boutons inpu
 .formulaire_editer_logo .titrem,.formulaire_editer_logo .ajouter_survol {text-transform: uppercase;}
 /* Date picker : passer par dessus des icones et du menu haut */
 .ui-datepicker { z-index: 1001 !important;}
+
+/* Bloc ajax invalid apres reload */
+.ajaxbloc.invalid {
+       box-shadow: 0 0 var(--spip-alert-spacing-x) hsl(var(--spip-color-error--h), var(--spip-color-error--s), 50%);
+}
\ No newline at end of file
index c2b44b4..ee892c7 100644 (file)
@@ -1,7 +1,7 @@
 <paquet
        prefix="dist"
        categorie="squelette"
-       version="3.2.3"
+       version="3.2.4"
        etat="stable"
        compatibilite="[3.2.0;3.2.*]"
        logo="icon/skel.png"
index 3cdb609..16866fb 100644 (file)
@@ -8,14 +8,17 @@
 User-agent: *
 Allow:    /local/cache-css/
 Allow:    /local/cache-js/
-Disallow: /local/
+Noindex: /local/
+Noindex: /plugins-dist/
+Noindex: /plugins/
+Noindex: /squelettes-dist/
+Noindex: /squelettes/
 Disallow: /ecrire/
-Disallow: /plugins-dist/
 Disallow: /lib/
-Disallow: /plugins/
 Disallow: /prive/
-Disallow: /squelettes-dist/
-Disallow: /squelettes/
+Disallow: /spip.php?action=*
+Disallow: /spip.php?page=login*
+Disallow: /*.api/
 Crawl-delay: 1
 
-Sitemap: #URL_SITE_SPIP/sitemap.xml
\ No newline at end of file
+Sitemap: #URL_SITE_SPIP/sitemap.xml