diff -Nru spip-3.2.7/CHANGELOG.TXT spip-3.2.15.1/CHANGELOG.TXT
--- spip-3.2.7/CHANGELOG.TXT 2019-12-12 21:25:12.000000000 +0000
+++ spip-3.2.15.1/CHANGELOG.TXT 2022-05-20 16:59:18.000000000 +0100
@@ -1,3 +1,321 @@
+SPIP-Core v3.2.14 -> v3.2.15 (2022-05-20)
+-----------------------------------------
+
+ 8283532c9 | claffont | 2022-04-20 | Suppression de l'argument `formulaire_action_sign` dans l'url ACTION Ticket #5155
+ 2ce34e62e | cedric | 2022-04-13 | Incrementer spip_version_code pour recompiler les squelettes
+ ac67fc5be | cedric | 2022-04-13 | Securiser le retour de nettoyer_titre_email quand il est utilisé dans un squelette (Louka) https://git.spip.net/spip-t..
+ 901f58302 | cedric | 2022-04-13 | Masquer aussi les cookies sensibles dans $_SERVER['HTTP_COOKIE'] et $_ENV['HTTP_COOKIE'] (suite de #54 et https://git...
+ 871777b0f | cedric | 2022-04-13 | echapper sel_db avant de la reinserer dans une hidden (mais c'est assez theorique car si on arrive la c'est qu'on a re..
+ 754677579 | cedric | 2022-04-13 | securiser HTTP_HOST et REQUEST_URI dans url_de_base() https://git.spip.net/spip-team/securite/issues/3728
+ 97845aa30 | cedric | 2022-04-13 | Utiliser \b plutot que \s pour etre plus robuste sur la regexp de _PROTEGE_BLOCS https://git.spip.net/spip-team/securi..
+ d99890f66 | cedric | 2022-04-13 | securiser la construction de la regexp dans parametre_url https://git.spip.net/spip-team/securite/issues/3702
+ e9a03a38d | cedric | 2022-04-13 | securiser l'affichage de erreur quand il arrive de l'url https://git.spip.net/spip-team/securite/issues/3698
+ 772a4baed | cedric | 2022-04-13 | Securiser l'usage des var_mode_xx dans le debuggueur https://git.spip.net/spip-team/securite/issues/3602
+ b28e1f9a3 | cedric | 2022-04-13 | spip_htmlspecialchars() sur tous les affichages de variable dans le html + filtrer $adresse_ldap https://git.spip.net/..
+ edb6a01c6 | cedric | 2022-04-13 | ne pas accepter un test_dir avec des .. dedans lors du test des repertoires en ecriture https://git.spip.net/spip-team..
+ 3b99287c9 | rastapopoulos | 2022-03-06 | Fix #5076 : réparer la fonction buguée en n'utilisant jamais les clés raccourcis qui sont non fiables, mais les autres..
+
+SPIP-plugins-dist v3.2.14 -> v3.2.15 (2022-05-20)
+------------------------------------------------
+
+ SVP | bf0ff95 | cedric | 2022-04-13 | Echapper l'url dans le html affiche https://git.spip.net/spip-team/securite/issues/3733
+
+
+
+SPIP-Core v3.2.13 -> v3.2.14 (04 Mars 2022)
+--------------------------------------------
+
+SPIP-plugins-dist v3.2.13 -> v3.2.14 (04 Mars 2022)
+----------------------------------------------------
+
+medias | e4a3137 | marcimat | 2022-03-04 | Pas de typage pour les vieux PHP
+medias | 3014b84 | marcimat | 2022-02-22 | Déprécier et sécuriser l’insertion d’une galerie dans le formulaires d’ajout de document. Ce mode n’est plus utilisé d..
+mots | 844893f | bitbucket | 2022-02-11 | un point d'interrogation pour le id_groupe qui permet d'afficher les groupes que l'on souhaite dans un formulaire d'as..
+squelettes-dist | 93cee41 | marcimat | 2022-02-24 | Report de 8505e7c0ed9118ee31 qui était dans la dist, et non reporté du squelette neodist
+
+
+SPIP-Core v3.2.12 -> v3.2.13 (02 Février 2022)
+-----------------------------------------------
+
+9ed1818f1 | cedric | 2022-02-02 | Verifier qu'on a bien le droit de modifier le login avant d'accepter un post sur cette variable
+dec69cb7d | marcimat | 2022-02-02 | Les tags de chaque plugin dist dans plugins-dist.json
+39fbb0a8e | jamesrezo | 2022-01-26 | feat(header_silencieux) : ajout et application du filtre |header_silencieux (#5010)
+00222255b | cedric | 2022-01-04 | Ne pas stocker formulaire_action_sign dans les configurations des plugins... (hum)
+e48c92558 | bruno | 2021-12-03 | prise en charge des fichiers .jpeg lors de l'ajout d'un document distant
+b2f8e3a59 | cedric | 2021-12-29 | appliquer rawurlencode() aussi sur les tableaux qu'on passe en argument de parametre_url() #4819
+f1b7feae8 | cedric | 2021-12-17 | Eviter une indefinie si get_spip_script() est appelé depuis mes_options, avant que la constante _SPIP_SCRIPT soit defi..
+b6236a92e | bruno | 2021-12-16 | rétablir le traitement _TRAITEMENT_TYPO_SANS_NUMERO (multi, supprimer_numero, etc) sur la balise #NOM des auteurs
+712f5b5df | cedric | 2021-03-18 | Rediriger sans boucle infinie quand on a un probleme de var_mode (probleme qui arrive parfois sur une install un peu b..
+d793f599e | cedric | 2021-12-16 | sur certains sites on veut absolument garder certains caches on peut donc inhiber la purge de ces répertoires pour evi..
+c4a362f35 | taffit | 2021-12-14 | Drop misplaced changelog
+
+
+SPIP-plugins-dist v3.2.12 -> v3.2.13 (02 Février 2022)
+-------------------------------------------------------
+
+squelettes-dist | f872fdb | marcimat | 2022-02-02 | Version 3.2.5
+squelettes-dist | ae985dd | james | 2022-01-26 | feat(header_silencieux) : application du filtre |header_silencieux
+
+
+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)
+--------------------------------------------
+
+b52a4a5b3 | cedric | 2021-03-12 | twitterbot est aussi notre ami pour le laisser scraper l'url qu'on veut touitter (fil)
+58d5d6190 | cedric | 2021-02-15 | Report de https://git.spip.net/spip-contrib-outils/securite/commit/e7b571681a92eb40eddabbbb24b45dc472e113c1 qui fix #4..
+6611fd50b | cedric | 2021-02-15 | Report de https://git.spip.net/spip-contrib-outils/securite/commit/3eccaf41426d4f3c8f28b50d81e12fbe5f8af4c2
+62d33c975 | marcimat | 2021-03-26 | Notice-- : Attribut sans ses quotes... (realet)
+
+
+
+SPIP-Core v3.2.9 -> v3.2.10 (26 mars 2021)
+-------------------------------------------
+
+0b1bd0542 | marcimat | 2018-09-05 | Compat PHP 7.x : Scorie résiduelle du passage à mysqli. Mais ces fonctions ne semblent plus utilisées.
+7621a660a | marcimat | 2021-03-19 | Retour partiel sur 31df72005 pour compat PHP 5.4 ...
+4de4b3c34 | marcimat | 2021-03-19 | Correction deprecated php 7.4 : ordre de join inversé.
+0ea620c9a | marcimat | 2018-09-05 | Tickets #4059 et #4138 : meilleure compat PHP 7.2
+f69b39c9e | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+a54ab9a89 | rastapopoulos | 2021-03-14 | Backport de 2e55e3a60e à la main car plus dans le même fichier en 3.3.
+bdc53dcc9 | marcimat | 2021-03-11 | Lorsqu'on déclare un traitement à un champ de rubrique, tel que `$table_des_traitements['DEMO']['rubriques'] = ...`, c..
+510983b09 | cedric | 2021-03-09 | Fix https://core.spip.net/issues/4442 : le vieux parseur xml a la main (qu'il faudrait virer) ne tolerait pas l'utilis..
+31df72005 | marcimat | 2021-03-05 | Suite de e11b28be4 : plus éviter une fatale en PHP 8 si unicode2charset cherche à utiliser un charset inexistant
+00c2038da | marcimat | 2021-03-05 | Correction d'une Fatale Suite à 27e4f1bcc. C'est sport mais le commit ajoute des accents dans le squelettes prive/sque..
+e380b0afd | cy.altern | 2021-03-04 | report a4cdf3b633
+916b67198 | marcimat | 2021-03-04 | Ticket #4348 : Compat PHP 7.4 (deprecated curly braces array)
+910c245ea | marcimat | 2020-03-26 | Compat PHP 7.4 : éviter une notice lorsque la pagination ne trouve aucune entrée.
+1b5549e51 | marcimat | 2019-08-26 | Ticket #4348 : Compat PHP 7.4 (notice).
+c5492ea3e | marcimat | 2019-08-26 | Ticket #4348 : Compat PHP 7.4 (deprecated curly braces array)
+da6dfc068 | marcimat | 2019-08-26 | Ticket #4348 : Compat PHP 7.4, Trying to access array offset on value of type null.
+db1814dc5 | marcimat | 2019-08-25 | Compat PHP 7.4, Deprecated: Array and string offset access syntax with curly braces (Francky)
+330eb930f | marcimat | 2019-06-17 | Ticket #4348 : Correction pour PHP 7.4 (Left-associative ternary operator deprecation)
+130ada180 | marcimat | 2018-02-09 | Compatibilité PHP 7.2 : create_function => function xxx each => key, current, next
+8075d79f2 | marcimat | 2017-12-11 | Ticket #4059 : Compat PHP 7.2, remplacer un create_function.
+061107f80 | marcimat | 2017-12-11 | Ticket #4059 : Compat PHP 7.2, remplacer des create_function.
+af94fa5d9 | marcimat | 2017-12-11 | Ticket #4059 : Compat PHP 7.2, remplacer des create_function. (encore un eval du coup).
+e7fe0d5aa | marcimat | 2017-12-11 | Ticket #4059 : Compat PHP 7.2, remplacer des create_function.
+49f24e83b | marcimat | 2017-12-11 | Ticket #4059 : Compat PHP 7.2. Un create_function de moins. Pour le coup, ça semble obligé ici de conserver une évalua..
+6555cb7b4 | marcimat | 2021-03-04 | Report adapté de 5647069fb (Meilleure compat PHP 7.3)
+fcb3e1f5e | marcimat | 2019-08-21 | Ticket #4348 : Notices/Warning en PHP 7.3+ : éviter un appel à time() avec un argument.
+31c614782 | bruno | 2020-03-13 | report adapté de a0c24ecb6f8c1d70dce86b859eb448fb0415d869
+60d4d3d1f | cedric | 2021-02-17 | Fix vraiment #4167 : _deja_loge peut contenir un js de redirection et doit donc etre non filtre par interdire_scripts()
+7046e391d | cedric | 2021-02-17 | Fix #4387 : Revert "Fix #4167 : éviter d'afficher le script de redirection js quand le form de login est utilisé en aj..
+03cc99fce | cedric | 2021-02-17 | Fix l'utilisation du niveau de log 0 (maieul) cf https://git.spip.net/spip/spip/pulls/106
+62e4284fd | bruno | 2021-02-10 | éviter un plantage avec url_page quand on utilise une fonction perso pour generer_generer_url_XXX
+0281d90f2 | maieul | 2021-02-10 | fix #4633, ne pas passer une date quotée au pipeline optimiser_base_disparus
+
+
+SPIP-plugins-dist v3.2.9 -> v3.2.10 (26 mars 2021)
+---------------------------------------------------
+
+aide | 329cfce | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+archiviste | de3283f | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+breves | 668efb9 | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+breves | 658f025 | maieul | 2021-02-10 | Adaptation du code au fix du core https://core.spip.net/issues/4633
+compagnon | d8aaa96 | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+compresseur | 08b96ff | marcimat | 2021-03-24 | Mise à jour de CSSTidy en version 1.7.3
+compresseur | 30d1b1f | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+compresseur | 827ba88 | marcimat | 2018-09-05 | Tickets #4059 et #4138 : meilleure compat PHP 7.2
+dump | d767e27 | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+filtres_images | eb9ace8 | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+forum | cb90b1a | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+jquery_ui | b04572e | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+mediabox | bcadf3d | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+medias | d096d93 | marcimat | 2021-03-26 | Report de d1ca0c8c : Suite de 890506eb99 : Il faut ajouteur la classe .portfolios__titre aux autres blocs documents du..
+medias | 4e13bea | cedric | 2021-03-25 | Fix regression (Maieul via https://git.spip.net/spip/medias/pulls/17)
+medias | 1d917cd | spip.franck | 2020-07-12 | - Mise à jour de la lib getid3 en 1.9.20, nous étions en 1.9.18 - Le changelog est dispo ici: https://github.com/James..
+medias | e019d3e | spip.franck | 2019-09-20 | Mise à jour de la lib getid3 en 1.9.18, nous étions en 1.9.16. Le changelog est dispo ici: https://github.com/JamesHei..
+medias | 2dc03d5 | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+mots | 6a346ba | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+organiseur | a7177ba | marcimat | 2021-03-19 | Correction join à l'envers.
+organiseur | 7c665fc | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+petitions | 2909a25 | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+plan | e722c87 | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+porte_plume | 0003d09 | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+revisions | 1d88a68 | bruno | 2018-09-15 | retour sur r111482 : éviter une erreur Maximum execution time
+revisions | 2f2d47c | marcimat | 2018-09-05 | Tickets #4059 et #4138 : meilleure compat PHP 7.2
+revisions | 535cb2f | marcimat | 2018-09-15 | Correction sur r111486 (compat PHP 7.2, suppression each()) qui était erronné.
+revisions | aa56bf3 | marcimat | 2018-09-05 | Ticket #4138 : Compatibilité PHP 7.2
+revisions | df4b821 | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+revisions | 19c0b6c | marcimat | 2019-08-21 | Ticket #4348 : Compat PHP 7.4+ Deprecated: The behavior of unparenthesized expressions containing both '.' and '+'/'-'
+safehtml | b2853a1 | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+safehtml | 6e81e13 | marcimat | 2019-08-26 | Tiket #4348 / Compat PHP 7.4 : Array and string offset access syntax with curly braces is deprecated
+sites | 622387c | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+squelettes_par_rubrique | 357b283 | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+statistiques | 291386b | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+svp | a3c6abf | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+svp | 9fd9349 | marcimat | 2019-08-25 | Compat PHP 7.4, Deprecated: Array and string offset access syntax with curly braces (Francky)
+textwheel | 8f70594 | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+textwheel | 84d32c5 | cedric | 2018-09-06 | create_function est deprecie en PHP 7.2, on reecrit donc l'optimisation des subwheels via une fonction anonyme de type..
+textwheel | 1bf8732 | marcimat | 2018-02-09 | Compat PHP 7.2 : create_function => function (les plus simples, mais il en reste !…)
+urls_etendues | be9066b | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+vertebres | a381bc9 | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+squelettes-dist | 6323be9 | marcimat | 2021-03-18 | Suppression du fichier .gitattributes inutile.
+
+
+
+SPIP-Core v3.2.8 -> v3.2.9 (12 février 2021)
+---------------------------------------------
+
+c965889bc | cedric | 2021-02-10 | Fix #4316 : la PR a ete fermee sur github quand on est passe a git.spip.net je suppose
+c76c39a6e | cedric | 2021-02-10 | nonsense code, copie colle surement, fix #4315
+93a917a4d | cedric | 2021-02-10 | Fix #4140 (deja fixe en 3.3)
+7246f1966 | cedric | 2021-02-08 | Fix #3869 (ou du moins on espere, sinon c'est pas si grave)
+55bc9fd5d | erational | 2021-02-08 | [bugfix] empecher warning sur le count de l'iterateur devrait resoudre le ticket https://core.spip.net/issues/4450 et ..
+42898eb47 | rastapopoulos | 2021-02-05 | Corrige 4401 en améliorant la rustine déjà en place
+24eda3678 | cedric | 2021-02-05 | nettoyer l'adresse site qu'on enregistre fix #4629
+bb69f3466 | bruno | 2021-02-05 | ne pas stocker le champ ldap_password dans les fichiers de session
+2269d0a6a | cedric | 2021-02-01 | appels a autoriser sur les formulaires editer, a minima quand on les utilise en modification d'un objet existant depui..
+610c24f06 | cedric | 2021-02-02 | Eviter d'utiliser une globale, gerer le flag en static avec operations de lecture+reset
+a8493a3ce | cedric | 2021-02-01 | Eviter de donner sa langue au chat
+f9d9e5b1a | cedric | 2021-02-01 | on accepte pas une fonction de config inconnue si elle vient d'un modele
+962a95f44 | cedric | 2021-02-01 | Utiliser contexte_compil pour reperer les appels a executer_balise_dynamique() venant d'un modele, et lever un flag le..
+c35edb769 | cedric | 2021-02-01 | une fonction pour detecter qu'un formulaire a ete inclu via un modele et non directement via une balide #FORMULAIRE_xxx
+577ad8d21 | bruno | 2021-01-21 | éviter d'afficher n'importe quoi dans le message d'édition concurrente
+f1f27e9f7 | bruno | 2021-02-01 | attribut_html() sur les attributs renvoyés par env_to_params() & env_to_attributs()
+6c6b6c6d4 | nicod | 2021-01-06 | Stocker les contextes dans des fichiers en cache si la longueur de l’argument géneré est plus long que ce qui est tolé..
+2be11db95 | bruno | 2020-10-25 | fix undefined index sur l'action réparation de la base
+
+
+
+SPIP-plugins-dist v3.2.8 -> v3.2.9 (12 février 2021)
+-----------------------------------------------------
+
+breves | ba1e040 | cedric | 2021-02-04 | verifier l'autorisation de modifier la breve passe en argument
+mediabox | 9020d16 | cedric | 2021-02-08 | #4625 : echapper les valeurs injectees dans le js via les parametres mediabox, c'est plus propre
+medias | 96bf7b2 | cedric | 2021-02-04 | Verifier l'autorisation de modifier les documents passes en argument du formulaire
+medias | bfc3319 | cedric | 2021-01-20 | Report de 049dee8 : Extraire la fonction de determination automatique du statut d'un document dans une fonction inc_de..
+medias | 9764525 | cedric | 2021-01-19 | Normaliser le comportement de document_instituer() en appelant les pipelines pre_editon et post_edition avec action=in..
+medias | 2293b84 | tcharlss | 2021-01-19 | Report de 890506eb99 : Pour le JS des modes d'affichages, cibler plus précisément l'élément, sinon les boutons peuvent..
+mots | 0955e0d | cedric | 2021-02-04 | Verifier les autorisations de modifier les mots/groupes de mots passes en argument du formulaire d'edition
+revisions | e573977 | bruno | 2020-10-23 | éviter un warning dans les révisions lors de la suppression d'un lien par une personne non identifiée
+sites | 28bdb59 | cedric | 2021-02-10 | Fix #4296 : l'url peut etre dans le href meme si c'est pas un link autofermant...
+sites | 92994f3 | cedric | 2021-02-04 | verifier l'autorisation de modifier le site passe en argument du formulaire d'edition
+sites | 638ceef | cedric | 2020-12-18 | Fix le id_mot manquant sur les syndic_articles. Ce n'est pas un usage frequent, mais il existe et soyons homogene avec..
+textwheel | 317b045 | rastapopoulos | 2021-02-05 | Correction de 4508 : on ne gère le caption/summary *réellement* qu'en première ligne, seulement si on n'a pas déjà gén..
+
+
+SPIP-Core v3.2.7 -> v3.2.8 (29 septembre 2020)
+----------------------------------------------
+a5cda7ff8 | cedric | 2020-09-17 | Si une page preview est visualisee dans un element embed on sandbox l'element et on redirige sur la home pour eviter t..
+6c2e56441 | marcimat | 2020-09-28 | On intègre plugins-dist.json à la place de .gitsvnextmodules pour lister les plugins-dist. Report de 7306ba9a sans big..
+10718d144 | marcimat | 2020-09-08 | Lorsqu’un champ date contient un souligné, tel que "date_modif_manuelle", permettre d’utiliser les critères {age_modif..
+85e8576b4 | nicod_ | 2020-09-11 | issue_4549 (!58)
+f868732de | cedric | 2020-09-11 | #4494 : masquer les cookies sensible de le phpinfo
+eaa08a27c | cedric | 2020-09-11 | Ajouter des logs sur le genie optimiser, dans un log dedie, c'est bien le moins qu'on puisse faire pour savoir un peu ..
+978cec0d5 | cedric | 2020-09-11 | Complement a 52764a1611 : permettre d'utiliser une vue aussi pour une table de liens, en declarant les cles dans table..
+8158f8b6f | cedric | 2020-09-02 | Fix petit cas tordu sur trouver_table() quand on l'utilise sur une vue qui est un filtre d'une table reelle : sql_show..
+6418ceb40 | cedric | 2020-05-27 | cot cot cot...
+e593f2fbb | cedric | 2020-05-27 | _oups donc (aka un base64_encode ca fait pas de mal)
+6b5de38ac | cedric | 2020-05-19 | Divers petites sanitization et une balise manquante #4494
+f6cfbce16 | rastapopoulos | 2020-06-24 | Corriger un bug présent dans plusieurs navigateurs, qui fait que ça agrandit tous les fieldsets dès qu'il y a un éléme..
+925abdf1d | bruno | 2020-06-23 | API modifier : passer l'éventuelle la liste de champs fixe au pipeline pre_edition
+319b9acbf | bruno | 2020-06-19 | corriger le filtre singuler_ou_pluriel quand la valeur est 0
+44ebe4927 | bruno | 2020-06-16 | Améliorer le filtre singulier_ou_pluriel pour prendre en compte les valeurs non entières (!41)
+bd9957b0b | marcimat | 2020-06-05 | Sanitiser les préférences utilisateurs. (g0uz)
+ae4267eba | cedric | 2020-06-05 | n'enregistrer que les preferences licites (g0uZ)
+0880b517b | cedric | 2020-05-29 | Fix petite salade autour de la suppression des resultats de recherche trop vieux : - on utilise le champ maj comme ind..
+f6e3627c5 | maieul | 2019-09-19 | filtre |balise_svg > supprimer l'entête XML + effacer pour gagner un peu de place les commentaires XML
+f02e933cc | cedric | 2020-03-11 | class grostitre manquante dans l'echafaudage
+db97552ff | cedric | 2020-02-10 | Permettre de preciser le #SELF utilise par la pagination dans l'appel de la balise pagination, ce qui permet de nettoy..
+adda869ce | cedric | 2020-01-22 | Fix : utiliser propre sur les nom de plugin est dangereux, car certains plugins peuvent enrichir avec un lien et comme..
+f7a93668f | ben.spip | 2019-12-12 | SPIP 3.2.7
+d3c2db6b9 | ben.spip | 2019-12-12 | la 3.2.6 est stable (realet)
+a306385cc | ben.spip | 2019-12-12 | SPIP 3.2.6
+
+
+SPIP-plugins-dist v3.2.7 -> v3.2.8 (29 septembre 2020)
+------------------------------------------------------
+aide | fe76f13 | spip.franck | 2020-01-01 | Bonne année "aide" de spip 3.2
+archiviste | 94be628 | spip.franck | 2020-01-01 | Bonne année "archives" de spip 3.2
+breves | 7f4e2ac | spip.franck | 2020-01-01 | Bonne Année "breves" de spip 3.2
+compresseur | 4785c1a | cedric | 2020-06-04 | Tentative de fix de l'inflation du repertoire local/cache-css : tenir compte des timestamps des fichiers a concatener ..
+compresseur | 2372cf3 | spip.franck | 2020-01-01 | Bonne Année "compresseur" de spip 3.2
+dump | 0955b05 | spip.franck | 2020-01-01 | Bonne Année "dump" de spip 3.2
+filtres_images | 190bf90 | spip.franck | 2020-01-01 | Bonne année "filtres_images" de spip 3.2
+forum | 2e18f59 | spip.franck | 2020-01-01 | Bonne année "forum" de spip 3.2
+medias | bc5a517 | cedric | 2020-06-05 | Utilisation des fonctions de sanitization sur galerie et _galerie en lien avec #4494 du core
+medias | a4484ea | spip.franck | 2020-01-02 | ajout du cartouche spip avec accord de cerdic (spip 3.2)
+medias | fa3c5b3 | spip.franck | 2020-01-01 | Bonne année "medias" de spip 3.2
+mots | 012f539 | spip.franck | 2020-01-01 | Bonne année "mots" de spip 3.2
+organiseur | 4a30bd8 | marcimat | 2020-09-23 | FullCalendar 3.10.2 (c’est vieux, mais des bugs en moins) et Moment 2.29 + Correction sur les rendez vous dont le cale..
+organiseur | 53a76b0 | marcimat | 2020-09-23 | Notice PHP en moins.
+organiseur | aa7eb97 | spip.franck | 2020-01-01 | Bonne année "organiseur" de spip 3.2
+petitions | 1f40e1b | spip.franck | 2020-01-01 | Bonne année "petitions" de spip 3.2
+porte_plume | 57cae2a | cedric | 2020-08-25 | Deux constantes pour piloter une desactivation partielle ou totale du porte_plume : * `define('_PORTE_PLUME_INSERER_AU..
+revisions | 44d7df8 | spip.franck | 2020-01-01 | Bonne année "revisions" de spip 3.2
+safehtml | c404945 | spip.franck | 2020-01-01 | Bonne année "safehtml" de spip 3.2
+sites | 0f362a7 | spip.franck | 2020-01-01 | Bonne année "sites" de spip 3.2
+squelettes_par_rubrique | 4a70c9f | spip.franck | 2020-01-01 | Bonne année "squelettes_par_rubrique" de spip 3.2
+statistiques | d64d037 | spip.franck | 2020-01-01 | Bonne année "statistiques" de spip 3.2
+svp | dcaf67b | cedric | 2020-03-31 | Support des logos au format svg en provenance de l'empaqueteur, meme si le paquet.xml reference un png + support de la..
+svp | 0e1d905 | spip.franck | 2020-01-01 | Bonne année "svp" de spip 3.2
+svp | 9f8caf6 | eric | 2019-12-23 | Utiliser le logo SVG ou PNG si il existe en se servant de la nouvelle balise incluse par Smart-Paquets. Compatible ave..
+textwheel | 77f1aac | cyrille | 2020-06-11 | éviter un warning lorsqu'il y a une ligne de cellules vides dans un table
+textwheel | 578a21f | cyrille | 2020-06-11 | éviter un warning lorsqu'il y a une ligne de cellules vides dans un table
+textwheel | 216519a | spip.franck | 2020-01-01 | Bonne année "textwheel" de spip 3.2
+urls_etendues | b74a272 | spip.franck | 2020-01-01 | Bonne année "urls_etendues" de spip 3.2
+vertebres | d84a81e | spip.franck | 2020-01-01 | Bonne année "vertebres" de spip 3.2
+squelettes-dist | ea695c1 | spip.franck | 2020-01-01 | Bonne Année "dist" de spip 3.2
+
+
SPIP-Core spip-3.2.6 -> spip-3.2.7 12 décembre 2019
-------------------------------------------------------------
diff -Nru spip-3.2.7/config/ecran_securite.php spip-3.2.15.1/config/ecran_securite.php
--- spip-3.2.7/config/ecran_securite.php 2019-12-12 21:25:12.000000000 +0000
+++ spip-3.2.15.1/config/ecran_securite.php 2022-05-20 16:59:18.000000000 +0100
@@ -5,7 +5,7 @@
* ------------------
*/
-define('_ECRAN_SECURITE', '1.3.13'); // 2019-12-04
+define('_ECRAN_SECURITE', '1.4.1'); // 2021-03-12
/*
* Documentation : http://www.spip.net/fr_article4200.html
@@ -17,6 +17,10 @@
if (isset($_GET['test_ecran_securite']))
$ecran_securite_raison = 'test '._ECRAN_SECURITE;
+if (file_exists($f = __DIR__ . DIRECTORY_SEPARATOR . 'ecran_securite_options.php')) {
+ include ($f);
+}
+
/*
* Monitoring
* var_isbot=0 peut etre utilise par un bot de monitoring pour surveiller la disponibilite d'un site vu par les users
@@ -226,12 +230,15 @@
if (!defined('_IS_BOT_FRIEND')){
define('_IS_BOT_FRIEND',
isset($_SERVER['HTTP_USER_AGENT'])
- and preg_match(',' . implode ('|', array(
- 'facebookexternalhit',
- 'flipboardproxy',
- 'wordpress'
- )) . ',i',
- (string)$_SERVER['HTTP_USER_AGENT'])
+ and preg_match(
+ ',' . implode('|', array(
+ 'facebookexternalhit',
+ 'twitterbot',
+ 'flipboardproxy',
+ 'wordpress'
+ )) . ',i',
+ (string)$_SERVER['HTTP_USER_AGENT']
+ )
);
}
@@ -544,6 +551,7 @@
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
header("Content-Type: text/html");
+ header("Connection: close");
die("
Error 403: Forbidden
Error 403
You are not authorized to view this page ($ecran_securite_raison)
");
}
diff -Nru spip-3.2.7/debian/changelog spip-3.2.15.1/debian/changelog
--- spip-3.2.7/debian/changelog 2019-12-12 20:02:58.000000000 +0000
+++ spip-3.2.15.1/debian/changelog 2022-05-31 21:24:18.000000000 +0100
@@ -1,3 +1,11 @@
+spip (3.2.15.1-0ubuntu0.20.04.1) focal-security; urgency=medium
+
+ * New upstream maintenance and security release, that fixes CVE-2020-28984,
+ CVE-2021-44118, CVE-2021-44120, CVE-2021-44122, CVE-2021-44123,
+ CVE-2022-26846 and CVE-2022-26847 (LP: #1971185).
+
+ -- Luís Infante da Câmara Tue, 31 May 2022 21:24:18 +0100
+
spip (3.2.7-1) unstable; urgency=medium
* Critical security fix, allowing identified authors to inject content
diff -Nru spip-3.2.7/debian/control spip-3.2.15.1/debian/control
--- spip-3.2.7/debian/control 2019-12-12 20:02:09.000000000 +0000
+++ spip-3.2.15.1/debian/control 2022-05-31 21:24:18.000000000 +0100
@@ -1,7 +1,8 @@
Source: spip
Section: web
Priority: optional
-Maintainer: David Prévot
+Maintainer: Ubuntu Developers
+XSBC-Original-Maintainer: David Prévot
Build-Depends: cssmin, debhelper-compat (= 12), dh-apache2, node-uglify
Homepage: https://www.spip.net/
Standards-Version: 4.4.1
diff -Nru spip-3.2.7/debian/patches/0005-Use-HTMLSax3-class-from-the-php-xml-htmlsax3-package.patch spip-3.2.15.1/debian/patches/0005-Use-HTMLSax3-class-from-the-php-xml-htmlsax3-package.patch
--- spip-3.2.7/debian/patches/0005-Use-HTMLSax3-class-from-the-php-xml-htmlsax3-package.patch 2019-12-12 20:02:20.000000000 +0000
+++ spip-3.2.15.1/debian/patches/0005-Use-HTMLSax3-class-from-the-php-xml-htmlsax3-package.patch 2022-05-31 21:24:18.000000000 +0100
@@ -27,11 +27,11 @@
--- a/plugins-dist/safehtml/lib/safehtml/classes/safehtml.php
+++ b/plugins-dist/safehtml/lib/safehtml/classes/safehtml.php
@@ -18,7 +18,7 @@
-
- if (!defined('_ECRIRE_INC_VERSION')) return;
-
+ * This package requires HTMLSax3 package
+ */
-require_once(XML_HTMLSAX3 . 'HTMLSax3.php');
+require_once 'XML/HTMLSax3.php';
/**
+ * HTML_Safe Parser
*
diff -Nru spip-3.2.7/debian/source/lintian-overrides spip-3.2.15.1/debian/source/lintian-overrides
--- spip-3.2.7/debian/source/lintian-overrides 2019-09-16 19:54:38.000000000 +0100
+++ spip-3.2.15.1/debian/source/lintian-overrides 2022-05-31 21:24:18.000000000 +0100
@@ -4,3 +4,87 @@
source-contains-prebuilt-javascript-object plugins-dist/compresseur/lib/jQl/jQl.min.js
source-contains-prebuilt-javascript-object plugins-dist/medias/javascript/mejs-init.min.js
source-contains-prebuilt-javascript-object plugins-dist/organiseur/lib/fullcalendar/fullcalendar.min.js
+
+source-is-missing plugins-dist/medias/lib/mejs/mediaelement-and-player.js line length is 480 characters (>256)
+source-is-missing plugins-dist/medias/lib/mejs/mediaelement.js line length is 480 characters (>256)
+source-is-missing plugins-dist/medias/lib/mejs/renderers/dailymotion.js line length is 480 characters (>256)
+source-is-missing plugins-dist/medias/lib/mejs/renderers/facebook.js line length is 480 characters (>256)
+source-is-missing plugins-dist/medias/lib/mejs/renderers/soundcloud.js line length is 480 characters (>256)
+source-is-missing plugins-dist/medias/lib/mejs/renderers/twitch.js line length is 480 characters (>256)
+source-is-missing plugins-dist/medias/lib/mejs/renderers/vimeo.js line length is 480 characters (>256)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale-all.js line length is 32768 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/af.js line length is 2977 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ar-dz.js line length is 3262 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ar-kw.js line length is 3220 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ar-ly.js line length is 4292 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ar-ma.js line length is 3220 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ar-sa.js line length is 3716 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ar-tn.js line length is 3223 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ar.js line length is 4447 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/be.js line length is 4969 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/bg.js line length is 3646 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/bs.js line length is 3656 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ca.js line length is 3443 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/cs.js line length is 4557 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/da.js line length is 2787 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/de-at.js line length is 3145 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/de-ch.js line length is 3138 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/de.js line length is 3166 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/el.js line length is 4554 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/en-au.js line length is 2713 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/en-ca.js line length is 2086 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/en-gb.js line length is 2709 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/en-ie.js line length is 2097 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/en-nz.js line length is 2713 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/es-do.js line length is 3833 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/es-us.js line length is 3833 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/es.js line length is 3845 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/et.js line length is 3193 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/eu.js line length is 3044 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/fa.js line length is 3783 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/fi.js line length is 3686 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/fr-ca.js line length is 3043 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/fr-ch.js line length is 3059 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/fr.js line length is 3073 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/gl.js line length is 3149 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/he.js line length is 3741 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/hi.js line length is 4571 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/hr.js line length is 3864 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/hu.js line length is 3673 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/id.js line length is 2983 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/is.js line length is 3625 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/it.js line length is 3359 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ja.js line length is 3920 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ka.js line length is 4708 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/kk.js line length is 3689 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ko.js line length is 3117 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/lb.js line length is 3476 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/lt.js line length is 4026 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/lv.js line length is 3585 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/mk.js line length is 3690 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ms-my.js line length is 3035 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ms.js line length is 3026 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/nb.js line length is 2844 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/nl-be.js line length is 3628 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/nl.js line length is 3628 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/nn.js line length is 2858 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/pl.js line length is 3742 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/pt-br.js line length is 3021 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/pt.js line length is 2968 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ro.js line length is 2966 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/ru.js line length is 6514 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/sk.js line length is 3837 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/sl.js line length is 4098 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/sq.js line length is 2960 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/sr-cyrl.js line length is 4442 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/sr.js line length is 3706 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/sv.js line length is 2917 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/th.js line length is 4250 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/tr.js line length is 3129 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/uk.js line length is 5240 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/vi.js line length is 3372 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/zh-cn.js line length is 3498 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/zh-hk.js line length is 3476 characters (>512)
+source-is-missing plugins-dist/organiseur/lib/fullcalendar/locale/zh-tw.js line length is 3479 characters (>512)
+source-is-missing plugins-dist/statistiques/javascript/jquery.flot.js line length is 3134 characters (>512)
+source-is-missing prive/javascript/sha256.js line length is 722 characters (>512)
diff -Nru spip-3.2.7/ecrire/action/editer_liens.php spip-3.2.15.1/ecrire/action/editer_liens.php
--- spip-3.2.7/ecrire/action/editer_liens.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/action/editer_liens.php 2022-05-20 16:59:18.000000000 +0100
@@ -211,6 +211,7 @@
* @return int
*/
function objet_optimiser_liens($objets_source, $objets_lies) {
+ spip_log("objet_optimiser_liens : ".json_encode($objets_source) . ', ' . json_encode($objets_lies), 'genie'._LOG_DEBUG);
return objet_traiter_liaisons('lien_optimise', $objets_source, $objets_lies);
}
@@ -652,8 +653,10 @@
array("$primary=" . $row['id'], "id_objet=" . $row['id_objet'], "objet=" . sql_quote($type)));
if ($e != false) {
$dels += $e;
- spip_log("Entree " . $row['id'] . "/" . $row['id_objet'] . "/$type supprimee dans la table $table_lien",
- _LOG_INFO_IMPORTANTE);
+ spip_log(
+ "lien_optimise: Entree " . $row['id'] . "/" . $row['id_objet'] . "/$type supprimee dans la table $table_lien",
+ 'genie'._LOG_INFO_IMPORTANTE
+ );
}
}
}
diff -Nru spip-3.2.7/ecrire/action/editer_objet.php spip-3.2.15.1/ecrire/action/editer_objet.php
--- spip-3.2.7/ecrire/action/editer_objet.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/action/editer_objet.php 2022-05-20 16:59:18.000000000 +0100
@@ -489,6 +489,12 @@
include_spip('inc/rubriques');
//$postdate = ($GLOBALS['meta']["post_dates"] == "non" AND isset($champs['date']) AND (strtotime($champs['date']) < time()))?$champs['date']:false;
$postdate = false;
- calculer_rubriques_if($id_rubrique, $champs, $statut, $postdate);
+ // On rajoute les infos de l'objet
+ $infos = array(
+ 'objet' => $objet,
+ 'id_objet' => $id,
+ 'statut_ancien' => $statut,
+ );
+ calculer_rubriques_if($id_rubrique, $champs, $infos, $postdate);
}
}
diff -Nru spip-3.2.7/ecrire/auth/sha256.inc.php spip-3.2.15.1/ecrire/auth/sha256.inc.php
--- spip-3.2.7/ecrire/auth/sha256.inc.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/auth/sha256.inc.php 2022-05-20 16:59:18.000000000 +0100
@@ -258,7 +258,7 @@
return false;
}
- $h = ord($c{$index});
+ $h = ord($c[$index]);
if ($h <= 0x7F) {
$bytes = 1;
@@ -274,20 +274,20 @@
if ($h <= 0xDF && $index < $len-1) {
$bytes = 2;
- return ($h & 0x1F) << 6 | (ord($c{$index+1}) & 0x3F);
+ return ($h & 0x1F) << 6 | (ord($c[$index+1]) & 0x3F);
} else {
if ($h <= 0xEF && $index < $len-2) {
$bytes = 3;
- return ($h & 0x0F) << 12 | (ord($c{$index+1}) & 0x3F) << 6
- | (ord($c{$index+2}) & 0x3F);
+ return ($h & 0x0F) << 12 | (ord($c[$index+1]) & 0x3F) << 6
+ | (ord($c[$index+2]) & 0x3F);
} else {
if ($h <= 0xF4 && $index < $len-3) {
$bytes = 4;
- return ($h & 0x0F) << 18 | (ord($c{$index+1}) & 0x3F) << 12
- | (ord($c{$index+2}) & 0x3F) << 6
- | (ord($c{$index+3}) & 0x3F);
+ return ($h & 0x0F) << 18 | (ord($c[$index+1]) & 0x3F) << 12
+ | (ord($c[$index+2]) & 0x3F) << 6
+ | (ord($c[$index+3]) & 0x3F);
} else {
// pas utf mais renvoyer quand meme ce qu'on a
$bytes = 1;
diff -Nru spip-3.2.7/ecrire/balise/formulaire_.php spip-3.2.15.1/ecrire/balise/formulaire_.php
--- spip-3.2.7/ecrire/balise/formulaire_.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/balise/formulaire_.php 2022-05-20 16:59:18.000000000 +0100
@@ -78,6 +78,36 @@
return trouver_fond($form, 'formulaires/') ? $form : false;
}
+/**
+ * Tester si un formulaire est appele via un modele type et le cas echeant retourne les arguments passes au modele
+ * false sinon
+ * @return false|array
+ */
+function test_formulaire_inclus_par_modele() {
+ $trace = debug_backtrace(null, 20);
+ $trace_fonctions = array_column($trace, 'function');
+ $trace_fonctions = array_map('strtolower', $trace_fonctions);
+
+ // regarder si un flag a ete leve juste avant l'appel de balise_FORMULAIRE_dyn
+ if (function_exists('arguments_balise_dyn_depuis_modele')
+ and $form = arguments_balise_dyn_depuis_modele(null, 'read')) {
+ if (in_array('balise_formulaire__dyn', $trace_fonctions)) {
+ $k = array_search('balise_formulaire__dyn', $trace_fonctions);
+ if ($trace[$k]['args'][0] === $form) {
+ return $trace[$k]['args'];
+ }
+ }
+ }
+
+ // fallback qui ne repose pas sur le flag lie a l'analyse de contexte_compil,
+ // mais ne marche pas si executer_balise_dynamique est appelee via du php dans le squelette
+ if (in_array('eval', $trace_fonctions) and in_array('inclure_modele', $trace_fonctions)) {
+ $k = array_search('inclure_modele', $trace_fonctions);
+ // les arguments de recuperer_fond() passes par inclure_modele()
+ return $trace[$k-1]['args'][1]['args'];
+ }
+ return false;
+}
/**
* Balises Formulaires par défaut.
@@ -218,8 +248,12 @@
// nettoyer l'url
$action = parametre_url($action, 'formulaire_action', '');
$action = parametre_url($action, 'formulaire_action_args', '');
+ $action = parametre_url($action, 'formulaire_action_sign', '');
}
+ /**
+ * 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);
@@ -237,6 +271,13 @@
$valeurs['action'] = $action;
$valeurs['form'] = $form;
+ $valeurs['formulaire_sign'] = '';
+ if (!empty($GLOBALS['visiteur_session']['id_auteur'])) {
+ $securiser_action = charger_fonction('securiser_action', 'inc');
+ $secu = $securiser_action($valeurs['form'], $valeurs['formulaire_args'], '', -1);
+ $valeurs['formulaire_sign'] = $secu['hash'];
+ }
+
if (!isset($valeurs['id'])) {
$valeurs['id'] = 'new';
}
diff -Nru spip-3.2.7/ecrire/balise/url_.php spip-3.2.15.1/ecrire/balise/url_.php
--- spip-3.2.7/ecrire/balise/url_.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/balise/url_.php 2022-05-20 16:59:18.000000000 +0100
@@ -277,7 +277,7 @@
$code .= ", $args";
}
$code = $f('page', $code, $s);
-
+ $p->code = $code;
return $p;
}
$s = 'connect=' . addslashes($s);
diff -Nru spip-3.2.7/ecrire/base/connect_sql.php spip-3.2.15.1/ecrire/base/connect_sql.php
--- spip-3.2.7/ecrire/base/connect_sql.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/base/connect_sql.php 2022-05-20 16:59:18.000000000 +0100
@@ -426,10 +426,29 @@
* @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 @@
$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 @@
* @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;
@@ -525,6 +546,7 @@
* - indéfini sinon.
**/
function spip_query($query, $serveur = '') {
+
$f = spip_connect_sql($GLOBALS['spip_sql_version'], 'query', $serveur, true);
return function_exists($f) ? $f($query, $serveur) : false;
diff -Nru spip-3.2.7/ecrire/base/create.php spip-3.2.15.1/ecrire/base/create.php
--- spip-3.2.7/ecrire/base/create.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/base/create.php 2022-05-20 16:59:18.000000000 +0100
@@ -70,7 +70,9 @@
$autoinc = base_determine_autoinc($table, $desc);
}
#spip_log("sql_create $table autoinc=$autoinc","dbinstall"._LOG_INFO_IMPORTANTE);
- sql_create($table, $desc['field'], $desc['key'], $autoinc, false, $serveur);
+ if (isset($desc['field']) and isset($desc['key'])) {
+ sql_create($table, $desc['field'], $desc['key'], $autoinc, false, $serveur);
+ }
// verifier la bonne installation de la table (php-fpm es-tu la ?)
$sql_desc = sql_showtable($table, true, $serveur);
#if (!$sql_desc) $sql_desc = false;
@@ -92,19 +94,23 @@
// on ne supprime jamais les champs, car c'est dangereux
// c'est toujours a faire manuellement
$last = '';
- foreach ($desc['field'] as $field => $type) {
- if (!isset($sql_desc['field'][$field])) {
- sql_alter("TABLE $table ADD $field $type" . ($last ? " AFTER $last" : ""), $serveur);
+ if (isset($desc['field'])) {
+ foreach ($desc['field'] as $field => $type) {
+ if (!isset($sql_desc['field'][$field])) {
+ sql_alter("TABLE $table ADD $field $type" . ($last ? " AFTER $last" : ""), $serveur);
+ }
+ $last = $field;
}
- $last = $field;
}
- foreach ($desc['key'] as $key => $type) {
- // Ne pas oublier les cas des cles non nommees dans la declaration et qui sont retournees
- // par le showtable sous la forme d'un index de tableau "KEY $type" et non "KEY"
- if (!isset($sql_desc['key'][$key]) and !isset($sql_desc['key']["$key $type"])) {
- sql_alter("TABLE $table ADD $key ($type)", $serveur);
+ if (isset($desc['key'])) {
+ foreach ($desc['key'] as $key => $type) {
+ // Ne pas oublier les cas des cles non nommees dans la declaration et qui sont retournees
+ // par le showtable sous la forme d'un index de tableau "KEY $type" et non "KEY"
+ if (!isset($sql_desc['key'][$key]) and !isset($sql_desc['key']["$key $type"])) {
+ sql_alter("TABLE $table ADD $key ($type)", $serveur);
+ }
+ $last = $field;
}
- $last = $field;
}
}
diff -Nru spip-3.2.7/ecrire/base/trouver_table.php spip-3.2.15.1/ecrire/base/trouver_table.php
--- spip-3.2.7/ecrire/base/trouver_table.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/base/trouver_table.php 2022-05-20 16:59:18.000000000 +0100
@@ -152,7 +152,7 @@
$desc = sql_showtable($nom_sql, $table_spip, $serveur);
if (!$desc or !$desc['field']) {
if (!$fdesc) {
- spip_log("trouver_table: table inconnue '$serveur' '$nom'", _LOG_INFO_IMPORTANTE);
+ spip_log("trouver_table: table inconnue '$serveur' '$nom'", 'base' . _LOG_INFO_IMPORTANTE);
return null;
}
@@ -162,6 +162,12 @@
$desc['exist'] = false;
} else {
$desc['exist'] = true;
+ // gerer le cas des cles vides (echec de l'analyse sur une vue par exemple)
+ // pour recuperer la declaration de lister_tables_objets_sql() si il y en a une
+ if (! $desc['key']) {
+ spip_log("trouver_table: table sans cle '$serveur' '$nom'", 'base');
+ unset($desc['key']);
+ }
}
$desc['table'] = $desc['table_sql'] = $nom_sql;
@@ -171,6 +177,13 @@
// en lui passant les infos connues
// $desc est prioritaire pour la description de la table
$desc = array_merge(lister_tables_objets_sql($nom_sql, $desc), $desc);
+ // s'assurer qu'on a toujours un 'key'
+ if (!isset($desc['key']) && !empty($fdesc['key'])){
+ $desc['key'] = $fdesc['key'];
+ }
+ if (! isset($desc['key'])) {
+ $desc['key'] = array();
+ }
// si tables_objets_sql est bien fini d'init, on peut cacher
$connexion['tables'][$nom_sql] = $desc;
diff -Nru spip-3.2.7/ecrire/base/upgrade.php spip-3.2.15.1/ecrire/base/upgrade.php
--- spip-3.2.7/ecrire/base/upgrade.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/base/upgrade.php 2022-05-20 16:59:18.000000000 +0100
@@ -92,7 +92,7 @@
* @param string $redirect
* @return array|bool
*/
-function maj_base($version_cible = 0, $redirect = '') {
+function maj_base($version_cible = 0, $redirect = '', $debut_page = true) {
$version_installee = @$GLOBALS['meta']['version_installee'];
//
@@ -152,7 +152,7 @@
include_spip('maj/svn10000');
ksort($GLOBALS['maj']);
- $res = maj_while($version_installee, $cible, $GLOBALS['maj'], 'version_installee', 'meta', $redirect, true);
+ $res = maj_while($version_installee, $cible, $GLOBALS['maj'], 'version_installee', 'meta', $redirect, $debut_page);
if ($res) {
if (!is_array($res)) {
spip_log("Pb d'acces SQL a la mise a jour", 'maj.' . _LOG_INFO_ERREUR);
@@ -381,8 +381,7 @@
define('_TIME_OUT', $time + _UPGRADE_TIME_OUT);
}
- reset($maj);
- while (list($v, ) = each($maj)) {
+ foreach ($maj as $v => $operations) {
// si une maj pour cette version
if ($v == 'init' or
(spip_version_compare($v, $installee, '>')
@@ -392,7 +391,7 @@
maj_debut_page($v, $meta, $table);
}
echo "MAJ $v";
- $etape = serie_alter($v, $maj[$v], $meta, $table, $redirect);
+ $etape = serie_alter($v, $operations, $meta, $table, $redirect);
$trouver_table(''); // vider le cache des descriptions de table
# echec sur une etape en cours ?
# on sort
diff -Nru spip-3.2.7/ecrire/CHANGELOG.txt spip-3.2.15.1/ecrire/CHANGELOG.txt
--- spip-3.2.7/ecrire/CHANGELOG.txt 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/CHANGELOG.txt 1970-01-01 01:00:00.000000000 +0100
@@ -1,66 +0,0 @@
-
-SPIP-Core spip-3.2.0 -> spip-3.2.1 14 mars 2018
--------------------------------------------------------------
-
-r23781 | erational | (mer. 18 oct. 2017) | report de r23780 passer la requête http://query.yahooapis.com en https://
-r23784 | marcimat | (jeu. 19 oct. 2017) | Report de r23783 : Cet argument pour sqlite est un tableau et provoque sinon des warnings lors des mises à jours.
-r23788 | rasta | (mar. 24 oct. 2017) | Backport de r23787 : Franck proposait de mettre les versions min tout comme PHP dans ce fichier d'install pour ne pas avoir à se poser de questions.
-r23791 | b_b | (mar. 31 oct. 2017) | retour sur r23686 : $streamContext n'est pas un tableau mais un contexte de fluxref #3751 thx to Thierry Voyat
-r23794 | cedric | (lun. 06 nov. 2017) | Fix #4033 : quand le champ est complexe (expression calculee pour age) il faut faillir la regexp de decomposition du sql_quote pour le recaster proprement. On contourne en utilisant un type par defaut inexistant @@defaultcast@@ et facilement reperable et un elseif de plus
-r23799 | kent1 | (ven. 10 nov. 2017) | Report de r23796Les Mongols utilisent en général le cyrillique (cf http://www.mfa.gov.mn/ par exemple)
-r23811 | rasta | (dim. 19 nov. 2017) | Backport de r23810, ça n'avait pas été backporté sur la dernière version (mais en 3.1).
-r23817 | b_b | (jeu. 07 déc. 2017) | report de r23816Fix #3418 again : ajouter un log pour signaler le problème de conf opcache
-r23820 | b_b | (ven. 08 déc. 2017) | report de r23819
-r23837 | cedric | (jeu. 14 déc. 2017) | Report de r23836 : Meme si _VAR_MODE est deja definie, il faut exclure calcul et recalcul de l'analyse pour ne pas provoquer une redirection erronnee
-r23839 | erational | (jeu. 21 déc. 2017) | [CSS] Empêcher les débordements de texte sur les colonnes latérales (chankalan)https://core.spip.net/issues/3622
-r23843 | b_b | (lun. 25 déc. 2017) | report de r23842indentation
-r23858 | cedric | (jeu. 04 janv. 2018) | Report de petites ameliorations contenues dans le plugin FullText + modifs pour homogeneiser le code
-r23861 | b_b | (jeu. 04 janv. 2018) | report de r23860Fix #3392 : ajouter un title sur les liens editer des listes d'objets
-r23862 | cedric | (ven. 05 janv. 2018) | Fix indentation du selecteur de rubrique dans FF :Finie l'exception de Firefox : le padding/margin ne marche plus, au moins sur Mac OSX recent, on simplfie donc le code et traite tous les navigateurs de la meme facon+ petit ajustement sur l'indentation de base pour eviter trop de decalage entre 1er et 2nd niveau, le 1er niveau etant bien distingue par la couleur
-r23867 | rasta | (lun. 08 janv. 2018) | Backport de r23866 : fix #4069 : harmonisation entre la manière de chercher les options pour les champs date et heure, utilisation de la fonction data() puisque c'est ce qu'on cherche, commentaires. Il y a toujours un pas par défaut global en amont et définissable avec heure_pas dans l'inclusion, mais on harmonise avec la recherche d'options directement sur les champs, et directement avec le nom des options. Du coup au passage on ajoute startTime et endTime.
-r23869 | rasta | (lun. 08 janv. 2018) | Backport de r23868 : Oups, il n'y a pas de casse pour les attributs html, mais en revanche il y en a pour la fonction data(), donc tout mettre en minuscule.
-r23871 | marcimat | (lun. 08 janv. 2018) | Report de r23870 : petite correction sur certains create table sqlite.
-r23874 | b_b | (lun. 08 janv. 2018) | report de r23873Fix #3626 : installation, ne pas permettre un prefixe qui commence par des chiffres puisqu'on ne le prend pas en charge
-r23876 | cedric | (mar. 09 janv. 2018) | Amelioration du #FORMULAIRE_DATER a qui on peut passer explicitement le champ date et le champ date_redac que l'on veut utiliser ainsi que les labels associes, ce qui permet d'en etendre l'usage et la reutilisation possible
-r23880 | b_b | (mar. 09 janv. 2018) | report de r23879Fix #3426 : enrichir la détection des robots
-r23883 | marcimat | (mer. 10 janv. 2018) | Report de r23882 : Ticket #3426, Correction de r23879, éviter un ||.
-r23886 | rasta | (jeu. 11 janv. 2018) | backport de r23885 : les admins doivent voir les comptes à confirmer aussi (peetdu) + je n'avais pas placée la fonction au même endroit par rapport aux autres en 3.2
-r23890 | marcimat | (jeu. 11 janv. 2018) | Report de r23888 : Ticket #3426, Correction de r23879, 'web' attrape webkit, qui n’est pas un bot. On l’enlève !
-r23894 | erational | (jeu. 18 janv. 2018) | Début de résolution de #3996 . Ne plus afficher quota_cache qui est obsolète et qui n'est plus utilisé dans SPIP
-r23899 | b_b | (mer. 24 janv. 2018) | report de r23898Fix #3557 : simplifier l'entête compsed-by en y indiquant l'url du fichier local/config.txt
-r23901 | marcimat | (mer. 24 janv. 2018) | Report de r23900 : Corriger r23898 : url_absolue n’est pas forcément présente.
-r23905 | b_b | (jeu. 01 févr. 2018) | report de r23904Fix #4084 : retour sur r23507 permettre de saisir des horaires à la 23e heure ou à la 59e minute + ne pas vérifier la daite saisie si on annule la modification
-r23906 | cedric | (ven. 09 févr. 2018) | Prise en compte amelioree du flag process
-r23907 | cedric | (ven. 09 févr. 2018) | Revert de r23906 errone
-r23908 | cedric | (ven. 09 févr. 2018) | Prise en compte amelioree du flag process
-r23922 | rasta | (sam. 24 févr. 2018) | Backport de r23921 : Correction cohérence : le pipeline affiche_enfants est depuis des années appelé sur TOUS les objets par l'échafaudage. Donc les objets du noyau qui surchargent l'échafaudage doivent l'appeler aussi.
-r23925 | rasta | (mar. 27 févr. 2018) | Backport de r23924 : Ajouter l'information de l'id_parent dans les pipelines insertion puisqu'on l'a (remplie ou pas peu importe).
-r23927 | booz | (mer. 28 févr. 2018) | Report de [23926] ; voir aussi https://core.spip.net/issues/3924
-
-SPIP-plugins-dist spip-3.2.0 -> spip-3.2.1 14 mars 2018
--------------------------------------------------------------
-
-r107073 | chankalan | (ven. 20 oct. 2017) | éviter des notices php, report de https://zone.spip.org/trac/spip-zone/changeset/107072
-r107342 | maieul | (sam. 04 nov. 2017) | Afficher les documents les plus récents en haut dans la colonne des documents liés à un objet.Cela permet de ne pas scroller tout en bas pour trouver le document qu'on vient d'ajouter.Notes: - J'espère avoir commité aux bon en endroits (entre les branches et le trunk, je suis perdu). En tout cas, je commit pas sur la v3.0 car n'est plus maintenu que pour raison de sécurité. - On se base sur l'idée document et pas sur la date associée au document, pour éviter une jointure peut utile dans le cas présent.fix #4039
-r107345 | maieul | (sam. 04 nov. 2017) | dans un premier tps, r107342 n'aurait du être que sur le trunk
-r107867 | erational | (mar. 05 déc. 2017) | Ajout d'un critère facultatif annee qui permet de limiter les articles d'une année donnée et contourner la limitation des 2000 items du sitemap.xml généralL'appel par année se fait: monsite.org/sitemap.xml?annee=1981
-r108116 | chankalan | (mar. 19 déc. 2017) | un seul lien par objet pour les objets liés à chaque document, voir évolution #4065 + z
-r108119 | b_b | (mar. 19 déc. 2017) | report de r108118retour sur r108117 cf https://core.spip.net/issues/4065#note-3
-r108185 | b_b | (lun. 25 déc. 2017) | report de r108184Fix #3427 : afficher les poids total des documents listés par la médiathèque
-r108187 | b_b | (lun. 25 déc. 2017) | report de r108186indentation
-r108189 | b_b | (lun. 25 déc. 2017) | report de r108188indentation
-r108306 | cedric | (mer. 03 janv. 2018) | Report de r108305 : Mise a jour de MediaElement.js en version 4.2.7 qui corrige le bug d'affichage du temps + procure mejs avec la bonne version - on inclue egalement les fichiers package.js et json de mejs pour avoir dans le dossier lib les informations de version
-r108317 | cedric | (mer. 03 janv. 2018) | Retablir l'initialisation JS de mediaelement.js via le script mejs-init.js qui prend en charge les attributs data- et ajoute les class paused/playing selon l'etat du player. Retrait de la class mejs__player qui avait ete ajoutee pour declencher l'init automatique au lieu de reparer le script mejs-init.js
-r108321 | cedric | (mer. 03 janv. 2018) | Suite de r108317 : pas de mejs__player sur video non plus, et aussi on evite que le script mejs-init de doublle initialise un audio ou un video avec cette classe
-r108328 | cedric | (mer. 03 janv. 2018) | Renseigner la duree du son ou de la video si on a l'info en base (en general oui avec ID3)
-r108363 | b_b | (jeu. 04 janv. 2018) | report de r108362Fix #3392 : ajouter un title sur les liens editer des listes d'objets
-r108519 | cedric | (lun. 15 janv. 2018) | Report de r108517 : Eviter un fatal memory si jamais un tampon est ouvert
-r108607 | b_b | (mer. 24 janv. 2018) | report de r108606lisiblité des forums privé pas de font-size à 11px
-r108693 | cedric | (mar. 30 janv. 2018) | Report de r108692 : le titrage des documents a partir du nom de fichier est un peu restritif, on donne la possibilite de definir sa regle via une fonction inc_titrer_document_dist surchargeable
-r108734 | cedric | (ven. 02 févr. 2018) | mise a jour du test unitaire suite au changement de serveur math : la taille de l'image test change de 1px
-r108782 | b_b | (sam. 03 févr. 2018) | report de r108781
-r108786 | jluc | (sam. 03 févr. 2018) | suite fix couleur_saturation dans le cas où couleur est FFFFFF ou #ffffff
-r108842 | b_b | (mer. 07 févr. 2018) | report de r108841Fix #4088 : fix autorisation moderation forum pour un objet spécifique
-r109113 | rasta | (sam. 24 févr. 2018) | Backport de [109112] : Correction cohérence : le pipeline affiche_enfants est depuis des années appelé sur TOUS les objets par l'échafaudage. Donc les objets du noyau qui surchargent l'échafaudage doivent l'appeler aussi.
-r109376 | booz | (jeu. 08 mars 2018) | report de https://zone.spip.org/trac/spip-zone/changeset/109375
-r109454 | booz | (lun. 12 mars 2018) | z+1 (franck)
diff -Nru spip-3.2.7/ecrire/exec/admin_plugin.php spip-3.2.15.1/ecrire/exec/admin_plugin.php
--- spip-3.2.7/ecrire/exec/admin_plugin.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/exec/admin_plugin.php 2022-05-20 16:59:18.000000000 +0100
@@ -116,7 +116,7 @@
// message d'erreur au retour d'une operation
if ($erreur) {
- echo "
$erreur
";
+ echo "
".spip_htmlspecialchars($erreur)."
";
}
if ($erreur_activation) {
echo "
$erreur_activation
";
diff -Nru spip-3.2.7/ecrire/genie/optimiser.php spip-3.2.15.1/ecrire/genie/optimiser.php
--- spip-3.2.7/ecrire/genie/optimiser.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/genie/optimiser.php 2022-05-20 16:59:18.000000000 +0100
@@ -37,6 +37,7 @@
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
@@ -46,6 +47,17 @@
}
/**
+ * 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
*
* Supprime les relicats d'éléments qui ont disparu
@@ -84,15 +96,16 @@
$tables[] = array_shift($row);
}
+ spip_log("optimiser_base_une_table ".json_encode($tables), 'genie'._LOG_DEBUG);
if ($tables) {
$table_op = intval(lire_config('optimiser_table', 0) + 1) % sizeof($tables);
ecrire_config('optimiser_table', $table_op);
$q = $tables[$table_op];
- spip_log("debut d'optimisation de la table $q");
+ spip_log("optimiser_base_une_table : debut d'optimisation de la table $q", 'genie'._LOG_DEBUG);
if (sql_optimize($q)) {
- spip_log("fin d'optimisation de la table $q");
+ spip_log("optimiser_base_une_table : fin d'optimisation de la table $q", 'genie'._LOG_DEBUG);
} else {
- spip_log("Pas d'optimiseur necessaire");
+ spip_log("optimiser_base_une_table : Pas d'optimiseur necessaire", 'genie'._LOG_DEBUG);
}
}
}
@@ -128,7 +141,7 @@
if ($in) {
sql_delete($table, sql_in($id, array_keys($in)) . ($and ? " AND $and" : ''));
- spip_log("Numeros des entrees $id supprimees dans la table $table: " . implode(', ', array_keys($in)));
+ spip_log("optimiser_sansref: Numeros des entrees $id supprimees dans la table $table: " . implode(', ', array_keys($in)), 'genie'._LOG_DEBUG);
}
return count($in);
@@ -154,12 +167,13 @@
function optimiser_base_disparus($attente = 86400) {
# format = 20060610110141, si on veut forcer une optimisation tout de suite
- $mydate = sql_quote(date("Y-m-d H:i:s", time() - $attente));
+ $mydate = date("Y-m-d H:i:s", time() - $attente);
+ $mydate_quote = sql_quote($mydate);
$n = 0;
//
- // Rubriques
+ // Rubriques
//
# les articles qui sont dans une id_rubrique inexistante
@@ -172,12 +186,12 @@
ON A.id_rubrique=R.id_rubrique",
"A.id_rubrique > 0
AND R.id_rubrique IS NULL
- AND A.maj < $mydate");
+ AND A.maj < $mydate_quote");
$n += optimiser_sansref('spip_articles', 'id_article', $res);
// les articles a la poubelle
- sql_delete("spip_articles", "statut='poubelle' AND maj < $mydate");
+ sql_delete("spip_articles", "statut='poubelle' AND maj < $mydate_quote");
//
// Auteurs
@@ -194,7 +208,7 @@
LEFT JOIN spip_auteurs_liens AS L
ON L.id_auteur=A.id_auteur",
"L.id_auteur IS NULL
- AND A.statut='5poubelle' AND A.maj < $mydate");
+ AND A.statut='5poubelle' AND A.maj < $mydate_quote");
$n += optimiser_sansref('spip_auteurs', 'id_auteur', $res);
@@ -220,7 +234,6 @@
'data' => $n
));
- if (!$n) {
- spip_log("Optimisation des tables: aucun lien mort");
- }
+
+ spip_log("optimiser_base_disparus : {$n} lien(s) mort(s)", 'genie'._LOG_DEBUG);
}
diff -Nru spip-3.2.7/ecrire/inc/auth.php spip-3.2.15.1/ecrire/inc/auth.php
--- spip-3.2.7/ecrire/inc/auth.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/auth.php 2022-05-20 16:59:18.000000000 +0100
@@ -228,6 +228,7 @@
unset($GLOBALS['visiteur_session']['htpass']);
unset($GLOBALS['visiteur_session']['alea_actuel']);
unset($GLOBALS['visiteur_session']['alea_futur']);
+ unset($GLOBALS['visiteur_session']['ldap_password']);
// creer la session au besoin
if (!isset($_COOKIE['spip_session'])) {
@@ -271,7 +272,7 @@
// Administrateurs
if (in_array($GLOBALS['connect_statut'], explode(',', _STATUT_AUTEUR_RUBRIQUE))) {
- if (is_array($GLOBALS['visiteur_session']['restreint'])) {
+ if (isset($GLOBALS['visiteur_session']['restreint']) and is_array($GLOBALS['visiteur_session']['restreint'])) {
$GLOBALS['connect_id_rubrique'] = $GLOBALS['visiteur_session']['restreint'];
}
if ($GLOBALS['connect_statut'] == '0minirezo') {
diff -Nru spip-3.2.7/ecrire/inc/charsets.php spip-3.2.15.1/ecrire/inc/charsets.php
--- spip-3.2.7/ecrire/inc/charsets.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/charsets.php 2022-05-20 16:59:18.000000000 +0100
@@ -404,20 +404,26 @@
default:
// mbstring presente ?
if (init_mb_string()) {
- if ($order = mb_detect_order() # mb_string connait-il $charset?
- and mb_detect_order($charset)
- ) {
- $s = mb_convert_encoding($texte, 'utf-8', $charset);
- if ($s && $s != $texte) {
- return utf_8_to_unicode($s);
+ $order = mb_detect_order();
+ try {
+ # mb_string connait-il $charset?
+ if ($order and mb_detect_order($charset)) {
+ $s = mb_convert_encoding($texte, 'utf-8', $charset);
+ if ($s && $s != $texte) {
+ return utf_8_to_unicode($s);
+ }
}
- }
+
+ } catch (\Exception $e) {
+ // Le charset n'existe probablement pas
+ }
mb_detect_order($order); # remettre comme precedemment
}
// Sinon, peut-etre connaissons-nous ce charset ?
if (!isset($trans[$charset])) {
- if ($cset = load_charset($charset)
+ if (
+ $cset = load_charset($charset)
and is_array($GLOBALS['CHARSET'][$cset])
) {
foreach ($GLOBALS['CHARSET'][$cset] as $key => $val) {
@@ -425,7 +431,7 @@
}
}
}
- if (count($trans[$charset])) {
+ if (isset($trans[$charset]) and count($trans[$charset])) {
return str_replace(array_keys($trans[$charset]), array_values($trans[$charset]), $texte);
}
@@ -831,7 +837,7 @@
* @return string
*/
function translitteration_rapide($texte, $charset = 'AUTO', $complexe = '') {
- static $trans;
+ static $trans = [];
if ($charset == 'AUTO') {
$charset = $GLOBALS['meta']['charset'];
}
@@ -842,7 +848,8 @@
$table_translit = 'translit' . $complexe;
// 2. Translitterer grace a la table predefinie
- if (!$trans[$complexe]) {
+ if (!isset($trans[$complexe])) {
+ $trans[$complexe] = [];
load_charset($table_translit);
foreach ($GLOBALS['CHARSET'][$table_translit] as $key => $val) {
$trans[$complexe][caractere_utf_8($key)] = $val;
@@ -897,8 +904,11 @@
$texte = translitteration($texte, 'AUTO', 'complexe');
if ($chiffres) {
- $texte = preg_replace("/[aeiuoyd]['`?~.^+(-]{1,2}/eS",
- "translitteration_chiffree('\\0')", $texte);
+ $texte = preg_replace_callback(
+ "/[aeiuoyd]['`?~.^+(-]{1,2}/S",
+ function($m) { return translitteration_chiffree($m[0]); },
+ $texte
+ );
}
return $texte;
@@ -994,34 +1004,29 @@
return $texte;
}
- // Reconnaitre le BOM utf-8 (0xEFBBBF)
if (bom_utf8($texte)) {
+ // Reconnaitre le BOM utf-8 (0xEFBBBF)
$charset = 'utf-8';
$texte = substr($texte, 3);
- } // charset precise par le contenu (xml)
- else {
- if (preg_match(
- ',<[?]xml[^>]*encoding[^>]*=[^>]*([-_a-z0-9]+?),UimsS', $texte, $regs)) {
- $charset = trim(strtolower($regs[1]));
- } // charset precise par le contenu (html)
- else {
- if (preg_match(
- ',<(meta|html|body)[^>]*charset[^>]*=[^>]*([-_a-z0-9]+?),UimsS',
- $texte, $regs)
- # eviter #CHARSET des squelettes
- and (($tmp = trim(strtolower($regs[2]))) != 'charset')
- ) {
- $charset = $tmp;
- } // charset de la reponse http
- else {
- if (preg_match(',charset=([-_a-z0-9]+),i', $headers, $regs)) {
- $charset = trim(strtolower($regs[1]));
- } else {
- $charset = '';
- }
- }
- }
+ } elseif (preg_match(',<[?]xml[^>]*encoding[^>]*=[^>]*([-_a-z0-9]+?),UimsS', $texte, $regs)) {
+ // charset precise par le contenu (xml)
+ $charset = trim(strtolower($regs[1]));
+ } elseif (
+ // charset precise par le contenu (html)
+ preg_match(',<(meta|html|body)[^>]*charset[^>]*=[^>]*([#-_a-z0-9]+?),UimsS', $texte, $regs)
+ # eviter toute balise SPIP tel que #CHARSET ou #CONFIG d'un squelette
+ and false === strpos($regs[2], '#')
+ and $tmp = trim(strtolower($regs[2]))
+ ) {
+ $charset = $tmp;
+ } elseif (preg_match(',charset=([-_a-z0-9]+),i', $headers, $regs)) {
+ // charset de la reponse http
+ $charset = trim(strtolower($regs[1]));
+ } else {
+ $charset = '';
}
+
+
// normaliser les noms du shif-jis japonais
if (preg_match(',^(x|shift)[_-]s?jis$,i', $charset)) {
$charset = 'shift-jis';
diff -Nru spip-3.2.7/ecrire/inc/commencer_page.php spip-3.2.15.1/ecrire/inc/commencer_page.php
--- spip-3.2.7/ecrire/inc/commencer_page.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/commencer_page.php 2022-05-20 16:59:18.000000000 +0100
@@ -157,16 +157,14 @@
* @return string Classes CSS (séparées par des espaces)
*/
function init_body_class() {
- $GLOBALS['spip_display'] = isset($GLOBALS['visiteur_session']['prefs']['display'])
- ? $GLOBALS['visiteur_session']['prefs']['display']
- : 2;
- $spip_display_navigation = isset($GLOBALS['visiteur_session']['prefs']['display_navigation'])
- ? $GLOBALS['visiteur_session']['prefs']['display_navigation']
- : 'navigation_avec_icones';
- $spip_display_outils = isset($GLOBALS['visiteur_session']['prefs']['display_outils'])
- ? ($GLOBALS['visiteur_session']['prefs']['display_outils'] ? 'navigation_avec_outils' : 'navigation_sans_outils')
+ $prefs = isset($GLOBALS['visiteur_session']['prefs']) ? $GLOBALS['visiteur_session']['prefs'] : array();
+
+ $GLOBALS['spip_display'] = isset($prefs['display']) ? (int) $prefs['display'] : 2;
+ $spip_display_navigation = isset($prefs['display_navigation']) ? spip_sanitize_classname($prefs['display_navigation']) : 'navigation_avec_icones';
+ $spip_display_outils = isset($prefs['display_outils'])
+ ? ($prefs['display_outils'] ? 'navigation_avec_outils' : 'navigation_sans_outils')
: 'navigation_avec_outils';
- $GLOBALS['spip_ecran'] = isset($_COOKIE['spip_ecran']) ? $_COOKIE['spip_ecran'] : "etroit";
+ $GLOBALS['spip_ecran'] = isset($_COOKIE['spip_ecran']) ? spip_sanitize_classname($_COOKIE['spip_ecran']) : "etroit";
$display_class = array(
0 => 'icones_img_texte'
@@ -176,7 +174,8 @@
3 => 'icones_img'
);
- return $GLOBALS['spip_ecran'] . " $spip_display_navigation $spip_display_outils " . $display_class[$GLOBALS['spip_display']];
+ $classes = $GLOBALS['spip_ecran'] . " $spip_display_navigation $spip_display_outils " . $display_class[$GLOBALS['spip_display']];
+ return spip_sanitize_classname($classes);
}
diff -Nru spip-3.2.7/ecrire/inc/config.php spip-3.2.15.1/ecrire/inc/config.php
--- spip-3.2.7/ecrire/inc/config.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/config.php 2022-05-20 16:59:18.000000000 +0100
@@ -544,8 +544,8 @@
// verifier le impt=non
sql_updateq('spip_meta', array('impt' => 'non'), sql_in('nom', $meta_serveur));
- while (list($nom, $valeur) = each($liste_meta)) {
- if (!isset($GLOBALS['meta'][$nom]) or !$GLOBALS['meta'][$nom]) {
+ foreach ($liste_meta as $nom => $valeur) {
+ if (empty($GLOBALS['meta'][$nom])) {
ecrire_meta($nom, $valeur);
}
}
@@ -607,6 +607,8 @@
$adresse_site = "http://$adresse_site";
}
+ $adresse_site = entites_html($adresse_site);
+
ecrire_meta('adresse_site', $adresse_site);
}
diff -Nru spip-3.2.7/ecrire/inc/cvt_autosave.php spip-3.2.15.1/ecrire/inc/cvt_autosave.php
--- spip-3.2.7/ecrire/inc/cvt_autosave.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/cvt_autosave.php 2022-05-20 16:59:18.000000000 +0100
@@ -63,6 +63,20 @@
}
}
+ // si on est dans le charger() qui suit le traiter(), l'autosave a normalement ete vide
+ // mais si il y a plusieurs sessions il peut y avoir concurrence et un retour de l'autosave
+ if ($je_suis_poste and _request('autosave') === $cle_autosave and function_exists('terminer_actualiser_sessions')) {
+ terminer_actualiser_sessions();
+ // et verifions si jamais l'autosave a fait un come back, dans ce cas on le revide
+ if (isset($GLOBALS['visiteur_session']['session_autosave_' . $cle_autosave])) {
+ session_set('session_autosave_' . $cle_autosave, null);
+ // en court sleep pour etre certain que la concurrence est finie
+ sleep(1);
+ terminer_actualiser_sessions();
+ }
+ }
+
+
/**
* Envoyer le input hidden et le bout de js qui l'utilisera
*/
diff -Nru spip-3.2.7/ecrire/inc/cvt_configurer.php spip-3.2.15.1/ecrire/inc/cvt_configurer.php
--- spip-3.2.7/ecrire/inc/cvt_configurer.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/cvt_configurer.php 2022-05-20 16:59:18.000000000 +0100
@@ -187,7 +187,7 @@
foreach ($balises as $b) {
if ($n = extraire_attribut($b, 'name')
and preg_match(",^([\w\-]+)(\[\w*\])?$,", $n, $r)
- and !in_array($n, array('formulaire_action', 'formulaire_action_args'))
+ and !in_array($n, array('formulaire_action', 'formulaire_action_args', 'formulaire_action_sign'))
and extraire_attribut($b, 'type') !== 'submit'
) {
$valeurs[$r[1]] = '';
diff -Nru spip-3.2.7/ecrire/inc/cvt_multietapes.php spip-3.2.15.1/ecrire/inc/cvt_multietapes.php
--- spip-3.2.7/ecrire/inc/cvt_multietapes.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/cvt_multietapes.php 2022-05-20 16:59:18.000000000 +0100
@@ -208,7 +208,7 @@
/**
* Verifier les etapes de saisie
- *
+ *
* @param array $args
* @param $erreurs
* @return array
@@ -221,13 +221,15 @@
) {
// 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 @@
}
// 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 @@
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 @@
$erreurs = isset($erreurs_etapes[$etape]) ? $erreurs_etapes[$etape] : array();
// Ne pas se tromper dans le texte du message d'erreur : la clé '_etapes' n'est pas une erreur !
if ($erreurs) {
- $erreurs['message_erreur'] = singulier_ou_pluriel(count($erreurs), 'avis_1_erreur_saisie', 'avis_nb_erreurs_saisie');
+ if (!isset($erreurs['message_erreur'])) {
+ $erreurs['message_erreur'] = singulier_ou_pluriel(count($erreurs), 'avis_1_erreur_saisie', 'avis_nb_erreurs_saisie');
+ }
} else {
$erreurs['message_erreur'] = "";
}
diff -Nru spip-3.2.7/ecrire/inc/distant.php spip-3.2.15.1/ecrire/inc/distant.php
--- spip-3.2.7/ecrire/inc/distant.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/distant.php 2022-05-20 16:59:18.000000000 +0100
@@ -193,21 +193,28 @@
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;
}
}
@@ -1091,6 +1098,7 @@
# charger les alias des types mime
include_spip('base/typedoc');
+ include_spip('action/ajouter_documents');
$a = array();
$mime_type = '';
@@ -1121,13 +1129,13 @@
if (!$t
and preg_match(',\.([a-z0-9]+)(\?.*)?$,i', $source, $rext)
) {
- $t = sql_fetsel('extension', 'spip_types_documents', 'extension=' . sql_quote($rext[1], '', 'text'));
+ $t = sql_fetsel('extension', 'spip_types_documents', 'extension=' . sql_quote(corriger_extension($rext[1]), '', 'text'));
}
if (!$t
and preg_match(',^Content-Disposition:\s*attachment;\s*filename=(.*)$,Uims', $headers, $m)
and preg_match(',\.([a-z0-9]+)(\?.*)?$,i', $m[1], $rext)
) {
- $t = sql_fetsel('extension', 'spip_types_documents', 'extension=' . sql_quote($rext[1], '', 'text'));
+ $t = sql_fetsel('extension', 'spip_types_documents', 'extension=' . sql_quote(corriger_extension($rext[1]), '', 'text'));
}
}
@@ -1143,7 +1151,7 @@
and preg_match(',\.([a-z0-9]+)(\?.*)?$,i', $source, $rext)
) {
# eviter xxx.3 => 3gp (> SPIP 3)
- $t = sql_fetsel('extension', 'spip_types_documents', 'extension=' . sql_quote($rext[1], '', 'text'));
+ $t = sql_fetsel('extension', 'spip_types_documents', 'extension=' . sql_quote(corriger_extension($rext[1]), '', 'text'));
}
if ($t) {
diff -Nru spip-3.2.7/ecrire/inc/documents.php spip-3.2.15.1/ecrire/inc/documents.php
--- spip-3.2.7/ecrire/inc/documents.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/documents.php 2022-05-20 16:59:18.000000000 +0100
@@ -139,6 +139,19 @@
// pour les images transformees par rotation (action/documenter)
$dest = preg_replace(',-r(90|180|270)$,', '', $dest);
+ while (preg_match(",\.(\w+)$,", $dest, $m)) {
+ if (!function_exists('verifier_upload_autorise')
+ or !$r = verifier_upload_autorise($dest)
+ or $r['autozip']) {
+ $dest = substr($dest, 0, -strlen($m[0])) . '_' . $m[1];
+ break;
+ }
+ else {
+ $dest = substr($dest, 0, -strlen($m[0]));
+ $ext = $m[1] . "." . $ext;
+ }
+ }
+
// Si le document "source" est deja au bon endroit, ne rien faire
if ($source == ($dir . $dest . '.' . $ext)) {
return $source;
diff -Nru spip-3.2.7/ecrire/inc/editer.php spip-3.2.15.1/ecrire/inc/editer.php
--- spip-3.2.7/ecrire/inc/editer.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/editer.php 2022-05-20 16:59:18.000000000 +0100
@@ -140,7 +140,7 @@
if (!isset($erreurs[$champ])) {
$erreurs[$champ] = '';
}
- $erreurs[$champ] .= _T('alerte_modif_info_concourante') . " ';
+ $erreurs[$champ] .= _T('alerte_modif_info_concourante') . " ';
}
}
}
@@ -207,9 +207,21 @@
$row = array(),
$hidden = ''
) {
+
$table_objet = table_objet($type);
$table_objet_sql = table_objet_sql($type);
$id_table_objet = id_table_objet($type);
+
+ // on accepte pas une fonction de config inconnue si elle vient d'un modele
+ if ($config_fonc
+ and !in_array($config_fonc, ['articles_edit_config', 'rubriques_edit_config', 'auteurs_edit_config'])
+ and $config_fonc !== $table_objet . '_edit_config') {
+ if ($args = test_formulaire_inclus_par_modele()
+ and in_array($config_fonc, $args)) {
+ $config_fonc = '';
+ }
+ }
+
$new = !is_numeric($id);
// Appel direct dans un squelette
if (!$row) {
diff -Nru spip-3.2.7/ecrire/inc/filtres_ecrire.php spip-3.2.15.1/ecrire/inc/filtres_ecrire.php
--- spip-3.2.7/ecrire/inc/filtres_ecrire.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/filtres_ecrire.php 2022-05-20 16:59:18.000000000 +0100
@@ -572,8 +572,11 @@
} else {
$res = objet_trouver_liens(array($objet_source => '*'), array($objet => $id_objet));
}
+ // Si les liens qu'on cherche sont ceux de la table de lien, l'info est dans la clé de l'objet
+ // Sinon c'est dans "id_objet"
+ $cle = ($objet_source == $objet_lien ? id_table_objet($objet_source) : 'id_objet');
while ($row = array_shift($res)) {
- $l[] = $row[$objet_source];
+ $l[] = $row[$cle];
}
return $l;
diff -Nru spip-3.2.7/ecrire/inc/filtres_images_lib_mini.php spip-3.2.15.1/ecrire/inc/filtres_images_lib_mini.php
--- spip-3.2.7/ecrire/inc/filtres_images_lib_mini.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/filtres_images_lib_mini.php 2022-05-20 16:59:18.000000000 +0100
@@ -853,7 +853,7 @@
// enlever le width et height du style
$style = preg_replace(",(^|;)\s*(width|height)\s*:\s*[^;]+,ims", "", $style);
- if ($style and $style{0} == ';') {
+ if ($style and $style[0] == ';') {
$style = substr($style, 1);
}
diff -Nru spip-3.2.7/ecrire/inc/filtres.php spip-3.2.15.1/ecrire/inc/filtres.php
--- spip-3.2.7/ecrire/inc/filtres.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/filtres.php 2022-05-20 16:59:18.000000000 +0100
@@ -165,6 +165,21 @@
return $version;
}
+/**
+ * Masque la version de SPIP si la globale spip_header_silencieux le demande.
+ *
+ * @global spip_header_silencieux permet de rendre le header minimal pour raisons de securité
+ *
+ * @param string $version
+ * @return void
+ */
+function header_silencieux($version) {
+ if (isset($GLOBALS['spip_header_silencieux']) && (bool) $GLOBALS['spip_header_silencieux']) {
+ $version = '';
+ }
+
+ return $version;
+}
/**
* Retrouve un numéro de révision SVN d'un répertoire
@@ -353,6 +368,17 @@
}
/**
+ * @param array $Pile
+ * @param array|string $keys
+ * @return string
+ */
+function filtre_sanitize_env(&$Pile, $keys) {
+ $Pile[0] = spip_sanitize_from_request($Pile[0], $keys);
+ return '';
+}
+
+
+/**
* Filtre `debug` qui affiche un debug de la valeur en entrée
*
* Log la valeur dans `debug.log` et l'affiche si on est webmestre.
@@ -1905,11 +1931,13 @@
**/
function extraire_attribut($balise, $attribut, $complet = false) {
if (is_array($balise)) {
- array_walk($balise,
- create_function('&$a,$key,$t',
- '$a = extraire_attribut($a,$t);'
- ),
- $attribut);
+ array_walk(
+ $balise,
+ function(&$a, $key, $t){
+ $a = extraire_attribut($a, $t);
+ },
+ $attribut
+ );
return $balise;
}
@@ -2350,7 +2378,7 @@
function tags2dcsubject($tags) {
$subjects = '';
foreach (extraire_balises($tags, 'a') as $e) {
- if (extraire_attribut($e, rel) == 'tag') {
+ if (extraire_attribut($e, 'rel') == 'tag') {
$subjects .= ''
. texte_backend(textebrut($e))
. '' . "\n";
@@ -2389,7 +2417,9 @@
if (is_array($texte)) {
array_walk(
$texte,
- create_function('&$a,$key,$t', '$a = extraire_balise($a,$t);'),
+ function(&$a, $key, $t){
+ $a = extraire_balise($a, $t);
+ },
$tag
);
@@ -2431,7 +2461,9 @@
if (is_array($texte)) {
array_walk(
$texte,
- create_function('&$a,$key,$t', '$a = extraire_balises($a,$t);'),
+ function(&$a, $key, $t){
+ $a = extraire_balises($a, $t);
+ },
$tag
);
@@ -2789,9 +2821,10 @@
return $ancres[$ancre];
}
+ $self = (empty($env['self']) ? self() : $env['self']);
$pagination = array(
'debut' => $debut,
- 'url' => parametre_url(self(), 'fragment', ''), // nettoyer l'id ahah eventuel
+ 'url' => parametre_url($self, 'fragment', ''), // nettoyer l'id ahah eventuel
'total' => $total,
'position' => intval($position),
'pas' => $pas,
@@ -2834,9 +2867,11 @@
return preg_replace_callback(
",url\s*\(\s*['\"]?([^'\"/#\s][^:]*)['\"]?\s*\),Uims",
- create_function('$x',
- 'return "url(\'".suivre_lien(\'' . $path . '\',$x[1])."\')";'
- ), $contenu);
+ function($x) use ($path) {
+ return "url('" . suivre_lien($path, $x[1]) . "')";
+ },
+ $contenu
+ );
}
@@ -3244,7 +3279,7 @@
if ($env) {
foreach ($env as $i => $j) {
if (is_string($j) and !in_array($i, $ignore_params)) {
- $texte .= "";
+ $texte .= "";
}
}
}
@@ -3283,7 +3318,7 @@
if ($env) {
foreach ($env as $i => $j) {
if (is_string($j) and !in_array($i, $ignore_params)) {
- $texte .= $i . "='" . $j . "' ";
+ $texte .= attribut_html($i) . "='" . attribut_html($j) . "' ";
}
}
}
@@ -3438,6 +3473,10 @@
}
$balise_svg = $match[0];
$balise_svg_source = $balise_svg;
+
+ // entete XML à supprimer
+ $svg = preg_replace(',^\s*<\?xml[^>]*\?' . '>,', '', $svg);
+
// IE est toujours mon ami
$balise_svg = inserer_attribut($balise_svg, 'focusable', 'false');
if ($class) {
@@ -3661,10 +3700,10 @@
$cle = calculer_cle_action($form . $c);
$c = "$cle:$c";
- // on ne stocke pas les contextes dans des fichiers caches
- // par defaut, sauf si cette configuration a ete forcee
- // OU que la longueur de l''argument generee est plus long
- // que ce que telere Suhosin.
+ // on ne stocke pas les contextes dans des fichiers en cache
+ // par defaut, sauf si cette configuration a été forcée
+ // OU que la longueur de l’argument géneré est plus long
+ // que ce qui est toléré.
$cache_contextes_ajax = (defined('_CACHE_CONTEXTES_AJAX') and _CACHE_CONTEXTES_AJAX);
if (!$cache_contextes_ajax) {
$env = $c;
@@ -3678,9 +3717,20 @@
}
$env = _xor($env);
$env = base64_encode($env);
- // tester Suhosin et la valeur maximale des variables en GET...
- if ($max_len = @ini_get('suhosin.get.max_value_length')
- and $max_len < ($len = strlen($env))
+ $len = strlen($env);
+ // Si l’url est trop longue pour le navigateur
+ $max_len = _CACHE_CONTEXTES_AJAX_SUR_LONGUEUR;
+ if ($len > $max_len) {
+ $cache_contextes_ajax = true;
+ spip_log("Contextes AJAX forces en fichiers !"
+ . " Cela arrive lorsque la valeur du contexte"
+ . " depasse la longueur maximale autorisee ($max_len). Ici : $len."
+ , _LOG_AVERTISSEMENT);
+ }
+ // Sinon si Suhosin est actif et a une la valeur maximale des variables en GET...
+ elseif (
+ $max_len = @ini_get('suhosin.get.max_value_length')
+ and $max_len < $len
) {
$cache_contextes_ajax = true;
spip_log("Contextes AJAX forces en fichiers !"
@@ -3689,7 +3739,8 @@
. " ($max_len) dans 'suhosin.get.max_value_length'. Ici : $len."
. " Vous devriez modifier les parametres de Suhosin"
. " pour accepter au moins 1024 caracteres.", _LOG_AVERTISSEMENT);
- }
+ }
+
}
if ($cache_contextes_ajax) {
@@ -3880,20 +3931,20 @@
*
* @param int $nb : le nombre
* @param string $chaine_un : l'item de langue si $nb vaut un
- * @param string $chaine_plusieurs : l'item de lanque si $nb > 1
+ * @param string $chaine_plusieurs : l'item de lanque si $nb >= 2
* @param string $var : La variable à remplacer par $nb dans l'item de langue (facultatif, défaut "nb")
* @param array $vars : Les autres variables nécessaires aux chaines de langues (facultatif)
* @return string : la chaine de langue finale en utilisant la fonction _T()
*/
function singulier_ou_pluriel($nb, $chaine_un, $chaine_plusieurs, $var = 'nb', $vars = array()) {
- if (!$nb = intval($nb)) {
+ if (!is_numeric($nb) or $nb == 0) {
return "";
}
if (!is_array($vars)) {
return "";
}
$vars[$var] = $nb;
- if ($nb > 1) {
+ if ($nb >= 2) {
return _T($chaine_plusieurs, $vars);
} else {
return _T($chaine_un, $vars);
@@ -4245,12 +4296,16 @@
/**
* Proteger les champs passes dans l'url et utiliser dans {tri ...}
* preserver l'espace pour interpreter ensuite num xxx et multi xxx
+ * on permet d'utiliser les noms de champ prefixes
+ * articles.titre
+ * et les propriete json
+ * properties.gis[0].ville
*
* @param string $t
* @return string
*/
function tri_protege_champ($t) {
- return preg_replace(',[^\s\w.+],', '', $t);
+ return preg_replace(',[^\s\w.+\[\]],', '', $t);
}
/**
@@ -4799,7 +4854,13 @@
function filtre_nettoyer_titre_email_dist($titre) {
include_spip('inc/envoyer_mail');
- return nettoyer_titre_email($titre);
+ $titre = nettoyer_titre_email($titre);
+ // on est dans un squelette : securiser le retour
+ if (strpos($titre, '<') !== false) {
+ $titre = interdire_scripts($titre);
+ }
+
+ return $titre;
}
/**
diff -Nru spip-3.2.7/ecrire/inc/headers.php spip-3.2.15.1/ecrire/inc/headers.php
--- spip-3.2.7/ecrire/inc/headers.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/headers.php 2022-05-20 16:59:18.000000000 +0100
@@ -186,35 +186,14 @@
*
* Ainsi `http_status(301)` enverra le message `301 Moved Permanently`.
*
- * @link http://php.net/manual/fr/function.header.php Fonction header() de PHP utilisée ici
+ * @link https://www.php.net/manual/fr/function.http-response-code.php
+ * @uses http_response_code()
*
* @param int $status
* Code d'erreur
**/
function http_status($status) {
-
- static $status_string = array(
- 200 => '200 OK',
- 204 => '204 No Content',
- 301 => '301 Moved Permanently',
- 302 => '302 Found',
- 304 => '304 Not Modified',
- 401 => '401 Unauthorized',
- 403 => '403 Forbidden',
- 404 => '404 Not Found',
- 503 => '503 Service Unavailable'
- );
-
- if (!empty($GLOBALS['REDIRECT_STATUS']) && $GLOBALS['REDIRECT_STATUS'] == $status) {
- return;
- }
-
- $php_cgi = ($GLOBALS['flag_sapi_name'] and preg_match(",cgi,i", @php_sapi_name()));
- if ($php_cgi) {
- header("Status: " . $status_string[$status]);
- } else {
- header("HTTP/1.0 " . $status_string[$status]);
- }
+ http_response_code($status);
}
// Retourne ce qui va bien pour que le navigateur ne mette pas la page en cache
diff -Nru spip-3.2.7/ecrire/inc/idna_convert.class.php spip-3.2.15.1/ecrire/inc/idna_convert.class.php
--- spip-3.2.7/ecrire/inc/idna_convert.class.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/idna_convert.class.php 2022-05-20 16:59:18.000000000 +0100
@@ -423,7 +423,7 @@
$delim_pos = strrpos($encoded, '-');
if ($delim_pos > self::byteLength($this->_punycode_prefix)) {
for ($k = self::byteLength($this->_punycode_prefix); $k < $delim_pos; ++$k) {
- $decoded[] = ord($encoded{$k});
+ $decoded[] = ord($encoded[$k]);
}
}
$deco_len = count($decoded);
@@ -437,7 +437,7 @@
for ($enco_idx = ($delim_pos) ? ($delim_pos + 1) : 0; $enco_idx < $enco_len; ++$deco_len) {
for ($old_idx = $idx, $w = 1, $k = $this->_base; 1; $k += $this->_base) {
- $digit = $this->_decode_digit($encoded{$enco_idx++});
+ $digit = $this->_decode_digit($encoded[$enco_idx++]);
$idx += $digit * $w;
$t = ($k <= $bias) ? $this->_tmin :
(($k >= $bias + $this->_tmax) ? $this->_tmax : ($k - $bias));
@@ -864,7 +864,7 @@
$mode = 'next';
$test = 'none';
for ($k = 0; $k < $inp_len; ++$k) {
- $v = ord($input{$k}); // Extract byte from input string
+ $v = ord($input[$k]); // Extract byte from input string
if ($v < 128) { // We found an ASCII char - put into stirng as is
$output[$out_len] = $v;
++$out_len;
@@ -995,7 +995,7 @@
$out_len++;
$output[$out_len] = 0;
}
- $output[$out_len] += ord($input{$i}) << (8 * (3 - ($i % 4) ) );
+ $output[$out_len] += ord($input[$i]) << (8 * (3 - ($i % 4) ) );
}
return $output;
}
diff -Nru spip-3.2.7/ecrire/inc/invalideur.php spip-3.2.15.1/ecrire/inc/invalideur.php
--- spip-3.2.7/ecrire/inc/invalideur.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/invalideur.php 2022-05-20 16:59:18.000000000 +0100
@@ -178,11 +178,18 @@
**/
function purger_repertoire($dir, $options = array()) {
if (!is_dir($dir) or !is_readable($dir)) {
- return;
+ return 0;
}
+
+ // sur certains sites on veut absolument garder certains caches référencés dans un CDN
+ // on peut donc inhiber la purge de ces répertoires pour eviter tout probleme
+ if (file_exists(rtrim($dir,'/') . '/inhib_purger_repertoire.txt')) {
+ return 0;
+ }
+
$handle = opendir($dir);
if (!$handle) {
- return;
+ return 0;
}
$total = 0;
diff -Nru spip-3.2.7/ecrire/inc/math.php spip-3.2.15.1/ecrire/inc/math.php
--- spip-3.2.7/ecrire/inc/math.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/math.php 2022-05-20 16:59:18.000000000 +0100
@@ -60,7 +60,7 @@
// MathML
if ($GLOBALS['traiter_math'] == 'mathml') {
- return join(file("$fichier"), "");
+ return implode("", file($fichier));
} // TeX
else {
list(, , , $size) = @getimagesize($fichier);
diff -Nru spip-3.2.7/ecrire/inc/modifier.php spip-3.2.15.1/ecrire/inc/modifier.php
--- spip-3.2.7/ecrire/inc/modifier.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/modifier.php 2022-05-20 16:59:18.000000000 +0100
@@ -160,6 +160,7 @@
'spip_table_objet' => $spip_table_objet,
'type' => $objet,
'id_objet' => $id_objet,
+ 'data' => isset($options['data']) ? $options['data'] : null,
'champs' => isset($options['champs']) ? $options['champs'] : array(), // [doc] c'est quoi ?
'serveur' => $serveur,
'action' => isset($options['action']) ? $options['action'] : 'modifier'
@@ -231,7 +232,9 @@
foreach ($moof as $k => $v) {
if ($v !== $champs[$k]
// ne pas alerter si le champ est numerique est que les valeurs sont equivalentes
- and (!is_numeric($v) or intval($v) != intval($champs[$k]))
+ and (!is_numeric($v) or intval($v) !== intval($champs[$k]))
+ // ne pas alerter si le champ est date, qu'on a envoye une valeur vide et qu'on recupere une date nulle
+ and (strlen($champs[$k]) or !in_array($v, ['0000-00-00 00:00:00', '0000-00-00']))
) {
$liste[] = $k;
$conflits[$k]['post'] = $champs[$k];
diff -Nru spip-3.2.7/ecrire/inc/pipelines.php spip-3.2.15.1/ecrire/inc/pipelines.php
--- spip-3.2.7/ecrire/inc/pipelines.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/pipelines.php 2022-05-20 16:59:18.000000000 +0100
@@ -99,10 +99,10 @@
include_spip('inc/surligne');
if (isset($_SERVER['HTTP_REFERER'])) {
- $_SERVER['HTTP_REFERER'] = preg_replace(',[^\w\,/#&;-]+,', ' ', $_SERVER['HTTP_REFERER']);
+ $_SERVER['HTTP_REFERER'] = preg_replace(',[^\w\,/#&;:-]+,', ' ', $_SERVER['HTTP_REFERER']);
}
if ($rech){
- $rech = preg_replace(',[^\w\,/#&;-]+,', ' ', $rech);
+ $rech = preg_replace(',[^\w\,/#&;:-]+,', ' ', $rech);
}
return surligner_mots($texte, $rech);
@@ -207,6 +207,12 @@
$pos = strlen($texte);
}
$texte = substr_replace($texte, $x, $pos, 0);
+ // pas de preview en fenetre enfant
+ $x = "";
+ if (!$pos = stripos($texte, '', $pos)) {
+ $pos = -1;
+ }
+ $texte = substr_replace($texte, $x, $pos+1, 0);
}
if (isset($GLOBALS['affiche_boutons_admin']) and $GLOBALS['affiche_boutons_admin']) {
diff -Nru spip-3.2.7/ecrire/inc/plonger.php spip-3.2.15.1/ecrire/inc/plonger.php
--- spip-3.2.7/ecrire/inc/plonger.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/plonger.php 2022-05-20 16:59:18.000000000 +0100
@@ -57,8 +57,8 @@
$rec = generer_url_ecrire('plonger', "rac=$idom&exclus=$exclu&do=$do&col=" . ($col + 1));
$info = generer_url_ecrire('informer', "type=rubrique&rac=$idom&do=$do&id=");
$args = "'$idom',this,$col,'" . $GLOBALS['spip_lang_left'] . "','$info',event";
- while (list($id, $titrebrut) = each($ordre)) {
+ foreach ($ordre as $id => $titrebrut) {
$titre = supprimer_numero($titrebrut);
$classe1 = $id_rubrique ? 'petite-rubrique' : "petit-secteur";
diff -Nru spip-3.2.7/ecrire/inc/plugin.php spip-3.2.15.1/ecrire/inc/plugin.php
--- spip-3.2.7/ecrire/inc/plugin.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/plugin.php 2022-05-20 16:59:18.000000000 +0100
@@ -209,7 +209,7 @@
// cas du plugin qui n'est compatible qu'avec cette nouvelle version
}
- $minimum_inc = $intervalle{0} == "[";
+ $minimum_inc = $intervalle[0] == "[";
$maximum_inc = substr($intervalle, -1) == "]";
if (strlen($minimum)) {
@@ -699,7 +699,7 @@
$minimum = $regs[1];
$maximum = $regs[2];
- $minimum_inclus = $intervalle{0} == "[";
+ $minimum_inclus = $intervalle[0] == "[";
$maximum_inclus = substr($intervalle, -1) == "]";
if (strlen($minimum)) {
@@ -933,7 +933,7 @@
$GLOBALS['spip_version_branche'], 'spip')
) {
$dir = $chemin['path'];
- if (strlen($dir) and $dir{0} == "/") {
+ if (strlen($dir) and $dir[0] == "/") {
$dir = substr($dir, 1);
}
if (strlen($dir) and $dir == "./") {
diff -Nru spip-3.2.7/ecrire/inc/precharger_objet.php spip-3.2.15.1/ecrire/inc/precharger_objet.php
--- spip-3.2.7/ecrire/inc/precharger_objet.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/precharger_objet.php 2022-05-20 16:59:18.000000000 +0100
@@ -50,7 +50,7 @@
// si l'objet existe deja, on retourne simplement ses valeurs
if (is_numeric($id_objet)) {
- return sql_fetsel("*", $table, "$_id_objet=$id_objet");
+ return sql_fetsel("*", $table, "$_id_objet=".intval($id_objet));
}
// ici, on demande une creation.
@@ -133,7 +133,7 @@
$_id_objet = id_table_objet($table);
// Recuperer les donnees de l'objet original
- $row = sql_fetsel("*", $table, "$_id_objet=$lier_trad");
+ $row = sql_fetsel("*", $table, "$_id_objet=".intval($lier_trad));
if ($row) {
include_spip('inc/filtres');
$row[$champ_titre] = filtrer_entites(objet_T($type, 'info_nouvelle_traduction')) . ' ' . $row[$champ_titre];
@@ -172,12 +172,12 @@
$id_parent = 0;
} else {
// on cherche une rubrique soeur dans la bonne langue
- $row_rub = sql_fetsel("id_parent", "spip_rubriques", "id_rubrique=$id_rubrique");
+ $row_rub = sql_fetsel("id_parent", "spip_rubriques", "id_rubrique=".intval($id_rubrique));
$id_parent = $row_rub['id_parent'];
}
$row_rub = sql_fetsel("id_rubrique", "spip_rubriques",
- "lang='" . $GLOBALS['spip_lang'] . "' AND id_parent=$id_parent");
+ "lang='" . $GLOBALS['spip_lang'] . "' AND id_parent=".intval($id_parent));
if ($row_rub) {
$row['id_rubrique'] = $row_rub['id_rubrique'];
}
diff -Nru spip-3.2.7/ecrire/inc/prepare_recherche.php spip-3.2.15.1/ecrire/inc/prepare_recherche.php
--- spip-3.2.7/ecrire/inc/prepare_recherche.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/prepare_recherche.php 2022-05-20 16:59:18.000000000 +0100
@@ -77,14 +77,14 @@
$rechercher = false;
+ $where_resultat_recent = sql_date_proche('maj', (0 - ($delai_fraicheur + 100)), " SECOND");
if (!isset($cache[$serveur][$table][$recherche])) {
$hash_serv = ($serveur ? substr(md5($serveur), 0, 16) : '');
$hash = substr(md5($recherche . $table), 0, 16);
$where = "(resultats.recherche='$hash' AND resultats.table_objet=" . sql_quote($table) . " AND resultats.serveur='$hash_serv')";
- $row = sql_fetsel('UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(resultats.maj) AS fraicheur', 'spip_resultats AS resultats',
- $where, '', 'fraicheur DESC', '0,1');
+ $row = sql_fetsel('recherche', 'spip_resultats AS resultats',
+ $where . " AND $where_resultat_recent", '', '', '0,1');
if (!$row
- or ($row['fraicheur'] > $delai_fraicheur)
or (defined('_VAR_MODE') and _VAR_MODE == 'recalcul')
) {
$rechercher = true;
@@ -122,8 +122,9 @@
// pas de AS resultats dans un delete (mysql)
$whered = str_replace(array("resultats.recherche", "resultats.table_objet", "resultats.serveur"),
array("recherche", "table_objet", "serveur"), $where);
+
sql_delete('spip_resultats',
- 'NOT(' . sql_date_proche('maj', (0 - ($delai_fraicheur + 100)), " SECOND") . ") OR ($whered)");
+ "NOT($where_resultat_recent) OR ($whered)");
// inserer les resultats dans la table de cache des resultats
if (count($points)) {
diff -Nru spip-3.2.7/ecrire/inc/queue.php spip-3.2.15.1/ecrire/inc/queue.php
--- spip-3.2.7/ecrire/inc/queue.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/queue.php 2022-05-20 16:59:18.000000000 +0100
@@ -701,11 +701,13 @@
return $texte;
}
- // en derniere solution, on insere un appel xhr non bloquant ou une image background dans la page si pas de JS
- $url_cron = generer_url_action('cron');
- $texte = ''
- . ""
- . "";
+ if (!defined('_HTML_BG_CRON_INHIB') or !_HTML_BG_CRON_INHIB) {
+ // en derniere solution, on insere un appel xhr non bloquant ou une image background dans la page si pas de JS
+ $url_cron = generer_url_action('cron');
+ $texte = ''
+ . ""
+ . "";
+ }
return $texte;
}
diff -Nru spip-3.2.7/ecrire/inc/rubriques.php spip-3.2.15.1/ecrire/inc/rubriques.php
--- spip-3.2.7/ecrire/inc/rubriques.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/rubriques.php 2022-05-20 16:59:18.000000000 +0100
@@ -46,16 +46,43 @@
* 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 @@
} elseif (isset($modifs['id_rubrique'])) {
$neuf |= publier_branche_rubrique($modifs['id_rubrique']);
}
- } elseif (isset($modifs['statut']) and $modifs['statut'] == 'publie') {
+ } elseif (isset($modifs['statut']) and in_array($modifs['statut'], $statuts_publies)) {
if ($postdate) {
calculer_prochain_postdate(true);
$neuf |= (strtotime($postdate) <= time()); // par securite
diff -Nru spip-3.2.7/ecrire/inc/session.php spip-3.2.15.1/ecrire/inc/session.php
--- spip-3.2.7/ecrire/inc/session.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/session.php 2022-05-20 16:59:18.000000000 +0100
@@ -77,16 +77,26 @@
*/
function supprimer_sessions($id_auteur, $toutes = true, $actives = true) {
+ $nb_files = 0;
+ $nb_max_files = (defined('_MAX_NB_SESSIONS_OUVERTES') ? _MAX_NB_SESSIONS_OUVERTES : 1000);
spip_log("supprimer sessions auteur $id_auteur", "session");
if ($toutes or $id_auteur !== $GLOBALS['visiteur_session']['id_auteur']) {
if ($dir = opendir(_DIR_SESSIONS)) {
+ $t = $_SERVER['REQUEST_TIME'] - (4*_RENOUVELLE_ALEA); // 48h par defaut
+ $t_short = $_SERVER['REQUEST_TIME'] - max(_RENOUVELLE_ALEA/4,3*3600); // 3h par defaut
$t = time() - (4 * _RENOUVELLE_ALEA);
while (($f = readdir($dir)) !== false) {
+ $nb_files++;
if (preg_match(",^[^\d-]*(-?\d+)_\w{32}\.php[3]?$,", $f, $regs)) {
$f = _DIR_SESSIONS . $f;
if (($actives and $regs[1] == $id_auteur) or ($t > filemtime($f))) {
spip_unlink($f);
}
+ // si il y a trop de sessions ouvertes, on purge les sessions anonymes de plus de 3H
+ // cf http://core.spip.org/issues/3276
+ elseif ($nb_files>$nb_max_files and !intval($regs[1]) and ($t_short > filemtime($f))) {
+ spip_unlink($f);
+ }
}
}
}
diff -Nru spip-3.2.7/ecrire/inc/texte_mini.php spip-3.2.15.1/ecrire/inc/texte_mini.php
--- spip-3.2.7/ecrire/inc/texte_mini.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/texte_mini.php 2022-05-20 16:59:18.000000000 +0100
@@ -168,7 +168,7 @@
return $regs[0];
}
-define('_PROTEGE_BLOCS', ',<(html|code|cadre|frame|script|style)(\s[^>]*)?>(.*)\1>,UimsS');
+define('_PROTEGE_BLOCS', ',<(html|code|cadre|frame|script|style)(\b[^>]*)?>(.*)\1>,UimsS');
// - pour $source voir commentaire infra (echappe_retour)
// - pour $no_transform voir le filtre post_autobr dans inc/filtres
diff -Nru spip-3.2.7/ecrire/inc/utils.php spip-3.2.15.1/ecrire/inc/utils.php
--- spip-3.2.7/ecrire/inc/utils.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/utils.php 2022-05-20 16:59:18.000000000 +0100
@@ -328,9 +328,12 @@
if (!isset($regs[1]) or !$logname = $regs[1]) {
$logname = null;
}
- if (!isset($regs[2]) or !$niveau = $regs[2]) {
+ if (!isset($regs[2])) {
$niveau = _LOG_INFO;
}
+ else {
+ $niveau = intval($regs[2]);
+ }
if ($niveau <= (defined('_LOG_FILTRE_GRAVITE') ? _LOG_FILTRE_GRAVITE : _LOG_INFO_IMPORTANTE)) {
if (!$pre) {
@@ -446,6 +449,43 @@
return false; # n'affecte pas $c
}
+/**
+ * Sanitizer une valeur *SI* elle provient du GET ou POST
+ * Utile dans les squelettes pour les valeurs qu'on attrape dans le env,
+ * dont on veut permettre à un squelette de confiance appelant de fournir une valeur complexe
+ * mais qui doit etre nettoyee si elle provient de l'URL
+ *
+ * On peut sanitizer
+ * - une valeur simple : `$where = spip_sanitize_from_request($value, 'where')`
+ * - un tableau en partie : `$env = spip_sanitize_from_request($env, ['key1','key2'])`
+ * - un tableau complet : `$env = spip_sanitize_from_request($env, '*')`
+ *
+ * @param string|array $value
+ * @param string|array $key
+ * @param string $sanitize_function
+ * @return array|mixed|string
+ */
+function spip_sanitize_from_request($value, $key, $sanitize_function='entites_html') {
+ if (is_array($value)) {
+ if ($key=='*') {
+ $key = array_keys($value);
+ }
+ if (!is_array($key)) {
+ $key = [$key];
+ }
+ foreach ($key as $k) {
+ if (!empty($value[$k])) {
+ $value[$k] = spip_sanitize_from_request($value[$k], $k, $sanitize_function);
+ }
+ }
+ return $value;
+ }
+ // si la valeur vient des GET ou POST on la sanitize
+ if (!empty($value) and $value == _request($key)) {
+ $value = $sanitize_function($value);
+ }
+ return $value;
+}
/**
* Tester si une URL est absolue
@@ -512,7 +552,12 @@
$a = './';
}
- $regexp = ',^(' . str_replace('[]', '\[\]', $c) . '[[]?[]]?)(=.*)?$,';
+ // preparer la regexp de maniere securisee
+ $regexp = explode('|', $c);
+ foreach ($regexp as $r => $e) {
+ $regexp[$r] = str_replace('[]', '\[\]', preg_replace(',[^\w\d\[\]-],', '', $e));
+ }
+ $regexp = ',^(' . implode('|', $regexp) . '[[]?[]]?)(=.*)?$,';
$ajouts = array_flip(explode('|', $c));
$u = is_array($v) ? $v : rawurlencode($v);
$testv = (is_array($v) ? count($v) : strlen($v));
@@ -563,7 +608,7 @@
} else {
$id = (substr($k, -2) == '[]') ? $k : ($k . "[]");
foreach ($v as $w) {
- $url[] = $id . '=' . (is_array($w) ? 'Array' : $w);
+ $url[] = $id . '=' . (is_array($w) ? 'Array' : rawurlencode($w));
}
}
}
@@ -865,7 +910,7 @@
}
if (($GLOBALS['test_i18n'] or (_request('var_mode') == 'traduction')) and is_null($options['class'])) {
- return "$text";
+ return "$text";
} else {
return $text;
}
@@ -1891,7 +1936,11 @@
}
// note : HTTP_HOST contient le :port si necessaire
- $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null;
+ if ($host = (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null)) {
+ // Filtrer $host pour proteger d'attaques d'entete HTTP
+ $host = (filter_var($host, FILTER_SANITIZE_URL) ?: null);
+ }
+
// si on n'a pas trouvé d'hôte du tout, en dernier recours on utilise adresse_site comme fallback
if (is_null($host) and isset($GLOBALS['meta']['adresse_site'])) {
$host = $GLOBALS['meta']['adresse_site'];
@@ -1931,6 +1980,9 @@
}
}
+ // Et nettoyer l'url
+ $GLOBALS['REQUEST_URI'] = (filter_var($GLOBALS['REQUEST_URI'], FILTER_SANITIZE_URL) ?: '');
+
$url[$profondeur] = url_de_($http, $host, $GLOBALS['REQUEST_URI'], $profondeur);
return $url[$profondeur];
@@ -2065,6 +2117,9 @@
* Nom du fichier (constante _SPIP_SCRIPT), sinon nom par défaut
**/
function get_spip_script($default = '') {
+ if (!defined('_SPIP_SCRIPT')) {
+ return 'spip.php';
+ }
# cas define('_SPIP_SCRIPT', '');
if (_SPIP_SCRIPT) {
return _SPIP_SCRIPT;
@@ -2704,9 +2759,11 @@
// les anciens IIS n'acceptent pas les POST sur ecrire/ (#419)
// meme pb sur thttpd cf. http://forum.spip.net/fr_184153.html
if (!defined('_SPIP_ECRIRE_SCRIPT')) {
- define('_SPIP_ECRIRE_SCRIPT', (empty($_SERVER['SERVER_SOFTWARE']) ? '' :
- preg_match(',IIS|thttpd,', $_SERVER['SERVER_SOFTWARE']) ?
- 'index.php' : ''));
+ if (!empty($_SERVER['SERVER_SOFTWARE']) and preg_match(',IIS|thttpd,', $_SERVER['SERVER_SOFTWARE'])) {
+ define('_SPIP_ECRIRE_SCRIPT', 'index.php');
+ } else {
+ define('_SPIP_ECRIRE_SCRIPT', '');
+ }
}
@@ -2912,13 +2969,17 @@
}
} // pas autorise ?
else {
- // si on n'est pas connecte on se redirige
- if (!$GLOBALS['visiteur_session']) {
- include_spip('inc/headers');
- redirige_par_entete(generer_url_public('login',
- 'url=' . rawurlencode(
- parametre_url(self(), 'var_mode', $_GET['var_mode'], '&')
- ), true));
+ // si on n'est pas connecte on se redirige, si on est pas en cli et pas deja en train de se loger
+ if (!$GLOBALS['visiteur_session']
+ and !empty($_SERVER['HTTP_HOST'])
+ and !empty($_SERVER['REQUEST_METHOD'])
+ and $_SERVER['REQUEST_METHOD'] === 'GET') {
+ $self = self('&', true);
+ if (strpos($self, 'page=login') === false) {
+ include_spip('inc/headers');
+ $redirect = parametre_url(self('&', true), 'var_mode', $_GET['var_mode'], '&');
+ redirige_par_entete(generer_url_public('login','url=' . rawurlencode($redirect), true));
+ }
}
// sinon tant pis
}
@@ -3125,7 +3186,29 @@
include_spip('inc/autoriser');
if (autoriser('webmestre')) {
+ $cookies_masques = ['spip_session', 'PHPSESSID'];
+ $cookies_backup = [];
+ $server_backup = ['HTTP_COOKIE' => $_SERVER['HTTP_COOKIE']];
+ $env_backup = ['HTTP_COOKIE' => $_ENV['HTTP_COOKIE']];
+ $mask = '******************************';
+ foreach ($cookies_masques as $k) {
+ if (!empty($_COOKIE[$k])) {
+ $cookies_backup[$k] = $_COOKIE[$k];
+ $_SERVER['HTTP_COOKIE'] = str_replace("$k=".$_COOKIE[$k], "$k=$mask", $_SERVER['HTTP_COOKIE']);
+ $_ENV['HTTP_COOKIE'] = str_replace("$k=".$_COOKIE[$k], "$k=$mask", $_ENV['HTTP_COOKIE']);
+ $_COOKIE[$k] = $mask;
+ }
+ }
phpinfo();
+ foreach ($cookies_backup as $k => $v) {
+ $_COOKIE[$k] = $v;
+ }
+ foreach ($server_backup as $k => $v) {
+ $_SERVER[$k] = $v;
+ }
+ foreach ($env_backup as $k => $v) {
+ $_ENV[$k] = $v;
+ }
} else {
include_spip('inc/filtres');
sinon_interdire_acces();
@@ -3585,4 +3668,21 @@
}
}
-}
\ No newline at end of file
+}
+
+/**
+ * Nettoie une chaine pour servir comme classes CSS.
+ *
+ * @note
+ * les classes CSS acceptent théoriquement tous les caractères sauf NUL.
+ * Ici, on limite (enlève) les caractères autres qu’alphanumérique, espace, - + _ @
+ *
+ * @param string|string[] $classes
+ * @return string|string[]
+ */
+function spip_sanitize_classname($classes) {
+ if (is_array($classes)) {
+ return array_map('spip_sanitize_classname', $classes);
+ }
+ return preg_replace("/[^ 0-9a-z_\-+@]/i", "", $classes);
+}
diff -Nru spip-3.2.7/ecrire/inc/xml.php spip-3.2.15.1/ecrire/inc/xml.php
--- spip-3.2.7/ecrire/inc/xml.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc/xml.php 2022-05-20 16:59:18.000000000 +0100
@@ -212,13 +212,12 @@
function spip_xml_decompose_tag($tag) {
$tagname = spip_xml_tagname($tag);
$liste = array();
- $p = strpos($tag, ' ');
- $tag = substr($tag, $p);
+ $tag = ltrim(strpbrk($tag, " \n\t"));
$p = strpos($tag, '=');
while ($p !== false) {
$attr = trim(substr($tag, 0, $p));
$tag = ltrim(substr($tag, $p + 1));
- $quote = $tag{0};
+ $quote = $tag[0];
$p = strpos($tag, $quote, 1);
$cont = substr($tag, 1, $p - 1);
$liste[$attr] = $cont;
diff -Nru spip-3.2.7/ecrire/inc_version.php spip-3.2.15.1/ecrire/inc_version.php
--- spip-3.2.7/ecrire/inc_version.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/inc_version.php 2022-05-20 16:59:18.000000000 +0100
@@ -374,18 +374,18 @@
// 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.7";
-define('_SPIP_VERSION_ID', 30207);
+$spip_version_branche = "3.2.15";
+define('_SPIP_VERSION_ID', 30215);
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 = 20220413;
// 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;
@@ -468,6 +468,13 @@
define('_OUTILS_DEVELOPPEURS', false);
}
+if (!defined('_CACHE_CONTEXTES_AJAX_SUR_LONGUEUR')) {
+ /**
+ * Basculer les contextes ajax en fichier si la longueur d’url est trop grande
+ * @var int Nombre de caractères */
+ define('_CACHE_CONTEXTES_AJAX_SUR_LONGUEUR', 2000);
+}
+
// charger systematiquement inc/autoriser dans l'espace restreint
if (test_espace_prive()) {
include_spip('inc/autoriser');
diff -Nru spip-3.2.7/ecrire/index.php spip-3.2.15.1/ecrire/index.php
--- spip-3.2.7/ecrire/index.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/index.php 2022-05-20 16:59:18.000000000 +0100
@@ -147,9 +147,9 @@
// compatibilite ascendante : obsolete, ne plus utiliser
$GLOBALS['spip_display'] = isset($GLOBALS['visiteur_session']['prefs']['display'])
- ? $GLOBALS['visiteur_session']['prefs']['display']
+ ? (int) $GLOBALS['visiteur_session']['prefs']['display']
: 0;
-$GLOBALS['spip_ecran'] = isset($_COOKIE['spip_ecran']) ? $_COOKIE['spip_ecran'] : "etroit";
+$GLOBALS['spip_ecran'] = isset($_COOKIE['spip_ecran']) ? preg_replace('/[^a-z0-9]/i', '', $_COOKIE['spip_ecran']) : "etroit";
// si la langue est specifiee par cookie et ne correspond pas
// (elle a ete changee dans une autre session, et on retombe sur un vieux cookie)
diff -Nru spip-3.2.7/ecrire/install/etape_3.php spip-3.2.15.1/ecrire/install/etape_3.php
--- spip-3.2.7/ecrire/install/etape_3.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/install/etape_3.php 2022-05-20 16:59:18.000000000 +0100
@@ -370,7 +370,7 @@
$hidden = predef_ou_cache($adresse_db, $login_db, $pass_db, $server_db)
. (defined('_INSTALL_NAME_DB') ? ''
- : "\n");
+ : "\n");
$auteur_obligatoire = ($ldap_present ? 0 : !sql_countsel('spip_auteurs', '', '', '', $server_db));
diff -Nru spip-3.2.7/ecrire/install/etape_chmod.php spip-3.2.15.1/ecrire/install/etape_chmod.php
--- spip-3.2.7/ecrire/install/etape_chmod.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/install/etape_chmod.php 2022-05-20 16:59:18.000000000 +0100
@@ -76,7 +76,7 @@
$test_dir = _request('test_dir');
$chmod = 0;
- if ($test_dir) {
+ if ($test_dir and strpos($test_dir, '..') === false) {
if (substr($test_dir, -1) !== '/') {
$test_dir .= '/';
}
@@ -93,7 +93,7 @@
$bad_dirs = array();
$absent_dirs = array();
- while (list(, $my_dir) = each($GLOBALS['test_dirs'])) {
+ foreach ($GLOBALS['test_dirs'] as $i => $my_dir) {
$test = test_ecrire($my_dir);
if (!$test) {
$m = preg_replace(',^' . _DIR_RACINE . ',', '', $my_dir);
diff -Nru spip-3.2.7/ecrire/install/etape_ldap2.php spip-3.2.15.1/ecrire/install/etape_ldap2.php
--- spip-3.2.7/ecrire/install/etape_ldap2.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/install/etape_ldap2.php 2022-05-20 16:59:18.000000000 +0100
@@ -42,8 +42,15 @@
$tls = true;
}
}
+ else {
+ $tls_ldap == 'non';
+ }
+
+ // Verifions que l'adresse demandee est valide
+ $adresse_ldap = filter_var($adresse_ldap, FILTER_SANITIZE_URL) ?: '';
+
$ldap_link = ldap_connect($adresse_ldap, $port_ldap);
- $erreur = "ldap_connect($adresse_ldap, $port_ldap)";
+ $erreur = "ldap_connect(".spip_htmlspecialchars($adresse_ldap).", ".spip_htmlspecialchars($port_ldap).")";
if ($ldap_link) {
if (!ldap_set_option($ldap_link, LDAP_OPT_PROTOCOL_VERSION, $protocole_ldap)) {
@@ -52,13 +59,19 @@
}
if ($tls === true) {
if (!ldap_start_tls($ldap_link)) {
- $erreur = "ldap_start_tls($ldap_link) $adresse_ldap, $port_ldap";
+ $erreur = "ldap_start_tls(".spip_htmlspecialchars($ldap_link)
+ ." ".spip_htmlspecialchars($adresse_ldap)
+ .", ".spip_htmlspecialchars($port_ldap).")";
$ldap_link = false;
}
}
if ($ldap_link) {
$ldap_link = ldap_bind($ldap_link, $login_ldap, $pass_ldap);
- $erreur = "ldap_bind('$ldap_link', '$login_ldap', '$pass_ldap'): $adresse_ldap, $port_ldap";
+ $erreur = "ldap_bind('".spip_htmlspecialchars($ldap_link)
+ ."', '".spip_htmlspecialchars($login_ldap)
+ ."', '".spip_htmlspecialchars($pass_ldap)
+ ."'): ".spip_htmlspecialchars($adresse_ldap)
+ .", ".spip_htmlspecialchars($port_ldap);
}
}
@@ -69,12 +82,12 @@
), _T('info_connexion_ldap_ok');
echo generer_form_ecrire('install', (
"\n"
- . "\n"
- . "\n"
- . "\n"
- . "\n"
- . "\n"
- . "\n"
+ . "\n"
+ . "\n"
+ . "\n"
+ . "\n"
+ . "\n"
+ . "\n"
. bouton_suivant()));
} else {
echo info_etape(_T('titre_connexion_ldap')), info_progression_etape(1, 'etape_ldap', 'install/', true),
diff -Nru spip-3.2.7/ecrire/iterateur/data.php spip-3.2.15.1/ecrire/iterateur/data.php
--- spip-3.2.7/ecrire/iterateur/data.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/iterateur/data.php 2022-05-20 16:59:18.000000000 +0100
@@ -127,7 +127,9 @@
*/
public function rewind() {
reset($this->tableau);
- list($this->cle, $this->valeur) = each($this->tableau);
+ $this->cle = key($this->tableau);
+ $this->valeur = current($this->tableau);
+ next($this->tableau);
}
/**
@@ -433,7 +435,7 @@
*
**/
protected function select_datapath() {
- list(, $base) = each($this->command['datapath']);
+ $base = reset($this->command['datapath']);
if (strlen($base = ltrim(trim($base), "/"))) {
$this->tableau = table_valeur($this->tableau, $base);
if (!is_array($this->tableau)) {
@@ -486,17 +488,17 @@
$a = ' . sprintf($tv, '$aa') . ';
$b = ' . sprintf($tv, '$bb') . ';
if ($a <> $b)
- return ($a ' . ((isset($r[2]) and $r[2]) ? '>' : '<') . ' $b) ? -1 : 1;';
+ return ($a ' . (!empty($r[2]) ? '>' : '<') . ' $b) ? -1 : 1;';
}
}
}
}
if ($sortfunc) {
- uasort($this->tableau, create_function('$aa,$bb',
- $sortfunc . '
- return 0;'
- ));
+ $sortfunc .= "\n return 0;";
+ uasort($this->tableau, function($aa, $bb) use ($sortfunc) {
+ return eval($sortfunc);
+ });
}
}
@@ -556,7 +558,9 @@
*/
public function next() {
if ($this->valid()) {
- list($this->cle, $this->valeur) = each($this->tableau);
+ $this->cle = key($this->tableau);
+ $this->valeur = current($this->tableau);
+ next($this->tableau);
}
}
@@ -680,9 +684,7 @@
* @return array|bool
*/
function inc_json_to_array_dist($u) {
- if (is_array($json = json_decode($u))
- or is_object($json)
- ) {
+ if (is_array($json = json_decode($u, true))) {
return (array)$json;
}
}
diff -Nru spip-3.2.7/ecrire/maj/svn10000.php spip-3.2.15.1/ecrire/maj/svn10000.php
--- spip-3.2.7/ecrire/maj/svn10000.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/maj/svn10000.php 2022-05-20 16:59:18.000000000 +0100
@@ -670,7 +670,7 @@
/**
* 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'][23375] = array(
array('sql_alter', "TABLE spip_auteurs CHANGE prefs prefs text"),
);
+
+// adaptation des timestamp mysql
+$GLOBALS['maj'][24379] = [['maj_timestamp_mysql']];
+
+/**
+ * Mise à jour des bdd Mysql pour réparer les timestamp auto-update absents
+ *
+ * @uses base_lister_toutes_tables()
+ * @uses _mysql_remplacements_definitions_table()
+ **/
+function maj_timestamp_mysql($tables = null) {
+
+ include_spip('base/dump');
+ if (is_null($tables)) {
+ $tables = base_lister_toutes_tables();
+ } elseif (is_string($tables)) {
+ $tables = [$tables];
+ } elseif (!is_array($tables)) {
+ return;
+ }
+
+ // rien a faire si base non mysql
+ if (strncmp($GLOBALS['connexions'][0]['type'], 'mysql', 5) !== 0) {
+ return;
+ }
+
+ $trouver_table = charger_fonction('trouver_table', 'base');
+ // forcer le vidage de cache
+ $trouver_table('');
+
+ foreach ($tables as $table) {
+ if (time() >= _TIME_OUT) {
+ return;
+ }
+ if ($desc = $trouver_table($table)) {
+ $fields_corrected = _mysql_remplacements_definitions_table($desc['field']);
+ $d = array_diff($desc['field'], $fields_corrected);
+ if ($d) {
+ spip_log("Table $table TIMESTAMP incorrect", "maj");
+ foreach ($desc['field'] as $field => $type) {
+ if ($desc['field'][$field] !== $fields_corrected[$field]) {
+ spip_log("Adaptation TIMESTAMP table $table", "maj." . _LOG_INFO_IMPORTANTE);
+ sql_alter("table $table change $field $field " . $fields_corrected[$field]);
+ $trouver_table('');
+ $new_desc = $trouver_table($table);
+ spip_log("Apres conversion $table : " . var_export($new_desc['field'], true),
+ "maj." . _LOG_INFO_IMPORTANTE);
+ }
+ }
+ }
+ }
+ }
+
+ // forcer le vidage de cache
+ $trouver_table('');
+}
\ No newline at end of file
diff -Nru spip-3.2.7/ecrire/paquet.xml spip-3.2.15.1/ecrire/paquet.xml
--- spip-3.2.7/ecrire/paquet.xml 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/paquet.xml 2022-05-20 16:59:18.000000000 +0100
@@ -1,10 +1,10 @@
false));
}
- return propre($texte);
+ return $propre($texte);
+}
+
+function plugin_typo($texte, $module = '') {
+ return plugin_propre($texte, $module, 'typo');
}
diff -Nru spip-3.2.7/ecrire/public/aiguiller.php spip-3.2.15.1/ecrire/public/aiguiller.php
--- spip-3.2.7/ecrire/public/aiguiller.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/public/aiguiller.php 2022-05-20 16:59:18.000000000 +0100
@@ -15,6 +15,13 @@
}
function securiser_redirect_action($redirect) {
+ // cas d'un double urlencode : si un urldecode de l'url n'est pas secure, on retient ca comme redirect
+ if (strpos($redirect, '%') !== false) {
+ $r2 = urldecode($redirect);
+ if (($r3 = securiser_redirect_action($r2)) !== $r2) {
+ return $r3;
+ }
+ }
if ((tester_url_absolue($redirect) or preg_match(',^\w+:,',trim($redirect)))
and !defined('_AUTORISER_ACTION_ABS_REDIRECT')) {
// si l'url est une url du site, on la laisse passer sans rien faire
@@ -142,7 +149,7 @@
}
} else {
include_spip('inc/headers');
- http_status(403);
+ http_status(400);
$texte = _L('signature ajax bloc incorrecte');
}
ajax_retour($texte, false);
@@ -176,9 +183,30 @@
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 {
diff -Nru spip-3.2.7/ecrire/public/assembler.php spip-3.2.15.1/ecrire/public/assembler.php
--- spip-3.2.7/ecrire/public/assembler.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/public/assembler.php 2022-05-20 16:59:18.000000000 +0100
@@ -345,6 +345,8 @@
// 4: langue
function inserer_balise_dynamique($contexte_exec, $contexte_compil) {
+ arguments_balise_dyn_depuis_modele(null, 'reset');
+
if (!is_array($contexte_exec)) {
echo $contexte_exec;
} // message d'erreur etc
@@ -457,6 +459,29 @@
return $page;
}
+/**
+ * gerer le flag qui permet de reperer qu'une balise dynamique a ete inseree depuis un modele
+ * utilisee dans les #FORMULAIRE_xx
+ *
+ * @param string|null $arg
+ * @param string $operation
+ * @return mixed
+ */
+function arguments_balise_dyn_depuis_modele($arg, $operation = 'set') {
+ static $balise_dyn_appellee_par_modele = null;
+ switch ($operation) {
+ case 'read':
+ return $balise_dyn_appellee_par_modele;
+ case 'reset':
+ $balise_dyn_appellee_par_modele = null;
+ return null;
+ case 'set':
+ default:
+ $balise_dyn_appellee_par_modele = $arg;
+ return $arg;
+ }
+}
+
// temporairement ici : a mettre dans le futur inc/modeles
// creer_contexte_de_modele('left', 'autostart=true', ...) renvoie un array()
// http://code.spip.net/@creer_contexte_de_modele
@@ -512,11 +537,10 @@
$params = array_filter(explode('|', $params));
if ($params) {
- list(, $soustype) = each($params);
+ $soustype = current($params);
$soustype = strtolower(trim($soustype));
- if (in_array($soustype,
- array('left', 'right', 'center', 'ajax'))) {
- list(, $soustype) = each($params);
+ if (in_array($soustype, array('left', 'right', 'center', 'ajax'))) {
+ $soustype = next($params);
$soustype = strtolower($soustype);
}
diff -Nru spip-3.2.7/ecrire/public/balises.php spip-3.2.15.1/ecrire/public/balises.php
--- spip-3.2.7/ecrire/public/balises.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/public/balises.php 2022-05-20 16:59:18.000000000 +0100
@@ -395,7 +395,7 @@
* @see spip_version()
* @example
* ```
- *
+ * []
* ```
*
* @param Champ $p
@@ -1158,7 +1158,7 @@
// si true, les arguments simples (sans truc=chose) vont degager
$_contexte = argumenter_inclure($p->param, true, $p, $p->boucles, $p->id_boucle, false, false);
if (count($_contexte)) {
- list($key, $val) = each($_contexte);
+ $key = key($_contexte);
if (is_numeric($key)) {
array_shift($_contexte);
$__modele = interprete_argument_balise(1, $p);
@@ -1728,6 +1728,19 @@
return $p;
}
+/**
+ * Une balise #NULL quand on a besoin de passer un argument null sur l'appel d'un filtre ou formulaire
+ * (evite un #EVAL{null})
+ * @param $p
+ * @return mixed
+ */
+function balise_NULL_dist($p) {
+ $p->code = "null";
+ $p->interdire_scripts = false;
+
+ return $p;
+}
+
/**
* Compile la balise `#HTTP_HEADER` envoyant des entêtes de retour HTTP
@@ -2549,6 +2562,8 @@
value=\'' . $_form . '\' />' .
'' .
+ '' .
(!empty(\$Pile[0]['_hidden']) ? @\$Pile[0]['_hidden'] : '') .
''";
diff -Nru spip-3.2.7/ecrire/public/compiler.php spip-3.2.15.1/ecrire/public/compiler.php
--- spip-3.2.7/ecrire/public/compiler.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/public/compiler.php 2022-05-20 16:59:18.000000000 +0100
@@ -1194,7 +1194,13 @@
$i++;
}
$squelette = preg_replace_callback(',\\\\([#[()\]{}<>]),',
- create_function('$a', "return '$inerte-'.ord(\$a[1]).'-';"), $squelette, -1, $esc);
+ function($a) use ($inerte) {
+ return "$inerte-" . ord($a[1]) . '-';
+ },
+ $squelette,
+ -1,
+ $esc
+ );
$descr = array(
'nom' => $nom,
@@ -1215,11 +1221,20 @@
// restituer les echappements
if ($esc) {
foreach ($boucles as $i => $boucle) {
- $boucles[$i]->return = preg_replace_callback(",$inerte-(\d+)-,", create_function('$a', 'return chr($a[1]);'),
- $boucle->return);
- $boucles[$i]->descr['squelette'] = preg_replace_callback(",$inerte-(\d+)-,",
- create_function('$a', 'return "\\\\".chr($a[1]);'),
- $boucle->descr['squelette']);
+ $boucles[$i]->return = preg_replace_callback(
+ ",$inerte-(\d+)-,",
+ function($a) {
+ return chr($a[1]);
+ },
+ $boucle->return
+ );
+ $boucles[$i]->descr['squelette'] = preg_replace_callback(
+ ",$inerte-(\d+)-,",
+ function($a) {
+ return "\\\\" . chr($a[1]);
+ },
+ $boucle->descr['squelette']
+ );
}
}
diff -Nru spip-3.2.7/ecrire/public/composer.php spip-3.2.15.1/ecrire/public/composer.php
--- spip-3.2.7/ecrire/public/composer.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/public/composer.php 2022-05-20 16:59:18.000000000 +0100
@@ -399,11 +399,23 @@
if (strncmp($file, "/", 1) !== 0) {
$file = './" . _DIR_RACINE . "' . $file;
}
+
+ $lang = $context_compil[4];
+ if (preg_match(",\W,", $lang)) {
+ $lang = '';
+ }
+
+ $args = array_map('argumenter_squelette', $args);
+ if (!empty($context_compil['appel_php_depuis_modele'])) {
+ $args[0] = 'arguments_balise_dyn_depuis_modele('.$args[0].')';
+ }
+ $args = join(', ', $args);
+
$r = sprintf(CODE_INCLURE_BALISE,
$file,
- $context_compil[4] ? $context_compil[4] : '',
+ $lang,
$nom,
- join(', ', array_map('argumenter_squelette', $args)),
+ $args,
join(', ', array_map('_q', $context_compil)));
return $r;
@@ -467,6 +479,16 @@
$nomfonction = $nom;
$nomfonction_generique = "";
+ $appel_php_depuis_modele = false;
+ if (is_array($context_compil)
+ and !is_numeric($context_compil[3])
+ and empty($context_compil[0])
+ and empty($context_compil[1])
+ and empty($context_compil[2])
+ and empty($context_compil[3])) {
+ $appel_php_depuis_modele = true;
+ }
+
// Calculer un nom générique (ie. 'formulaire_' dans 'formulaire_editer_article')
if (false !== ($p = strpos($nom, "_"))) {
$nomfonction_generique = substr($nom, 0, $p + 1);
@@ -526,6 +548,9 @@
}
}
+ if ($appel_php_depuis_modele) {
+ $context_compil['appel_php_depuis_modele'] = true;
+ }
return synthetiser_balise_dynamique($nomfonction, $r, $file, $context_compil);
}
@@ -954,7 +979,8 @@
// penser a regarder aussi la clause groubpy pour ne pas simplifier abusivement
// #TOTAL_BOUCLE/B10>
- list($t, $c) = each($from);
+ $t = key($from);
+ $c = current($from);
reset($from);
$e = '/\b(' . "$t\\." . join("|" . $t . '\.', $equiv) . ')\b/';
if (!(strpos($t, ' ') or // jointure des le depart cf boucle_doc
@@ -966,8 +992,8 @@
calculer_jointnul($t, $having, $e))
&& count($afrom[$t])
) {
- reset($afrom[$t]);
- list($nt, $nfrom) = each($afrom[$t]);
+ $nfrom = reset($afrom[$t]);
+ $nt = key($afrom[$t]);
unset($from[$t]);
$from[$nt] = $nfrom[1];
unset($afrom[$t][$nt]);
diff -Nru spip-3.2.7/ecrire/public/criteres.php spip-3.2.15.1/ecrire/public/criteres.php
--- spip-3.2.7/ecrire/public/criteres.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/public/criteres.php 2022-05-20 16:59:18.000000000 +0100
@@ -547,10 +547,6 @@
$boucle->id_table . '.' . $boucle->primary
. "', lister_objets_avec_logos('" . $boucle->primary . "'), '')";
- if ($crit->cond) {
- $c = "($arg ? $c : 1)";
- }
-
if ($not) {
$boucle->where[] = array("'NOT'", $c);
} else {
@@ -1563,11 +1559,11 @@
if (isset($crit->param[0])) {
$_where = calculer_liste($crit->param[0], array(), $boucles, $boucle->id_parent);
} else {
- $_where = '@$Pile[0]["where"]';
+ $_where = 'spip_sanitize_from_request(@$Pile[0]["where"],"where","vide")';
}
if ($crit->cond) {
- $_where = "(($_where) ? ($_where) : '')";
+ $_where = "((\$zzw = $_where) ? \$zzw : '')";
}
if ($crit->not) {
@@ -2412,7 +2408,7 @@
* - nom de la colonne de date (si le calcul n'est pas relatif)
**/
function calculer_critere_infixe_date($idb, &$boucles, $col) {
- if (!preg_match(",^((age|jour|mois|annee)_relatif|date|mois|annee|jour|heure|age)(_[a-z]+)?$,", $col, $regs)) {
+ if (!preg_match(",^((age|jour|mois|annee)_relatif|date|mois|annee|jour|heure|age)(_[a-z_]+)?$,", $col, $regs)) {
return '';
}
diff -Nru spip-3.2.7/ecrire/public/debusquer.php spip-3.2.15.1/ecrire/public/debusquer.php
--- spip-3.2.7/ecrire/public/debusquer.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/public/debusquer.php 2022-05-20 16:59:18.000000000 +0100
@@ -123,8 +123,9 @@
}
lang_select($GLOBALS['visiteur_session']['lang']);
- $fonc = _request('var_mode_objet');
- $mode = _request('var_mode_affiche');
+ $fonc = preg_replace(",\W,", "_", _request('var_mode_objet') ?? '');
+ $mode = preg_replace(",\W,", "_", _request('var_mode_affiche') ?? '');
+
$self = str_replace("\\'", ''', self());
$self = parametre_url($self, 'var_mode', 'debug');
@@ -816,7 +817,7 @@
html_lang_attributes() .
"\n" .
('SPIP ' . $GLOBALS['spip_version_affichee'] . ' ' .
- _T('admin_debug') . ' ' . $titre . ' (' .
+ _T('admin_debug') . ' ' . spip_htmlspecialchars($titre) . ' (' .
supprimer_tags(corriger_typo($GLOBALS['meta']['nom_site']))) .
")\n" .
" 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 @@
// $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('. _TRAITEMENT_TYPO_SANS_NUMERO.')';
$GLOBALS['table_des_traitements']['CHAPO'][] = _TRAITEMENT_RACCOURCIS;
$GLOBALS['table_des_traitements']['DATE'][] = 'normaliser_date(%s)';
$GLOBALS['table_des_traitements']['DATE_REDAC'][] = 'normaliser_date(%s)';
diff -Nru spip-3.2.7/ecrire/public/iterateur.php spip-3.2.15.1/ecrire/public/iterateur.php
--- spip-3.2.7/ecrire/public/iterateur.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/public/iterateur.php 2022-05-20 16:59:18.000000000 +0100
@@ -279,7 +279,7 @@
// * 3 : {x op y} ; on recoit $v[0] = 'op', $v[1] = x, $v[2] = y
// 1 : forcement traite par un critere, on passe
- if (count($v) == 1) {
+ if (!$v or count($v) == 1) {
continue;
}
if (count($v) == 2 and is_array($v[1])) {
@@ -300,7 +300,10 @@
// Creer la fonction de filtrage sur $this
if ($this->filtre) {
- $this->func_filtre = create_function('$me', $b = 'return (' . join(') AND (', $this->filtre) . ');');
+ $filtres = 'return (' . join(') AND (', $this->filtre) . ');';
+ $this->func_filtre = function () use ($filtres) {
+ return eval($filtres);
+ };
}
}
@@ -320,7 +323,7 @@
# if (!in_array($cle, array('cle', 'valeur')))
# return;
- $a = '$me->get_select(\'' . $cle . '\')';
+ $a = '$this->get_select(\'' . $cle . '\')';
$filtre = '';
@@ -566,7 +569,7 @@
**/
public function accept() {
if ($f = $this->func_filtre) {
- return $f($this);
+ return $f();
}
return true;
diff -Nru spip-3.2.7/ecrire/public/quete.php spip-3.2.15.1/ecrire/public/quete.php
--- spip-3.2.7/ecrire/public/quete.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/public/quete.php 2022-05-20 16:59:18.000000000 +0100
@@ -669,7 +669,7 @@
$pos++;
}
// si on a pas trouve
- if ($row[$primary] != $valeur) {
+ if (!$row or $row[$primary] != $valeur) {
return 0;
}
diff -Nru spip-3.2.7/ecrire/public/references.php spip-3.2.15.1/ecrire/public/references.php
--- spip-3.2.7/ecrire/public/references.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/public/references.php 2022-05-20 16:59:18.000000000 +0100
@@ -98,6 +98,9 @@
$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 @@
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,17 +705,33 @@
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"
if ($table_sql and isset($ps[$table_sql])) {
$ps = $ps[$table_sql];
} // ou pour une boucle en particulier "DATA","articles"
elseif ($type_requete and isset($ps[$type_requete])) {
$ps = $ps[$type_requete];
- } // ou pour indiferrement quelle que soit la boucle
+ } // 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];
} else {
diff -Nru spip-3.2.7/ecrire/public/tracer.php spip-3.2.15.1/ecrire/public/tracer.php
--- spip-3.2.7/ecrire/public/tracer.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/public/tracer.php 2022-05-20 16:59:18.000000000 +0100
@@ -129,6 +129,7 @@
foreach ($temps as $k => $v) {
$titre = strip_tags($v[2]);
$href = quote_amp($GLOBALS['REQUEST_URI']) . "#req$i";
+ $href = str_replace("\\'", ''', $href);
if (!isset($t[$v[2]])) {
$t[$v[2]] = array();
diff -Nru spip-3.2.7/ecrire/req/mysql.php spip-3.2.15.1/ecrire/req/mysql.php
--- spip-3.2.7/ecrire/req/mysql.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/req/mysql.php 2022-05-20 16:59:18.000000000 +0100
@@ -243,7 +243,7 @@
if (defined('_DEBUG_SLOW_QUERIES') and _DEBUG_SLOW_QUERIES) {
if (isset($GLOBALS['debug']['aucasou'])) {
list(, $id, , $infos) = $GLOBALS['debug']['aucasou'];
- $debug .= "BOUCLE$id @ " . $infos[0] . " | ";
+ $debug .= "BOUCLE$id @ " . (isset($infos[0]) ? $infos[0] : '') . " | ";
}
$debug .= $_SERVER['REQUEST_URI'] . ' + ' . $GLOBALS['ip'];
$debug = ' /* ' . mysqli_real_escape_string($link, str_replace('*/', '@/', $debug)) . ' */';
@@ -524,9 +524,10 @@
* @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 @@
// 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 @@
/**
* 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 @@
$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;
}
@@ -1543,12 +1562,13 @@
* Expression SQL
**/
function spip_mysql_date_proche($champ, $interval, $unite) {
+ $use_now = ( ($champ === 'maj' or strpos($champ, '.maj')) ? true : false );
return '('
. $champ
. (($interval <= 0) ? '>' : '<')
. (($interval <= 0) ? 'DATE_SUB' : 'DATE_ADD')
. '('
- . sql_quote(date('Y-m-d H:i:s'))
+ . ($use_now ? 'NOW()' : sql_quote(date('Y-m-d H:i:s')))
. ', INTERVAL '
. (($interval > 0) ? $interval : (0 - $interval))
. ' '
@@ -1680,7 +1700,8 @@
$nom = "$bd:$prefixe:$nom" . _LOCK_TIME;
$connexion['last'] = $q = "SELECT GET_LOCK(" . _q($nom) . ", $timeout) AS n";
- $q = @sql_fetch(mysql_query($q));
+
+ $q = @sql_fetch(mysqli_query(_mysql_link(), $q));
if (!$q) {
spip_log("pas de lock sql pour $nom", _LOG_ERREUR);
}
diff -Nru spip-3.2.7/ecrire/req/sqlite_generique.php spip-3.2.15.1/ecrire/req/sqlite_generique.php
--- spip-3.2.7/ecrire/req/sqlite_generique.php 2019-12-12 21:25:14.000000000 +0000
+++ spip-3.2.15.1/ecrire/req/sqlite_generique.php 2022-05-20 16:59:18.000000000 +0100
@@ -1826,8 +1826,10 @@
}
$def = query_reinjecte_textes($r[2], $echaps); // valeur du champ
- # rustine pour DECIMAL(10,2)
- if (false !== strpos($k, ')')) {
+ // rustine pour DECIMAL(10,2)
+ // s'il y a une parenthèse fermante dans la clé
+ // ou dans la définition sans qu'il n'y ait une ouverture avant
+ if (false !== strpos($k, ')') or preg_match('/^[^\(]*\)/', $def)) {
$fields[$k_precedent] .= ',' . $k . ' ' . $def;
continue;
}
@@ -2296,16 +2298,14 @@
function _sqlite_modifier_table($table, $colonne, $opt = array(), $serveur = '') {
if (is_array($table)) {
- reset($table);
- list($table_origine, $table_destination) = each($table);
+ list($table_origine, $table_destination) = reset($table);
} else {
$table_origine = $table_destination = $table;
}
// ne prend actuellement qu'un changement
// mais pourra etre adapte pour changer plus qu'une colonne a la fois
if (is_array($colonne)) {
- reset($colonne);
- list($colonne_origine, $colonne_destination) = each($colonne);
+ list($colonne_origine, $colonne_destination) = reset($colonne);
} else {
$colonne_origine = $colonne_destination = $colonne;
}
@@ -2515,9 +2515,9 @@
/**
- * $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 @@
'/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',
@@ -2723,9 +2724,10 @@
// mais ceux-ci ne sont pas utilises dans le core
$tables[$table] = array();
+ $now = _sqlite_func_now();
foreach ($desc['field'] as $k => $v) {
if (strpos(strtolower(ltrim($v)), 'timestamp') === 0) {
- $tables[$table][$k] = "datetime('now')";
+ $tables[$table][$k] = _sqlite_calculer_cite($now, $v);
}
}
}
diff -Nru spip-3.2.7/.gitignore spip-3.2.15.1/.gitignore
--- spip-3.2.7/.gitignore 1970-01-01 01:00:00.000000000 +0100
+++ spip-3.2.15.1/.gitignore 2022-05-20 16:59:18.000000000 +0100
@@ -0,0 +1,129 @@
+/.DS_Store
+/.buildpath
+/.htaccess
+/.project
+/.settings
+IMG/*
+IMG/.DS_Store
+IMG/.htaccess
+config/*
+config/.DS_Store
+config/.htaccess
+ecrire/.DS_Store
+ecrire/.htaccess
+ecrire/action/.DS_Store
+ecrire/action/.htaccess
+ecrire/auth/.DS_Store
+ecrire/auth/.htaccess
+ecrire/balise/.DS_Store
+ecrire/balise/.htaccess
+ecrire/base/.DS_Store
+ecrire/base/.htaccess
+ecrire/charsets/.DS_Store
+ecrire/charsets/.htaccess
+ecrire/exec/.DS_Store
+ecrire/exec/.htaccess
+ecrire/genie/.DS_Store
+ecrire/genie/.htaccess
+ecrire/inc/.DS_Store
+ecrire/inc/.htaccess
+ecrire/inc_connect.php3
+ecrire/inc_meta_cache.php3
+ecrire/install/.DS_Store
+ecrire/install/.htaccess
+ecrire/iterateur/.DS_Store
+ecrire/iterateur/.htaccess
+ecrire/lang/.DS_Store
+ecrire/lang/.htaccess
+ecrire/maj/.DS_Store
+ecrire/maj/.htaccess
+ecrire/notifications/.DS_Store
+ecrire/notifications/.htaccess
+ecrire/plugins/.DS_Store
+ecrire/plugins/.htaccess
+ecrire/public/.DS_Store
+ecrire/public/.htaccess
+ecrire/req/.DS_Store
+ecrire/req/.htaccess
+ecrire/typographie/.DS_Store
+ecrire/typographie/.htaccess
+ecrire/urls/.DS_Store
+ecrire/urls/.htaccess
+ecrire/xml/.DS_Store
+ecrire/xml/.htaccess
+/extensions
+/lib
+local/*
+local/.DS_Store
+local/.htaccess
+/mutualisation
+/plugins
+/plugins-dist
+prive/.DS_Store
+prive/.htaccess
+prive/echafaudage/.DS_Store
+prive/echafaudage/.htaccess
+prive/echafaudage/contenu/.DS_Store
+prive/echafaudage/contenu/.htaccess
+prive/echafaudage/extra/.DS_Store
+prive/echafaudage/extra/.htaccess
+prive/echafaudage/hierarchie/.DS_Store
+prive/echafaudage/hierarchie/.htaccess
+prive/echafaudage/navigation/.DS_Store
+prive/echafaudage/navigation/.htaccess
+prive/formulaires/.DS_Store
+prive/formulaires/.htaccess
+prive/formulaires/dateur/.DS_Store
+prive/formulaires/dateur/.htaccess
+prive/formulaires/selecteur/.DS_Store
+prive/formulaires/selecteur/.htaccess
+prive/images/.DS_Store
+prive/images/.htaccess
+prive/javascript/.DS_Store
+prive/javascript/.htaccess
+prive/modeles/.DS_Store
+prive/modeles/.htaccess
+prive/objets/.DS_Store
+prive/objets/.htaccess
+prive/objets/contenu/.DS_Store
+prive/objets/contenu/.htaccess
+prive/objets/editer/.DS_Store
+prive/objets/editer/.htaccess
+prive/objets/infos/.DS_Store
+prive/objets/infos/.htaccess
+prive/objets/liste/.DS_Store
+prive/objets/liste/.htaccess
+prive/rss/.DS_Store
+prive/rss/.htaccess
+prive/squelettes/.DS_Store
+prive/squelettes/.htaccess
+prive/squelettes/contenu/.DS_Store
+prive/squelettes/contenu/.htaccess
+prive/squelettes/extra/.DS_Store
+prive/squelettes/extra/.htaccess
+prive/squelettes/head/.DS_Store
+prive/squelettes/head/.htaccess
+prive/squelettes/hierarchie/.DS_Store
+prive/squelettes/hierarchie/.htaccess
+prive/squelettes/inclure/.DS_Store
+prive/squelettes/inclure/.htaccess
+prive/squelettes/navigation/.DS_Store
+prive/squelettes/navigation/.htaccess
+prive/squelettes/top/.DS_Store
+prive/squelettes/top/.htaccess
+prive/themes/.DS_Store
+prive/themes/.htaccess
+prive/themes/spip/.DS_Store
+prive/themes/spip/.htaccess
+prive/themes/spip/images/.DS_Store
+prive/themes/spip/images/.htaccess
+prive/transmettre/.DS_Store
+prive/transmettre/.htaccess
+/sites
+/squelettes
+/squelettes-dist
+/tests
+/themes
+tmp/*
+tmp/.DS_Store
+tmp/.htaccess
diff -Nru spip-3.2.7/plugins-dist/aide/inc/aide.php spip-3.2.15.1/plugins-dist/aide/inc/aide.php
--- spip-3.2.7/plugins-dist/aide/inc/aide.php 2019-12-12 21:31:12.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/aide/inc/aide.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/aide/paquet.xml spip-3.2.15.1/plugins-dist/aide/paquet.xml
--- spip-3.2.7/plugins-dist/aide/paquet.xml 2019-12-12 21:31:12.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/aide/paquet.xml 2022-05-20 16:59:18.000000000 +0100
@@ -1,7 +1,7 @@
-
\ No newline at end of file
+
diff -Nru spip-3.2.7/plugins-dist/breves/prive/squelettes/contenu/breves.html spip-3.2.15.1/plugins-dist/breves/prive/squelettes/contenu/breves.html
--- spip-3.2.7/plugins-dist/breves/prive/squelettes/contenu/breves.html 2019-12-12 21:31:04.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/breves/prive/squelettes/contenu/breves.html 2022-05-20 16:59:18.000000000 +0100
@@ -2,7 +2,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/compagnon/paquet.xml spip-3.2.15.1/plugins-dist/compagnon/paquet.xml
--- spip-3.2.7/plugins-dist/compagnon/paquet.xml 2019-12-12 21:31:04.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/compagnon/paquet.xml 2022-05-20 16:59:18.000000000 +0100
@@ -1,7 +1,7 @@
$file) {
+ if (!is_array($file)){
+ if (strpos($file, "?")!==false){
+ $file = explode('?', $file, 2);
+ if (is_numeric(end($file))){
+ $lastmodified = max($lastmodified, end($file));
+ }
+ $file = reset($file);
+ }
+ }
+ $file_wo_timestamp[] = $file;
+ }
+ $nom_fichier_concat = $dir . md5(json_encode($file_wo_timestamp) . json_encode($callbacks)) . ".$format";
+ return array($nom_fichier_concat, $lastmodified);
+}
+
+/**
* Une callback pour la minification par défaut
*
* Mais justement, par défaut on ne minifie rien !
diff -Nru spip-3.2.7/plugins-dist/compresseur/inc/compresseur_embarquer.php spip-3.2.15.1/plugins-dist/compresseur/inc/compresseur_embarquer.php
--- spip-3.2.7/plugins-dist/compresseur/inc/compresseur_embarquer.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/compresseur/inc/compresseur_embarquer.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
@@ -47,10 +47,9 @@
return preg_replace_callback(
",url\s*\(\s*['\"]?([^'\"/][^:]*[.](png|gif|jpg))['\"]?\s*\),Uims",
- create_function(
- '$x',
- 'return "url(\"".' . $filtre_embarque_fichier . '($x[1],"' . $base . '",_CSS_EMBARQUE_FICHIER_MAX_SIZE)."\")";'
- ),
+ function($x) use ($filtre_embarque_fichier, $base) {
+ return "url(\"" . $filtre_embarque_fichier($x[1], $base, _CSS_EMBARQUE_FICHIER_MAX_SIZE) . "\")";
+ },
$contenu
);
}
diff -Nru spip-3.2.7/plugins-dist/compresseur/inc/compresseur_minifier.php spip-3.2.15.1/plugins-dist/compresseur/inc/compresseur_minifier.php
--- spip-3.2.7/plugins-dist/compresseur/inc/compresseur_minifier.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/compresseur/inc/compresseur_minifier.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/compresseur/inc/compresseur.php spip-3.2.15.1/plugins-dist/compresseur/inc/compresseur.php
--- spip-3.2.7/plugins-dist/compresseur/inc/compresseur.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/compresseur/inc/compresseur.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/compresseur/lib/csstidy/class.csstidy_optimise.php spip-3.2.15.1/plugins-dist/compresseur/lib/csstidy/class.csstidy_optimise.php
--- spip-3.2.7/plugins-dist/compresseur/lib/csstidy/class.csstidy_optimise.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/compresseur/lib/csstidy/class.csstidy_optimise.php 2022-05-20 16:59:18.000000000 +0100
@@ -358,8 +358,8 @@
// #aabbcc -> #abc
if (strlen($color) == 7) {
$color_temp = strtolower($color);
- if ($color_temp{0} === '#' && $color_temp{1} == $color_temp{2} && $color_temp{3} == $color_temp{4} && $color_temp{5} == $color_temp{6}) {
- $color = '#' . $color{1} . $color{3} . $color{5};
+ if ($color_temp[0] === '#' && $color_temp[1] == $color_temp[2] && $color_temp[3] == $color_temp[4] && $color_temp[5] == $color_temp[6]) {
+ $color = '#' . $color[1] . $color[3] . $color[5];
}
}
@@ -438,7 +438,7 @@
*/
public function AnalyseCssNumber($string) {
// most simple checks first
- if (strlen($string) == 0 || ctype_alpha($string{0})) {
+ if (strlen($string) == 0 || ctype_alpha($string[0])) {
return false;
}
@@ -647,22 +647,22 @@
for ($i = 0, $len = strlen($string); $i < $len; $i++) {
switch ($status) {
case 'st':
- if ($string{$i} == $sep && !$this->parser->escaped($string, $i)) {
+ if ($string[$i] == $sep && !$this->parser->escaped($string, $i)) {
++$num;
- } elseif ($string{$i} === '"' || $string{$i} === '\'' || (!$explode_in_parenthesis && $string{$i} === '(') && !$this->parser->escaped($string, $i)) {
+ } elseif ($string[$i] === '"' || $string[$i] === '\'' || (!$explode_in_parenthesis && $string[$i] === '(') && !$this->parser->escaped($string, $i)) {
$status = 'str';
- $to = ($string{$i} === '(') ? ')' : $string{$i};
- (isset($output[$num])) ? $output[$num] .= $string{$i} : $output[$num] = $string{$i};
+ $to = ($string[$i] === '(') ? ')' : $string[$i];
+ (isset($output[$num])) ? $output[$num] .= $string[$i] : $output[$num] = $string[$i];
} else {
- (isset($output[$num])) ? $output[$num] .= $string{$i} : $output[$num] = $string{$i};
+ (isset($output[$num])) ? $output[$num] .= $string[$i] : $output[$num] = $string[$i];
}
break;
case 'str':
- if ($string{$i} == $to && !$this->parser->escaped($string, $i)) {
+ if ($string[$i] == $to && !$this->parser->escaped($string, $i)) {
$status = 'st';
}
- (isset($output[$num])) ? $output[$num] .= $string{$i} : $output[$num] = $string{$i};
+ (isset($output[$num])) ? $output[$num] .= $string[$i] : $output[$num] = $string[$i];
break;
}
}
@@ -797,9 +797,9 @@
$have['clip'] = true;
} elseif (in_array($str_value[$i][$j], $origin, true)) {
$return['background-origin'] .= $str_value[$i][$j] . ',';
- } elseif ($str_value[$i][$j]{0} === '(') {
+ } elseif ($str_value[$i][$j][0] === '(') {
$return['background-size'] .= substr($str_value[$i][$j], 1, -1) . ',';
- } elseif (in_array($str_value[$i][$j], $pos, true) || is_numeric($str_value[$i][$j]{0}) || $str_value[$i][$j]{0} === null || $str_value[$i][$j]{0} === '-' || $str_value[$i][$j]{0} === '.') {
+ } elseif (in_array($str_value[$i][$j], $pos, true) || is_numeric($str_value[$i][$j][0]) || $str_value[$i][$j][0] === null || $str_value[$i][$j][0] === '-' || $str_value[$i][$j][0] === '.') {
$return['background-position'] .= $str_value[$i][$j];
if (!$have['pos'])
$return['background-position'] .= ' '; else
@@ -945,7 +945,7 @@
} elseif ($have['style'] === false && in_array($str_value[0][$j], $font_style)) {
$return['font-style'] = $str_value[0][$j];
$have['style'] = true;
- } elseif ($have['size'] === false && (is_numeric($str_value[0][$j]{0}) || $str_value[0][$j]{0} === null || $str_value[0][$j]{0} === '.')) {
+ } elseif ($have['size'] === false && (is_numeric($str_value[0][$j][0]) || $str_value[0][$j][0] === null || $str_value[0][$j][0] === '.')) {
$size = $this->explode_ws('/', trim($str_value[0][$j]));
$return['font-size'] = $size[0];
if (isset($size[1])) {
@@ -975,7 +975,7 @@
// Fix for 100 and more font-size
if ($have['size'] === false && isset($return['font-weight']) &&
- is_numeric($return['font-weight']{0})) {
+ is_numeric($return['font-weight'][0])) {
$return['font-size'] = $return['font-weight'];
unset($return['font-weight']);
}
@@ -1011,8 +1011,8 @@
$family = trim($family);
$len = strlen($family);
if (strpos($family, ' ') &&
- !(($family{0} === '"' && $family{$len - 1} === '"') ||
- ($family{0} === "'" && $family{$len - 1} === "'"))) {
+ !(($family[0] === '"' && $family[$len - 1] === '"') ||
+ ($family[0] === "'" && $family[$len - 1] === "'"))) {
$family = '"' . $family . '"';
}
$result_families[] = $family;
@@ -1278,16 +1278,25 @@
if (stripos($value, 'left') === false and stripos($value, 'right') === false) {
$values = $this->explode_ws(' ', trim($value));
$values = array_map('trim', $values);
- $values = array_filter($values);
+ $values = array_filter($values, function ($v) { return strlen($v);});
$values = array_values($values);
if (count($values) == 1) {
+ if (in_array($value, array('center', 'top', 'bottom', 'inherit', 'initial', 'unset'))) {
+ return $value;
+ }
return "left $value";
}
if ($values[1] == 'top' or $values[1] == 'bottom') {
+ if ($values[0] === 'center') {
+ return $value;
+ }
return 'left ' . implode(' ', $values);
}
else {
$last = array_pop($values);
+ if ($last === 'center') {
+ return $value;
+ }
return implode(' ', $values) . ' left ' . $last;
}
}
diff -Nru spip-3.2.7/plugins-dist/compresseur/lib/csstidy/class.csstidy.php spip-3.2.15.1/plugins-dist/compresseur/lib/csstidy/class.csstidy.php
--- spip-3.2.7/plugins-dist/compresseur/lib/csstidy/class.csstidy.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/compresseur/lib/csstidy/class.csstidy.php 2022-05-20 16:59:18.000000000 +0100
@@ -33,31 +33,6 @@
*/
/**
- * Defines ctype functions if required.
- *
- * @TODO: Make these methods of CSSTidy.
- * @since 1.0.0
- */
-if (!function_exists('ctype_space')){
- /* ctype_space Check for whitespace character(s) */
- function ctype_space($text){
- return (1===preg_match("/^[ \r\n\t\f]+$/", $text));
- }
-}
-if (!function_exists('ctype_alpha')){
- /* ctype_alpha Check for alphabetic character(s) */
- function ctype_alpha($text){
- return (1===preg_match('/^[a-zA-Z]+$/', $text));
- }
-}
-if (!function_exists('ctype_xdigit')){
- /* ctype_xdigit Check for HEX character(s) */
- function ctype_xdigit($text){
- return (1===preg_match('/^[a-fA-F0-9]+$/', $text));
- }
-}
-
-/**
* Defines constants
* @todo //TODO: make them class constants of csstidy
*/
@@ -95,7 +70,7 @@
* An online version should be available here: http://cdburnerxp.se/cssparse/css_optimiser.php
* @package csstidy
* @author Florian Schmitz (floele at gmail dot com) 2005-2006
- * @version 1.6.5
+ * @version 1.7.3
*/
class csstidy {
@@ -148,7 +123,7 @@
* @var string
* @access private
*/
- public $version = '1.6.5';
+ public $version = '1.7.3';
/**
* Stores the settings
* @var array
@@ -416,7 +391,17 @@
*/
public function _add_token($type, $data, $do = false) {
if ($this->get_cfg('preserve_css') || $do) {
- $this->tokens[] = array($type, ($type == COMMENT or $type == IMPORTANT_COMMENT) ? $data : trim($data));
+ // nested @... : if opening a new part we just closed, remove the previous closing instead of adding opening
+ if ($type === AT_START
+ and count($this->tokens)
+ and $last = end($this->tokens)
+ and $last[0] === AT_END
+ and $last[1] === trim($data)) {
+ array_pop($this->tokens);
+ }
+ else {
+ $this->tokens[] = array($type, ($type == COMMENT or $type == IMPORTANT_COMMENT) ? $data : trim($data));
+ }
}
}
@@ -452,10 +437,10 @@
$add = '';
$replaced = false;
- while ($i < strlen($string) && (ctype_xdigit($string{$i}) || ctype_space($string{$i})) && strlen($add) < 6) {
- $add .= $string{$i};
+ while ($i < strlen($string) && (ctype_xdigit($string[$i]) || ctype_space($string[$i])) && strlen($add) < 6) {
+ $add .= $string[$i];
- if (ctype_space($string{$i})) {
+ if (ctype_space($string[$i])) {
break;
}
$i++;
@@ -469,12 +454,12 @@
$add = trim('\\' . $add);
}
- if (@ctype_xdigit($string{$i + 1}) && ctype_space($string{$i})
- && !$replaced || !ctype_space($string{$i})) {
+ if (@ctype_xdigit($string[$i + 1]) && ctype_space($string[$i])
+ && !$replaced || !ctype_space($string[$i])) {
$i--;
}
- if ($add !== '\\' || !$this->get_cfg('remove_bslash') || strpos($this->tokens_list, $string{$i + 1}) !== false) {
+ if ($add !== '\\' || !$this->get_cfg('remove_bslash') || strpos($this->tokens_list, $string[$i + 1]) !== false) {
return $add;
}
@@ -576,7 +561,7 @@
* @version 1.11
*/
public function is_token(&$string, $i) {
- return (strpos($this->tokens_list, $string{$i}) !== false && !$this->escaped($string, $i));
+ return (strpos($this->tokens_list, $string[$i]) !== false && !$this->escaped($string, $i));
}
/**
@@ -603,9 +588,10 @@
$this->print->input_css = $string;
$string = str_replace("\r\n", "\n", $string) . ' ';
$cur_comment = '';
+ $cur_at = '';
for ($i = 0, $size = strlen($string); $i < $size; $i++) {
- if ($string{$i} === "\n" || $string{$i} === "\r") {
+ if ($string[$i] === "\n" || $string[$i] === "\r") {
++$this->line;
}
@@ -613,27 +599,27 @@
/* Case in at-block */
case 'at':
if ($this->is_token($string, $i)) {
- if ($string{$i} === '/' && @$string{$i + 1} === '*') {
+ if ($string[$i] === '/' && @$string[$i + 1] === '*') {
$this->status = 'ic';
++$i;
$this->from[] = 'at';
- } elseif ($string{$i} === '{') {
+ } elseif ($string[$i] === '{') {
$this->status = 'is';
- $this->at = $this->css_new_media_section($this->at);
+ $this->at = $this->css_new_media_section($this->at, $cur_at);
$this->_add_token(AT_START, $this->at);
- } elseif ($string{$i} === ',') {
- $this->at = trim($this->at) . ',';
- } elseif ($string{$i} === '\\') {
- $this->at .= $this->_unicode($string, $i);
+ } elseif ($string[$i] === ',') {
+ $cur_at = trim($cur_at) . ',';
+ } elseif ($string[$i] === '\\') {
+ $cur_at .= $this->_unicode($string, $i);
}
// fix for complicated media, i.e @media screen and (-webkit-min-device-pixel-ratio:1.5)
- elseif (in_array($string{$i}, array('(', ')', ':', '.', '/'))) {
- $this->at .= $string{$i};
+ elseif (in_array($string[$i], array('(', ')', ':', '.', '/'))) {
+ $cur_at .= $string[$i];
}
} else {
- $lastpos = strlen($this->at) - 1;
- if (!( (ctype_space($this->at{$lastpos}) || $this->is_token($this->at, $lastpos) && $this->at{$lastpos} === ',') && ctype_space($string{$i}))) {
- $this->at .= $string{$i};
+ $lastpos = strlen($cur_at) - 1;
+ if (!( (ctype_space($cur_at[$lastpos]) || $this->is_token($cur_at, $lastpos) && $cur_at[$lastpos] === ',') && ctype_space($string[$i]))) {
+ $cur_at .= $string[$i];
}
}
break;
@@ -641,24 +627,25 @@
/* Case in-selector */
case 'is':
if ($this->is_token($string, $i)) {
- if ($string{$i} === '/' && @$string{$i + 1} === '*' && trim($this->selector) == '') {
+ if ($string[$i] === '/' && @$string[$i + 1] === '*' && trim($this->selector) == '') {
$this->status = 'ic';
++$i;
$this->from[] = 'is';
- } elseif ($string{$i} === '@' && trim($this->selector) == '') {
+ } elseif ($string[$i] === '@' && trim($this->selector) == '') {
// Check for at-rule
$this->invalid_at = true;
foreach ($at_rules as $name => $type) {
if (!strcasecmp(substr($string, $i + 1, strlen($name)), $name)) {
- ($type === 'at') ? $this->at = '@' . $name : $this->selector = '@' . $name;
+ ($type === 'at') ? $cur_at = '@' . $name : $this->selector = '@' . $name;
if ($type === 'atis') {
$this->next_selector_at = ($this->next_selector_at?$this->next_selector_at:($this->at?$this->at:DEFAULT_AT));
- $this->at = $this->css_new_media_section(' ');
+ $this->at = $this->css_new_media_section($this->at, ' ', true);
$type = 'is';
}
$this->status = $type;
$i += strlen($name);
$this->invalid_at = false;
+ break;
}
}
@@ -666,54 +653,55 @@
$this->selector = '@';
$invalid_at_name = '';
for ($j = $i + 1; $j < $size; ++$j) {
- if (!ctype_alpha($string{$j})) {
+ if (!ctype_alpha($string[$j])) {
break;
}
- $invalid_at_name .= $string{$j};
+ $invalid_at_name .= $string[$j];
}
$this->log('Invalid @-rule: ' . $invalid_at_name . ' (removed)', 'Warning');
}
- } elseif (($string{$i} === '"' || $string{$i} === "'")) {
- $this->cur_string[] = $string{$i};
+ } elseif (($string[$i] === '"' || $string[$i] === "'")) {
+ $this->cur_string[] = $string[$i];
$this->status = 'instr';
- $this->str_char[] = $string{$i};
+ $this->str_char[] = $string[$i];
$this->from[] = 'is';
/* fixing CSS3 attribute selectors, i.e. a[href$=".mp3" */
- $this->quoted_string[] = ($string{$i - 1} === '=' );
- } elseif ($this->invalid_at && $string{$i} === ';') {
+ $this->quoted_string[] = ($string[$i - 1] === '=' );
+ } elseif ($this->invalid_at && $string[$i] === ';') {
$this->invalid_at = false;
$this->status = 'is';
if ($this->next_selector_at) {
- $this->at = $this->css_new_media_section($this->next_selector_at);
+ $this->at = $this->css_close_media_section($this->at);
+ $this->at = $this->css_new_media_section($this->at, $this->next_selector_at);
$this->next_selector_at = '';
}
- } elseif ($string{$i} === '{') {
+ } elseif ($string[$i] === '{') {
$this->status = 'ip';
if ($this->at == '') {
- $this->at = $this->css_new_media_section(DEFAULT_AT);
+ $this->at = $this->css_new_media_section($this->at, DEFAULT_AT);
}
$this->selector = $this->css_new_selector($this->at,$this->selector);
$this->_add_token(SEL_START, $this->selector);
$this->added = false;
- } elseif ($string{$i} === '}') {
+ } elseif ($string[$i] === '}') {
$this->_add_token(AT_END, $this->at);
- $this->at = '';
+ $this->at = $this->css_close_media_section($this->at);
$this->selector = '';
$this->sel_separate = array();
- } elseif ($string{$i} === ',') {
+ } elseif ($string[$i] === ',') {
$this->selector = trim($this->selector) . ',';
$this->sel_separate[] = strlen($this->selector);
- } elseif ($string{$i} === '\\') {
+ } elseif ($string[$i] === '\\') {
$this->selector .= $this->_unicode($string, $i);
- } elseif ($string{$i} === '*' && @in_array($string{$i + 1}, array('.', '#', '[', ':')) && ($i==0 OR $string{$i - 1}!=='/')) {
+ } elseif ($string[$i] === '*' && @in_array($string[$i + 1], array('.', '#', '[', ':')) && ($i==0 OR $string[$i - 1]!=='/')) {
// remove unnecessary universal selector, FS#147, but not comment in selector
} else {
- $this->selector .= $string{$i};
+ $this->selector .= $string[$i];
}
} else {
$lastpos = strlen($this->selector) - 1;
- if ($lastpos == -1 || !( (ctype_space($this->selector{$lastpos}) || $this->is_token($this->selector, $lastpos) && $this->selector{$lastpos} === ',') && ctype_space($string{$i}))) {
- $this->selector .= $string{$i};
+ if ($lastpos == -1 || !( (ctype_space($this->selector[$lastpos]) || $this->is_token($this->selector, $lastpos) && $this->selector[$lastpos] === ',') && ctype_space($string[$i]))) {
+ $this->selector .= $string[$i];
}
}
break;
@@ -721,17 +709,17 @@
/* Case in-property */
case 'ip':
if ($this->is_token($string, $i)) {
- if (($string{$i} === ':' || $string{$i} === '=') && $this->property != '') {
+ if (($string[$i] === ':' || $string[$i] === '=') && $this->property != '') {
$this->status = 'iv';
if (!$this->get_cfg('discard_invalid_properties') || $this->property_is_valid($this->property)) {
$this->property = $this->css_new_property($this->at,$this->selector,$this->property);
$this->_add_token(PROPERTY, $this->property);
}
- } elseif ($string{$i} === '/' && @$string{$i + 1} === '*' && $this->property == '') {
+ } elseif ($string[$i] === '/' && @$string[$i + 1] === '*' && $this->property == '') {
$this->status = 'ic';
++$i;
$this->from[] = 'ip';
- } elseif ($string{$i} === '}') {
+ } elseif ($string[$i] === '}') {
$this->explode_selectors();
$this->status = 'is';
$this->invalid_at = false;
@@ -739,45 +727,46 @@
$this->selector = '';
$this->property = '';
if ($this->next_selector_at) {
- $this->at = $this->css_new_media_section($this->next_selector_at);
+ $this->at = $this->css_close_media_section($this->at);
+ $this->at = $this->css_new_media_section($this->at, $this->next_selector_at);
$this->next_selector_at = '';
}
- } elseif ($string{$i} === ';') {
+ } elseif ($string[$i] === ';') {
$this->property = '';
- } elseif ($string{$i} === '\\') {
+ } elseif ($string[$i] === '\\') {
$this->property .= $this->_unicode($string, $i);
}
// else this is dumb IE a hack, keep it
// including //
- elseif (($this->property === '' && !ctype_space($string{$i}))
- || ($this->property === '/' || $string{$i} === '/')) {
- $this->property .= $string{$i};
+ elseif (($this->property === '' && !ctype_space($string[$i]))
+ || ($this->property === '/' || $string[$i] === '/')) {
+ $this->property .= $string[$i];
}
- } elseif (!ctype_space($string{$i})) {
- $this->property .= $string{$i};
+ } elseif (!ctype_space($string[$i])) {
+ $this->property .= $string[$i];
}
break;
/* Case in-value */
case 'iv':
- $pn = (($string{$i} === "\n" || $string{$i} === "\r") && $this->property_is_next($string, $i + 1) || $i == strlen($string) - 1);
+ $pn = (($string[$i] === "\n" || $string[$i] === "\r") && $this->property_is_next($string, $i + 1) || $i == strlen($string) - 1);
if ($this->is_token($string, $i) || $pn) {
- if ($string{$i} === '/' && @$string{$i + 1} === '*') {
+ if ($string[$i] === '/' && @$string[$i + 1] === '*') {
$this->status = 'ic';
++$i;
$this->from[] = 'iv';
- } elseif (($string{$i} === '"' || $string{$i} === "'" || $string{$i} === '(')) {
- $this->cur_string[] = $string{$i};
- $this->str_char[] = ($string{$i} === '(') ? ')' : $string{$i};
+ } elseif (($string[$i] === '"' || $string[$i] === "'" || $string[$i] === '(')) {
+ $this->cur_string[] = $string[$i];
+ $this->str_char[] = ($string[$i] === '(') ? ')' : $string[$i];
$this->status = 'instr';
$this->from[] = 'iv';
$this->quoted_string[] = in_array(strtolower($this->property), $quoted_string_properties);
- } elseif ($string{$i} === ',') {
+ } elseif ($string[$i] === ',') {
$this->sub_value = trim($this->sub_value) . ',';
- } elseif ($string{$i} === '\\') {
+ } elseif ($string[$i] === '\\') {
$this->sub_value .= $this->_unicode($string, $i);
- } elseif ($string{$i} === ';' || $pn) {
- if ($this->selector{0} === '@' && isset($at_rules[substr($this->selector, 1)]) && $at_rules[substr($this->selector, 1)] === 'iv') {
+ } elseif ($string[$i] === ';' || $pn) {
+ if ($this->selector[0] === '@' && isset($at_rules[substr($this->selector, 1)]) && $at_rules[substr($this->selector, 1)] === 'iv') {
/* Add quotes to charset, import, namespace */
$this->sub_value_arr[] = trim($this->sub_value);
@@ -799,12 +788,12 @@
} else {
$this->status = 'ip';
}
- } elseif ($string{$i} !== '}') {
- $this->sub_value .= $string{$i};
+ } elseif ($string[$i] !== '}') {
+ $this->sub_value .= $string[$i];
}
- if (($string{$i} === '}' || $string{$i} === ';' || $pn) && !empty($this->selector)) {
+ if (($string[$i] === '}' || $string[$i] === ';' || $pn) && !empty($this->selector)) {
if ($this->at == '') {
- $this->at = $this->css_new_media_section(DEFAULT_AT);
+ $this->at = $this->css_new_media_section($this->at,DEFAULT_AT);
}
// case settings
@@ -850,21 +839,22 @@
$this->sub_value_arr = array();
$this->value = '';
}
- if ($string{$i} === '}') {
+ if ($string[$i] === '}') {
$this->explode_selectors();
$this->_add_token(SEL_END, $this->selector);
$this->status = 'is';
$this->invalid_at = false;
$this->selector = '';
if ($this->next_selector_at) {
- $this->at = $this->css_new_media_section($this->next_selector_at);
+ $this->at = $this->css_close_media_section($this->at);
+ $this->at = $this->css_new_media_section($this->at, $this->next_selector_at);
$this->next_selector_at = '';
}
}
} elseif (!$pn) {
- $this->sub_value .= $string{$i};
+ $this->sub_value .= $string[$i];
- if (ctype_space($string{$i})) {
+ if (ctype_space($string[$i])) {
$this->optimise->subvalue();
if ($this->sub_value != '') {
$this->sub_value_arr[] = $this->sub_value;
@@ -879,26 +869,26 @@
$_str_char = $this->str_char[count($this->str_char)-1];
$_cur_string = $this->cur_string[count($this->cur_string)-1];
$_quoted_string = $this->quoted_string[count($this->quoted_string)-1];
- $temp_add = $string{$i};
+ $temp_add = $string[$i];
// Add another string to the stack. Strings can't be nested inside of quotes, only parentheses, but
// parentheticals can be nested more than once.
- if ($_str_char === ")" && ($string{$i} === "(" || $string{$i} === '"' || $string{$i} === '\'') && !$this->escaped($string, $i)) {
- $this->cur_string[] = $string{$i};
- $this->str_char[] = $string{$i} === '(' ? ')' : $string{$i};
+ if ($_str_char === ")" && ($string[$i] === "(" || $string[$i] === '"' || $string[$i] === '\'') && !$this->escaped($string, $i)) {
+ $this->cur_string[] = $string[$i];
+ $this->str_char[] = $string[$i] === '(' ? ')' : $string[$i];
$this->from[] = 'instr';
- $this->quoted_string[] = ($_str_char === ')' && $string{$i} !== '(' && trim($_cur_string)==='(')?$_quoted_string:!($string{$i} === '(');
+ $this->quoted_string[] = ($_str_char === ')' && $string[$i] !== '(' && trim($_cur_string)==='(')?$_quoted_string:!($string[$i] === '(');
continue 2;
}
- if ($_str_char !== ")" && ($string{$i} === "\n" || $string{$i} === "\r") && !($string{$i - 1} === '\\' && !$this->escaped($string, $i - 1))) {
+ if ($_str_char !== ")" && ($string[$i] === "\n" || $string[$i] === "\r") && !($string[$i - 1] === '\\' && !$this->escaped($string, $i - 1))) {
$temp_add = "\\A";
$this->log('Fixed incorrect newline in string', 'Warning');
}
$_cur_string .= $temp_add;
- if ($string{$i} === $_str_char && !$this->escaped($string, $i)) {
+ if ($string[$i] === $_str_char && !$this->escaped($string, $i)) {
$this->status = array_pop($this->from);
if (!preg_match('|[' . implode('', $this->data['csstidy']['whitespace']) . ']|uis', $_cur_string) && $this->property !== 'content') {
@@ -949,7 +939,7 @@
/* Case in-comment */
case 'ic':
- if ($string{$i} === '*' && $string{$i + 1} === '/') {
+ if ($string[$i] === '*' && $string[$i + 1] === '/') {
$this->status = array_pop($this->from);
$i++;
if (strlen($cur_comment) > 1 and strncmp($cur_comment, '!', 1) === 0) {
@@ -961,7 +951,7 @@
}
$cur_comment = '';
} else {
- $cur_comment .= $string{$i};
+ $cur_comment .= $string[$i];
}
break;
}
@@ -1044,7 +1034,7 @@
* @version 1.02
*/
static function escaped(&$string, $pos) {
- return!(@($string{$pos - 1} !== '\\') || csstidy::escaped($string, $pos - 1));
+ return!(@($string[$pos - 1] !== '\\') || csstidy::escaped($string, $pos - 1));
}
@@ -1091,29 +1081,27 @@
}
/**
- * Start a new media section.
- * Check if the media is not already known,
- * else rename it with extra spaces
- * to avoid merging
+ * Check if a current media section is the continuation of the last one
+ * if not inc the name of the media section to avoid a merging
*
- * @param string $media
- * @return string
+ * @param int|string $media
+ * @return int|string
*/
- public function css_new_media_section($media) {
- if ($this->get_cfg('preserve_css')) {
+ public function css_check_last_media_section_or_inc($media) {
+ // are we starting?
+ if (!$this->css || !is_array($this->css) || empty($this->css)) {
return $media;
}
// if the last @media is the same as this
// keep it
- if (!$this->css || !is_array($this->css) || empty($this->css)) {
- return $media;
- }
end($this->css);
$at = key($this->css);
if ($at == $media) {
return $media;
}
+
+ // else inc the section in the array
while (isset($this->css[$media]))
if (is_numeric($media))
$media++;
@@ -1123,6 +1111,56 @@
}
/**
+ * Start a new media section.
+ * Check if the media is not already known,
+ * else rename it with extra spaces
+ * to avoid merging
+ *
+ * @param string $current_media
+ * @param string $media
+ * @param bool $at_root
+ * @return string
+ */
+ public function css_new_media_section($current_media, $new_media, $at_root = false) {
+ if ($this->get_cfg('preserve_css')) {
+ return $new_media;
+ }
+
+ // if we already are in a media and CSS level is 3, manage nested medias
+ if ($current_media
+ && !$at_root
+ // numeric $current_media means DEFAULT_AT or inc
+ && !is_numeric($current_media)
+ && strncmp($this->get_cfg('css_level'), 'CSS3', 4) == 0) {
+
+ $new_media = rtrim($current_media) . "{" . rtrim($new_media);
+ }
+
+ return $this->css_check_last_media_section_or_inc($new_media);
+ }
+
+ /**
+ * Close a media section
+ * Find the parent media we were in before or the root
+ * @param $current_media
+ * @return string
+ */
+ public function css_close_media_section($current_media) {
+ if ($this->get_cfg('preserve_css')) {
+ return '';
+ }
+
+ if (strpos($current_media, '{') !== false) {
+ $current_media = explode('{', $current_media);
+ array_pop($current_media);
+ $current_media = implode('{', $current_media);
+ return $current_media;
+ }
+
+ return '';
+ }
+
+ /**
* Start a new selector.
* If already referenced in this media section,
* rename it with extra space to avoid merging
@@ -1255,7 +1293,7 @@
/**
* Checks if a property is valid
* @param string $property
- * @return bool;
+ * @return bool
* @access public
* @version 1.0
*/
@@ -1279,7 +1317,6 @@
* @param string
* @return array
*/
-
public function parse_string_list($value) {
$value = trim($value);
@@ -1292,26 +1329,26 @@
$current_string = '';
for ($i = 0, $_len = strlen($value); $i < $_len; $i++) {
- if (($value{$i} === ',' || $value{$i} === ' ') && $in_str === true) {
+ if (($value[$i] === ',' || $value[$i] === ' ') && $in_str === true) {
$in_str = false;
$strings[] = $current_string;
$current_string = '';
- } elseif ($value{$i} === '"' || $value{$i} === "'") {
- if ($in_str === $value{$i}) {
+ } elseif ($value[$i] === '"' || $value[$i] === "'") {
+ if ($in_str === $value[$i]) {
$strings[] = $current_string;
$in_str = false;
$current_string = '';
continue;
} elseif (!$in_str) {
- $in_str = $value{$i};
+ $in_str = $value[$i];
}
} else {
if ($in_str) {
- $current_string .= $value{$i};
+ $current_string .= $value[$i];
} else {
- if (!preg_match("/[\s,]/", $value{$i})) {
+ if (!preg_match("/[\s,]/", $value[$i])) {
$in_str = true;
- $current_string = $value{$i};
+ $current_string = $value[$i];
}
}
}
diff -Nru spip-3.2.7/plugins-dist/compresseur/lib/csstidy/class.csstidy_print.php spip-3.2.15.1/plugins-dist/compresseur/lib/csstidy/class.csstidy_print.php
--- spip-3.2.7/plugins-dist/compresseur/lib/csstidy/class.csstidy_print.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/compresseur/lib/csstidy/class.csstidy_print.php 2022-05-20 16:59:18.000000000 +0100
@@ -219,20 +219,25 @@
$output .= $template[0] . '@namespace ' . $template[5] . $this->namespace . $template[6] . $template[13];
}
- $in_at_out = '';
+ $in_at_out = [];
$out = & $output;
+ $indent_level = 0;
foreach ($this->tokens as $key => $token) {
switch ($token[0]) {
case AT_START:
$out .= $template[0] . $this->_htmlsp($token[1], $plain) . $template[1];
- $out = & $in_at_out;
+ $indent_level++;
+ if (!isset($in_at_out[$indent_level])) {
+ $in_at_out[$indent_level] = '';
+ }
+ $out = & $in_at_out[$indent_level];
break;
case SEL_START:
if ($this->parser->get_cfg('lowercase_s'))
$token[1] = strtolower($token[1]);
- $out .= ( $token[1]{0} !== '@') ? $template[2] . $this->_htmlsp($token[1], $plain) : $template[0] . $this->_htmlsp($token[1], $plain);
+ $out .= ( $token[1][0] !== '@') ? $template[2] . $this->_htmlsp($token[1], $plain) : $template[0] . $this->_htmlsp($token[1], $plain);
$out .= $template[3];
break;
@@ -261,12 +266,28 @@
break;
case AT_END:
- $out = & $output;
- $in_at_out = str_replace("\n\n", "\r\n", $in_at_out); // don't fill empty lines
- $in_at_out = str_replace("\n", "\n" . $template[10], $in_at_out);
- $in_at_out = str_replace("\r\n", "\n\n", $in_at_out);
- $out .= $template[10] . $in_at_out . $template[9];
- $in_at_out = '';
+ if (strlen($template[10])) {
+ // indent the bloc we are closing
+ $out = str_replace("\n\n", "\r\n", $out); // don't fill empty lines
+ $out = str_replace("\n", "\n" . $template[10], $out);
+ $out = str_replace("\r\n", "\n\n", $out);
+ }
+ if ($indent_level > 1) {
+ $out = & $in_at_out[$indent_level-1];
+ }
+ else {
+ $out = & $output;
+ }
+ $out .= $template[10] . $in_at_out[$indent_level];
+ if ($this->_seeknocomment($key, 1) != AT_END) {
+ $out .= $template[9];
+ }
+ else {
+ $out .= rtrim($template[9]);
+ }
+
+ unset($in_at_out[$indent_level]);
+ $indent_level--;
break;
case IMPORTANT_COMMENT:
@@ -332,7 +353,10 @@
if (intval($medium) < DEFAULT_AT) {
// un medium vide (contenant @font-face ou autre @) ne produit aucun conteneur
if (strlen(trim($medium))) {
- $this->parser->_add_token(AT_START, $medium, true);
+ $parts_to_open = explode('{', $medium);
+ foreach ($parts_to_open as $part) {
+ $this->parser->_add_token(AT_START, $part, true);
+ }
}
} elseif ($default_media) {
$this->parser->_add_token(AT_START, $default_media, true);
@@ -372,7 +396,10 @@
if (intval($medium) < DEFAULT_AT) {
// un medium vide (contenant @font-face ou autre @) ne produit aucun conteneur
if (strlen(trim($medium))) {
- $this->parser->_add_token(AT_END, $medium, true);
+ $parts_to_close = explode('{', $medium);
+ foreach (array_reverse($parts_to_close) as $part) {
+ $this->parser->_add_token(AT_END, $part, true);
+ }
}
} elseif ($default_media) {
$this->parser->_add_token(AT_END, $default_media, true);
diff -Nru spip-3.2.7/plugins-dist/compresseur/lib/csstidy/data.inc.php spip-3.2.15.1/plugins-dist/compresseur/lib/csstidy/data.inc.php
--- spip-3.2.7/plugins-dist/compresseur/lib/csstidy/data.inc.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/compresseur/lib/csstidy/data.inc.php 2022-05-20 16:59:18.000000000 +0100
@@ -55,7 +55,7 @@
* @global array $data['csstidy']['at_rules']
* @version 1.1
*/
-$data['csstidy']['at_rules'] = array('page' => 'is','font-face' => 'atis','charset' => 'iv', 'import' => 'iv','namespace' => 'iv','media' => 'at','keyframes' => 'at','-moz-keyframes' => 'at','-o-keyframes' => 'at','-webkit-keyframes' => 'at','-ms-keyframes' => 'at');
+$data['csstidy']['at_rules'] = array('page' => 'is','font-face' => 'atis','charset' => 'iv', 'import' => 'iv','namespace' => 'iv','media' => 'at', 'supports' => 'at', 'keyframes' => 'at','-moz-keyframes' => 'at','-o-keyframes' => 'at','-webkit-keyframes' => 'at','-ms-keyframes' => 'at');
/**
* Properties that need a value with unit
@@ -588,20 +588,20 @@
* @version 1.0
* @see csstidy::load_template()
*/
-$data['csstidy']['predefined_templates']['default'][] = ''; //string before @rule
-$data['csstidy']['predefined_templates']['default'][] = '{'."\n"; //bracket after @-rule
-$data['csstidy']['predefined_templates']['default'][] = ''; //string before selector
-$data['csstidy']['predefined_templates']['default'][] = '{'."\n"; //bracket after selector
-$data['csstidy']['predefined_templates']['default'][] = ''; //string before property
-$data['csstidy']['predefined_templates']['default'][] = ''; //string after property+before value
-$data['csstidy']['predefined_templates']['default'][] = ';'."\n"; //string after value
-$data['csstidy']['predefined_templates']['default'][] = '}'; //closing bracket - selector
-$data['csstidy']['predefined_templates']['default'][] = "\n\n"; //space between blocks {...}
-$data['csstidy']['predefined_templates']['default'][] = "\n".'}'. "\n\n"; //closing bracket @-rule
-$data['csstidy']['predefined_templates']['default'][] = ''; //indent in @-rule
-$data['csstidy']['predefined_templates']['default'][] = ''; // before comment
-$data['csstidy']['predefined_templates']['default'][] = ''."\n"; // after comment
-$data['csstidy']['predefined_templates']['default'][] = "\n"; // after each line @-rule
+$data['csstidy']['predefined_templates']['default'][0] = ''; //string before @rule
+$data['csstidy']['predefined_templates']['default'][1] = '{'."\n"; //bracket after @-rule
+$data['csstidy']['predefined_templates']['default'][2] = ''; //string before selector
+$data['csstidy']['predefined_templates']['default'][3] = '{'."\n"; //bracket after selector
+$data['csstidy']['predefined_templates']['default'][4] = ''; //string before property
+$data['csstidy']['predefined_templates']['default'][5] = ''; //string after property+before value
+$data['csstidy']['predefined_templates']['default'][6] = ';'."\n"; //string after value
+$data['csstidy']['predefined_templates']['default'][7] = '}'; //closing bracket - selector
+$data['csstidy']['predefined_templates']['default'][8] = "\n\n"; //space between blocks {...}
+$data['csstidy']['predefined_templates']['default'][9] = "\n".'}'. "\n\n"; //closing bracket @-rule
+$data['csstidy']['predefined_templates']['default'][10] = ''; //indent in @-rule
+$data['csstidy']['predefined_templates']['default'][11] = ''; // before comment
+$data['csstidy']['predefined_templates']['default'][12] = ''."\n"; // after comment
+$data['csstidy']['predefined_templates']['default'][13] = "\n"; // after each line @-rule
$data['csstidy']['predefined_templates']['high_compression'][] = '';
$data['csstidy']['predefined_templates']['high_compression'][] = '{'."\n";
diff -Nru spip-3.2.7/plugins-dist/compresseur/lib/csstidy/NEWS spip-3.2.15.1/plugins-dist/compresseur/lib/csstidy/NEWS
--- spip-3.2.7/plugins-dist/compresseur/lib/csstidy/NEWS 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/compresseur/lib/csstidy/NEWS 1970-01-01 01:00:00.000000000 +0100
@@ -1,28 +0,0 @@
-Changelog
-
-Key: # = backwards incompatible change, ! = new feature, - = bugfix.
-
-1.4, unknown release date
-# CSSTidy is now licensed under LGPL!
-! csstidy->set_cfg now accept a single parameter, an associative array, to
- set all configuration options
-! Templates can now be loaded via set_cfg using the 'template' config
- parameter
-! csstidy_print->formatted_page added, returns a full XHTML page based
- off of csstidy_print->formatted
-! cssparsed.css created, contains just the CSS for formatted CSS output
-! New CSS 3 units "ch" and "turn" added
-! Unit tests added, requires Text_Diff (PEAR) and SimpleTest
-! Some invalid selectors are now removed during optimization, this can
- be turned off by setting 'discard_invalid_selectors' to false
-- Added localizations for css_optimiser.php
-- Fixed bug with cookie setting for custom templates
-- Minor security problem in css_optimiser.php fixed
-- Fixed bug with float handling in exotic locales
-- Fixed bug with non-functioning getenv in ASAPI
-- Fixed bug with bad hexadecimal syntax recovery
-- At-selectors optimized by removing unnecessary url()
-- Fixed optimisation: 1.0 was not optimised to 1
-- Fixed incorrect parsing of !imporant close to numbers
-- Allowed Copy to Clipboard for Firefox if preference set (if not, gives
- instructions on how to add and warning re: security)
\ No newline at end of file
diff -Nru spip-3.2.7/plugins-dist/compresseur/lib/csstidy/README.md spip-3.2.15.1/plugins-dist/compresseur/lib/csstidy/README.md
--- spip-3.2.7/plugins-dist/compresseur/lib/csstidy/README.md 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/compresseur/lib/csstidy/README.md 2022-05-20 16:59:18.000000000 +0100
@@ -2,20 +2,58 @@
CSSTidy is a CSS minifier
+* css_optimiser.php is the web-interface
+* class.csstidy.php is the parser
+* bin/pcsstidy is the standalone command line executable
+
+This class represents a CSS parser which reads CSS code and saves it in an array.
+In opposite to most other CSS parsers, it does not use regular expressions and
+thus has full CSS3 support and a higher reliability. The downside of not using regular expressions
+is a lower speed though.
+Additional to that it applies some optimisations and fixes to the CSS code.
+
+
+## Usage
+
+```
+include('class.csstidy.php');
+$csstidy = new csstidy();
+
+// Set some options :
+$csstidy->set_cfg('optimise_shorthands', 2);
+$csstidy->set_cfg('template', 'high');
+
+// Parse the CSS
+$csstidy->parse($css_code);
+
+// Get back the optimized CSS Code
+$css_code_opt = $csstidy->print->plain();
+```
+
+
+## Changelog
+* v1.7.3 :
+ - fix bug and notice on reverse_left_and_right option
+* v1.7.1 :
+ - fix deprecated with PHP 7.4
+* v1.7.0 :
+ - provide bin/pcsstidy for command line usage
+ - support nested @media and @supports rules
* v1.6.5 :
- fix warnings with PHP 7.3
+ - fix warnings with PHP 7.3
* v1.6.4 :
- preserve important comments (starting with !) in the minification /*! Credits/Licence */
+ - preserve important comments (starting with !) in the minification /*! Credits/Licence */
* v1.6.3 :
- border-radius shorthands optimisation, reverse_left_and_right option
+ - border-radius shorthands optimisation, reverse_left_and_right option
* v1.5.7 :
- PHP 7 compatibility, composer update, Travis CI integration
+ - PHP 7 compatibility, composer update, Travis CI integration
* v1.5.6 :
- fixes minor bugs, mainly on CSS3 properties/units
+ - fixes minor bugs, mainly on CSS3 properties/units
* v1.5.2 :
- is PHP 5.4+ compliant, removes use of GLOBALS, fixes some bugs, integrates CSS3 units
- and now available on https://packagist.org/packages/cerdic/css-tidy
-* v1.4 : is the new version coming from master branch (corresponds to the initial trunk of svn repository) after beeing stabilized
+ - is PHP 5.4+ compliant, removes use of GLOBALS, fixes some bugs, integrates CSS3 units
+ - and now available on https://packagist.org/packages/cerdic/css-tidy
+* v1.4 :
+Is the new version coming from master branch (corresponds to the initial trunk of svn repository) after beeing stabilized
* v1.3 branch corresponds to the last stable relase published by the author.
It integrates some bugfixes and a 1.3.1 version has been taged
Since the original project (http://csstidy.sourceforge.net/index.php) has been suspended
@@ -23,34 +61,26 @@
Only PHP version is here maintained
----
-
-## CSSTidy
-
-Original Tracker :
-http://sourceforge.net/tracker/?group_id=148404&atid=771415
+## Licence
-css_optimiser.php is the web-interface, css_parser.php contains the PHP class (CSSTidy).
+ Copyright 2005-2007 Florian Schmitz
+ Copyright 2010-2019 Cedric Morin
-This class represents a CSS parser which reads CSS code and saves it in an array.
-In opposite to most other CSS parsers, it does not use regular expressions and
-thus has full CSS2 support and a higher reliability. The downside of not using regular expressions
-is a lower speed though.
-Additional to that it applies some optimisations and fixes to the CSS code.
-An online version should be available here: http://cdburnerxp.se/cssparse/css_optimiser.php
+ CSSTidy is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ CSSTidy is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
- Copyright 2005, 2006, 2007 Florian Schmitz
- CSSTidy is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- CSSTidy is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
+## History
- You should have received a copy of the GNU Lesser General Public License
- along with this program. If not, see .
+Original Tracker :
+http://sourceforge.net/tracker/?group_id=148404&atid=771415
diff -Nru spip-3.2.7/plugins-dist/compresseur/paquet.xml spip-3.2.15.1/plugins-dist/compresseur/paquet.xml
--- spip-3.2.7/plugins-dist/compresseur/paquet.xml 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/compresseur/paquet.xml 2022-05-20 16:59:18.000000000 +0100
@@ -1,7 +1,7 @@
Collectif SPIP
+ Cerdic/CSSTidy
+
GPL
@@ -24,4 +26,6 @@
+
+
diff -Nru spip-3.2.7/plugins-dist/dump/action/restaurer.php spip-3.2.15.1/plugins-dist/dump/action/restaurer.php
--- spip-3.2.7/plugins-dist/dump/action/restaurer.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/dump/action/restaurer.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/dump/action/sauvegarder.php spip-3.2.15.1/plugins-dist/dump/action/sauvegarder.php
--- spip-3.2.7/plugins-dist/dump/action/sauvegarder.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/dump/action/sauvegarder.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/dump/action/supprimer_dump.php spip-3.2.15.1/plugins-dist/dump/action/supprimer_dump.php
--- spip-3.2.7/plugins-dist/dump/action/supprimer_dump.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/dump/action/supprimer_dump.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/dump/action/telecharger_dump.php spip-3.2.15.1/plugins-dist/dump/action/telecharger_dump.php
--- spip-3.2.7/plugins-dist/dump/action/telecharger_dump.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/dump/action/telecharger_dump.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/dump/base/restaurer.php spip-3.2.15.1/plugins-dist/dump/base/restaurer.php
--- spip-3.2.7/plugins-dist/dump/base/restaurer.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/dump/base/restaurer.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/dump/connect/dump.php spip-3.2.15.1/plugins-dist/dump/connect/dump.php
--- spip-3.2.7/plugins-dist/dump/connect/dump.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/dump/connect/dump.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/dump/dump_autoriser.php spip-3.2.15.1/plugins-dist/dump/dump_autoriser.php
--- spip-3.2.7/plugins-dist/dump/dump_autoriser.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/dump/dump_autoriser.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/dump/exec/base_restaurer.php spip-3.2.15.1/plugins-dist/dump/exec/base_restaurer.php
--- spip-3.2.7/plugins-dist/dump/exec/base_restaurer.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/dump/exec/base_restaurer.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/dump/formulaires/restaurer.php spip-3.2.15.1/plugins-dist/dump/formulaires/restaurer.php
--- spip-3.2.7/plugins-dist/dump/formulaires/restaurer.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/dump/formulaires/restaurer.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/dump/formulaires/sauvegarder.php spip-3.2.15.1/plugins-dist/dump/formulaires/sauvegarder.php
--- spip-3.2.7/plugins-dist/dump/formulaires/sauvegarder.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/dump/formulaires/sauvegarder.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/dump/inc/dump.php spip-3.2.15.1/plugins-dist/dump/inc/dump.php
--- spip-3.2.7/plugins-dist/dump/inc/dump.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/dump/inc/dump.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/dump/inc/sauvegarder.php spip-3.2.15.1/plugins-dist/dump/inc/sauvegarder.php
--- spip-3.2.7/plugins-dist/dump/inc/sauvegarder.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/dump/inc/sauvegarder.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/dump/paquet.xml spip-3.2.15.1/plugins-dist/dump/paquet.xml
--- spip-3.2.7/plugins-dist/dump/paquet.xml 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/dump/paquet.xml 2022-05-20 16:59:18.000000000 +0100
@@ -1,7 +1,7 @@
/* '{current}', 'total' => '{total}'))
- . '",str_prev:"' . _T('mediabox:boxstr_previous')
- . '",str_next:"' . _T('mediabox:boxstr_next')
- . '",str_close:"' . _T('mediabox:boxstr_close')
- . '",splash_url:"' . $config['splash_url']
+ . ',sel_g:"' . mediabox_quote_js_param($config['selecteur_galerie'])
+ . '",sel_c:"' . mediabox_quote_js_param($config['selecteur_commun'])
+ . '",trans:"' . mediabox_quote_js_param($config['transition'])
+ . '",speed:"' . mediabox_quote_js_param($config['speed'])
+ . '",ssSpeed:"' . mediabox_quote_js_param($config['slideshow_speed'])
+ . '",maxW:"' . mediabox_quote_js_param($config['maxWidth'])
+ . '",maxH:"' . mediabox_quote_js_param($config['maxHeight'])
+ . '",minW:"' . mediabox_quote_js_param($config['minWidth'])
+ . '",minH:"' . mediabox_quote_js_param($config['minHeight'])
+ . '",opa:"' . mediabox_quote_js_param($config['opacite'])
+ . '",str_ssStart:"' . mediabox_quote_js_param(unicode2charset(html2unicode(_T('mediabox:boxstr_slideshowStart'))))
+ . '",str_ssStop:"' . mediabox_quote_js_param(unicode2charset(html2unicode(_T('mediabox:boxstr_slideshowStop'))))
+ . '",str_cur:"' . mediabox_quote_js_param(_T('mediabox:boxstr_current', array('current' => '{current}', 'total' => '{total}')))
+ . '",str_prev:"' . mediabox_quote_js_param(_T('mediabox:boxstr_previous'))
+ . '",str_next:"' . mediabox_quote_js_param(_T('mediabox:boxstr_next'))
+ . '",str_close:"' . mediabox_quote_js_param(_T('mediabox:boxstr_close'))
+ . '",splash_url:"' . mediabox_quote_js_param($config['splash_url'])
. '"};' . "\n";
// 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 = "' . $config['splash_width'] . '";
-var box_settings_splash_height = "' . $config['splash_height'] . '";' . "\n";
+ $configmediabox .= 'var box_settings_splash_width = "' . mediabox_quote_js_param($config['splash_width']) . '";
+var box_settings_splash_height = "' . mediabox_quote_js_param($config['splash_height']) . '";' . "\n";
$configmediabox .= 'var box_settings_iframe = true;' . "\n";
}
$flux = $configmediabox . '/* ]]> */' . "\n" . $flux;
@@ -102,6 +102,9 @@
return $flux;
}
+function mediabox_quote_js_param($valeur) {
+ return str_replace(["'", "<"], ["\\'", "<"], $valeur);
+}
function mediabox_timestamp($fichier) {
if ($m = filemtime($fichier)) {
diff -Nru spip-3.2.7/plugins-dist/mediabox/paquet.xml spip-3.2.15.1/plugins-dist/mediabox/paquet.xml
--- spip-3.2.7/plugins-dist/mediabox/paquet.xml 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mediabox/paquet.xml 2022-05-20 16:59:18.000000000 +0100
@@ -1,7 +1,7 @@
$fichier, 'name' => basename($fichier));
@@ -84,6 +87,9 @@
return true;
} else {
spip_log("echec copie locale $source", 'medias' . _LOG_ERREUR);
+ if ($fichier) {
+ @unlink(_DIR_RACINE . $fichier);
+ }
}
} else {
spip_log("echec copie locale $source n'est pas une URL distante", 'medias' . _LOG_ERREUR);
diff -Nru spip-3.2.7/plugins-dist/medias/action/desordonner_liens_documents.php spip-3.2.15.1/plugins-dist/medias/action/desordonner_liens_documents.php
--- spip-3.2.7/plugins-dist/medias/action/desordonner_liens_documents.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/action/desordonner_liens_documents.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/action/dissocier_document.php spip-3.2.15.1/plugins-dist/medias/action/dissocier_document.php
--- spip-3.2.7/plugins-dist/medias/action/dissocier_document.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/action/dissocier_document.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/action/editer_document.php spip-3.2.15.1/plugins-dist/medias/action/editer_document.php
--- spip-3.2.7/plugins-dist/medias/action/editer_document.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/action/editer_document.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
@@ -189,73 +189,82 @@
$statut_ancien = $row['statut'];
$date_publication_ancienne = $row['date_publication'];
+ $champs = array();
+
/* Autodetermination du statut si non fourni */
if (is_null($statut)) {
- $statut = 'prepa';
+ $determiner_statut_document = charger_fonction('determiner_statut_document', 'inc');
+ $champs = $determiner_statut_document($id_document, $statut_ancien, $date_publication_ancienne);
- $trouver_table = charger_fonction('trouver_table', 'base');
- $res = sql_select(
- 'id_objet,objet',
- 'spip_documents_liens',
- "objet!='document' AND id_document=" . intval($id_document)
- );
- // On aura 19 jours 3h14 et 7 secondes pour corriger en 2038 (limitation de la représentation POSIX du temps sur les 32 bits)
- $date_publication = strtotime('2038-01-01 00:00:00');
- include_spip('base/objets');
- while ($row = sql_fetch($res)) {
- if (
- // cas particulier des rubriques qui sont publiees des qu'elles contiennent un document !
- $row['objet'] == 'rubrique'
- // ou si objet publie selon sa declaration
- or objet_test_si_publie($row['objet'], $row['id_objet'])
- ) {
- $statut = 'publie';
- $date_publication = 0;
- continue;
- } // si pas publie, et article, il faut checker la date de post-publi eventuelle
- elseif ($row['objet'] == 'article'
- and $row2 = sql_fetsel(
- 'date',
- 'spip_articles',
- 'id_article=' . intval($row['id_objet']) . " AND statut='publie'"
- )
- ) {
- $statut = 'publie';
- $date_publication = min($date_publication, strtotime($row2['date']));
- }
- }
- $date_publication = date('Y-m-d H:i:s', $date_publication);
- if ($statut == 'publie' and $statut_ancien == 'publie' and $date_publication == $date_publication_ancienne) {
+ // rien a faire
+ if ($champs === false) {
return false;
}
- if ($statut != 'publie' and $statut_ancien != 'publie' and $statut_ancien != '0') {
- return false;
+
+ }
+ else {
+ if ($statut !== $statut_ancien) {
+ $champs['statut'] = $statut;
}
}
- if ($statut !== $statut_ancien
- or $date_publication != $date_publication_ancienne
- ) {
- sql_updateq(
- 'spip_documents',
- array('statut' => $statut, 'date_publication' => $date_publication),
- 'id_document=' . intval($id_document)
+
+ if (!is_null($date_publication)
+ and empty($champs['date_publication'])
+ and $date_publication != $date_publication_ancienne) {
+ $champs['date_publication'] = $date_publication;
+ }
+
+ // Envoyer aux plugins
+ $champs = pipeline('pre_edition',
+ array(
+ 'args' => array(
+ 'table' => 'spip_documents',
+ 'id_objet' => $id_document,
+ 'action' => 'instituer',
+ 'statut_ancien' => $statut_ancien,
+ 'date_ancienne' => $date_publication_ancienne,
+ ),
+ 'data' => $champs
+ )
+ );
+
+ if (!count($champs)) {
+ return false;
+ }
+
+ sql_updateq('spip_documents', $champs, 'id_document=' . intval($id_document));
+ if (!empty($champs['statut'])) {
+ $publier_rubriques = sql_allfetsel(
+ 'id_objet',
+ 'spip_documents_liens',
+ "objet='rubrique' AND id_document=" . intval($id_document)
);
- if ($statut !== $statut_ancien) {
- $publier_rubriques = sql_allfetsel(
- 'id_objet',
- 'spip_documents_liens',
- "objet='rubrique' AND id_document=" . intval($id_document)
- );
- if (count($publier_rubriques)) {
- include_spip('inc/rubriques');
- foreach ($publier_rubriques as $r) {
- calculer_rubriques_if($r['id_objet'], array('statut' => $statut), $statut_ancien, false);
- }
+ if (count($publier_rubriques)) {
+ include_spip('inc/rubriques');
+ foreach ($publier_rubriques as $r) {
+ calculer_rubriques_if($r['id_objet'], array('statut' => $champs['statut']), $statut_ancien, false);
}
}
- return true;
}
- return false;
+
+ // Invalider les caches
+ include_spip('inc/invalideur');
+ suivre_invalideur("id='document/$id_document'");
+
+ pipeline('post_edition',
+ array(
+ 'args' => array(
+ 'table' => 'spip_documents',
+ 'id_objet' => $id_document,
+ 'action' => 'instituer',
+ 'statut_ancien' => $statut_ancien,
+ 'date_ancienne' => $date_publication_ancienne,
+ ),
+ 'data' => $champs
+ )
+ );
+
+ return true;
}
diff -Nru spip-3.2.7/plugins-dist/medias/action/supprimer_document.php spip-3.2.15.1/plugins-dist/medias/action/supprimer_document.php
--- spip-3.2.7/plugins-dist/medias/action/supprimer_document.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/action/supprimer_document.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/action/supprimer_tous_orphelins.php spip-3.2.15.1/plugins-dist/medias/action/supprimer_tous_orphelins.php
--- spip-3.2.7/plugins-dist/medias/action/supprimer_tous_orphelins.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/action/supprimer_tous_orphelins.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/action/tourner.php spip-3.2.15.1/plugins-dist/medias/action/tourner.php
--- spip-3.2.7/plugins-dist/medias/action/tourner.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/action/tourner.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/action/verifier_documents_brises.php spip-3.2.15.1/plugins-dist/medias/action/verifier_documents_brises.php
--- spip-3.2.7/plugins-dist/medias/action/verifier_documents_brises.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/action/verifier_documents_brises.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/action/verifier_documents_liens.php spip-3.2.15.1/plugins-dist/medias/action/verifier_documents_liens.php
--- spip-3.2.7/plugins-dist/medias/action/verifier_documents_liens.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/action/verifier_documents_liens.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/base/medias.php spip-3.2.15.1/plugins-dist/medias/base/medias.php
--- spip-3.2.7/plugins-dist/medias/base/medias.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/base/medias.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/base/typedoc.php spip-3.2.15.1/plugins-dist/medias/base/typedoc.php
--- spip-3.2.7/plugins-dist/medias/base/typedoc.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/base/typedoc.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/formulaires/changer_fichier_document.php spip-3.2.15.1/plugins-dist/medias/formulaires/changer_fichier_document.php
--- spip-3.2.7/plugins-dist/medias/formulaires/changer_fichier_document.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/formulaires/changer_fichier_document.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/formulaires/configurer_documents.php spip-3.2.15.1/plugins-dist/medias/formulaires/configurer_documents.php
--- spip-3.2.7/plugins-dist/medias/formulaires/configurer_documents.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/formulaires/configurer_documents.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/formulaires/editer_document.php spip-3.2.15.1/plugins-dist/medias/formulaires/editer_document.php
--- spip-3.2.7/plugins-dist/medias/formulaires/editer_document.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/formulaires/editer_document.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
@@ -30,6 +30,12 @@
) {
$valeurs = formulaires_editer_objet_charger('document', $id_document, $id_parent, $lier_trad, $retour, $config_fonc, $row, $hidden);
+ if (test_formulaire_inclus_par_modele()) {
+ if (intval($id_document) and !autoriser('modifier', 'document', intval($id_document))) {
+ $valeurs['editable'] = '';
+ }
+ }
+
// relier les parents
$valeurs['parents'] = array();
$valeurs['_hidden'] = '';
diff -Nru spip-3.2.7/plugins-dist/medias/formulaires/illustrer_document.php spip-3.2.15.1/plugins-dist/medias/formulaires/illustrer_document.php
--- spip-3.2.7/plugins-dist/medias/formulaires/illustrer_document.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/formulaires/illustrer_document.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
@@ -31,6 +31,12 @@
$valeurs['id_vignette'] = $vignette['id_document'];
$valeurs['_pipeline'] = array('editer_contenu_objet', array('type' => 'illustrer_document', 'id' => $id_document));
+ if (test_formulaire_inclus_par_modele()) {
+ if (intval($id_document) and !autoriser('modifier', 'document', intval($id_document))) {
+ $valeurs['editable'] = '';
+ }
+ }
+
return $valeurs;
}
diff -Nru spip-3.2.7/plugins-dist/medias/formulaires/joindre_document.html spip-3.2.15.1/plugins-dist/medias/formulaires/joindre_document.html
--- spip-3.2.7/plugins-dist/medias/formulaires/joindre_document.html 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/formulaires/joindre_document.html 2022-05-20 16:59:18.000000000 +0100
@@ -18,6 +18,7 @@
]
-[(#ENV{_galerie,''}|oui)
+[(#REM) @deprecated 4.0 - SPIP 4.1 ]
+[(#ENV{_galerie,''}|joindre_document_galerie_valide|oui)
[(#INCLURE{fond=#ENV{_galerie}, env, ajax})]
]
diff -Nru spip-3.2.7/plugins-dist/medias/formulaires/joindre_document.php spip-3.2.15.1/plugins-dist/medias/formulaires/joindre_document.php
--- spip-3.2.7/plugins-dist/medias/formulaires/joindre_document.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/formulaires/joindre_document.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
@@ -49,6 +49,21 @@
}
/**
+ * Indique si une galerie demandée est valide
+ *
+ * @deprecated 4.0 (SPIP 4.1) L’inclusion de galerie est déprécié (non utilisé depuis SPIP 3.0). Préferez ajax_reload() après upload.
+ * @global array medias_deprecated_liste_galeries Liste de chemins de fichiers depuis la racine SPIP autorisés.
+ * @param string|null $galerie Le fichier de galerie désiré
+ */
+function joindre_document_galerie_valide($galerie) {
+ $galeries = [];
+ if (isset($GLOBALS['medias_deprecated_liste_galeries']) and is_array($GLOBALS['medias_deprecated_liste_galeries'])) {
+ $galeries = $GLOBALS['medias_deprecated_liste_galeries'];
+ }
+ return in_array($galerie, $galeries);
+}
+
+/**
* Chargement du formulaire
*
* @param int|string $id_document
@@ -60,6 +75,7 @@
* @param string $mode
* Le mode du document (auto,choix,document,image,vignette...), par défaut auto
* @param string $galerie
+ * Deprecated 4.0 (SPIP 4.1)
* Passer optionnellement une galerie jointe au form, plus utilise nativement,
* on prefere la mise a jour apres upload par ajaxReload('documents')
* @param bool|string $proposer_media
@@ -91,7 +107,7 @@
$valeurs['fichier_upload'] = $valeurs['_options_upload_ftp'] = $valeurs['_dir_upload_ftp'] = '';
$valeurs['joindre_upload'] = $valeurs['joindre_distant'] =
$valeurs['joindre_ftp'] = $valeurs['joindre_mediatheque'] = '';
-
+
// gérer le focus de la méthode d'upload lorsque le formulaire est envoyé
$valeurs['methode_focus'] = _request('methode_focus');
@@ -128,7 +144,8 @@
// On ne propose le FTP que si on a des choses a afficher
$valeurs['proposer_ftp'] = ($valeurs['_options_upload_ftp'] or $valeurs['_dir_upload_ftp']);
- if ($galerie) {
+ /** @deprecated 4.0 (SPIP 4.1). Utiliser ajaxReload('documents') après upload */
+ if ($galerie and joindre_document_galerie_valide($galerie)) {
# passer optionnellement une galerie jointe au form
# plus utilise nativement, on prefere la mise a jour
# apres upload par ajaxReload('documents')
@@ -159,6 +176,7 @@
* @param string $mode
* Le mode du document (auto,choix,document,image,vignette...), par défaut auto
* @param string $galerie
+ * Deprecated 4.0 (SPIP 4.1)
* Passer optionnellement une galerie jointe au form, plus utilise nativement,
* on prefere la mise a jour apres upload par ajaxReload('documents')
* @param bool|string $proposer_media
@@ -257,6 +275,7 @@
* @param string $mode
* Le mode du document (auto,choix,document,image,vignette...), par défaut auto
* @param string $galerie
+ * Deprecated 4.0 (SPIP 4.1)
* Passer optionnellement une galerie jointe au form, plus utilise nativement,
* on prefere la mise a jour apres upload par ajaxReload('documents')
* @param bool|string $proposer_media
diff -Nru spip-3.2.7/plugins-dist/medias/inc/choisir_mode_document.php spip-3.2.15.1/plugins-dist/medias/inc/choisir_mode_document.php
--- spip-3.2.7/plugins-dist/medias/inc/choisir_mode_document.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/inc/choisir_mode_document.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/inc/determiner_statut_document.php spip-3.2.15.1/plugins-dist/medias/inc/determiner_statut_document.php
--- spip-3.2.7/plugins-dist/medias/inc/determiner_statut_document.php 1970-01-01 01:00:00.000000000 +0100
+++ spip-3.2.15.1/plugins-dist/medias/inc/determiner_statut_document.php 2022-05-20 16:59:18.000000000 +0100
@@ -0,0 +1,83 @@
+mysqli = new mysqli($host, $username, $password);
- if (!$this->mysqli) {
- throw new Exception('mysqli_connect() failed - check permissions and spelling.');
+ if ($this->mysqli->connect_error) {
+ throw new Exception('Connect Error (' . $this->mysqli->connect_errno . ') ' . $this->mysqli->connect_error);
}
// Select database
@@ -124,14 +129,15 @@
// Create cache table if not exists
$this->create_table();
+ $this->db_structure_check = true; // set to false if you know your table structure has already been migrated to use `hash` as the primary key to avoid
+ $this->migrate_db_structure();
+
// Check version number and clear cache if changed
$version = '';
$SQLquery = 'SELECT `value`';
$SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
$SQLquery .= ' WHERE (`filename` = \''.$this->mysqli->real_escape_string(getID3::VERSION).'\')';
- $SQLquery .= ' AND (`filesize` = -1)';
- $SQLquery .= ' AND (`filetime` = -1)';
- $SQLquery .= ' AND (`analyzetime` = -1)';
+ $SQLquery .= ' AND (`hash` = \'getID3::VERSION\')';
if ($this->cursor = $this->mysqli->query($SQLquery)) {
list($version) = $this->cursor->fetch_array();
}
@@ -147,23 +153,55 @@
* clear cache
*/
public function clear_cache() {
- $this->mysqli->query('DELETE FROM `'.$this->mysqli->real_escape_string($this->table).'`');
- $this->mysqli->query('INSERT INTO `'.$this->mysqli->real_escape_string($this->table).'` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (\''.getID3::VERSION.'\', -1, -1, -1, \''.getID3::VERSION.'\')');
+ $this->mysqli->query('TRUNCATE TABLE `'.$this->mysqli->real_escape_string($this->table).'`');
+ $this->mysqli->query('INSERT INTO `'.$this->mysqli->real_escape_string($this->table).'` (`hash`, `filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (\'getID3::VERSION\', \''.getID3::VERSION.'\', -1, -1, -1, \''.getID3::VERSION.'\')');
+ }
+
+
+ /**
+ * migrate database structure if needed
+ */
+ public function migrate_db_structure() {
+ // Check for table structure
+ if ($this->db_structure_check) {
+ $SQLquery = 'SHOW COLUMNS';
+ $SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
+ $SQLquery .= ' LIKE \'hash\'';
+ $this->cursor = $this->mysqli->query($SQLquery);
+ if ($this->cursor->num_rows == 0) {
+ // table has not been migrated, add column, add hashes, change index
+ $SQLquery = 'ALTER TABLE `getid3_cache` DROP PRIMARY KEY, ADD `hash` CHAR(32) NOT NULL DEFAULT \'\' FIRST, ADD PRIMARY KEY(`hash`)';
+ $this->mysqli->query($SQLquery);
+
+ $SQLquery = 'UPDATE `getid3_cache` SET';
+ $SQLquery .= ' `hash` = MD5(`filename`, `filesize`, `filetime`)';
+ $SQLquery .= ' WHERE (`filesize` > -1)';
+ $this->mysqli->query($SQLquery);
+
+ $SQLquery = 'UPDATE `getid3_cache` SET';
+ $SQLquery .= ' `hash` = \'getID3::VERSION\'';
+ $SQLquery .= ' WHERE (`filesize` = -1)';
+ $SQLquery .= ' AND (`filetime` = -1)';
+ $SQLquery .= ' AND (`filetime` = -1)';
+ $this->mysqli->query($SQLquery);
+ }
+ }
}
/**
* analyze file
*
- * @param string $filename
- * @param int $filesize
- * @param string $original_filename
+ * @param string $filename
+ * @param int $filesize
+ * @param string $original_filename
+ * @param resource $fp
*
* @return mixed
*/
- public function analyze($filename, $filesize=null, $original_filename='') {
+ public function analyze($filename, $filesize=null, $original_filename='', $fp=null) {
- $filetime = 0;
+ $filetime = 0;
if (file_exists($filename)) {
// Short-hands
@@ -173,9 +211,7 @@
// Lookup file
$SQLquery = 'SELECT `value`';
$SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
- $SQLquery .= ' WHERE (`filename` = \''.$this->mysqli->real_escape_string($filename).'\')';
- $SQLquery .= ' AND (`filesize` = \''.$this->mysqli->real_escape_string($filesize).'\')';
- $SQLquery .= ' AND (`filetime` = \''.$this->mysqli->real_escape_string($filetime).'\')';
+ $SQLquery .= ' WHERE (`hash` = \''.$this->mysqli->real_escape_string(md5($filename.$filesize.$filetime)).'\')';
$this->cursor = $this->mysqli->query($SQLquery);
if ($this->cursor->num_rows > 0) {
// Hit
@@ -185,16 +221,18 @@
}
// Miss
- $analysis = parent::analyze($filename, $filesize, $original_filename);
+ $analysis = parent::analyze($filename, $filesize, $original_filename, $fp);
// Save result
if (file_exists($filename)) {
- $SQLquery = 'INSERT INTO `'.$this->mysqli->real_escape_string($this->table).'` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (';
- $SQLquery .= '\''.$this->mysqli->real_escape_string($filename).'\'';
+ $SQLquery = 'INSERT INTO `'.$this->mysqli->real_escape_string($this->table).'` (`hash`, `filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (';
+ $SQLquery .= '\''.$this->mysqli->real_escape_string(md5($filename.$filesize.$filetime)).'\'';
+ $SQLquery .= ', \''.$this->mysqli->real_escape_string($filename).'\'';
$SQLquery .= ', \''.$this->mysqli->real_escape_string($filesize).'\'';
$SQLquery .= ', \''.$this->mysqli->real_escape_string($filetime).'\'';
- $SQLquery .= ', \''.$this->mysqli->real_escape_string(time() ).'\'';
- $SQLquery .= ', \''.$this->mysqli->real_escape_string(base64_encode(serialize($analysis))).'\')';
+ $SQLquery .= ', UNIX_TIMESTAMP()';
+ $SQLquery .= ', \''.$this->mysqli->real_escape_string(base64_encode(serialize($analysis))).'\'';
+ $SQLquery .= ')';
$this->cursor = $this->mysqli->query($SQLquery);
}
return $analysis;
@@ -207,13 +245,18 @@
* @param bool $drop
*/
private function create_table($drop=false) {
+ if ($drop) {
+ $SQLquery = 'DROP TABLE IF EXISTS `'.$this->mysqli->real_escape_string($this->table).'`';
+ $this->mysqli->query($SQLquery);
+ }
$SQLquery = 'CREATE TABLE IF NOT EXISTS `'.$this->mysqli->real_escape_string($this->table).'` (';
- $SQLquery .= '`filename` VARCHAR(990) NOT NULL DEFAULT \'\'';
+ $SQLquery .= '`hash` CHAR(32) NOT NULL DEFAULT \'\'';
+ $SQLquery .= ', `filename` VARCHAR(1000) NOT NULL DEFAULT \'\'';
$SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\'';
$SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\'';
$SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\'';
$SQLquery .= ', `value` LONGTEXT NOT NULL';
- $SQLquery .= ', PRIMARY KEY (`filename`, `filesize`, `filetime`))';
+ $SQLquery .= ', PRIMARY KEY (`hash`))';
$this->cursor = $this->mysqli->query($SQLquery);
echo $this->mysqli->error;
}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/extension.cache.mysql.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/extension.cache.mysql.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/extension.cache.mysql.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/extension.cache.mysql.php 2022-05-20 16:59:18.000000000 +0100
@@ -159,15 +159,16 @@
/**
* analyze file
*
- * @param string $filename
- * @param int $filesize
- * @param string $original_filename
+ * @param string $filename
+ * @param int $filesize
+ * @param string $original_filename
+ * @param resource $fp
*
* @return mixed
*/
- public function analyze($filename, $filesize=null, $original_filename='') {
+ public function analyze($filename, $filesize=null, $original_filename='', $fp=null) {
- $filetime = 0;
+ $filetime = 0;
if (file_exists($filename)) {
// Short-hands
@@ -189,7 +190,7 @@
}
// Miss
- $analysis = parent::analyze($filename, $filesize, $original_filename);
+ $analysis = parent::analyze($filename, $filesize, $original_filename, $fp);
// Save result
if (file_exists($filename)) {
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/extension.cache.sqlite3.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/extension.cache.sqlite3.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/extension.cache.sqlite3.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/extension.cache.sqlite3.php 2022-05-20 16:59:18.000000000 +0100
@@ -172,13 +172,14 @@
/**
* analyze file and cache them, if cached pull from the db
*
- * @param string $filename
- * @param integer $filesize
- * @param string $original_filename
+ * @param string $filename
+ * @param integer $filesize
+ * @param string $original_filename
+ * @param resource $fp
*
* @return mixed|false
*/
- public function analyze($filename, $filesize=null, $original_filename='') {
+ public function analyze($filename, $filesize=null, $original_filename='', $fp=null) {
if (!file_exists($filename)) {
return false;
}
@@ -201,7 +202,7 @@
return unserialize(base64_decode($result));
}
// if it hasn't been analyzed before, then do it now
- $analysis = parent::analyze($filename, $filesize, $original_filename);
+ $analysis = parent::analyze($filename, $filesize, $original_filename, $fp);
// Save result
$sql = $this->getQuery('cache_file');
$stmt = $db->prepare($sql);
@@ -262,25 +263,18 @@
switch ($name) {
case 'version_check':
return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = '-1' AND filetime = '-1' AND analyzetime = '-1'";
- break;
case 'delete_cache':
return "DELETE FROM $this->table";
- break;
case 'set_version':
return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, -1, -1, -1, :val)";
- break;
case 'get_id3_data':
return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = :filesize AND filetime = :filetime";
- break;
case 'cache_file':
return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, :filesize, :filetime, :atime, :val)";
- break;
case 'make_table':
return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) DEFAULT '', dirname VARCHAR(255) DEFAULT '', filesize INT(11) DEFAULT '0', filetime INT(11) DEFAULT '0', analyzetime INT(11) DEFAULT '0', val text, PRIMARY KEY (filename, filesize, filetime))";
- break;
case 'get_cached_dir':
return "SELECT val FROM $this->table WHERE dirname = :dirname";
- break;
default:
return null;
}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/getid3.lib.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/getid3.lib.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/getid3.lib.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/getid3.lib.php 2022-05-20 16:59:18.000000000 +0100
@@ -15,10 +15,10 @@
class getid3_lib
{
/**
- * @param string $string
- * @param bool $hex
- * @param bool $spaces
- * @param string $htmlencoding
+ * @param string $string
+ * @param bool $hex
+ * @param bool $spaces
+ * @param string|bool $htmlencoding
*
* @return string
*/
@@ -26,9 +26,9 @@
$returnstring = '';
for ($i = 0; $i < strlen($string); $i++) {
if ($hex) {
- $returnstring .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT);
+ $returnstring .= str_pad(dechex(ord($string[$i])), 2, '0', STR_PAD_LEFT);
} else {
- $returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string{$i}) ? $string{$i} : '¤');
+ $returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string[$i]) ? $string[$i] : '¤');
}
if ($spaces) {
$returnstring .= ' ';
@@ -152,11 +152,11 @@
public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) {
if (strpos($binarypointnumber, '.') === false) {
$binarypointnumber = '0.'.$binarypointnumber;
- } elseif ($binarypointnumber{0} == '.') {
+ } elseif ($binarypointnumber[0] == '.') {
$binarypointnumber = '0'.$binarypointnumber;
}
$exponent = 0;
- while (($binarypointnumber{0} != '1') || (substr($binarypointnumber, 1, 1) != '.')) {
+ while (($binarypointnumber[0] != '1') || (substr($binarypointnumber, 1, 1) != '.')) {
if (substr($binarypointnumber, 1, 1) == '.') {
$exponent--;
$binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3);
@@ -164,7 +164,7 @@
$pointpos = strpos($binarypointnumber, '.');
$exponent += ($pointpos - 1);
$binarypointnumber = str_replace('.', '', $binarypointnumber);
- $binarypointnumber = $binarypointnumber{0}.'.'.substr($binarypointnumber, 1);
+ $binarypointnumber = $binarypointnumber[0].'.'.substr($binarypointnumber, 1);
}
}
$binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT);
@@ -216,7 +216,6 @@
default:
return false;
- break;
}
if ($floatvalue >= 0) {
$signbit = '0';
@@ -255,7 +254,7 @@
if (!$bitword) {
return 0;
}
- $signbit = $bitword{0};
+ $signbit = $bitword[0];
$floatvalue = 0;
$exponentbits = 0;
$fractionbits = 0;
@@ -275,7 +274,7 @@
// 80-bit Apple SANE format
// http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
$exponentstring = substr($bitword, 1, 15);
- $isnormalized = intval($bitword{16});
+ $isnormalized = intval($bitword[16]);
$fractionstring = substr($bitword, 17, 63);
$exponent = pow(2, self::Bin2Dec($exponentstring) - 16383);
$fraction = $isnormalized + self::DecimalBinary2Float($fractionstring);
@@ -284,11 +283,9 @@
$floatvalue *= -1;
}
return $floatvalue;
- break;
default:
return false;
- break;
}
$exponentstring = substr($bitword, 1, $exponentbits);
$fractionstring = substr($bitword, $exponentbits + 1, $fractionbits);
@@ -343,9 +340,9 @@
for ($i = 0; $i < $bytewordlen; $i++) {
if ($synchsafe) { // disregard MSB, effectively 7-bit bytes
//$intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); // faster, but runs into problems past 2^31 on 32-bit systems
- $intvalue += (ord($byteword{$i}) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7);
+ $intvalue += (ord($byteword[$i]) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7);
} else {
- $intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i));
+ $intvalue += ord($byteword[$i]) * pow(256, ($bytewordlen - 1 - $i));
}
}
if ($signed && !$synchsafe) {
@@ -390,7 +387,7 @@
$binvalue = '';
$bytewordlen = strlen($byteword);
for ($i = 0; $i < $bytewordlen; $i++) {
- $binvalue .= str_pad(decbin(ord($byteword{$i})), 8, '0', STR_PAD_LEFT);
+ $binvalue .= str_pad(decbin(ord($byteword[$i])), 8, '0', STR_PAD_LEFT);
}
return $binvalue;
}
@@ -451,7 +448,7 @@
public static function Bin2Dec($binstring, $signed=false) {
$signmult = 1;
if ($signed) {
- if ($binstring{0} == '1') {
+ if ($binstring[0] == '1') {
$signmult = -1;
}
$binstring = substr($binstring, 1);
@@ -500,8 +497,8 @@
}
/**
- * @param array $array1
- * @param array $array2
+ * @param mixed $array1
+ * @param mixed $array2
*
* @return array|false
*/
@@ -523,8 +520,8 @@
}
/**
- * @param array $array1
- * @param array $array2
+ * @param mixed $array1
+ * @param mixed $array2
*
* @return array|false
*/
@@ -544,8 +541,8 @@
}
/**
- * @param array $array1
- * @param array $array2
+ * @param mixed $array1
+ * @param mixed $array2
*
* @return array|false|null
*/
@@ -684,10 +681,10 @@
*/
public static function array_max($arraydata, $returnkey=false) {
$maxvalue = false;
- $maxkey = false;
+ $maxkey = false;
foreach ($arraydata as $key => $value) {
if (!is_array($value)) {
- if ($value > $maxvalue) {
+ if (($maxvalue === false) || ($value > $maxvalue)) {
$maxvalue = $value;
$maxkey = $key;
}
@@ -704,10 +701,10 @@
*/
public static function array_min($arraydata, $returnkey=false) {
$minvalue = false;
- $minkey = false;
+ $minkey = false;
foreach ($arraydata as $key => $value) {
if (!is_array($value)) {
- if ($value > $minvalue) {
+ if (($minvalue === false) || ($value < $minvalue)) {
$minvalue = $value;
$minkey = $key;
}
@@ -735,9 +732,9 @@
}
/**
- * @param SimpleXMLElement|array $XMLobject
+ * @param SimpleXMLElement|array|mixed $XMLobject
*
- * @return array
+ * @return mixed
*/
public static function SimpleXMLelement2array($XMLobject) {
if (!is_object($XMLobject) && !is_array($XMLobject)) {
@@ -751,9 +748,7 @@
}
/**
- * self::md5_data() - returns md5sum for a file from startuing position to absolute end position
- *
- * @author Allan Hansen
+ * Returns checksum for a file from starting position to absolute end position.
*
* @param string $file
* @param int $offset
@@ -761,97 +756,30 @@
* @param string $algorithm
*
* @return string|false
- * @throws Exception
* @throws getid3_exception
*/
public static function hash_data($file, $offset, $end, $algorithm) {
- static $tempdir = '';
- $windows_call = null;
- $unix_call = null;
- $hash_length = null;
- $hash_function = null;
if (!self::intValueSupported($end)) {
return false;
}
- switch ($algorithm) {
- case 'md5':
- $hash_function = 'md5_file';
- $unix_call = 'md5sum';
- $windows_call = 'md5sum.exe';
- $hash_length = 32;
- break;
-
- case 'sha1':
- $hash_function = 'sha1_file';
- $unix_call = 'sha1sum';
- $windows_call = 'sha1sum.exe';
- $hash_length = 40;
- break;
-
- default:
- throw new Exception('Invalid algorithm ('.$algorithm.') in self::hash_data()');
- break;
+ if (!in_array($algorithm, array('md5', 'sha1'))) {
+ throw new getid3_exception('Invalid algorithm ('.$algorithm.') in self::hash_data()');
}
- $size = $end - $offset;
- while (true) {
- if (GETID3_OS_ISWINDOWS) {
-
- // It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data
- // Fall back to create-temp-file method:
- if ($algorithm == 'sha1') {
- break;
- }
-
- $RequiredFiles = array('cygwin1.dll', 'head.exe', 'tail.exe', $windows_call);
- foreach ($RequiredFiles as $required_file) {
- if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
- // helper apps not available - fall back to old method
- break 2;
- }
- }
- $commandline = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' '.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)).' | ';
- $commandline .= GETID3_HELPERAPPSDIR.'tail.exe -c '.$size.' | ';
- $commandline .= GETID3_HELPERAPPSDIR.$windows_call;
- } else {
-
- $commandline = 'head -c'.$end.' '.escapeshellarg($file).' | ';
- $commandline .= 'tail -c'.$size.' | ';
- $commandline .= $unix_call;
-
- }
- if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
- //throw new Exception('PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm');
- break;
- }
- return substr(`$commandline`, 0, $hash_length);
- }
+ $size = $end - $offset;
- if (empty($tempdir)) {
- // yes this is ugly, feel free to suggest a better way
- require_once(dirname(__FILE__).'/getid3.php');
- $getid3_temp = new getID3();
- $tempdir = $getid3_temp->tempdir;
- unset($getid3_temp);
- }
- // try to create a temporary file in the system temp directory - invalid dirname should force to system temp dir
- if (($data_filename = tempnam($tempdir, 'gI3')) === false) {
- // can't find anywhere to create a temp file, just fail
- return false;
+ $fp = fopen($file, 'rb');
+ fseek($fp, $offset);
+ $ctx = hash_init($algorithm);
+ while ($size > 0) {
+ $buffer = fread($fp, min($size, getID3::FREAD_BUFFER_SIZE));
+ hash_update($ctx, $buffer);
+ $size -= getID3::FREAD_BUFFER_SIZE;
}
+ $hash = hash_final($ctx);
+ fclose($fp);
- // Init
- $result = false;
-
- // copy parts of file
- try {
- self::CopyFileParts($file, $data_filename, $offset, $end - $offset);
- $result = $hash_function($data_filename);
- } catch (Exception $e) {
- throw new Exception('self::CopyFileParts() failed in getid_lib::hash_data(): '.$e->getMessage());
- }
- unlink($data_filename);
- return $result;
+ return $hash;
}
/**
@@ -862,6 +790,8 @@
*
* @return bool
* @throws Exception
+ *
+ * @deprecated Unused, may be removed in future versions of getID3
*/
public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) {
if (!self::intValueSupported($offset + $length)) {
@@ -935,7 +865,7 @@
$newcharstring .= "\xEF\xBB\xBF";
}
for ($i = 0; $i < strlen($string); $i++) {
- $charval = ord($string{$i});
+ $charval = ord($string[$i]);
$newcharstring .= self::iconv_fallback_int_utf8($charval);
}
return $newcharstring;
@@ -955,7 +885,7 @@
$newcharstring .= "\xFE\xFF";
}
for ($i = 0; $i < strlen($string); $i++) {
- $newcharstring .= "\x00".$string{$i};
+ $newcharstring .= "\x00".$string[$i];
}
return $newcharstring;
}
@@ -974,7 +904,7 @@
$newcharstring .= "\xFF\xFE";
}
for ($i = 0; $i < strlen($string); $i++) {
- $newcharstring .= $string{$i}."\x00";
+ $newcharstring .= $string[$i]."\x00";
}
return $newcharstring;
}
@@ -1006,27 +936,27 @@
$offset = 0;
$stringlength = strlen($string);
while ($offset < $stringlength) {
- if ((ord($string{$offset}) | 0x07) == 0xF7) {
+ if ((ord($string[$offset]) | 0x07) == 0xF7) {
// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
- $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
- ((ord($string{($offset + 1)}) & 0x3F) << 12) &
- ((ord($string{($offset + 2)}) & 0x3F) << 6) &
- (ord($string{($offset + 3)}) & 0x3F);
+ $charval = ((ord($string[($offset + 0)]) & 0x07) << 18) &
+ ((ord($string[($offset + 1)]) & 0x3F) << 12) &
+ ((ord($string[($offset + 2)]) & 0x3F) << 6) &
+ (ord($string[($offset + 3)]) & 0x3F);
$offset += 4;
- } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
+ } elseif ((ord($string[$offset]) | 0x0F) == 0xEF) {
// 1110bbbb 10bbbbbb 10bbbbbb
- $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
- ((ord($string{($offset + 1)}) & 0x3F) << 6) &
- (ord($string{($offset + 2)}) & 0x3F);
+ $charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) &
+ ((ord($string[($offset + 1)]) & 0x3F) << 6) &
+ (ord($string[($offset + 2)]) & 0x3F);
$offset += 3;
- } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
+ } elseif ((ord($string[$offset]) | 0x1F) == 0xDF) {
// 110bbbbb 10bbbbbb
- $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) &
- (ord($string{($offset + 1)}) & 0x3F);
+ $charval = ((ord($string[($offset + 0)]) & 0x1F) << 6) &
+ (ord($string[($offset + 1)]) & 0x3F);
$offset += 2;
- } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
+ } elseif ((ord($string[$offset]) | 0x7F) == 0x7F) {
// 0bbbbbbb
- $charval = ord($string{$offset});
+ $charval = ord($string[$offset]);
$offset += 1;
} else {
// error? throw some kind of warning here?
@@ -1056,27 +986,27 @@
$offset = 0;
$stringlength = strlen($string);
while ($offset < $stringlength) {
- if ((ord($string{$offset}) | 0x07) == 0xF7) {
+ if ((ord($string[$offset]) | 0x07) == 0xF7) {
// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
- $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
- ((ord($string{($offset + 1)}) & 0x3F) << 12) &
- ((ord($string{($offset + 2)}) & 0x3F) << 6) &
- (ord($string{($offset + 3)}) & 0x3F);
+ $charval = ((ord($string[($offset + 0)]) & 0x07) << 18) &
+ ((ord($string[($offset + 1)]) & 0x3F) << 12) &
+ ((ord($string[($offset + 2)]) & 0x3F) << 6) &
+ (ord($string[($offset + 3)]) & 0x3F);
$offset += 4;
- } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
+ } elseif ((ord($string[$offset]) | 0x0F) == 0xEF) {
// 1110bbbb 10bbbbbb 10bbbbbb
- $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
- ((ord($string{($offset + 1)}) & 0x3F) << 6) &
- (ord($string{($offset + 2)}) & 0x3F);
+ $charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) &
+ ((ord($string[($offset + 1)]) & 0x3F) << 6) &
+ (ord($string[($offset + 2)]) & 0x3F);
$offset += 3;
- } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
+ } elseif ((ord($string[$offset]) | 0x1F) == 0xDF) {
// 110bbbbb 10bbbbbb
- $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) &
- (ord($string{($offset + 1)}) & 0x3F);
+ $charval = ((ord($string[($offset + 0)]) & 0x1F) << 6) &
+ (ord($string[($offset + 1)]) & 0x3F);
$offset += 2;
- } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
+ } elseif ((ord($string[$offset]) | 0x7F) == 0x7F) {
// 0bbbbbbb
- $charval = ord($string{$offset});
+ $charval = ord($string[$offset]);
$offset += 1;
} else {
// error? throw some kind of warning here?
@@ -1106,27 +1036,27 @@
$offset = 0;
$stringlength = strlen($string);
while ($offset < $stringlength) {
- if ((ord($string{$offset}) | 0x07) == 0xF7) {
+ if ((ord($string[$offset]) | 0x07) == 0xF7) {
// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
- $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
- ((ord($string{($offset + 1)}) & 0x3F) << 12) &
- ((ord($string{($offset + 2)}) & 0x3F) << 6) &
- (ord($string{($offset + 3)}) & 0x3F);
+ $charval = ((ord($string[($offset + 0)]) & 0x07) << 18) &
+ ((ord($string[($offset + 1)]) & 0x3F) << 12) &
+ ((ord($string[($offset + 2)]) & 0x3F) << 6) &
+ (ord($string[($offset + 3)]) & 0x3F);
$offset += 4;
- } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
+ } elseif ((ord($string[$offset]) | 0x0F) == 0xEF) {
// 1110bbbb 10bbbbbb 10bbbbbb
- $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
- ((ord($string{($offset + 1)}) & 0x3F) << 6) &
- (ord($string{($offset + 2)}) & 0x3F);
+ $charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) &
+ ((ord($string[($offset + 1)]) & 0x3F) << 6) &
+ (ord($string[($offset + 2)]) & 0x3F);
$offset += 3;
- } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
+ } elseif ((ord($string[$offset]) | 0x1F) == 0xDF) {
// 110bbbbb 10bbbbbb
- $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) &
- (ord($string{($offset + 1)}) & 0x3F);
+ $charval = ((ord($string[($offset + 0)]) & 0x1F) << 6) &
+ (ord($string[($offset + 1)]) & 0x3F);
$offset += 2;
- } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
+ } elseif ((ord($string[$offset]) | 0x7F) == 0x7F) {
// 0bbbbbbb
- $charval = ord($string{$offset});
+ $charval = ord($string[$offset]);
$offset += 1;
} else {
// error? maybe throw some warning here?
@@ -1281,6 +1211,16 @@
// mb_convert_encoding() available
if (function_exists('mb_convert_encoding')) {
+ if ((strtoupper($in_charset) == 'UTF-16') && (substr($string, 0, 2) != "\xFE\xFF") && (substr($string, 0, 2) != "\xFF\xFE")) {
+ // if BOM missing, mb_convert_encoding will mishandle the conversion, assume UTF-16BE and prepend appropriate BOM
+ $string = "\xFF\xFE".$string;
+ }
+ if ((strtoupper($in_charset) == 'UTF-16') && (strtoupper($out_charset) == 'UTF-8')) {
+ if (($string == "\xFF\xFE") || ($string == "\xFE\xFF")) {
+ // if string consists of only BOM, mb_convert_encoding will return the BOM unmodified
+ return '';
+ }
+ }
if ($converted_string = @mb_convert_encoding($string, $out_charset, $in_charset)) {
switch ($out_charset) {
case 'ISO-8859-1':
@@ -1290,9 +1230,9 @@
return $converted_string;
}
return $string;
- }
+
// iconv() available
- else if (function_exists('iconv')) {
+ } elseif (function_exists('iconv')) {
if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) {
switch ($out_charset) {
case 'ISO-8859-1':
@@ -1397,22 +1337,22 @@
case 'utf-8':
$strlen = strlen($string);
for ($i = 0; $i < $strlen; $i++) {
- $char_ord_val = ord($string{$i});
+ $char_ord_val = ord($string[$i]);
$charval = 0;
if ($char_ord_val < 0x80) {
$charval = $char_ord_val;
} elseif ((($char_ord_val & 0xF0) >> 4) == 0x0F && $i+3 < $strlen) {
$charval = (($char_ord_val & 0x07) << 18);
- $charval += ((ord($string{++$i}) & 0x3F) << 12);
- $charval += ((ord($string{++$i}) & 0x3F) << 6);
- $charval += (ord($string{++$i}) & 0x3F);
+ $charval += ((ord($string[++$i]) & 0x3F) << 12);
+ $charval += ((ord($string[++$i]) & 0x3F) << 6);
+ $charval += (ord($string[++$i]) & 0x3F);
} elseif ((($char_ord_val & 0xE0) >> 5) == 0x07 && $i+2 < $strlen) {
$charval = (($char_ord_val & 0x0F) << 12);
- $charval += ((ord($string{++$i}) & 0x3F) << 6);
- $charval += (ord($string{++$i}) & 0x3F);
+ $charval += ((ord($string[++$i]) & 0x3F) << 6);
+ $charval += (ord($string[++$i]) & 0x3F);
} elseif ((($char_ord_val & 0xC0) >> 6) == 0x03 && $i+1 < $strlen) {
$charval = (($char_ord_val & 0x1F) << 6);
- $charval += (ord($string{++$i}) & 0x3F);
+ $charval += (ord($string[++$i]) & 0x3F);
}
if (($charval >= 32) && ($charval <= 127)) {
$HTMLstring .= htmlentities(chr($charval));
@@ -1536,6 +1476,15 @@
* @return array|false
*/
public static function GetDataImageSize($imgData, &$imageinfo=array()) {
+ if (PHP_VERSION_ID >= 50400) {
+ $GetDataImageSize = @getimagesizefromstring($imgData, $imageinfo);
+ if ($GetDataImageSize === false || !isset($GetDataImageSize[0], $GetDataImageSize[1])) {
+ return false;
+ }
+ $GetDataImageSize['height'] = $GetDataImageSize[0];
+ $GetDataImageSize['width'] = $GetDataImageSize[1];
+ return $GetDataImageSize;
+ }
static $tempdir = '';
if (empty($tempdir)) {
if (function_exists('sys_get_temp_dir')) {
@@ -1544,12 +1493,11 @@
// yes this is ugly, feel free to suggest a better way
if (include_once(dirname(__FILE__).'/getid3.php')) {
- if ($getid3_temp = new getID3()) {
- if ($getid3_temp_tempdir = $getid3_temp->tempdir) {
- $tempdir = $getid3_temp_tempdir;
- }
- unset($getid3_temp, $getid3_temp_tempdir);
+ $getid3_temp = new getID3();
+ if ($getid3_temp_tempdir = $getid3_temp->tempdir) {
+ $tempdir = $getid3_temp_tempdir;
}
+ unset($getid3_temp, $getid3_temp_tempdir);
}
}
$GetDataImageSize = false;
@@ -1581,13 +1529,20 @@
/**
* @param array $ThisFileInfo
+ * @param bool $option_tags_html default true (just as in the main getID3 class)
*
* @return bool
*/
- public static function CopyTagsToComments(&$ThisFileInfo) {
-
+ public static function CopyTagsToComments(&$ThisFileInfo, $option_tags_html=true) {
// Copy all entries from ['tags'] into common ['comments']
if (!empty($ThisFileInfo['tags'])) {
+ if (isset($ThisFileInfo['tags']['id3v1'])) {
+ // bubble ID3v1 to the end, if present to aid in detecting bad ID3v1 encodings
+ $ID3v1 = $ThisFileInfo['tags']['id3v1'];
+ unset($ThisFileInfo['tags']['id3v1']);
+ $ThisFileInfo['tags']['id3v1'] = $ID3v1;
+ unset($ID3v1);
+ }
foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) {
foreach ($tagarray as $tagname => $tagdata) {
foreach ($tagdata as $key => $value) {
@@ -1606,6 +1561,13 @@
break 2;
}
}
+ if (function_exists('mb_convert_encoding')) {
+ if (trim($value) == trim(substr(mb_convert_encoding($existingvalue, $ThisFileInfo['id3v1']['encoding'], $ThisFileInfo['encoding']), 0, 30))) {
+ // value stored in ID3v1 appears to be probably the multibyte value transliterated (badly) into ISO-8859-1 in ID3v1.
+ // As an example, Foobar2000 will do this if you tag a file with Chinese or Arabic or Cyrillic or something that doesn't fit into ISO-8859-1 the ID3v1 will consist of mostly "?" characters, one per multibyte unrepresentable character
+ break 2;
+ }
+ }
} elseif (!is_array($value)) {
@@ -1614,7 +1576,6 @@
$oldvaluelength = strlen(trim($existingvalue));
if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) {
$ThisFileInfo['comments'][$tagname][$existingkey] = trim($value);
- //break 2;
break;
}
}
@@ -1625,7 +1586,7 @@
if (!is_int($key) && !ctype_digit($key)) {
$ThisFileInfo['comments'][$tagname][$key] = $value;
} else {
- if (isset($ThisFileInfo['comments'][$tagname])) {
+ if (!isset($ThisFileInfo['comments'][$tagname])) {
$ThisFileInfo['comments'][$tagname] = array($value);
} else {
$ThisFileInfo['comments'][$tagname][] = $value;
@@ -1649,19 +1610,21 @@
}
}
- // Copy to ['comments_html']
- if (!empty($ThisFileInfo['comments'])) {
- foreach ($ThisFileInfo['comments'] as $field => $values) {
- if ($field == 'picture') {
- // pictures can take up a lot of space, and we don't need multiple copies of them
- // let there be a single copy in [comments][picture], and not elsewhere
- continue;
- }
- foreach ($values as $index => $value) {
- if (is_array($value)) {
- $ThisFileInfo['comments_html'][$field][$index] = $value;
- } else {
- $ThisFileInfo['comments_html'][$field][$index] = str_replace('', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding']));
+ if ($option_tags_html) {
+ // Copy ['comments'] to ['comments_html']
+ if (!empty($ThisFileInfo['comments'])) {
+ foreach ($ThisFileInfo['comments'] as $field => $values) {
+ if ($field == 'picture') {
+ // pictures can take up a lot of space, and we don't need multiple copies of them
+ // let there be a single copy in [comments][picture], and not elsewhere
+ continue;
+ }
+ foreach ($values as $index => $value) {
+ if (is_array($value)) {
+ $ThisFileInfo['comments_html'][$field][$index] = $value;
+ } else {
+ $ThisFileInfo['comments_html'][$field][$index] = str_replace('', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding']));
+ }
}
}
}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/getid3.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/getid3.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/getid3.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/getid3.php 2022-05-20 16:59:18.000000000 +0100
@@ -1,5 +1,4 @@
//
// available at https://github.com/JamesHeinrich/getID3 //
@@ -100,6 +99,13 @@
*/
public $encoding_id3v1 = 'ISO-8859-1';
+ /**
+ * ID3v1 should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'Windows-1251' or 'KOI8-R'. If true attempt to detect these encodings, but may return incorrect values for some tags actually in ISO-8859-1 encoding
+ *
+ * @var bool
+ */
+ public $encoding_id3v1_autodetect = false;
+
/*
* Optional tag checks - disable for speed.
*/
@@ -251,7 +257,7 @@
*/
protected $startup_warning = '';
- const VERSION = '1.9.16-201810171314';
+ const VERSION = '1.9.20-202006061653';
const FREAD_BUFFER_SIZE = 32768;
const ATTACHMENTS_NONE = false;
@@ -267,14 +273,16 @@
}
// Check memory
- $this->memory_limit = ini_get('memory_limit');
- if (preg_match('#([0-9]+) ?M#i', $this->memory_limit, $matches)) {
+ $memoryLimit = ini_get('memory_limit');
+ if (preg_match('#([0-9]+) ?M#i', $memoryLimit, $matches)) {
// could be stored as "16M" rather than 16777216 for example
- $this->memory_limit = $matches[1] * 1048576;
- } elseif (preg_match('#([0-9]+) ?G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
+ $memoryLimit = $matches[1] * 1048576;
+ } elseif (preg_match('#([0-9]+) ?G#i', $memoryLimit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
// could be stored as "2G" rather than 2147483648 for example
- $this->memory_limit = $matches[1] * 1073741824;
+ $memoryLimit = $matches[1] * 1073741824;
}
+ $this->memory_limit = $memoryLimit;
+
if ($this->memory_limit <= 0) {
// memory limits probably disabled
} elseif ($this->memory_limit <= 4194304) {
@@ -288,24 +296,26 @@
$this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
}
- if (($mbstring_func_overload = ini_get('mbstring.func_overload')) && ($mbstring_func_overload & 0x02)) {
+ if (($mbstring_func_overload = (int) ini_get('mbstring.func_overload')) && ($mbstring_func_overload & 0x02)) {
// http://php.net/manual/en/mbstring.overload.php
// "mbstring.func_overload in php.ini is a positive value that represents a combination of bitmasks specifying the categories of functions to be overloaded. It should be set to 1 to overload the mail() function. 2 for string functions, 4 for regular expression functions"
// getID3 cannot run when string functions are overloaded. It doesn't matter if mail() or ereg* functions are overloaded since getID3 does not use those.
$this->startup_error .= 'WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", getID3 cannot run with this setting (bitmask 2 (string functions) cannot be set). Recommended to disable entirely.'."\n";
}
- // Check for magic_quotes_runtime
- if (function_exists('get_magic_quotes_runtime')) {
- if (get_magic_quotes_runtime()) {
- $this->startup_error .= 'magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).'."\n";
+ // check for magic quotes in PHP < 7.4.0 (when these functions became deprecated)
+ if (version_compare(PHP_VERSION, '7.4.0', '<')) {
+ // Check for magic_quotes_runtime
+ if (function_exists('get_magic_quotes_runtime')) {
+ if (get_magic_quotes_runtime()) {
+ $this->startup_error .= 'magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).'."\n";
+ }
}
- }
-
- // Check for magic_quotes_gpc
- if (function_exists('magic_quotes_gpc')) {
- if (get_magic_quotes_gpc()) {
- $this->startup_error .= 'magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).'."\n";
+ // Check for magic_quotes_gpc
+ if (function_exists('get_magic_quotes_gpc')) {
+ if (get_magic_quotes_gpc()) {
+ $this->startup_error .= 'magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).'."\n";
+ }
}
}
@@ -321,7 +331,7 @@
// Needed for Windows only:
// Define locations of helper applications for Shorten, VorbisComment, MetaFLAC
- // as well as other helper functions such as head, tail, md5sum, etc
+ // as well as other helper functions such as head, etc
// This path cannot contain spaces, but the below code will attempt to get the
// 8.3-equivalent path automatically
// IMPORTANT: This path must include the trailing slash
@@ -399,14 +409,15 @@
}
/**
- * @param string $filename
- * @param int $filesize
+ * @param string $filename
+ * @param int $filesize
+ * @param resource $fp
*
* @return bool
*
* @throws getid3_exception
*/
- public function openfile($filename, $filesize=null) {
+ public function openfile($filename, $filesize=null, $fp=null) {
try {
if (!empty($this->startup_error)) {
throw new getid3_exception($this->startup_error);
@@ -433,7 +444,9 @@
// open local file
//if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see https://www.getid3.org/phpBB3/viewtopic.php?t=1720
- if ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
+ if (($fp != null) && ((get_resource_type($fp) == 'file') || (get_resource_type($fp) == 'stream'))) {
+ $this->fp = $fp;
+ } elseif ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
// great
} else {
$errormessagelist = array();
@@ -508,15 +521,16 @@
/**
* analyze file
*
- * @param string $filename
- * @param int $filesize
- * @param string $original_filename
+ * @param string $filename
+ * @param int $filesize
+ * @param string $original_filename
+ * @param resource $fp
*
* @return array
*/
- public function analyze($filename, $filesize=null, $original_filename='') {
+ public function analyze($filename, $filesize=null, $original_filename='', $fp=null) {
try {
- if (!$this->openfile($filename, $filesize)) {
+ if (!$this->openfile($filename, $filesize, $fp)) {
return $this->info;
}
@@ -550,8 +564,8 @@
$header = fread($this->fp, 10);
if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) {
$this->info['id3v2']['header'] = true;
- $this->info['id3v2']['majorversion'] = ord($header{3});
- $this->info['id3v2']['minorversion'] = ord($header{4});
+ $this->info['id3v2']['majorversion'] = ord($header[3]);
+ $this->info['id3v2']['minorversion'] = ord($header[4]);
$this->info['avdataoffset'] += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
}
}
@@ -833,12 +847,20 @@
// DSS - audio - Digital Speech Standard
'dss' => array(
- 'pattern' => '^[\\x02-\\x06]ds[s2]',
+ 'pattern' => '^[\\x02-\\x08]ds[s2]',
'group' => 'audio',
'module' => 'dss',
'mime_type' => 'application/octet-stream',
),
+ // DSDIFF - audio - Direct Stream Digital Interchange File Format
+ 'dsdiff' => array(
+ 'pattern' => '^FRM8',
+ 'group' => 'audio',
+ 'module' => 'dsdiff',
+ 'mime_type' => 'audio/dsd',
+ ),
+
// DTS - audio - Dolby Theatre System
'dts' => array(
'pattern' => '^\\x7F\\xFE\\x80\\x01',
@@ -966,6 +988,14 @@
'fail_ape' => 'ERROR',
),
+ // TAK - audio - Tom's lossless Audio Kompressor
+ 'tak' => array(
+ 'pattern' => '^tBaK',
+ 'group' => 'audio',
+ 'module' => 'tak',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
// TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org)
'tta' => array(
'pattern' => '^TTA', // could also be '^TTA(\\x01|\\x02|\\x03|2|1)'
@@ -1026,6 +1056,14 @@
'mime_type' => 'video/x-flv',
),
+ // IVF - audio/video - IVF
+ 'ivf' => array(
+ 'pattern' => '^DKIF',
+ 'group' => 'audio-video',
+ 'module' => 'ivf',
+ 'mime_type' => 'video/x-ivf',
+ ),
+
// MKAV - audio/video - Mastroka
'matroska' => array(
'pattern' => '^\\x1A\\x45\\xDF\\xA3',
@@ -1101,6 +1139,14 @@
'mime_type' => 'video/MP2T',
),
+ // WTV - audio/video - Windows Recorded TV Show
+ 'wtv' => array(
+ 'pattern' => '^\\xB7\\xD8\\x00\\x20\\x37\\x49\\xDA\\x11\\xA6\\x4E\\x00\\x07\\xE9\\x5E\\xAD\\x8D',
+ 'group' => 'audio-video',
+ 'module' => 'wtv',
+ 'mime_type' => 'video/x-ms-wtv',
+ ),
+
// Still-Image formats
@@ -1202,12 +1248,22 @@
'iconv_req' => false,
),
+ // HPK - data - HPK compressed data
+ 'hpk' => array(
+ 'pattern' => '^BPUL',
+ 'group' => 'archive',
+ 'module' => 'hpk',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
// RAR - data - RAR compressed data
'rar' => array(
'pattern' => '^Rar\\!',
'group' => 'archive',
'module' => 'rar',
- 'mime_type' => 'application/octet-stream',
+ 'mime_type' => 'application/vnd.rar',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
),
@@ -1252,6 +1308,16 @@
'fail_ape' => 'ERROR',
),
+ // XZ - data - XZ compressed data
+ 'xz' => array(
+ 'pattern' => '^\\xFD7zXZ\\x00',
+ 'group' => 'archive',
+ 'module' => 'xz',
+ 'mime_type' => 'application/x-xz',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
// Misc other formats
@@ -1323,7 +1389,7 @@
if (preg_match('#\\.mp[123a]$#i', $filename)) {
- // Too many mp3 encoders on the market put gabage in front of mpeg files
+ // Too many mp3 encoders on the market put garbage in front of mpeg files
// use assume format on these if format detection failed
$GetFileFormatArray = $this->GetFileFormatArray();
$info = $GetFileFormatArray['mp3'];
@@ -1399,6 +1465,7 @@
'flac' => array('vorbiscomment' , 'UTF-8'),
'divxtag' => array('divx' , 'ISO-8859-1'),
'iptc' => array('iptc' , 'ISO-8859-1'),
+ 'dsdiff' => array('dsdiff' , 'ISO-8859-1'),
);
}
@@ -1427,6 +1494,7 @@
}
}
if ($tag_key == 'picture') {
+ // pictures can take up a lot of space, and we don't need multiple copies of them; let there be a single copy in [comments][picture], and not elsewhere
unset($this->info[$comment_name]['comments'][$tag_key]);
}
}
@@ -1440,6 +1508,11 @@
if ($this->option_tags_html) {
foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
+ if ($tag_key == 'picture') {
+ // Do not to try to convert binary picture data to HTML
+ // https://github.com/JamesHeinrich/getID3/issues/178
+ continue;
+ }
$this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $this->info[$comment_name]['encoding']);
}
}
@@ -1448,8 +1521,7 @@
}
- // pictures can take up a lot of space, and we don't need multiple copies of them
- // let there be a single copy in [comments][picture], and not elsewhere
+ // pictures can take up a lot of space, and we don't need multiple copies of them; let there be a single copy in [comments][picture], and not elsewhere
if (!empty($this->info['tags'])) {
$unset_keys = array('tags', 'tags_html');
foreach ($this->info['tags'] as $tagtype => $tagarray) {
@@ -1496,6 +1568,17 @@
}
/**
+ * Calls getid3_lib::CopyTagsToComments() but passes in the option_tags_html setting from this instance of getID3
+ *
+ * @param array $ThisFileInfo
+ *
+ * @return bool
+ */
+ public function CopyTagsToComments(&$ThisFileInfo) {
+ return getid3_lib::CopyTagsToComments($ThisFileInfo, $this->option_tags_html);
+ }
+
+ /**
* @param string $algorithm
*
* @return array|bool
@@ -1508,7 +1591,6 @@
default:
return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()');
- break;
}
if (!empty($this->info['fileformat']) && !empty($this->info['dataformat']) && ($this->info['fileformat'] == 'ogg') && ($this->info['audio']['dataformat'] == 'vorbis')) {
@@ -1824,16 +1906,14 @@
*
* @return bool
*/
- public static function is_writable ($filename) {
- $ret = is_writable($filename);
-
- if (!$ret) {
- $perms = fileperms($filename);
- $ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002);
- }
-
- return $ret;
- }
+ public static function is_writable ($filename) {
+ $ret = is_writable($filename);
+ if (!$ret) {
+ $perms = fileperms($filename);
+ $ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002);
+ }
+ return $ret;
+ }
}
@@ -1976,7 +2056,8 @@
*/
$contents = '';
do {
- if (($this->getid3->memory_limit > 0) && ($bytes > $this->getid3->memory_limit)) {
+ //if (($this->getid3->memory_limit > 0) && ($bytes > $this->getid3->memory_limit)) {
+ if (($this->getid3->memory_limit > 0) && (($bytes / $this->getid3->memory_limit) > 0.99)) { // enable a more-fuzzy match to prevent close misses generating errors like "PHP Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 33554464 bytes)"
throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') that is more than available PHP memory ('.$this->getid3->memory_limit.')', 10);
}
$part = fread($this->getid3->fp, $bytes);
@@ -2026,6 +2107,61 @@
}
/**
+ * @return string|false
+ *
+ * @throws getid3_exception
+ */
+ protected function fgets() {
+ // must be able to handle CR/LF/CRLF but not read more than one lineend
+ $buffer = ''; // final string we will return
+ $prevchar = ''; // save previously-read character for end-of-line checking
+ if ($this->data_string_flag) {
+ while (true) {
+ $thischar = substr($this->data_string, $this->data_string_position++, 1);
+ if (($prevchar == "\r") && ($thischar != "\n")) {
+ // read one byte too many, back up
+ $this->data_string_position--;
+ break;
+ }
+ $buffer .= $thischar;
+ if ($thischar == "\n") {
+ break;
+ }
+ if ($this->data_string_position >= $this->data_string_length) {
+ // EOF
+ break;
+ }
+ $prevchar = $thischar;
+ }
+
+ } else {
+
+ // Ideally we would just use PHP's fgets() function, however...
+ // it does not behave consistently with regards to mixed line endings, may be system-dependent
+ // and breaks entirely when given a file with mixed \r vs \n vs \r\n line endings (e.g. some PDFs)
+ //return fgets($this->getid3->fp);
+ while (true) {
+ $thischar = fgetc($this->getid3->fp);
+ if (($prevchar == "\r") && ($thischar != "\n")) {
+ // read one byte too many, back up
+ fseek($this->getid3->fp, -1, SEEK_CUR);
+ break;
+ }
+ $buffer .= $thischar;
+ if ($thischar == "\n") {
+ break;
+ }
+ if (feof($this->getid3->fp)) {
+ break;
+ }
+ $prevchar = $thischar;
+ }
+
+ }
+ return $buffer;
+ }
+
+ /**
* @return bool
*/
protected function feof() {
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.archive.gzip.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.archive.gzip.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.archive.gzip.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.archive.gzip.php 2022-05-20 16:59:18.000000000 +0100
@@ -19,6 +19,9 @@
// //
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_gzip extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.archive.hpk.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.archive.hpk.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.archive.hpk.php 1970-01-01 01:00:00.000000000 +0100
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.archive.hpk.php 2022-05-20 16:59:18.000000000 +0100
@@ -0,0 +1,92 @@
+ //
+// available at https://github.com/JamesHeinrich/getID3 //
+// or https://www.getid3.org //
+// or http://getid3.sourceforge.net //
+// see readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.archive.hpk.php //
+// module for analyzing HPK files //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
+
+class getid3_hpk extends getid3_handler
+{
+ /**
+ * @return bool
+ */
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ $info['fileformat'] = 'hpk';
+
+ $this->fseek($info['avdataoffset']);
+ $HPKheader = $this->fread(36);
+
+ if (substr($HPKheader, 0, 4) == 'BPUL') {
+
+ $info['hpk']['header']['signature'] = substr($HPKheader, 0, 4);
+ $info['hpk']['header']['data_offset'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 4, 4));
+ $info['hpk']['header']['fragments_per_file'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 8, 4));
+ //$info['hpk']['header']['unknown1'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 12, 4));
+ $info['hpk']['header']['fragments_residual_offset'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 16, 4));
+ $info['hpk']['header']['fragments_residual_count'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 20, 4));
+ //$info['hpk']['header']['unknown2'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 24, 4));
+ $info['hpk']['header']['fragmented_filesystem_offset'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 28, 4));
+ $info['hpk']['header']['fragmented_filesystem_length'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 32, 4));
+
+ $info['hpk']['header']['filesystem_entries'] = $info['hpk']['header']['fragmented_filesystem_length'] / ($info['hpk']['header']['fragments_per_file'] * 8);
+ $this->fseek($info['hpk']['header']['fragmented_filesystem_offset']);
+ for ($i = 0; $i < $info['hpk']['header']['filesystem_entries']; $i++) {
+ $offset = getid3_lib::LittleEndian2Int($this->fread(4));
+ $length = getid3_lib::LittleEndian2Int($this->fread(4));
+ $info['hpk']['filesystem'][$i] = array('offset' => $offset, 'length' => $length);
+ }
+
+$this->error('HPK parsing incomplete (and mostly broken) in this version of getID3() ['.$this->getid3->version().']');
+
+/*
+ $filename = '';
+ $dirs = array();
+ foreach ($info['hpk']['filesystem'] as $key => $filesystemdata) {
+ $this->fseek($filesystemdata['offset']);
+ $first4 = $this->fread(4);
+ if (($first4 == 'LZ4 ') || ($first4 == 'ZLIB')) {
+ // actual data, ignore
+ $info['hpk']['toc'][$key] = array(
+ 'filename' => ltrim(implode('/', $dirs).'/'.$filename, '/'),
+ 'offset' => $filesystemdata['offset'],
+ 'length' => $filesystemdata['length'],
+ );
+ $filename = '';
+ $dirs = array();
+ } else {
+ $fragment_index = getid3_lib::LittleEndian2Int($first4);
+ $fragment_type = getid3_lib::LittleEndian2Int($this->fread(4)); // file = 0, directory = 1
+ $name_length = getid3_lib::LittleEndian2Int($this->fread(2));
+ if ($fragment_type == 1) {
+ $dirs[] = $this->fread($name_length);
+ } else {
+ $filename = $this->fread($name_length);
+ }
+ }
+ }
+*/
+
+ } else {
+ $this->error('Expecting "BPUL" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($HPKheader, 0, 4)).'"');
+ return false;
+ }
+
+ return true;
+ }
+
+}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.archive.rar.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.archive.rar.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.archive.rar.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.archive.rar.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_rar extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.archive.szip.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.archive.szip.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.archive.szip.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.archive.szip.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_szip extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.archive.tar.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.archive.tar.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.archive.tar.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.archive.tar.php 2022-05-20 16:59:18.000000000 +0100
@@ -19,6 +19,9 @@
// //
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_tar extends getid3_handler
{
@@ -44,13 +47,13 @@
// check the block
$checksum = 0;
for ($i = 0; $i < 148; $i++) {
- $checksum += ord($buffer{$i});
+ $checksum += ord($buffer[$i]);
}
for ($i = 148; $i < 156; $i++) {
$checksum += ord(' ');
}
for ($i = 156; $i < 512; $i++) {
- $checksum += ord($buffer{$i});
+ $checksum += ord($buffer[$i]);
}
$attr = unpack($unpack_header, $buffer);
$name = (isset($attr['fname'] ) ? trim($attr['fname'] ) : '');
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.archive.xz.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.archive.xz.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.archive.xz.php 1970-01-01 01:00:00.000000000 +0100
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.archive.xz.php 2022-05-20 16:59:18.000000000 +0100
@@ -0,0 +1,45 @@
+ //
+// available at https://github.com/JamesHeinrich/getID3 //
+// or https://www.getid3.org //
+// or http://getid3.sourceforge.net //
+// see readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.archive.xz.php //
+// module for analyzing XZ files //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
+
+class getid3_xz extends getid3_handler
+{
+
+ /**
+ * @return bool
+ */
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ $this->fseek($info['avdataoffset']);
+ $xzheader = $this->fread(6);
+
+ // https://tukaani.org/xz/xz-file-format-1.0.4.txt
+ $info['xz']['stream_header']['magic'] = substr($xzheader, 0, 6);
+ if ($info['xz']['stream_header']['magic'] != "\xFD".'7zXZ'."\x00") {
+ $this->error('Invalid XZ stream header magic (expecting FD 37 7A 58 5A 00, found '.getid3_lib::PrintHexBytes($info['xz']['stream_header']['magic']).') at offset '.$info['avdataoffset']);
+ return false;
+ }
+ $info['fileformat'] = 'xz';
+ $this->error('XZ parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
+ return false;
+
+ }
+
+}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.archive.zip.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.archive.zip.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.archive.zip.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.archive.zip.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_zip extends getid3_handler
{
@@ -92,19 +95,39 @@
}
}
+ // check for EPUB files
+ if (!empty($info['zip']['entries'][0]['filename']) &&
+ ($info['zip']['entries'][0]['filename'] == 'mimetype') &&
+ ($info['zip']['entries'][0]['compression_method'] == 'store') &&
+ ($info['zip']['entries'][0]['uncompressed_size'] == 20) &&
+ isset($info['zip']['entries'][0]['data_offset'])) {
+ // http://idpf.org/epub/30/spec/epub30-ocf.html
+ // "3.3 OCF ZIP Container Media Type Identification
+ // OCF ZIP Containers must include a mimetype file as the first file in the Container, and the contents of this file must be the MIME type string application/epub+zip.
+ // The contents of the mimetype file must not contain any leading padding or whitespace, must not begin with the Unicode signature (or Byte Order Mark),
+ // and the case of the MIME type string must be exactly as presented above. The mimetype file additionally must be neither compressed nor encrypted,
+ // and there must not be an extra field in its ZIP header."
+ $this->fseek($info['zip']['entries'][0]['data_offset']);
+ if ($this->fread(20) == 'application/epub+zip') {
+ $info['fileformat'] = 'zip.epub';
+ $info['mime_type'] = 'application/epub+zip';
+ }
+ }
+
+ // check for Office Open XML files (e.g. .docx, .xlsx)
if (!empty($info['zip']['files']['[Content_Types].xml']) &&
!empty($info['zip']['files']['_rels']['.rels']) &&
!empty($info['zip']['files']['docProps']['app.xml']) &&
!empty($info['zip']['files']['docProps']['core.xml'])) {
- // http://technet.microsoft.com/en-us/library/cc179224.aspx
- $info['fileformat'] = 'zip.msoffice';
- if (!empty($ThisFileInfo['zip']['files']['ppt'])) {
- $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
- } elseif (!empty($ThisFileInfo['zip']['files']['xl'])) {
- $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
- } elseif (!empty($ThisFileInfo['zip']['files']['word'])) {
- $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
- }
+ // http://technet.microsoft.com/en-us/library/cc179224.aspx
+ $info['fileformat'] = 'zip.msoffice';
+ if (!empty($ThisFileInfo['zip']['files']['ppt'])) {
+ $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
+ } elseif (!empty($ThisFileInfo['zip']['files']['xl'])) {
+ $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
+ } elseif (!empty($ThisFileInfo['zip']['files']['word'])) {
+ $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
+ }
}
return true;
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.aac.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.aac.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.aac.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.aac.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_aac extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.aa.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.aa.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.aa.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.aa.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_aa extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.ac3.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.ac3.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.ac3.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.ac3.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,20 +14,23 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_ac3 extends getid3_handler
{
/**
* @var array
*/
- private $AC3header = array();
+ private $AC3header = array();
/**
* @var int
*/
- private $BSIoffset = 0;
+ private $BSIoffset = 0;
- const syncword = 0x0B77;
+ const syncword = 0x0B77;
/**
* @return bool
@@ -422,7 +425,7 @@
} else {
$this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 16. Please submit a support ticket with a sample file.');
- unset($info['ac3']);
+ unset($info['ac3']);
return false;
}
@@ -485,7 +488,7 @@
/**
* @param int $length
*
- * @return float|int
+ * @return int
*/
private function readHeaderBSI($length) {
$data = substr($this->AC3header['bsi'], $this->BSIoffset, $length);
@@ -687,7 +690,7 @@
// -8 -42.14 dB
$fourbit = str_pad(decbin(($compre & 0xF0) >> 4), 4, '0', STR_PAD_LEFT);
- if ($fourbit{0} == '1') {
+ if ($fourbit[0] == '1') {
$log_gain = -8 + bindec(substr($fourbit, 1));
} else {
$log_gain = bindec(substr($fourbit, 1));
@@ -758,11 +761,13 @@
18 => array(2560, 2786, 3840) // 640 kbps
);
}
+ $paddingBytes = 0;
if (($fscod == 1) && $padding) {
// frame lengths are padded by 1 word (16 bits) at 44100
- $frameSizeLookup[$frmsizecod] += 2;
+ // (fscode==1) means 44100Hz (see sampleRateCodeLookup)
+ $paddingBytes = 2;
}
- return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] : false);
+ return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] + $paddingBytes : false);
}
/**
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.amr.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.amr.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.amr.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.amr.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_amr extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.au.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.au.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.au.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.au.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_au extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.avr.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.avr.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.avr.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.avr.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_avr extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.bonk.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.bonk.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.bonk.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.bonk.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_bonk extends getid3_handler
{
@@ -44,7 +47,7 @@
$this->fseek(0 - $BonkTagSize, SEEK_CUR);
$BonkTagOffset = $this->ftell();
$TagHeaderTest = $this->fread(5);
- if (($TagHeaderTest{0} != "\x00") || (substr($PossibleBonkTag, 4, 4) != strtolower(substr($PossibleBonkTag, 4, 4)))) {
+ if (($TagHeaderTest[0] != "\x00") || (substr($PossibleBonkTag, 4, 4) != strtolower(substr($PossibleBonkTag, 4, 4)))) {
$this->error('Expecting "'.getid3_lib::PrintHexBytes("\x00".strtoupper(substr($PossibleBonkTag, 4, 4))).'" at offset '.$BonkTagOffset.', found "'.getid3_lib::PrintHexBytes($TagHeaderTest).'"');
return false;
}
@@ -201,7 +204,7 @@
// ID3v2 checking is optional
if (class_exists('getid3_id3v2')) {
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
$getid3_id3v2 = new getid3_id3v2($getid3_temp);
$getid3_id3v2->StartingOffset = $info['bonk'][' ID3']['offset'] + 2;
$info['bonk'][' ID3']['valid'] = $getid3_id3v2->Analyze();
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.dsdiff.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.dsdiff.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.dsdiff.php 1970-01-01 01:00:00.000000000 +0100
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.dsdiff.php 2022-05-20 16:59:18.000000000 +0100
@@ -0,0 +1,310 @@
+ //
+// available at https://github.com/JamesHeinrich/getID3 //
+// or https://www.getid3.org //
+// or http://getid3.sourceforge.net //
+// see readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio.dsdiff.php //
+// module for analyzing Direct Stream Digital Interchange //
+// File Format (DSDIFF) files //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
+
+class getid3_dsdiff extends getid3_handler
+{
+ /**
+ * @return bool
+ */
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ $this->fseek($info['avdataoffset']);
+ $DSDIFFheader = $this->fread(4);
+
+ // https://dsd-guide.com/sites/default/files/white-papers/DSDIFF_1.5_Spec.pdf
+ if (substr($DSDIFFheader, 0, 4) != 'FRM8') {
+ $this->error('Expecting "FRM8" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($DSDIFFheader, 0, 4)).'"');
+ return false;
+ }
+ unset($DSDIFFheader);
+ $this->fseek($info['avdataoffset']);
+
+ $info['encoding'] = 'ISO-8859-1'; // not certain, but assumed
+ $info['fileformat'] = 'dsdiff';
+ $info['mime_type'] = 'audio/dsd';
+ $info['audio']['dataformat'] = 'dsdiff';
+ $info['audio']['bitrate_mode'] = 'cbr';
+ $info['audio']['bits_per_sample'] = 1;
+
+ $info['dsdiff'] = array();
+ while (!$this->feof() && ($ChunkHeader = $this->fread(12))) {
+ if (strlen($ChunkHeader) < 12) {
+ $this->error('Expecting chunk header at offset '.$thisChunk['offset'].', found insufficient data in file, aborting parsing');
+ break;
+ }
+ $thisChunk = array();
+ $thisChunk['offset'] = $this->ftell() - 12;
+ $thisChunk['name'] = substr($ChunkHeader, 0, 4);
+ if (!preg_match('#^[\\x21-\\x7E]+ *$#', $thisChunk['name'])) {
+ // "a concatenation of four printable ASCII characters in the range ' ' (space, 0x20) through '~'(0x7E). Space (0x20) cannot precede printing characters; trailing spaces are allowed."
+ $this->error('Invalid chunk name "'.$thisChunk['name'].'" ('.getid3_lib::PrintHexBytes($thisChunk['name']).') at offset '.$thisChunk['offset'].', aborting parsing');
+ }
+ $thisChunk['size'] = getid3_lib::BigEndian2Int(substr($ChunkHeader, 4, 8));
+ $datasize = $thisChunk['size'] + ($thisChunk['size'] % 2); // "If the data is an odd number of bytes in length, a pad byte must be added at the end. The pad byte is not included in ckDataSize."
+
+ switch ($thisChunk['name']) {
+ case 'FRM8':
+ $thisChunk['form_type'] = $this->fread(4);
+ if ($thisChunk['form_type'] != 'DSD ') {
+ $this->error('Expecting "DSD " at offset '.($this->ftell() - 4).', found "'.getid3_lib::PrintHexBytes($thisChunk['form_type']).'", aborting parsing');
+ break 2;
+ }
+ // do nothing further, prevent skipping subchunks
+ break;
+ case 'PROP': // PROPerty chunk
+ $thisChunk['prop_type'] = $this->fread(4);
+ if ($thisChunk['prop_type'] != 'SND ') {
+ $this->error('Expecting "SND " at offset '.($this->ftell() - 4).', found "'.getid3_lib::PrintHexBytes($thisChunk['prop_type']).'", aborting parsing');
+ break 2;
+ }
+ // do nothing further, prevent skipping subchunks
+ break;
+ case 'DIIN': // eDIted master INformation chunk
+ // do nothing, just prevent skipping subchunks
+ break;
+
+ case 'FVER': // Format VERsion chunk
+ if ($thisChunk['size'] == 4) {
+ $FVER = $this->fread(4);
+ $info['dsdiff']['format_version'] = ord($FVER[0]).'.'.ord($FVER[1]).'.'.ord($FVER[2]).'.'.ord($FVER[3]);
+ unset($FVER);
+ } else {
+ $this->warning('Expecting "FVER" chunk to be 4 bytes, found '.$thisChunk['size'].' bytes, skipping chunk');
+ $this->fseek($datasize, SEEK_CUR);
+ }
+ break;
+ case 'FS ': // sample rate chunk
+ if ($thisChunk['size'] == 4) {
+ $info['dsdiff']['sample_rate'] = getid3_lib::BigEndian2Int($this->fread(4));
+ $info['audio']['sample_rate'] = $info['dsdiff']['sample_rate'];
+ } else {
+ $this->warning('Expecting "FVER" chunk to be 4 bytes, found '.$thisChunk['size'].' bytes, skipping chunk');
+ $this->fseek($datasize, SEEK_CUR);
+ }
+ break;
+ case 'CHNL': // CHaNneLs chunk
+ $thisChunk['num_channels'] = getid3_lib::BigEndian2Int($this->fread(2));
+ if ($thisChunk['num_channels'] == 0) {
+ $this->warning('channel count should be greater than zero, skipping chunk');
+ $this->fseek($datasize - 2, SEEK_CUR);
+ }
+ for ($i = 0; $i < $thisChunk['num_channels']; $i++) {
+ $thisChunk['channels'][$i] = $this->fread(4);
+ }
+ $info['audio']['channels'] = $thisChunk['num_channels'];
+ break;
+ case 'CMPR': // CoMPRession type chunk
+ $thisChunk['compression_type'] = $this->fread(4);
+ $info['audio']['dataformat'] = trim($thisChunk['compression_type']);
+ $humanReadableByteLength = getid3_lib::BigEndian2Int($this->fread(1));
+ $thisChunk['compression_name'] = $this->fread($humanReadableByteLength);
+ if (($humanReadableByteLength % 2) == 0) {
+ // need to seek to multiple of 2 bytes, human-readable string length is only one byte long so if the string is an even number of bytes we need to seek past a padding byte after the string
+ $this->fseek(1, SEEK_CUR);
+ }
+ unset($humanReadableByteLength);
+ break;
+ case 'ABSS': // ABSolute Start time chunk
+ $ABSS = $this->fread(8);
+ $info['dsdiff']['absolute_start_time']['hours'] = getid3_lib::BigEndian2Int(substr($ABSS, 0, 2));
+ $info['dsdiff']['absolute_start_time']['minutes'] = getid3_lib::BigEndian2Int(substr($ABSS, 2, 1));
+ $info['dsdiff']['absolute_start_time']['seconds'] = getid3_lib::BigEndian2Int(substr($ABSS, 3, 1));
+ $info['dsdiff']['absolute_start_time']['samples'] = getid3_lib::BigEndian2Int(substr($ABSS, 4, 4));
+ unset($ABSS);
+ break;
+ case 'LSCO': // LoudSpeaker COnfiguration chunk
+ // 0 = 2-channel stereo set-up
+ // 3 = 5-channel set-up according to ITU-R BS.775-1 [ITU]
+ // 4 = 6-channel set-up, 5-channel set-up according to ITU-R BS.775-1 [ITU], plus additional Low Frequency Enhancement (LFE) loudspeaker. Also known as "5.1 configuration"
+ // 65535 = Undefined channel set-up
+ $thisChunk['loundspeaker_config_id'] = getid3_lib::BigEndian2Int($this->fread(2));
+ break;
+ case 'COMT': // COMmenTs chunk
+ $thisChunk['num_comments'] = getid3_lib::BigEndian2Int($this->fread(2));
+ for ($i = 0; $i < $thisChunk['num_comments']; $i++) {
+ $thisComment = array();
+ $COMT = $this->fread(14);
+ $thisComment['creation_year'] = getid3_lib::BigEndian2Int(substr($COMT, 0, 2));
+ $thisComment['creation_month'] = getid3_lib::BigEndian2Int(substr($COMT, 2, 1));
+ $thisComment['creation_day'] = getid3_lib::BigEndian2Int(substr($COMT, 3, 1));
+ $thisComment['creation_hour'] = getid3_lib::BigEndian2Int(substr($COMT, 4, 1));
+ $thisComment['creation_minute'] = getid3_lib::BigEndian2Int(substr($COMT, 5, 1));
+ $thisComment['comment_type_id'] = getid3_lib::BigEndian2Int(substr($COMT, 6, 2));
+ $thisComment['comment_ref_id'] = getid3_lib::BigEndian2Int(substr($COMT, 8, 2));
+ $thisComment['string_length'] = getid3_lib::BigEndian2Int(substr($COMT, 10, 4));
+ $thisComment['comment_text'] = $this->fread($thisComment['string_length']);
+ if ($thisComment['string_length'] % 2) {
+ // commentText[] is the description of the Comment. This text must be padded with a byte at the end, if needed, to make it an even number of bytes long. This pad byte, if present, is not included in count.
+ $this->fseek(1, SEEK_CUR);
+ }
+ $thisComment['comment_type'] = $this->DSDIFFcmtType($thisComment['comment_type_id']);
+ $thisComment['comment_reference'] = $this->DSDIFFcmtRef($thisComment['comment_type_id'], $thisComment['comment_ref_id']);
+ $thisComment['creation_unix'] = mktime($thisComment['creation_hour'], $thisComment['creation_minute'], 0, $thisComment['creation_month'], $thisComment['creation_day'], $thisComment['creation_year']);
+ $thisChunk['comments'][$i] = $thisComment;
+
+ $commentkey = ($thisComment['comment_reference'] ?: 'comment');
+ $info['dsdiff']['comments'][$commentkey][] = $thisComment['comment_text'];
+ unset($thisComment);
+ }
+ break;
+ case 'MARK': // MARKer chunk
+ $MARK = $this->fread(22);
+ $thisChunk['marker_hours'] = getid3_lib::BigEndian2Int(substr($MARK, 0, 2));
+ $thisChunk['marker_minutes'] = getid3_lib::BigEndian2Int(substr($MARK, 2, 1));
+ $thisChunk['marker_seconds'] = getid3_lib::BigEndian2Int(substr($MARK, 3, 1));
+ $thisChunk['marker_samples'] = getid3_lib::BigEndian2Int(substr($MARK, 4, 4));
+ $thisChunk['marker_offset'] = getid3_lib::BigEndian2Int(substr($MARK, 8, 4));
+ $thisChunk['marker_type_id'] = getid3_lib::BigEndian2Int(substr($MARK, 12, 2));
+ $thisChunk['marker_channel'] = getid3_lib::BigEndian2Int(substr($MARK, 14, 2));
+ $thisChunk['marker_flagraw'] = getid3_lib::BigEndian2Int(substr($MARK, 16, 2));
+ $thisChunk['string_length'] = getid3_lib::BigEndian2Int(substr($MARK, 18, 4));
+ $thisChunk['description'] = ($thisChunk['string_length'] ? $this->fread($thisChunk['string_length']) : '');
+ if ($thisChunk['string_length'] % 2) {
+ // markerText[] is the description of the marker. This text must be padded with a byte at the end, if needed, to make it an even number of bytes long. This pad byte, if present, is not included in count.
+ $this->fseek(1, SEEK_CUR);
+ }
+ $thisChunk['marker_type'] = $this->DSDIFFmarkType($thisChunk['marker_type_id']);
+ unset($MARK);
+ break;
+ case 'DIAR': // artist chunk
+ case 'DITI': // title chunk
+ $thisChunk['string_length'] = getid3_lib::BigEndian2Int($this->fread(4));
+ $thisChunk['description'] = ($thisChunk['string_length'] ? $this->fread($thisChunk['string_length']) : '');
+ if ($thisChunk['string_length'] % 2) {
+ // This text must be padded with a byte at the end, if needed, to make it an even number of bytes long. This pad byte, if present, is not included in count.
+ $this->fseek(1, SEEK_CUR);
+ }
+
+ if ($commentkey = (($thisChunk['name'] == 'DIAR') ? 'artist' : (($thisChunk['name'] == 'DITI') ? 'title' : ''))) {
+ @$info['dsdiff']['comments'][$commentkey][] = $thisChunk['description'];
+ }
+ break;
+ case 'EMID': // Edited Master ID chunk
+ if ($thisChunk['size']) {
+ $thisChunk['identifier'] = $this->fread($thisChunk['size']);
+ }
+ break;
+
+ case 'ID3 ':
+ $endOfID3v2 = $this->ftell() + $datasize; // we will need to reset the filepointer after parsing ID3v2
+
+ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
+ $getid3_id3v2 = new getid3_id3v2($getid3_temp);
+ $getid3_id3v2->StartingOffset = $this->ftell();
+ if ($thisChunk['valid'] = $getid3_id3v2->Analyze()) {
+ $info['id3v2'] = $getid3_temp->info['id3v2'];
+ }
+ unset($getid3_temp, $getid3_id3v2);
+
+ $this->fseek($endOfID3v2);
+ break;
+
+ case 'DSD ': // DSD sound data chunk
+ case 'DST ': // DST sound data chunk
+ // actual audio data, we're not interested, skip
+ $this->fseek($datasize, SEEK_CUR);
+ break;
+ default:
+ $this->warning('Unhandled chunk "'.$thisChunk['name'].'"');
+ $this->fseek($datasize, SEEK_CUR);
+ break;
+ }
+
+ @$info['dsdiff']['chunks'][] = $thisChunk;
+ //break;
+ }
+ if (empty($info['audio']['bitrate']) && !empty($info['audio']['channels']) && !empty($info['audio']['sample_rate']) && !empty($info['audio']['bits_per_sample'])) {
+ $info['audio']['bitrate'] = $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'] * $info['audio']['channels'];
+ }
+
+ return true;
+ }
+
+ /**
+ * @param int $cmtType
+ *
+ * @return string
+ */
+ public static function DSDIFFcmtType($cmtType) {
+ static $DSDIFFcmtType = array(
+ 0 => 'General (album) Comment',
+ 1 => 'Channel Comment',
+ 2 => 'Sound Source',
+ 3 => 'File History',
+ );
+ return (isset($DSDIFFcmtType[$cmtType]) ? $DSDIFFcmtType[$cmtType] : 'reserved');
+ }
+
+ /**
+ * @param int $cmtType
+ * @param int $cmtRef
+ *
+ * @return string
+ */
+ public static function DSDIFFcmtRef($cmtType, $cmtRef) {
+ static $DSDIFFcmtRef = array(
+ 2 => array( // Sound Source
+ 0 => 'DSD recording',
+ 1 => 'Analogue recording',
+ 2 => 'PCM recording',
+ ),
+ 3 => array( // File History
+ 0 => 'comment', // General Remark
+ 1 => 'encodeby', // Name of the operator
+ 2 => 'encoder', // Name or type of the creating machine
+ 3 => 'timezone', // Time zone information
+ 4 => 'revision', // Revision of the file
+ ),
+ );
+ switch ($cmtType) {
+ case 0:
+ // If the comment type is General Comment the comment reference must be 0
+ return '';
+ case 1:
+ // If the comment type is Channel Comment, the comment reference defines the channel number to which the comment belongs
+ return ($cmtRef ? 'channel '.$cmtRef : 'all channels');
+ case 2:
+ case 3:
+ return (isset($DSDIFFcmtRef[$cmtType][$cmtRef]) ? $DSDIFFcmtRef[$cmtType][$cmtRef] : 'reserved');
+ }
+ return 'unsupported $cmtType='.$cmtType;
+ }
+
+ /**
+ * @param int $cmtType
+ *
+ * @return string
+ */
+ public static function DSDIFFmarkType($markType) {
+ static $DSDIFFmarkType = array(
+ 0 => 'TrackStart', // Entry point for a Track start
+ 1 => 'TrackStop', // Entry point for ending a Track
+ 2 => 'ProgramStart', // Start point of 2-channel or multi-channel area
+ 3 => 'Obsolete', //
+ 4 => 'Index', // Entry point of an Index
+ );
+ return (isset($DSDIFFmarkType[$markType]) ? $DSDIFFmarkType[$markType] : 'reserved');
+ }
+
+}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.dsf.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.dsf.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.dsf.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.dsf.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
class getid3_dsf extends getid3_handler
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.dss.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.dss.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.dss.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.dss.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_dss extends getid3_handler
{
@@ -26,8 +29,8 @@
$this->fseek($info['avdataoffset']);
$DSSheader = $this->fread(1540);
- if (!preg_match('#^[\\x02-\\x06]ds[s2]#', $DSSheader)) {
- $this->error('Expecting "[02-06] 64 73 [73|32]" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($DSSheader, 0, 4)).'"');
+ if (!preg_match('#^[\\x02-\\x08]ds[s2]#', $DSSheader)) {
+ $this->error('Expecting "[02-08] 64 73 [73|32]" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($DSSheader, 0, 4)).'"');
return false;
}
@@ -46,7 +49,7 @@
// 32-37 = "FE FF FE FF F7 FF" in all the sample files I've seen
$info['dss']['date_create_unix'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 38, 12));
$info['dss']['date_complete_unix'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 50, 12));
- $info['dss']['playtime_sec'] = intval((substr($DSSheader, 62, 2) * 3600) + (substr($DSSheader, 64, 2) * 60) + substr($DSSheader, 66, 2)); // approximate file playtime in HHMMSS
+ $info['dss']['playtime_sec'] = ((int) substr($DSSheader, 62, 2) * 3600) + ((int) substr($DSSheader, 64, 2) * 60) + (int) substr($DSSheader, 66, 2); // approximate file playtime in HHMMSS
if ($info['dss']['version'] <= 3) {
$info['dss']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 512, 4)); // exact file playtime in milliseconds. Has also been observed at offset 530 in one sample file, with something else (unknown) at offset 512
$info['dss']['priority'] = ord(substr($DSSheader, 793, 1));
@@ -79,7 +82,7 @@
* @return int|false
*/
public function DSSdateStringToUnixDate($datestring) {
- $y = substr($datestring, 0, 2);
+ $y = (int) substr($datestring, 0, 2);
$m = substr($datestring, 2, 2);
$d = substr($datestring, 4, 2);
$h = substr($datestring, 6, 2);
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.dts.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.dts.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.dts.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.dts.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// //
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
/**
* @tutorial http://wiki.multimedia.cx/index.php?title=DTS
@@ -51,18 +54,18 @@
// check syncword
$sync = substr($DTSheader, 0, 4);
- if (($encoding = array_search($sync, self::$syncwords)) !== false) {
+ if (($encoding = array_search($sync, self::$syncwords)) !== false) {
- $info['dts']['raw']['magic'] = $sync;
+ $info['dts']['raw']['magic'] = $sync;
$this->readBinDataOffset = 32;
- } elseif ($this->isDependencyFor('matroska')) {
+ } elseif ($this->isDependencyFor('matroska')) {
// Matroska contains DTS without syncword encoded as raw big-endian format
$encoding = 0;
$this->readBinDataOffset = 0;
- } else {
+ } else {
unset($info['fileformat']);
return $this->error('Expecting "'.implode('| ', array_map('getid3_lib::PrintHexBytes', self::$syncwords)).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($sync).'"');
@@ -149,7 +152,7 @@
* @param string $bin
* @param int $length
*
- * @return float|int
+ * @return int
*/
private function readBinData($bin, $length) {
$data = substr($bin, $this->readBinDataOffset, $length);
@@ -252,36 +255,28 @@
switch ($index) {
case 0:
return 1;
- break;
case 1:
case 2:
case 3:
case 4:
return 2;
- break;
case 5:
case 6:
return 3;
- break;
case 7:
case 8:
return 4;
- break;
case 9:
return 5;
- break;
case 10:
case 11:
case 12:
return 6;
- break;
case 13:
return 7;
- break;
case 14:
case 15:
return 8;
- break;
}
return false;
}
@@ -323,10 +318,8 @@
switch ($version) {
case 7:
return 0 - $index;
- break;
case 6:
return 0 - 16 - $index;
- break;
}
return false;
}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.flac.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.flac.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.flac.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.flac.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,7 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
-
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, true);
/**
@@ -178,7 +180,7 @@
if (isset($info['flac']['STREAMINFO']['audio_signature'])) {
if ($info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) {
- $this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)');
+ $this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)');
}
else {
$info['md5_data_source'] = '';
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.la.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.la.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.la.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.la.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
class getid3_la extends getid3_handler
@@ -215,7 +218,6 @@
$this->error('Not a LA (Lossless-Audio) file');
}
return false;
- break;
}
$info['audio']['channels'] = $info['la']['channels'];
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.lpac.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.lpac.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.lpac.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.lpac.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
class getid3_lpac extends getid3_handler
@@ -80,7 +83,7 @@
}
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
$getid3_temp->info = $info;
$getid3_riff = new getid3_riff($getid3_temp);
$getid3_riff->Analyze();
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.midi.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.midi.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.midi.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.midi.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,10 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
+
define('GETID3_MIDI_MAGIC_MTHD', 'MThd'); // MIDI file header magic
define('GETID3_MIDI_MAGIC_MTRK', 'MTrk'); // MIDI track header magic
@@ -243,9 +247,9 @@
break;
case 0x58: // Time signature
- $timesig_numerator = getid3_lib::BigEndian2Int($METAeventData{0});
- $timesig_denominator = pow(2, getid3_lib::BigEndian2Int($METAeventData{1})); // $02 -> x/4, $03 -> x/8, etc
- $timesig_32inqnote = getid3_lib::BigEndian2Int($METAeventData{2}); // number of 32nd notes to the quarter note
+ $timesig_numerator = getid3_lib::BigEndian2Int($METAeventData[0]);
+ $timesig_denominator = pow(2, getid3_lib::BigEndian2Int($METAeventData[1])); // $02 -> x/4, $03 -> x/8, etc
+ $timesig_32inqnote = getid3_lib::BigEndian2Int($METAeventData[2]); // number of 32nd notes to the quarter note
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_32inqnote'] = $timesig_32inqnote;
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_numerator'] = $timesig_numerator;
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_denominator'] = $timesig_denominator;
@@ -254,13 +258,13 @@
break;
case 0x59: // Keysignature
- $keysig_sharpsflats = getid3_lib::BigEndian2Int($METAeventData{0});
+ $keysig_sharpsflats = getid3_lib::BigEndian2Int($METAeventData[0]);
if ($keysig_sharpsflats & 0x80) {
// (-7 -> 7 flats, 0 ->key of C, 7 -> 7 sharps)
$keysig_sharpsflats -= 256;
}
- $keysig_majorminor = getid3_lib::BigEndian2Int($METAeventData{1}); // 0 -> major, 1 -> minor
+ $keysig_majorminor = getid3_lib::BigEndian2Int($METAeventData[1]); // 0 -> major, 1 -> minor
$keysigs = array(-7=>'Cb', -6=>'Gb', -5=>'Db', -4=>'Ab', -3=>'Eb', -2=>'Bb', -1=>'F', 0=>'C', 1=>'G', 2=>'D', 3=>'A', 4=>'E', 5=>'B', 6=>'F#', 7=>'C#');
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_sharps'] = (($keysig_sharpsflats > 0) ? abs($keysig_sharpsflats) : 0);
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_flats'] = (($keysig_sharpsflats < 0) ? abs($keysig_sharpsflats) : 0);
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.mod.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.mod.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.mod.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.mod.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_mod extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.monkey.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.monkey.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.monkey.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.monkey.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_monkey extends getid3_handler
{
@@ -162,7 +165,7 @@
$info['md5_data_source'] = '';
$md5 = $thisfile_monkeysaudio_raw['cFileMD5'];
for ($i = 0; $i < strlen($md5); $i++) {
- $info['md5_data_source'] .= str_pad(dechex(ord($md5{$i})), 2, '00', STR_PAD_LEFT);
+ $info['md5_data_source'] .= str_pad(dechex(ord($md5[$i])), 2, '00', STR_PAD_LEFT);
}
if (!preg_match('/^[0-9a-f]{32}$/', $info['md5_data_source'])) {
unset($info['md5_data_source']);
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.mp3.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.mp3.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.mp3.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.mp3.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
// number of frames to scan to determine if MPEG-audio sequence is valid
// Lower this number to 5-20 for faster scanning
@@ -701,7 +704,7 @@
if ($thisfile_mpeg_audio['xing_flags']['toc']) {
$LAMEtocData = substr($headerstring, $VBRidOffset + 16, 100);
for ($i = 0; $i < 100; $i++) {
- $thisfile_mpeg_audio['toc'][$i] = ord($LAMEtocData{$i});
+ $thisfile_mpeg_audio['toc'][$i] = ord($LAMEtocData[$i]);
}
}
if ($thisfile_mpeg_audio['xing_flags']['vbr_scale']) {
@@ -719,8 +722,17 @@
$thisfile_mpeg_audio_lame['long_version'] = substr($headerstring, $VBRidOffset + 120, 20);
$thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9);
+ $thisfile_mpeg_audio_lame['numeric_version'] = str_replace('LAME', '', $thisfile_mpeg_audio_lame['short_version']);
+ if (preg_match('#^LAME([0-9\\.a-z]+)#', $thisfile_mpeg_audio_lame['long_version'], $matches)) {
+ $thisfile_mpeg_audio_lame['short_version'] = $matches[0];
+ $thisfile_mpeg_audio_lame['numeric_version'] = $matches[1];
+ }
+ foreach (explode('.', $thisfile_mpeg_audio_lame['numeric_version']) as $key => $number) {
+ $thisfile_mpeg_audio_lame['integer_version'][$key] = intval($number);
+ }
- if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {
+ //if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {
+ if ((($thisfile_mpeg_audio_lame['integer_version'][0] * 1000) + $thisfile_mpeg_audio_lame['integer_version'][1]) >= 3090) { // cannot use string version compare, may have "LAME3.90" or "LAME3.100" -- see https://github.com/JamesHeinrich/getID3/issues/207
// extra 11 chars are not part of version string when LAMEtag present
unset($thisfile_mpeg_audio_lame['long_version']);
@@ -1173,9 +1185,9 @@
$SyncPattern1 = substr($MPEGaudioData, 0, 4);
// may be different pattern due to padding
- $SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) | 0x02).$SyncPattern1{3};
+ $SyncPattern2 = $SyncPattern1[0].$SyncPattern1[1].chr(ord($SyncPattern1[2]) | 0x02).$SyncPattern1[3];
if ($SyncPattern2 === $SyncPattern1) {
- $SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) & 0xFD).$SyncPattern1{3};
+ $SyncPattern2 = $SyncPattern1[0].$SyncPattern1[1].chr(ord($SyncPattern1[2]) & 0xFD).$SyncPattern1[3];
}
$framelength = false;
@@ -1280,9 +1292,9 @@
if (strlen($head4) < 4) {
break;
}
- if ($head4{0} != "\xFF") {
+ if ($head4[0] != "\xFF") {
for ($i = 1; $i < 4; $i++) {
- if ($head4{$i} == "\xFF") {
+ if ($head4[$i] == "\xFF") {
$this->fseek($i - 4, SEEK_CUR);
continue 2;
}
@@ -1314,7 +1326,7 @@
$WhereWeWere = $this->ftell();
$this->fseek($MPEGaudioHeaderLengthCache[$head4] - 4, SEEK_CUR);
$next4 = $this->fread(4);
- if ($next4{0} == "\xFF") {
+ if ($next4[0] == "\xFF") {
if (!isset($MPEGaudioHeaderDecodeCache[$next4])) {
$MPEGaudioHeaderDecodeCache[$next4] = self::MPEGaudioHeaderDecode($next4);
}
@@ -1324,12 +1336,12 @@
if ($MPEGaudioHeaderValidCache[$next4]) {
$this->fseek(-4, SEEK_CUR);
- getid3_lib::safe_inc($Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]]);
- getid3_lib::safe_inc($Distribution['layer'][$LongMPEGlayerLookup[$head4]]);
- getid3_lib::safe_inc($Distribution['version'][$LongMPEGversionLookup[$head4]]);
- getid3_lib::safe_inc($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]);
- getid3_lib::safe_inc($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]);
- if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) {
+ $Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]] = isset($Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]]) ? ++$Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]] : 1;
+ $Distribution['layer'][$LongMPEGlayerLookup[$head4]] = isset($Distribution['layer'][$LongMPEGlayerLookup[$head4]]) ? ++$Distribution['layer'][$LongMPEGlayerLookup[$head4]] : 1;
+ $Distribution['version'][$LongMPEGversionLookup[$head4]] = isset($Distribution['version'][$LongMPEGversionLookup[$head4]]) ? ++$Distribution['version'][$LongMPEGversionLookup[$head4]] : 1;
+ $Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])] = isset($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]) ? ++$Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])] : 1;
+ $Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]] = isset($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]) ? ++$Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]] : 1;
+ if (++$frames_scanned >= $max_frames_scan) {
$pct_data_scanned = ($this->ftell() - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']);
$this->warning('too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.');
foreach ($Distribution as $key1 => $value1) {
@@ -1407,10 +1419,9 @@
static $MPEGaudioLayerLookup;
static $MPEGaudioBitrateLookup;
if (empty($MPEGaudioVersionLookup)) {
- $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
- $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
- $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
-
+ $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
+ $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
+ $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
}
$this->fseek($avdataoffset);
@@ -1460,7 +1471,7 @@
return false;
}
- if (($header{$SynchSeekOffset} == "\xFF") && ($header{($SynchSeekOffset + 1)} > "\xE0")) { // synch detected
+ if (($header[$SynchSeekOffset] == "\xFF") && ($header[($SynchSeekOffset + 1)] > "\xE0")) { // synch detected
$FirstFrameAVDataOffset = null;
if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) {
$FirstFrameThisfileInfo = $info;
@@ -1555,7 +1566,7 @@
$this->fseek($scan_start_offset[$current_segment]);
$buffer_4k = $this->fread(4096);
for ($j = 0; $j < (strlen($buffer_4k) - 4); $j++) {
- if (($buffer_4k{$j} == "\xFF") && ($buffer_4k{($j + 1)} > "\xE0")) { // synch detected
+ if (($buffer_4k[$j] == "\xFF") && ($buffer_4k[($j + 1)] > "\xE0")) { // synch detected
if ($this->decodeMPEGaudioHeader($scan_start_offset[$current_segment] + $j, $dummy, false, false, $FastMode)) {
$calculated_next_offset = $scan_start_offset[$current_segment] + $j + $dummy['mpeg']['audio']['framelength'];
if ($this->decodeMPEGaudioHeader($calculated_next_offset, $dummy, false, false, $FastMode)) {
@@ -1780,7 +1791,7 @@
* @return bool
*/
public static function MPEGaudioHeaderValid($rawarray, $echoerrors=false, $allowBitrate15=false) {
- if (($rawarray['synch'] & 0x0FFE) != 0x0FFE) {
+ if (!isset($rawarray['synch']) || ($rawarray['synch'] & 0x0FFE) != 0x0FFE) {
return false;
}
@@ -1877,18 +1888,18 @@
}
$MPEGrawHeader['synch'] = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4;
- $MPEGrawHeader['version'] = (ord($Header4Bytes{1}) & 0x18) >> 3; // BB
- $MPEGrawHeader['layer'] = (ord($Header4Bytes{1}) & 0x06) >> 1; // CC
- $MPEGrawHeader['protection'] = (ord($Header4Bytes{1}) & 0x01); // D
- $MPEGrawHeader['bitrate'] = (ord($Header4Bytes{2}) & 0xF0) >> 4; // EEEE
- $MPEGrawHeader['sample_rate'] = (ord($Header4Bytes{2}) & 0x0C) >> 2; // FF
- $MPEGrawHeader['padding'] = (ord($Header4Bytes{2}) & 0x02) >> 1; // G
- $MPEGrawHeader['private'] = (ord($Header4Bytes{2}) & 0x01); // H
- $MPEGrawHeader['channelmode'] = (ord($Header4Bytes{3}) & 0xC0) >> 6; // II
- $MPEGrawHeader['modeextension'] = (ord($Header4Bytes{3}) & 0x30) >> 4; // JJ
- $MPEGrawHeader['copyright'] = (ord($Header4Bytes{3}) & 0x08) >> 3; // K
- $MPEGrawHeader['original'] = (ord($Header4Bytes{3}) & 0x04) >> 2; // L
- $MPEGrawHeader['emphasis'] = (ord($Header4Bytes{3}) & 0x03); // MM
+ $MPEGrawHeader['version'] = (ord($Header4Bytes[1]) & 0x18) >> 3; // BB
+ $MPEGrawHeader['layer'] = (ord($Header4Bytes[1]) & 0x06) >> 1; // CC
+ $MPEGrawHeader['protection'] = (ord($Header4Bytes[1]) & 0x01); // D
+ $MPEGrawHeader['bitrate'] = (ord($Header4Bytes[2]) & 0xF0) >> 4; // EEEE
+ $MPEGrawHeader['sample_rate'] = (ord($Header4Bytes[2]) & 0x0C) >> 2; // FF
+ $MPEGrawHeader['padding'] = (ord($Header4Bytes[2]) & 0x02) >> 1; // G
+ $MPEGrawHeader['private'] = (ord($Header4Bytes[2]) & 0x01); // H
+ $MPEGrawHeader['channelmode'] = (ord($Header4Bytes[3]) & 0xC0) >> 6; // II
+ $MPEGrawHeader['modeextension'] = (ord($Header4Bytes[3]) & 0x30) >> 4; // JJ
+ $MPEGrawHeader['copyright'] = (ord($Header4Bytes[3]) & 0x08) >> 3; // K
+ $MPEGrawHeader['original'] = (ord($Header4Bytes[3]) & 0x04) >> 2; // L
+ $MPEGrawHeader['emphasis'] = (ord($Header4Bytes[3]) & 0x03); // MM
return $MPEGrawHeader;
}
@@ -1997,7 +2008,7 @@
public static function XingVBRidOffset($version, $channelmode) {
static $XingVBRidOffsetCache = array();
if (empty($XingVBRidOffsetCache)) {
- $XingVBRidOffsetCache = array (
+ $XingVBRidOffsetCache = array (
'1' => array ('mono' => 0x15, // 4 + 17 = 21
'stereo' => 0x24, // 4 + 32 = 36
'joint stereo' => 0x24,
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.mpc.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.mpc.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.mpc.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.mpc.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_mpc extends getid3_handler
{
@@ -200,7 +203,6 @@
default:
$this->error('Found unhandled key type "'.$thisPacket['key'].'" at offset '.$thisPacket['offset']);
return false;
- break;
}
if (!empty($thisPacket)) {
$info['mpc']['packets'][] = $thisPacket;
@@ -382,7 +384,6 @@
$info['error'] = 'Expecting 4, 5 or 6 in version field, found '.$thisfile_mpc_header['stream_version_major'].' instead';
unset($info['mpc']);
return false;
- break;
}
if (($thisfile_mpc_header['stream_version_major'] > 4) && ($thisfile_mpc_header['block_size'] != 1)) {
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.ogg.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.ogg.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.ogg.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.ogg.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.flac.php', __FILE__, true);
class getid3_ogg extends getid3_handler
@@ -615,7 +618,6 @@
default:
return false;
- break;
}
$VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.optimfrog.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.optimfrog.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.optimfrog.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.optimfrog.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
class getid3_optimfrog extends getid3_handler
@@ -76,7 +79,7 @@
$RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8);
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
$getid3_temp->info['avdataend'] = $info['avdataend'];
$getid3_riff = new getid3_riff($getid3_temp);
@@ -307,7 +310,7 @@
$RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8);
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
$getid3_temp->info['avdataend'] = $info['avdataend'];
$getid3_riff = new getid3_riff($getid3_temp);
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.rkau.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.rkau.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.rkau.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.rkau.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_rkau extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.shorten.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.shorten.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.shorten.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.shorten.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,7 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
-
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_shorten extends getid3_handler
{
/**
@@ -150,6 +152,9 @@
if (!empty($output) && (substr($output, 12, 4) == 'fmt ')) {
+ if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+ }
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
$fmt_size = getid3_lib::LittleEndian2Int(substr($output, 16, 4));
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.tak.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.tak.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.tak.php 1970-01-01 01:00:00.000000000 +0100
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.tak.php 2022-05-20 16:59:18.000000000 +0100
@@ -0,0 +1,214 @@
+ //
+// available at http://getid3.sourceforge.net //
+// or https://www.getid3.org //
+// also https://github.com/JamesHeinrich/getID3 //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio.tak.php //
+// module for analyzing Tom's lossless Audio Kompressor //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
+
+class getid3_tak extends getid3_handler
+{
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ $info['fileformat'] = 'tak';
+ $info['audio']['dataformat'] = 'tak';
+ $info['audio']['bitrate_mode'] = 'vbr';
+ $info['audio']['lossless'] = true;
+
+ $info['tak_audio']['raw'] = array();
+ $thisfile_takaudio = &$info['tak_audio'];
+ $thisfile_takaudio_raw = &$thisfile_takaudio['raw'];
+
+ $this->fseek($info['avdataoffset']);
+ $TAKMetaData = $this->fread(4);
+
+ $thisfile_takaudio_raw['magic'] = $TAKMetaData;
+ $magic = 'tBaK';
+ if ($thisfile_takaudio_raw['magic'] != $magic) {
+ $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_takaudio_raw['magic']).'"');
+ unset($info['fileformat']);
+ return false;
+ }
+ $offset = 4; //skip magic
+ $this->fseek($offset);
+ $TAKMetaData = $this->fread(4); //read Metadata Block Header
+ $objtype = getid3_lib::BigEndian2Int(substr($TAKMetaData, 0, 1)); //Metadata Block Object Type
+ $objlength = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 1, 3)); //Metadata Block Object Lenght excluding header
+ if ($objtype == 1) { //The First Metadata Block Object must be of Type 1 (STREAMINFO)
+ $offset += 4; //skip to Metadata Block contents
+ $this->fseek($offset);
+ $TAKMetaData = $this->fread($objlength); // Get the raw Metadata Block Data
+ $thisfile_takaudio_raw['STREAMINFO'] = getid3_lib::LittleEndian2Bin(substr($TAKMetaData, 0, $objlength - 3));
+ $offset += $objlength; // Move to the next Metadata Block Object
+ $thisfile_takaudio['channels'] = getid3_lib::Bin2Dec(substr($thisfile_takaudio_raw['STREAMINFO'], 1, 4)) + 1;
+ $thisfile_takaudio['bits_per_sample'] = getid3_lib::Bin2Dec(substr($thisfile_takaudio_raw['STREAMINFO'], 5, 5)) + 8;
+ $thisfile_takaudio['sample_rate'] = getid3_lib::Bin2Dec(substr($thisfile_takaudio_raw['STREAMINFO'], 10, 18)) + 6000;
+ $thisfile_takaudio['samples'] = getid3_lib::Bin2Dec(substr($thisfile_takaudio_raw['STREAMINFO'], 31, 35));
+ $thisfile_takaudio['framesize'] = self::TAKFramesizeLookup(getid3_lib::Bin2Dec(substr($thisfile_takaudio_raw['STREAMINFO'], 66, 4)));
+ $thisfile_takaudio['codectype'] = self::TAKCodecTypeLookup(getid3_lib::Bin2Dec(substr($thisfile_takaudio_raw['STREAMINFO'], 74, 6)));
+ } else {
+ $this->error('Expecting Type 1 (STREAMINFO) Metadata Object header, but found Type "'.$objtype.'" Object instead');
+ unset($info['fileformat']);
+ return false;
+ }
+ $this->fseek($offset);
+ $TAKMetaData = $this->fread(4);
+ $objtype = getid3_lib::BigEndian2Int(substr($TAKMetaData, 0, 1));
+ $objlength = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 1, 3));
+ while ($objtype != 0) {
+ switch ($objtype) {
+ case 4 :
+ // ENCODERINFO Metadata Block
+ $offset += 4;
+ $this->fseek($offset);
+ $TAKMetaData = $this->fread($objlength);
+ $ver = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 0, 3));
+ $major = ($ver & 0xff0000) >> 16;
+ $minor = ($ver & 0x00ff00) >> 8;
+ $revision= $ver & 0x0000ff;
+ $thisfile_takaudio['version'] = 'TAK V '.$major.'.'.$minor.'.'.$revision;
+ $thisfile_takaudio['profile'] = self::TAKProfileLookup(getid3_lib::BigEndian2Int(substr($TAKMetaData, 3, 1)));
+ $offset += $objlength;
+ break;
+ case 6 :
+ // MD5 Checksum Metadata Block
+ $offset += 4;
+ $this->fseek($offset);
+ $TAKMetaData = $this->fread($objlength);
+ $thisfile_takaudio_raw['MD5Data'] = substr($TAKMetaData, 0, 16);
+ $offset += $objlength;
+ break;
+ case 7 :
+ // LASTFRAME Metadata Block
+ $offset += 4;
+ $this->fseek($offset);
+ $TAKMetaData = $this->fread($objlength);
+ $thisfile_takaudio['lastframe_pos'] = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 0, 5));
+ $thisfile_takaudio['last_frame_size'] = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 5, 3));
+ $offset += $objlength;
+ break;
+ case 3 :
+ // ORIGINALFILEDATA Metadata Block
+ $offset += 4;
+ $this->fseek($offset);
+ $TAKMetaData = $this->fread($objlength);
+ $headersize = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 0, 3));
+ $footersize = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 3, 3));
+ if ($headersize) $thisfile_takaudio_raw['header_data'] = substr($TAKMetaData, 6, $headersize);
+ if ($footersize) $thisfile_takaudio_raw['footer_data'] = substr($TAKMetaData, $headersize, $footersize);
+ $offset += $objlength;
+ break;
+ default :
+ // PADDING or SEEKTABLE Metadata Block. Just skip it
+ $offset += 4;
+ $this->fseek($offset);
+ $TAKMetaData = $this->fread($objlength);
+ $offset += $objlength;
+ break;
+ }
+ $this->fseek($offset);
+ $TAKMetaData = $this->fread(4);
+ $objtype = getid3_lib::BigEndian2Int(substr($TAKMetaData, 0, 1));
+ $objlength = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 1, 3));
+ }
+ // Finished all Metadata Blocks. So update $info['avdataoffset'] because next block is the first Audio data block
+ $info['avdataoffset'] = $offset;
+
+ $info['audio']['channels'] = $thisfile_takaudio['channels'];
+ if ($thisfile_takaudio['sample_rate'] == 0) {
+ $this->error('Corrupt TAK file: samplerate == zero');
+ return false;
+ }
+ $info['audio']['sample_rate'] = $thisfile_takaudio['sample_rate'];
+ $thisfile_takaudio['playtime'] = $thisfile_takaudio['samples'] / $thisfile_takaudio['sample_rate'];
+ if ($thisfile_takaudio['playtime'] == 0) {
+ $this->error('Corrupt TAK file: playtime == zero');
+ return false;
+ }
+ $info['playtime_seconds'] = $thisfile_takaudio['playtime'];
+ $thisfile_takaudio['compressed_size'] = $info['avdataend'] - $info['avdataoffset'];
+ $thisfile_takaudio['uncompressed_size'] = $thisfile_takaudio['samples'] * $thisfile_takaudio['channels'] * ($thisfile_takaudio['bits_per_sample'] / 8);
+ if ($thisfile_takaudio['uncompressed_size'] == 0) {
+ $this->error('Corrupt TAK file: uncompressed_size == zero');
+ return false;
+ }
+ $thisfile_takaudio['compression_ratio'] = $thisfile_takaudio['compressed_size'] / ($thisfile_takaudio['uncompressed_size'] + $offset);
+ $thisfile_takaudio['bitrate'] = (($thisfile_takaudio['samples'] * $thisfile_takaudio['channels'] * $thisfile_takaudio['bits_per_sample']) / $thisfile_takaudio['playtime']) * $thisfile_takaudio['compression_ratio'];
+ $info['audio']['bitrate'] = $thisfile_takaudio['bitrate'];
+
+ if (empty($thisfile_takaudio_raw['MD5Data'])) {
+ //$this->warning('MD5Data is not set');
+ } elseif ($thisfile_takaudio_raw['MD5Data'] === str_repeat("\x00", 16)) {
+ //$this->warning('MD5Data is null');
+ } else {
+ $info['md5_data_source'] = '';
+ $md5 = $thisfile_takaudio_raw['MD5Data'];
+ for ($i = 0; $i < strlen($md5); $i++) {
+ $info['md5_data_source'] .= str_pad(dechex(ord($md5[$i])), 2, '00', STR_PAD_LEFT);
+ }
+ if (!preg_match('/^[0-9a-f]{32}$/', $info['md5_data_source'])) {
+ unset($info['md5_data_source']);
+ }
+ }
+
+ foreach (array('bits_per_sample', 'version', 'profile') as $key) {
+ if (!empty($thisfile_takaudio[$key])) {
+ $info['audio'][$key] = $thisfile_takaudio[$key];
+ }
+ }
+
+ return true;
+ }
+
+ public function TAKFramesizeLookup($framesize) {
+ static $TAKFramesizeLookup = array(
+ 0 => '94 ms',
+ 1 => '125 ms',
+ 2 => '188 ms',
+ 3 => '250 ms',
+ 4 => '4096 samples',
+ 5 => '8192 samples',
+ 6 => '16384 samples',
+ 7 => '512 samples',
+ 8 => '1024 samples',
+ 9 => '2048 samples'
+ );
+ return (isset($TAKFramesizeLookup[$framesize]) ? $TAKFramesizeLookup[$framesize] : 'invalid');
+ }
+ public function TAKCodecTypeLookup($code) {
+ static $TAKCodecTypeLookup = array(
+ 0 => 'Integer 24 bit (TAK 1.0)',
+ 1 => 'Experimental!',
+ 2 => 'Integer 24 bit (TAK 2.0)',
+ 3 => 'LossyWav (TAK 2.1)',
+ 4 => 'Integer 24 bit MC (TAK 2.2)'
+ );
+ return (isset($TAKCodecTypeLookup[$code]) ? $TAKCodecTypeLookup[$code] : 'invalid');
+ }
+ public function TAKProfileLookup($code) {
+ $out ='-p';
+ $evaluation = ($code & 0xf0) >> 4;
+ $compresion = $code & 0x0f;
+ static $TAKEvaluationLookup = array(
+ 0 => '',
+ 1 => 'e',
+ 2 => 'm'
+ );
+ return (isset($TAKEvaluationLookup[$evaluation]) ? $out .= $compresion . $TAKEvaluationLookup[$evaluation] : 'invalid');
+ }
+
+}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.tta.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.tta.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.tta.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.tta.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_tta extends getid3_handler
{
@@ -41,7 +44,7 @@
return false;
}
- switch ($ttaheader{3}) {
+ switch ($ttaheader[3]) {
case "\x01": // TTA v1.x
case "\x02": // TTA v1.x
case "\x03": // TTA v1.x
@@ -49,7 +52,7 @@
$info['tta']['major_version'] = 1;
$info['avdataoffset'] += 16;
- $info['tta']['compression_level'] = ord($ttaheader{3});
+ $info['tta']['compression_level'] = ord($ttaheader[3]);
$info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2));
$info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2));
$info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 4));
@@ -92,9 +95,8 @@
break;
default:
- $this->error('This version of getID3() ['.$this->getid3->version().'] only knows how to handle TTA v1 and v2 - it may not work correctly with this file which appears to be TTA v'.$ttaheader{3});
+ $this->error('This version of getID3() ['.$this->getid3->version().'] only knows how to handle TTA v1 and v2 - it may not work correctly with this file which appears to be TTA v'.$ttaheader[3]);
return false;
- break;
}
$info['audio']['encoder'] = 'TTA v'.$info['tta']['major_version'];
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.asf.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.asf.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.asf.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.asf.php 2022-05-20 16:59:18.000000000 +0100
@@ -13,6 +13,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
class getid3_asf extends getid3_handler
@@ -363,7 +366,7 @@
$thisfile_audio['codec'] = $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['name']);
if (!isset($thisfile_audio['bitrate']) && strstr($AudioCodecBitrate, 'kbps')) {
- $thisfile_audio['bitrate'] = (int) (trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000);
+ $thisfile_audio['bitrate'] = (int) trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000;
}
//if (!isset($thisfile_video['bitrate']) && isset($thisfile_audio['bitrate']) && isset($thisfile_asf['file_properties_object']['max_bitrate']) && ($thisfile_asf_codeclistobject['codec_entries_count'] > 1)) {
if (empty($thisfile_video['bitrate']) && !empty($thisfile_audio['bitrate']) && !empty($info['bitrate'])) {
@@ -797,17 +800,17 @@
case 'wm/tracknumber':
case 'tracknumber':
// be careful casting to int: casting unicode strings to int gives unexpected results (stops parsing at first non-numeric character)
- $thisfile_asf_comments['track'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
- foreach ($thisfile_asf_comments['track'] as $key => $value) {
+ $thisfile_asf_comments['track_number'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
+ foreach ($thisfile_asf_comments['track_number'] as $key => $value) {
if (preg_match('/^[0-9\x00]+$/', $value)) {
- $thisfile_asf_comments['track'][$key] = intval(str_replace("\x00", '', $value));
+ $thisfile_asf_comments['track_number'][$key] = intval(str_replace("\x00", '', $value));
}
}
break;
case 'wm/track':
- if (empty($thisfile_asf_comments['track'])) {
- $thisfile_asf_comments['track'] = array(1 + $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
+ if (empty($thisfile_asf_comments['track_number'])) {
+ $thisfile_asf_comments['track_number'] = array(1 + (int) $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
}
break;
@@ -1653,26 +1656,26 @@
* @return string
*/
public static function BytestringToGUID($Bytestring) {
- $GUIDstring = str_pad(dechex(ord($Bytestring{3})), 2, '0', STR_PAD_LEFT);
- $GUIDstring .= str_pad(dechex(ord($Bytestring{2})), 2, '0', STR_PAD_LEFT);
- $GUIDstring .= str_pad(dechex(ord($Bytestring{1})), 2, '0', STR_PAD_LEFT);
- $GUIDstring .= str_pad(dechex(ord($Bytestring{0})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring = str_pad(dechex(ord($Bytestring[3])), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[2])), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[1])), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[0])), 2, '0', STR_PAD_LEFT);
$GUIDstring .= '-';
- $GUIDstring .= str_pad(dechex(ord($Bytestring{5})), 2, '0', STR_PAD_LEFT);
- $GUIDstring .= str_pad(dechex(ord($Bytestring{4})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[5])), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[4])), 2, '0', STR_PAD_LEFT);
$GUIDstring .= '-';
- $GUIDstring .= str_pad(dechex(ord($Bytestring{7})), 2, '0', STR_PAD_LEFT);
- $GUIDstring .= str_pad(dechex(ord($Bytestring{6})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[7])), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[6])), 2, '0', STR_PAD_LEFT);
$GUIDstring .= '-';
- $GUIDstring .= str_pad(dechex(ord($Bytestring{8})), 2, '0', STR_PAD_LEFT);
- $GUIDstring .= str_pad(dechex(ord($Bytestring{9})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[8])), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[9])), 2, '0', STR_PAD_LEFT);
$GUIDstring .= '-';
- $GUIDstring .= str_pad(dechex(ord($Bytestring{10})), 2, '0', STR_PAD_LEFT);
- $GUIDstring .= str_pad(dechex(ord($Bytestring{11})), 2, '0', STR_PAD_LEFT);
- $GUIDstring .= str_pad(dechex(ord($Bytestring{12})), 2, '0', STR_PAD_LEFT);
- $GUIDstring .= str_pad(dechex(ord($Bytestring{13})), 2, '0', STR_PAD_LEFT);
- $GUIDstring .= str_pad(dechex(ord($Bytestring{14})), 2, '0', STR_PAD_LEFT);
- $GUIDstring .= str_pad(dechex(ord($Bytestring{15})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[10])), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[11])), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[12])), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[13])), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[14])), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring[15])), 2, '0', STR_PAD_LEFT);
return strtoupper($GUIDstring);
}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.bink.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.bink.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.bink.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.bink.php 2022-05-20 16:59:18.000000000 +0100
@@ -13,6 +13,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_bink extends getid3_handler
{
@@ -29,20 +32,14 @@
switch ($fileTypeID) {
case 'BIK':
return $this->ParseBink();
- break;
case 'SMK':
return $this->ParseSmacker();
- break;
default:
$this->error('Expecting "BIK" or "SMK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($fileTypeID).'"');
return false;
- break;
}
-
- return true;
-
}
/**
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.flv.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.flv.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.flv.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.flv.php 2022-05-20 16:59:18.000000000 +0100
@@ -53,6 +53,10 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
+
define('GETID3_FLV_TAG_AUDIO', 8);
define('GETID3_FLV_TAG_VIDEO', 9);
define('GETID3_FLV_TAG_META', 18);
@@ -597,7 +601,6 @@
// null
case 6:
return null;
- break;
// Mixed array
case 8:
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.ivf.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.ivf.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.ivf.php 1970-01-01 01:00:00.000000000 +0100
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.ivf.php 2022-05-20 16:59:18.000000000 +0100
@@ -0,0 +1,80 @@
+ //
+// available at https://github.com/JamesHeinrich/getID3 //
+// or https://www.getid3.org //
+// or http://getid3.sourceforge.net //
+// see readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio.ivf.php //
+// module for analyzing IVF audio-video files //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
+
+class getid3_ivf extends getid3_handler
+{
+ /**
+ * @return bool
+ */
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ $info['fileformat'] = 'ivf';
+ $info['video']['dataformat'] = 'ivf';
+
+ $this->fseek($info['avdataoffset']);
+ $IVFheader = $this->fread(32);
+
+ if (substr($IVFheader, 0, 4) == 'DKIF') {
+
+ // https://wiki.multimedia.cx/index.php/IVF
+ $info['ivf']['header']['signature'] = substr($IVFheader, 0, 4);
+ $info['ivf']['header']['version'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 4, 2)); // should be 0
+ $info['ivf']['header']['headersize'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 6, 2));
+ $info['ivf']['header']['fourcc'] = substr($IVFheader, 8, 4);
+ $info['ivf']['header']['resolution_x'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 12, 2));
+ $info['ivf']['header']['resolution_y'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 14, 2));
+ $info['ivf']['header']['timebase_numerator'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 16, 4));
+ $info['ivf']['header']['timebase_denominator'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 20, 4));
+ $info['ivf']['header']['frame_count'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 24, 4));
+ //$info['ivf']['header']['reserved'] = substr($IVFheader, 28, 4);
+
+ $info['ivf']['header']['frame_rate'] = (float) $info['ivf']['header']['timebase_numerator'] / $info['ivf']['header']['timebase_denominator'];
+
+ if ($info['ivf']['header']['version'] > 0) {
+ $this->warning('Expecting IVF header version 0, found version '.$info['ivf']['header']['version'].', results may not be accurate');
+ }
+
+ $info['video']['resolution_x'] = $info['ivf']['header']['resolution_x'];
+ $info['video']['resolution_y'] = $info['ivf']['header']['resolution_y'];
+ $info['video']['codec'] = $info['ivf']['header']['fourcc'];
+
+ $info['ivf']['frame_count'] = 0;
+ while (!$this->feof()) {
+ if ($frameheader = $this->fread(12)) {
+ $framesize = getid3_lib::LittleEndian2Int(substr($frameheader, 0, 4)); // size of frame in bytes (not including the 12-byte header)
+ $timestamp = getid3_lib::LittleEndian2Int(substr($frameheader, 4, 8)); // 64-bit presentation timestamp
+ $this->fseek($framesize, SEEK_CUR);
+ $info['ivf']['frame_count']++;
+ }
+ }
+ if ($info['ivf']['frame_count']) {
+ $info['playtime_seconds'] = $timestamp / 100000;
+ $info['video']['frame_rate'] = (float) $info['ivf']['frame_count'] / $info['playtime_seconds'];
+ }
+
+ } else {
+ $this->error('Expecting "DKIF" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($IVFheader, 0, 4)).'"');
+ return false;
+ }
+
+ return true;
+ }
+
+}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.matroska.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.matroska.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.matroska.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.matroska.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
define('EBML_ID_CHAPTERS', 0x0043A770); // [10][43][A7][70] -- A system to define basic menus and partition data. For more detailed information, look at the Chapters Explanation.
define('EBML_ID_SEEKHEAD', 0x014D9B74); // [11][4D][9B][74] -- Contains the position of other level 1 elements.
@@ -329,7 +332,7 @@
break;*/
}
- $info['video']['streams'][] = $track_info;
+ $info['video']['streams'][$trackarray['TrackUID']] = $track_info;
break;
case 2: // Audio
@@ -342,7 +345,7 @@
switch ($trackarray['CodecID']) {
case 'A_PCM/INT/LIT':
case 'A_PCM/INT/BIG':
- $track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth'];
+ $track_info['bitrate'] = $track_info['sample_rate'] * $track_info['channels'] * $trackarray['BitDepth'];
break;
case 'A_AC3':
@@ -362,7 +365,7 @@
// create temp instance
$getid3_temp = new getID3();
if ($track_info['dataformat'] != 'flac') {
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
}
$getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'];
if ($track_info['dataformat'][0] == 'm' || $track_info['dataformat'] == 'flac') {
@@ -478,7 +481,7 @@
break;
}
- $info['audio']['streams'][] = $track_info;
+ $info['audio']['streams'][$trackarray['TrackUID']] = $track_info;
break;
}
}
@@ -509,6 +512,30 @@
unset($info['mime_type']);
}
+ // use _STATISTICS_TAGS if available to set audio/video bitrates
+ if (!empty($info['matroska']['tags'])) {
+ $_STATISTICS_byTrackUID = array();
+ foreach ($info['matroska']['tags'] as $key1 => $value1) {
+ if (!empty($value1['Targets']['TagTrackUID'][0]) && !empty($value1['SimpleTag'])) {
+ foreach ($value1['SimpleTag'] as $key2 => $value2) {
+ if (!empty($value2['TagName']) && isset($value2['TagString'])) {
+ $_STATISTICS_byTrackUID[$value1['Targets']['TagTrackUID'][0]][$value2['TagName']] = $value2['TagString'];
+ }
+ }
+ }
+ }
+ foreach (array('audio','video') as $avtype) {
+ if (!empty($info[$avtype]['streams'])) {
+ foreach ($info[$avtype]['streams'] as $trackUID => $trackdata) {
+ if (!isset($trackdata['bitrate']) && !empty($_STATISTICS_byTrackUID[$trackUID]['BPS'])) {
+ $info[$avtype]['streams'][$trackUID]['bitrate'] = (int) $_STATISTICS_byTrackUID[$trackUID]['BPS'];
+ @$info[$avtype]['bitrate'] += $info[$avtype]['streams'][$trackUID]['bitrate'];
+ }
+ }
+ }
+ }
+ }
+
return true;
}
@@ -614,8 +641,10 @@
while ($this->getEBMLelement($subelement, $track_entry['end'], array(EBML_ID_VIDEO, EBML_ID_AUDIO, EBML_ID_CONTENTENCODINGS, EBML_ID_CODECPRIVATE))) {
switch ($subelement['id']) {
- case EBML_ID_TRACKNUMBER:
case EBML_ID_TRACKUID:
+ $track_entry[$subelement['id_name']] = getid3_lib::PrintHexBytes($subelement['data'], true, false);
+ break;
+ case EBML_ID_TRACKNUMBER:
case EBML_ID_TRACKTYPE:
case EBML_ID_MINCACHE:
case EBML_ID_MAXCACHE:
@@ -963,7 +992,7 @@
case EBML_ID_TAGEDITIONUID:
case EBML_ID_TAGCHAPTERUID:
case EBML_ID_TAGATTACHMENTUID:
- $targets_entry[$sub_sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
+ $targets_entry[$sub_sub_subelement['id_name']][] = getid3_lib::PrintHexBytes($sub_sub_subelement['data'], true, false);
break;
default:
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.mpeg.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.mpeg.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.mpeg.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.mpeg.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
class getid3_mpeg extends getid3_handler
@@ -90,11 +93,9 @@
break;
case 0xB3: // sequence_header_code
- /*
- Note: purposely doing the less-pretty (and probably a bit slower) method of using string of bits rather than bitwise operations.
- Mostly because PHP 32-bit doesn't handle unsigned integers well for bitwise operation.
- Also the MPEG stream is designed as a bitstream and often doesn't align nicely with byte boundaries.
- */
+ // Note: purposely doing the less-pretty (and probably a bit slower) method of using string of bits rather than bitwise operations.
+ // Mostly because PHP 32-bit doesn't handle unsigned integers well for bitwise operation.
+ // Also the MPEG stream is designed as a bitstream and often doesn't align nicely with byte boundaries.
$info['video']['codec'] = 'MPEG-1'; // will be updated if extension_start_code found
$bitstream = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $StartCodeOffset + 4, 8));
@@ -393,7 +394,7 @@
$info['mpeg']['packed_elementary_streams'][$PackedElementaryStream['stream_type']][$PackedElementaryStream['stream_id']][] = $PackedElementaryStream;
*/
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
$getid3_temp->info = $info;
$getid3_mp3 = new getid3_mp3($getid3_temp);
for ($i = 0; $i <= 7; $i++) {
@@ -521,7 +522,7 @@
* @param int $bits_to_read
* @param bool $return_singlebit_as_boolean
*
- * @return bool|float|int
+ * @return bool|int
*/
private function readBitsFromStream(&$bitstream, &$bitstreamoffset, $bits_to_read, $return_singlebit_as_boolean=true) {
$return = bindec(substr($bitstream, $bitstreamoffset, $bits_to_read));
@@ -622,7 +623,7 @@
/**
* @param int $rawaspectratio
- * @param int $mpeg_version
+ * @param int $mpeg_version
*
* @return string
*/
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.nsv.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.nsv.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.nsv.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.nsv.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_nsv extends getid3_handler
{
@@ -51,7 +54,6 @@
default:
$this->error('Expecting "NSVs" or "NSVf" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($NSVheader).'"');
return false;
- break;
}
if (!isset($info['nsv']['NSVf'])) {
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.quicktime.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.quicktime.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.quicktime.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.quicktime.php 2022-05-20 16:59:18.000000000 +0100
@@ -15,6 +15,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); // needed for ISO 639-2 language code lookup
@@ -38,7 +41,7 @@
$offset = 0;
$atomcounter = 0;
- $atom_data_read_buffer_size = max($this->getid3->option_fread_buffer_size * 1024, ($info['php_memory_limit'] ? round($info['php_memory_limit'] / 4) : 1024)); // set read buffer to 25% of PHP memory limit (if one is specified), otherwise use option_fread_buffer_size [default: 32MB]
+ $atom_data_read_buffer_size = $info['php_memory_limit'] ? round($info['php_memory_limit'] / 4) : $this->getid3->option_fread_buffer_size * 1024; // set read buffer to 25% of PHP memory limit (if one is specified), otherwise use option_fread_buffer_size [default: 32MB]
while ($offset < $info['avdataend']) {
if (!getid3_lib::intValueSupported($offset)) {
$this->error('Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions');
@@ -55,23 +58,33 @@
$atomsize = getid3_lib::BigEndian2Int($this->fread(8));
}
- $info['quicktime'][$atomname]['name'] = $atomname;
- $info['quicktime'][$atomname]['size'] = $atomsize;
- $info['quicktime'][$atomname]['offset'] = $offset;
-
if (($offset + $atomsize) > $info['avdataend']) {
+ $info['quicktime'][$atomname]['name'] = $atomname;
+ $info['quicktime'][$atomname]['size'] = $atomsize;
+ $info['quicktime'][$atomname]['offset'] = $offset;
$this->error('Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)');
return false;
}
-
if ($atomsize == 0) {
// Furthermore, for historical reasons the list of atoms is optionally
// terminated by a 32-bit integer set to 0. If you are writing a program
// to read user data atoms, you should allow for the terminating 0.
+ $info['quicktime'][$atomname]['name'] = $atomname;
+ $info['quicktime'][$atomname]['size'] = $atomsize;
+ $info['quicktime'][$atomname]['offset'] = $offset;
break;
}
+
$atomHierarchy = array();
- $info['quicktime'][$atomname] = $this->QuicktimeParseAtom($atomname, $atomsize, $this->fread(min($atomsize, $atom_data_read_buffer_size)), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms);
+ $parsedAtomData = $this->QuicktimeParseAtom($atomname, $atomsize, $this->fread(min($atomsize, $atom_data_read_buffer_size)), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms);
+ $parsedAtomData['name'] = $atomname;
+ $parsedAtomData['size'] = $atomsize;
+ $parsedAtomData['offset'] = $offset;
+ if (in_array($atomname, array('uuid'))) {
+ @$info['quicktime'][$atomname][] = $parsedAtomData;
+ } else {
+ $info['quicktime'][$atomname] = $parsedAtomData;
+ }
$offset += $atomsize;
$atomcounter++;
@@ -112,47 +125,44 @@
if (!empty($info['quicktime']['comments']['location.ISO6709'])) {
// https://en.wikipedia.org/wiki/ISO_6709
foreach ($info['quicktime']['comments']['location.ISO6709'] as $ISO6709string) {
- $latitude = false;
- $longitude = false;
- $altitude = false;
+ $ISO6709parsed = array('latitude'=>false, 'longitude'=>false, 'altitude'=>false);
if (preg_match('#^([\\+\\-])([0-9]{2}|[0-9]{4}|[0-9]{6})(\\.[0-9]+)?([\\+\\-])([0-9]{3}|[0-9]{5}|[0-9]{7})(\\.[0-9]+)?(([\\+\\-])([0-9]{3}|[0-9]{5}|[0-9]{7})(\\.[0-9]+)?)?/$#', $ISO6709string, $matches)) {
@list($dummy, $lat_sign, $lat_deg, $lat_deg_dec, $lon_sign, $lon_deg, $lon_deg_dec, $dummy, $alt_sign, $alt_deg, $alt_deg_dec) = $matches;
if (strlen($lat_deg) == 2) { // [+-]DD.D
- $latitude = floatval(ltrim($lat_deg, '0').$lat_deg_dec);
+ $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim($lat_deg, '0').$lat_deg_dec);
} elseif (strlen($lat_deg) == 4) { // [+-]DDMM.M
- $latitude = floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0').$lat_deg_dec / 60);
+ $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0').$lat_deg_dec / 60);
} elseif (strlen($lat_deg) == 6) { // [+-]DDMMSS.S
- $latitude = floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lat_deg, 4, 2), '0').$lat_deg_dec / 3600);
+ $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lat_deg, 4, 2), '0').$lat_deg_dec / 3600);
}
if (strlen($lon_deg) == 3) { // [+-]DDD.D
- $longitude = floatval(ltrim($lon_deg, '0').$lon_deg_dec);
+ $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim($lon_deg, '0').$lon_deg_dec);
} elseif (strlen($lon_deg) == 5) { // [+-]DDDMM.M
- $longitude = floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0').$lon_deg_dec / 60);
+ $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0').$lon_deg_dec / 60);
} elseif (strlen($lon_deg) == 7) { // [+-]DDDMMSS.S
- $longitude = floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lon_deg, 4, 2), '0').$lon_deg_dec / 3600);
+ $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lon_deg, 4, 2), '0').$lon_deg_dec / 3600);
}
if (strlen($alt_deg) == 3) { // [+-]DDD.D
- $altitude = floatval(ltrim($alt_deg, '0').$alt_deg_dec);
+ $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim($alt_deg, '0').$alt_deg_dec);
} elseif (strlen($alt_deg) == 5) { // [+-]DDDMM.M
- $altitude = floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0').$alt_deg_dec / 60);
+ $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0').$alt_deg_dec / 60);
} elseif (strlen($alt_deg) == 7) { // [+-]DDDMMSS.S
- $altitude = floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($alt_deg, 4, 2), '0').$alt_deg_dec / 3600);
+ $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($alt_deg, 4, 2), '0').$alt_deg_dec / 3600);
}
- if ($latitude !== false) {
- $info['quicktime']['comments']['gps_latitude'][] = (($lat_sign == '-') ? -1 : 1) * floatval($latitude);
- }
- if ($longitude !== false) {
- $info['quicktime']['comments']['gps_longitude'][] = (($lon_sign == '-') ? -1 : 1) * floatval($longitude);
- }
- if ($altitude !== false) {
- $info['quicktime']['comments']['gps_altitude'][] = (($alt_sign == '-') ? -1 : 1) * floatval($altitude);
+ foreach (array('latitude', 'longitude', 'altitude') as $key) {
+ if ($ISO6709parsed[$key] !== false) {
+ $value = (($lat_sign == '-') ? -1 : 1) * floatval($ISO6709parsed[$key]);
+ if (!isset($info['quicktime']['comments']['gps_'.$key]) || !in_array($value, $info['quicktime']['comments']['gps_'.$key])) {
+ @$info['quicktime']['comments']['gps_'.$key][] = (($lat_sign == '-') ? -1 : 1) * floatval($ISO6709parsed[$key]);
+ }
+ }
}
}
- if ($latitude === false) {
+ if ($ISO6709parsed['latitude'] === false) {
$this->warning('location.ISO6709 string not parsed correctly: "'.$ISO6709string.'", please submit as a bug');
}
break;
@@ -224,6 +234,7 @@
$atom_parent = end($atomHierarchy); // not array_pop($atomHierarchy); see https://www.getid3.org/phpBB3/viewtopic.php?t=1717
array_push($atomHierarchy, $atomname);
+ $atom_structure = array();
$atom_structure['hierarchy'] = implode(' ', $atomHierarchy);
$atom_structure['name'] = $atomname;
$atom_structure['size'] = $atomsize;
@@ -244,6 +255,7 @@
case 'mdia': // MeDIA container atom
case 'minf': // Media INFormation container atom
case 'dinf': // Data INFormation container atom
+ case 'nmhd': // Null Media HeaDer container atom
case 'udta': // User DaTA container atom
case 'cmov': // Compressed MOVie container atom
case 'rmra': // Reference Movie Record Atom
@@ -528,6 +540,7 @@
} elseif (preg_match('#^GIF#', $atom_structure['data'])) {
$atom_structure['image_mime'] = 'image/gif';
}
+ $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover');
break;
case 'atID':
@@ -554,6 +567,7 @@
} elseif (preg_match('#^GIF#', $atom_structure['data'])) {
$atom_structure['image_mime'] = 'image/gif';
}
+ $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover');
}
break;
@@ -568,8 +582,8 @@
}
}
}
- $this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']);
- break;
+ $this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']);
+ break;
case 'play': // auto-PLAY atom
@@ -757,6 +771,15 @@
$atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2));
$stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2);
+ if (substr($atom_structure['sample_description_table'][$i]['data'], 1, 54) == 'application/octet-stream;type=com.parrot.videometadata') {
+ // special handling for apparently-malformed (TextMetaDataSampleEntry?) data for some version of Parrot drones
+ $atom_structure['sample_description_table'][$i]['parrot_frame_metadata']['mime_type'] = substr($atom_structure['sample_description_table'][$i]['data'], 1, 55);
+ $atom_structure['sample_description_table'][$i]['parrot_frame_metadata']['metadata_version'] = (int) substr($atom_structure['sample_description_table'][$i]['data'], 55, 1);
+ unset($atom_structure['sample_description_table'][$i]['data']);
+$this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in this version of getID3() ['.$this->getid3->version().']');
+ continue;
+ }
+
$atom_structure['sample_description_table'][$i]['encoder_version'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 0, 2));
$atom_structure['sample_description_table'][$i]['encoder_revision'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 2, 2));
$atom_structure['sample_description_table'][$i]['encoder_vendor'] = substr($atom_structure['sample_description_table'][$i]['data'], 4, 4);
@@ -1044,6 +1067,7 @@
case 'stco': // Sample Table Chunk Offset atom
+// if (true) {
if ($ParseAllPossibleAtoms) {
$atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
@@ -1133,7 +1157,7 @@
$atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);
$atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
$atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
- $atom_structure['component_name'] = $this->Pascal2String(substr($atom_data, 24));
+ $atom_structure['component_name'] = $this->MaybePascal2String(substr($atom_data, 24));
if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) {
$info['video']['dataformat'] = 'quicktimevr';
@@ -1164,6 +1188,8 @@
if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
$info['comments']['language'][] = $atom_structure['language'];
}
+ $info['quicktime']['timestamps_unix']['create'][$atom_structure['hierarchy']] = $atom_structure['creation_time_unix'];
+ $info['quicktime']['timestamps_unix']['modify'][$atom_structure['hierarchy']] = $atom_structure['modify_time_unix'];
break;
@@ -1174,6 +1200,7 @@
$atom_structure['atom_index'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x01
$atom_structure['modification_date_unix'] = getid3_lib::DateMac2Unix($atom_structure['modification_date']);
+ $info['quicktime']['timestamps_unix']['modify'][$atom_structure['hierarchy']] = $atom_structure['modification_date_unix'];
break;
@@ -1271,6 +1298,8 @@
}
$atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
$atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
+ $info['quicktime']['timestamps_unix']['create'][$atom_structure['hierarchy']] = $atom_structure['creation_time_unix'];
+ $info['quicktime']['timestamps_unix']['modify'][$atom_structure['hierarchy']] = $atom_structure['modify_time_unix'];
$info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
$info['quicktime']['display_scale'] = $atom_structure['matrix_a'];
$info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale'];
@@ -1309,6 +1338,8 @@
$atom_structure['flags']['in_poster'] = (bool) ($atom_structure['flags_raw'] & 0x0008);
$atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
$atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
+ $info['quicktime']['timestamps_unix']['create'][$atom_structure['hierarchy']] = $atom_structure['creation_time_unix'];
+ $info['quicktime']['timestamps_unix']['modify'][$atom_structure['hierarchy']] = $atom_structure['modify_time_unix'];
// https://www.getid3.org/phpBB3/viewtopic.php?t=1908
// attempt to compute rotation from matrix values
@@ -1450,7 +1481,7 @@
$info['avdataend'] = $atom_structure['offset'] + $atom_structure['size']; // $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size'];
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
$getid3_temp->info['avdataend'] = $info['avdataend'];
$getid3_mp3 = new getid3_mp3($getid3_temp);
@@ -1639,6 +1670,146 @@
}
break;
+ case 'uuid': // user-defined atom often seen containing XML data, also used for potentially many other purposes, only a few specifically handled by getID3 (e.g. 360fly spatial data)
+ //Get the UUID ID in first 16 bytes
+ $uuid_bytes_read = unpack('H8time_low/H4time_mid/H4time_hi/H4clock_seq_hi/H12clock_seq_low', substr($atom_data, 0, 16));
+ $atom_structure['uuid_field_id'] = implode('-', $uuid_bytes_read);
+
+ switch ($atom_structure['uuid_field_id']) { // http://fileformats.archiveteam.org/wiki/Boxes/atoms_format#UUID_boxes
+
+ case '0537cdab-9d0c-4431-a72a-fa561f2a113e': // Exif - http://fileformats.archiveteam.org/wiki/Exif
+ case '2c4c0100-8504-40b9-a03e-562148d6dfeb': // Photoshop Image Resources - http://fileformats.archiveteam.org/wiki/Photoshop_Image_Resources
+ case '33c7a4d2-b81d-4723-a0ba-f1a3e097ad38': // IPTC-IIM - http://fileformats.archiveteam.org/wiki/IPTC-IIM
+ case '8974dbce-7be7-4c51-84f9-7148f9882554': // PIFF Track Encryption Box - http://fileformats.archiveteam.org/wiki/Protected_Interoperable_File_Format
+ case '96a9f1f1-dc98-402d-a7ae-d68e34451809': // GeoJP2 World File Box - http://fileformats.archiveteam.org/wiki/GeoJP2
+ case 'a2394f52-5a9b-4f14-a244-6c427c648df4': // PIFF Sample Encryption Box - http://fileformats.archiveteam.org/wiki/Protected_Interoperable_File_Format
+ case 'b14bf8bd-083d-4b43-a5ae-8cd7d5a6ce03': // GeoJP2 GeoTIFF Box - http://fileformats.archiveteam.org/wiki/GeoJP2
+ case 'd08a4f18-10f3-4a82-b6c8-32d8aba183d3': // PIFF Protection System Specific Header Box - http://fileformats.archiveteam.org/wiki/Protected_Interoperable_File_Format
+ $this->warning('Unhandled (but recognized) "uuid" atom identified by "'.$atom_structure['uuid_field_id'].'" at offset '.$atom_structure['offset'].' ('.strlen($atom_data).' bytes)');
+ break;
+
+ case 'be7acfcb-97a9-42e8-9c71-999491e3afac': // XMP data (in XML format)
+ $atom_structure['xml'] = substr($atom_data, 16, strlen($atom_data) - 16 - 8); // 16 bytes for UUID, 8 bytes header(?)
+ break;
+
+ case 'efe1589a-bb77-49ef-8095-27759eb1dc6f': // 360fly data
+ /* 360fly code in this block by Paul Lewis 2019-Oct-31 */
+ /* Sensor Timestamps need to be calculated using the recordings base time at ['quicktime']['moov']['subatoms'][0]['creation_time_unix']. */
+ $atom_structure['title'] = '360Fly Sensor Data';
+
+ //Get the UUID HEADER data
+ $uuid_bytes_read = unpack('vheader_size/vheader_version/vtimescale/vhardware_version/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/', substr($atom_data, 16, 32));
+ $atom_structure['uuid_header'] = $uuid_bytes_read;
+
+ $start_byte = 48;
+ $atom_SENSOR_data = substr($atom_data, $start_byte);
+ $atom_structure['sensor_data']['data_type'] = array(
+ 'fusion_count' => 0, // ID 250
+ 'fusion_data' => array(),
+ 'accel_count' => 0, // ID 1
+ 'accel_data' => array(),
+ 'gyro_count' => 0, // ID 2
+ 'gyro_data' => array(),
+ 'magno_count' => 0, // ID 3
+ 'magno_data' => array(),
+ 'gps_count' => 0, // ID 5
+ 'gps_data' => array(),
+ 'rotation_count' => 0, // ID 6
+ 'rotation_data' => array(),
+ 'unknown_count' => 0, // ID ??
+ 'unknown_data' => array(),
+ 'debug_list' => '', // Used to debug variables stored as comma delimited strings
+ );
+ $debug_structure['debug_items'] = array();
+ // Can start loop here to decode all sensor data in 32 Byte chunks:
+ foreach (str_split($atom_SENSOR_data, 32) as $sensor_key => $sensor_data) {
+ // This gets me a data_type code to work out what data is in the next 31 bytes.
+ $sensor_data_type = substr($sensor_data, 0, 1);
+ $sensor_data_content = substr($sensor_data, 1);
+ $uuid_bytes_read = unpack('C*', $sensor_data_type);
+ $sensor_data_array = array();
+ switch ($uuid_bytes_read[1]) {
+ case 250:
+ $atom_structure['sensor_data']['data_type']['fusion_count']++;
+ $uuid_bytes_read = unpack('cmode/Jtimestamp/Gyaw/Gpitch/Groll/x*', $sensor_data_content);
+ $sensor_data_array['mode'] = $uuid_bytes_read['mode'];
+ $sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
+ $sensor_data_array['yaw'] = $uuid_bytes_read['yaw'];
+ $sensor_data_array['pitch'] = $uuid_bytes_read['pitch'];
+ $sensor_data_array['roll'] = $uuid_bytes_read['roll'];
+ array_push($atom_structure['sensor_data']['data_type']['fusion_data'], $sensor_data_array);
+ break;
+ case 1:
+ $atom_structure['sensor_data']['data_type']['accel_count']++;
+ $uuid_bytes_read = unpack('cmode/Jtimestamp/Gyaw/Gpitch/Groll/x*', $sensor_data_content);
+ $sensor_data_array['mode'] = $uuid_bytes_read['mode'];
+ $sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
+ $sensor_data_array['yaw'] = $uuid_bytes_read['yaw'];
+ $sensor_data_array['pitch'] = $uuid_bytes_read['pitch'];
+ $sensor_data_array['roll'] = $uuid_bytes_read['roll'];
+ array_push($atom_structure['sensor_data']['data_type']['accel_data'], $sensor_data_array);
+ break;
+ case 2:
+ $atom_structure['sensor_data']['data_type']['gyro_count']++;
+ $uuid_bytes_read = unpack('cmode/Jtimestamp/Gyaw/Gpitch/Groll/x*', $sensor_data_content);
+ $sensor_data_array['mode'] = $uuid_bytes_read['mode'];
+ $sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
+ $sensor_data_array['yaw'] = $uuid_bytes_read['yaw'];
+ $sensor_data_array['pitch'] = $uuid_bytes_read['pitch'];
+ $sensor_data_array['roll'] = $uuid_bytes_read['roll'];
+ array_push($atom_structure['sensor_data']['data_type']['gyro_data'], $sensor_data_array);
+ break;
+ case 3:
+ $atom_structure['sensor_data']['data_type']['magno_count']++;
+ $uuid_bytes_read = unpack('cmode/Jtimestamp/Gmagx/Gmagy/Gmagz/x*', $sensor_data_content);
+ $sensor_data_array['mode'] = $uuid_bytes_read['mode'];
+ $sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
+ $sensor_data_array['magx'] = $uuid_bytes_read['magx'];
+ $sensor_data_array['magy'] = $uuid_bytes_read['magy'];
+ $sensor_data_array['magz'] = $uuid_bytes_read['magz'];
+ array_push($atom_structure['sensor_data']['data_type']['magno_data'], $sensor_data_array);
+ break;
+ case 5:
+ $atom_structure['sensor_data']['data_type']['gps_count']++;
+ $uuid_bytes_read = unpack('cmode/Jtimestamp/Glat/Glon/Galt/Gspeed/nbearing/nacc/x*', $sensor_data_content);
+ $sensor_data_array['mode'] = $uuid_bytes_read['mode'];
+ $sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
+ $sensor_data_array['lat'] = $uuid_bytes_read['lat'];
+ $sensor_data_array['lon'] = $uuid_bytes_read['lon'];
+ $sensor_data_array['alt'] = $uuid_bytes_read['alt'];
+ $sensor_data_array['speed'] = $uuid_bytes_read['speed'];
+ $sensor_data_array['bearing'] = $uuid_bytes_read['bearing'];
+ $sensor_data_array['acc'] = $uuid_bytes_read['acc'];
+ array_push($atom_structure['sensor_data']['data_type']['gps_data'], $sensor_data_array);
+ //array_push($debug_structure['debug_items'], $uuid_bytes_read['timestamp']);
+ break;
+ case 6:
+ $atom_structure['sensor_data']['data_type']['rotation_count']++;
+ $uuid_bytes_read = unpack('cmode/Jtimestamp/Grotx/Groty/Grotz/x*', $sensor_data_content);
+ $sensor_data_array['mode'] = $uuid_bytes_read['mode'];
+ $sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
+ $sensor_data_array['rotx'] = $uuid_bytes_read['rotx'];
+ $sensor_data_array['roty'] = $uuid_bytes_read['roty'];
+ $sensor_data_array['rotz'] = $uuid_bytes_read['rotz'];
+ array_push($atom_structure['sensor_data']['data_type']['rotation_data'], $sensor_data_array);
+ break;
+ default:
+ $atom_structure['sensor_data']['data_type']['unknown_count']++;
+ break;
+ }
+ }
+ //if (isset($debug_structure['debug_items']) && count($debug_structure['debug_items']) > 0) {
+ // $atom_structure['sensor_data']['data_type']['debug_list'] = implode(',', $debug_structure['debug_items']);
+ //} else {
+ $atom_structure['sensor_data']['data_type']['debug_list'] = 'No debug items in list!';
+ //}
+ break;
+
+ default:
+ $this->warning('Unhandled "uuid" atom identified by "'.$atom_structure['uuid_field_id'].'" at offset '.$atom_structure['offset'].' ('.strlen($atom_data).' bytes)');
+ }
+ break;
+
case 'gps ':
// https://dashcamtalk.com/forum/threads/script-to-extract-gps-data-from-novatek-mp4.20808/page-2#post-291730
// The 'gps ' contains simple look up table made up of 8byte rows, that point to the 'free' atoms that contains the actual GPS data.
@@ -1683,22 +1854,24 @@
// $GPRMC,094347.000,A,5342.0061,N,00737.9908,W,0.01,156.75,140217,,,A*7D
if (preg_match('#\\$GPRMC,([0-9\\.]*),([AV]),([0-9\\.]*),([NS]),([0-9\\.]*),([EW]),([0-9\\.]*),([0-9\\.]*),([0-9]*),([0-9\\.]*),([EW]?)(,[A])?(\\*[0-9A-F]{2})#', $GPS_free_data, $matches)) {
$GPS_this_GPRMC = array();
+ $GPS_this_GPRMC_raw = array();
list(
- $GPS_this_GPRMC['raw']['gprmc'],
- $GPS_this_GPRMC['raw']['timestamp'],
- $GPS_this_GPRMC['raw']['status'],
- $GPS_this_GPRMC['raw']['latitude'],
- $GPS_this_GPRMC['raw']['latitude_direction'],
- $GPS_this_GPRMC['raw']['longitude'],
- $GPS_this_GPRMC['raw']['longitude_direction'],
- $GPS_this_GPRMC['raw']['knots'],
- $GPS_this_GPRMC['raw']['angle'],
- $GPS_this_GPRMC['raw']['datestamp'],
- $GPS_this_GPRMC['raw']['variation'],
- $GPS_this_GPRMC['raw']['variation_direction'],
+ $GPS_this_GPRMC_raw['gprmc'],
+ $GPS_this_GPRMC_raw['timestamp'],
+ $GPS_this_GPRMC_raw['status'],
+ $GPS_this_GPRMC_raw['latitude'],
+ $GPS_this_GPRMC_raw['latitude_direction'],
+ $GPS_this_GPRMC_raw['longitude'],
+ $GPS_this_GPRMC_raw['longitude_direction'],
+ $GPS_this_GPRMC_raw['knots'],
+ $GPS_this_GPRMC_raw['angle'],
+ $GPS_this_GPRMC_raw['datestamp'],
+ $GPS_this_GPRMC_raw['variation'],
+ $GPS_this_GPRMC_raw['variation_direction'],
$dummy,
- $GPS_this_GPRMC['raw']['checksum'],
+ $GPS_this_GPRMC_raw['checksum'],
) = $matches;
+ $GPS_this_GPRMC['raw'] = $GPS_this_GPRMC_raw;
$hour = substr($GPS_this_GPRMC['raw']['timestamp'], 0, 2);
$minute = substr($GPS_this_GPRMC['raw']['timestamp'], 2, 2);
@@ -1706,7 +1879,7 @@
$ms = substr($GPS_this_GPRMC['raw']['timestamp'], 6); // may contain decimal seconds
$day = substr($GPS_this_GPRMC['raw']['datestamp'], 0, 2);
$month = substr($GPS_this_GPRMC['raw']['datestamp'], 2, 2);
- $year = substr($GPS_this_GPRMC['raw']['datestamp'], 4, 2);
+ $year = (int) substr($GPS_this_GPRMC['raw']['datestamp'], 4, 2);
$year += (($year > 90) ? 1900 : 2000); // complete lack of foresight: datestamps are stored with 2-digit years, take best guess
$GPS_this_GPRMC['timestamp'] = $year.'-'.$month.'-'.$day.' '.$hour.':'.$minute.':'.$second.$ms;
@@ -1829,17 +2002,22 @@
case 'thma': // subatom to "frea" -- "ThumbnailImage"
// https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea
if (strlen($atom_data) > 0) {
- $info['quicktime']['comments']['picture'][] = array('data'=>$atom_data, 'image_mime'=>'image/jpeg');
+ $info['quicktime']['comments']['picture'][] = array('data'=>$atom_data, 'image_mime'=>'image/jpeg', 'description'=>'ThumbnailImage');
}
break;
case 'scra': // subatom to "frea" -- "PreviewImage"
// https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea
// but the only sample file I've seen has no useful data here
if (strlen($atom_data) > 0) {
- $info['quicktime']['comments']['picture'][] = array('data'=>$atom_data, 'image_mime'=>'image/jpeg');
+ $info['quicktime']['comments']['picture'][] = array('data'=>$atom_data, 'image_mime'=>'image/jpeg', 'description'=>'PreviewImage');
}
break;
+ case 'cdsc': // timed metadata reference
+ // A QuickTime movie can contain none, one, or several timed metadata tracks. Timed metadata tracks can refer to multiple tracks.
+ // Metadata tracks are linked to the tracks they describe using a track-reference of type 'cdsc'. The metadata track holds the 'cdsc' track reference.
+ $atom_structure['track_number'] = getid3_lib::BigEndian2Int($atom_data);
+ break;
default:
$this->warning('Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).'), '.$atomsize.' bytes at offset '.$baseoffset);
@@ -1880,6 +2058,12 @@
}
return $atom_structure;
}
+ if (strlen($subatomdata) < ($subatomsize - 8)) {
+ // we don't have enough data to decode the subatom.
+ // this may be because we are refusing to parse large subatoms, or it may be because this atom had its size set too large
+ // so we passed in the start of a following atom incorrectly?
+ return $atom_structure;
+ }
$atom_structure[$subatomcounter++] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms);
$subatomoffset += $subatomsize;
}
@@ -2654,7 +2838,7 @@
$handyatomtranslatorarray["\xA9".'src'] = 'source_credit';
$handyatomtranslatorarray["\xA9".'swr'] = 'software';
$handyatomtranslatorarray["\xA9".'too'] = 'encoding_tool'; // iTunes 4.0
- $handyatomtranslatorarray["\xA9".'trk'] = 'track';
+ $handyatomtranslatorarray["\xA9".'trk'] = 'track_number';
$handyatomtranslatorarray["\xA9".'url'] = 'url';
$handyatomtranslatorarray["\xA9".'wrn'] = 'warning';
$handyatomtranslatorarray["\xA9".'wrt'] = 'composer';
@@ -2720,19 +2904,8 @@
}
if ($comment_key) {
if ($comment_key == 'picture') {
- if (!is_array($data)) {
- $image_mime = '';
- if (preg_match('#^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A#', $data)) {
- $image_mime = 'image/png';
- } elseif (preg_match('#^\xFF\xD8\xFF#', $data)) {
- $image_mime = 'image/jpeg';
- } elseif (preg_match('#^GIF#', $data)) {
- $image_mime = 'image/gif';
- } elseif (preg_match('#^BM#', $data)) {
- $image_mime = 'image/bmp';
- }
- $data = array('data'=>$data, 'image_mime'=>$image_mime);
- }
+ // already copied directly into [comments][picture] elsewhere, do not re-copy here
+ return true;
}
$gooddata = array($data);
if ($comment_key == 'genre') {
@@ -2740,6 +2913,10 @@
$gooddata = explode(';', $data);
}
foreach ($gooddata as $data) {
+ if (!empty($info['quicktime']['comments'][$comment_key]) && in_array($data, $info['quicktime']['comments'][$comment_key], true)) {
+ // avoid duplicate copies of identical data
+ continue;
+ }
$info['quicktime']['comments'][$comment_key][] = $data;
}
}
@@ -2752,38 +2929,35 @@
*
* @return string
*/
- public function LociString($lstring, &$count) {
- // Loci strings are UTF-8 or UTF-16 and null (x00/x0000) terminated. UTF-16 has a BOM
- // Also need to return the number of bytes the string occupied so additional fields can be extracted
- $len = strlen($lstring);
- if ($len == 0) {
- $count = 0;
- return '';
- }
- if ($lstring[0] == "\x00") {
- $count = 1;
- return '';
- }
- //check for BOM
- if ($len > 2 && (($lstring[0] == "\xFE" && $lstring[1] == "\xFF") || ($lstring[0] == "\xFF" && $lstring[1] == "\xFE"))) {
- //UTF-16
- if (preg_match('/(.*)\x00/', $lstring, $lmatches)){
- $count = strlen($lmatches[1]) * 2 + 2; //account for 2 byte characters and trailing \x0000
- return getid3_lib::iconv_fallback_utf16_utf8($lmatches[1]);
- } else {
- return '';
- }
- } else {
- //UTF-8
- if (preg_match('/(.*)\x00/', $lstring, $lmatches)){
- $count = strlen($lmatches[1]) + 1; //account for trailing \x00
- return $lmatches[1];
- }else {
- return '';
- }
-
- }
- }
+ public function LociString($lstring, &$count) {
+ // Loci strings are UTF-8 or UTF-16 and null (x00/x0000) terminated. UTF-16 has a BOM
+ // Also need to return the number of bytes the string occupied so additional fields can be extracted
+ $len = strlen($lstring);
+ if ($len == 0) {
+ $count = 0;
+ return '';
+ }
+ if ($lstring[0] == "\x00") {
+ $count = 1;
+ return '';
+ }
+ // check for BOM
+ if (($len > 2) && ((($lstring[0] == "\xFE") && ($lstring[1] == "\xFF")) || (($lstring[0] == "\xFF") && ($lstring[1] == "\xFE")))) {
+ // UTF-16
+ if (preg_match('/(.*)\x00/', $lstring, $lmatches)) {
+ $count = strlen($lmatches[1]) * 2 + 2; //account for 2 byte characters and trailing \x0000
+ return getid3_lib::iconv_fallback_utf16_utf8($lmatches[1]);
+ } else {
+ return '';
+ }
+ }
+ // UTF-8
+ if (preg_match('/(.*)\x00/', $lstring, $lmatches)) {
+ $count = strlen($lmatches[1]) + 1; //account for trailing \x00
+ return $lmatches[1];
+ }
+ return '';
+ }
/**
* @param string $nullterminatedstring
@@ -2808,6 +2982,23 @@
return substr($pascalstring, 1);
}
+ /**
+ * @param string $pascalstring
+ *
+ * @return string
+ */
+ public function MaybePascal2String($pascalstring) {
+ // Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string
+ // Check if string actually is in this format or written incorrectly, straight string, or null-terminated string
+ if (ord(substr($pascalstring, 0, 1)) == (strlen($pascalstring) - 1)) {
+ return substr($pascalstring, 1);
+ } elseif (substr($pascalstring, -1, 1) == "\x00") {
+ // appears to be null-terminated instead of Pascal-style
+ return substr($pascalstring, 0, -1);
+ }
+ return $pascalstring;
+ }
+
/**
* Helper functions for m4b audiobook chapters
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.real.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.real.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.real.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.real.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
class getid3_real extends getid3_handler
@@ -483,8 +486,9 @@
$ParsedArray['fourcc'] = $ParsedArray['fourcc3'];
}
+ /** @var string[]|false[] $value */
foreach ($ParsedArray['comments'] as $key => $value) {
- if ($ParsedArray['comments'][$key][0] === false) {
+ if ($value[0] === false) {
$ParsedArray['comments'][$key][0] = '';
}
}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.riff.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.riff.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.riff.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.riff.php 2022-05-20 16:59:18.000000000 +0100
@@ -23,6 +23,9 @@
* @todo Rewrite RIFF parser totally
*/
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true);
@@ -51,7 +54,7 @@
$thisfile_audio_dataformat = &$thisfile_audio['dataformat'];
$thisfile_riff_audio = &$thisfile_riff['audio'];
$thisfile_riff_video = &$thisfile_riff['video'];
- $thisfile_riff_WAVE = array();
+ $thisfile_riff_WAVE = array();
$Original['avdataoffset'] = $info['avdataoffset'];
$Original['avdataend'] = $info['avdataend'];
@@ -203,7 +206,7 @@
unset($thisfile_riff_audio[$streamindex]['raw']);
$thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
- $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
+ $thisfile_audio = (array) getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
$this->warning('Audio codec = '.$thisfile_audio['codec']);
}
@@ -703,13 +706,13 @@
'capturedfile' => 0x00010000,
'copyrighted' => 0x00020010,
);
- foreach ($flags as $flag => $value) {
+ foreach ($flags as $flag => $value) {
$thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value);
}
// shortcut
$thisfile_riff_video[$streamindex] = array();
- /** @var array $thisfile_riff_video_current */
+ /** @var array $thisfile_riff_video_current */
$thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
@@ -923,7 +926,7 @@
// http://en.wikipedia.org/wiki/CD-DA
case 'CDDA':
$info['fileformat'] = 'cda';
- unset($info['mime_type']);
+ unset($info['mime_type']);
$thisfile_audio_dataformat = 'cda';
@@ -943,7 +946,7 @@
$thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75;
$thisfile_riff_CDDA_fmt_0['playtime_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75;
- $info['comments']['track'] = $thisfile_riff_CDDA_fmt_0['track_num'];
+ $info['comments']['track_number'] = $thisfile_riff_CDDA_fmt_0['track_num'];
$info['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
// hardcoded data for CD-audio
@@ -956,7 +959,7 @@
}
break;
- // http://en.wikipedia.org/wiki/AIFF
+ // http://en.wikipedia.org/wiki/AIFF
case 'AIFF':
case 'AIFC':
$info['fileformat'] = 'aiff';
@@ -1066,7 +1069,7 @@
if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) {
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
$getid3_id3v2 = new getid3_id3v2($getid3_temp);
$getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
@@ -1169,7 +1172,7 @@
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true);
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
$getid3_mpeg = new getid3_mpeg($getid3_temp);
$getid3_mpeg->Analyze();
if (empty($getid3_temp->info['error'])) {
@@ -1255,7 +1258,7 @@
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
$getid3_id3v2 = new getid3_id3v2($getid3_temp);
$getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
@@ -1554,7 +1557,7 @@
// MP3
if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
$getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
$getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
$getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
@@ -1576,7 +1579,7 @@
// AC3
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
$getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
$getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
$getid3_ac3 = new getid3_ac3($getid3_temp);
@@ -1637,7 +1640,7 @@
// Probably is MP3 data
if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
$getid3_temp->info['avdataend'] = $info['avdataend'];
$getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
@@ -1654,7 +1657,7 @@
// This is probably AC-3 data
$getid3_temp = new getID3();
if ($isRegularAC3) {
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
$getid3_temp->info['avdataend'] = $info['avdataend'];
}
@@ -1688,7 +1691,7 @@
// This is probably DTS data
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
$getid3_dts = new getid3_dts($getid3_temp);
$getid3_dts->Analyze();
@@ -1756,6 +1759,75 @@
// $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize));
// break;
+ case 'scot':
+ // https://cmsdk.com/node-js/adding-scot-chunk-to-wav-file.html
+ $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['alter'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 0, 1);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['attrib'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 1, 1);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['artnum'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 2, 2));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['title'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 4, 43); // "name" in other documentation
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['copy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 47, 4);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['padd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 51, 1);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['asclen'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 52, 5);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['startseconds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 57, 2));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['starthundredths'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 59, 2));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['endseconds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 61, 2));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['endhundreths'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 63, 2));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['sdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 65, 6);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['kdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 71, 6);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['start_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 77, 1);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['kill_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 78, 1);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['digital'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 79, 1);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 80, 2));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['stereo'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 82, 1);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['compress'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 83, 1);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['eomstrt'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 84, 4));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['eomlen'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 88, 2));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['attrib2'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 90, 4));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['future1'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 94, 12);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['catfontcolor'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 106, 4));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['catcolor'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 110, 4));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['segeompos'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 114, 4));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['vt_startsecs'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 118, 2));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['vt_starthunds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 120, 2));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['priorcat'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 122, 3);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['priorcopy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 125, 4);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['priorpadd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 129, 1);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['postcat'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 130, 3);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['postcopy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 133, 4);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['postpadd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 137, 1);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['hrcanplay'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 138, 21);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['future2'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 159, 108);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['artist'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 267, 34);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['comment'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 301, 34); // "trivia" in other documentation
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['intro'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 335, 2);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['end'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 337, 1);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['year'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 338, 4);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['obsolete2'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 342, 1);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['rec_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 343, 1);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['rdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 344, 6);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['mpeg_bitrate'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 350, 2));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['pitch'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 352, 2));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['playlevel'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 354, 2));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['lenvalid'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 356, 1);
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 357, 4));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['newplaylevel'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 361, 2));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['chopsize'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 363, 4));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['vteomovr'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 367, 4));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['desiredlen'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 371, 4));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['triggers'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 375, 4));
+ $RIFFchunk[$chunkname][$thisindex]['parsed']['fillout'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 379, 33);
+
+ foreach (array('title', 'artist', 'comment') as $key) {
+ if (trim($RIFFchunk[$chunkname][$thisindex]['parsed'][$key])) {
+ $info['riff']['comments'][$key] = array($RIFFchunk[$chunkname][$thisindex]['parsed'][$key]);
+ }
+ }
+ if ($RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] && !empty($info['filesize']) && ($RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] != $info['filesize'])) {
+ $this->warning('RIFF.WAVE.scot.filelength ('.$RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'].') different from actual filesize ('.$info['filesize'].')');
+ }
+ break;
+
default:
if (!empty($LISTchunkParent) && isset($LISTchunkMaxOffset) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) {
$RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.swf.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.swf.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.swf.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.swf.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_swf extends getid3_handler
{
@@ -49,7 +52,6 @@
unset($info['swf']);
unset($info['fileformat']);
return false;
- break;
}
$info['swf']['header']['version'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 3, 1));
$info['swf']['header']['length'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 4, 4));
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.ts.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.ts.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.ts.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.ts.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_ts extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.wtv.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.wtv.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio-video.wtv.php 1970-01-01 01:00:00.000000000 +0100
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio-video.wtv.php 2022-05-20 16:59:18.000000000 +0100
@@ -0,0 +1,37 @@
+ //
+// available at https://github.com/JamesHeinrich/getID3 //
+// or https://www.getid3.org //
+// or http://getid3.sourceforge.net //
+// see readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio.wtv.php //
+// module for analyzing WTV (Windows Recorded TV Show) //
+// audio-video files //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
+
+class getid3_wtv extends getid3_handler
+{
+ /**
+ * @return bool
+ */
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ $info['fileformat'] = 'wtv';
+ $info['video']['dataformat'] = 'wtv';
+
+ $this->error('WTV (Windows Recorded TV Show) files not properly processed by this version of getID3() ['.$this->getid3->version().']');
+
+ return true;
+ }
+
+}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.voc.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.voc.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.voc.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.voc.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_voc extends getid3_handler
{
@@ -61,7 +64,7 @@
$BlockOffset = $this->ftell();
$BlockData = $this->fread(4);
- $BlockType = ord($BlockData{0});
+ $BlockType = ord($BlockData[0]);
$BlockSize = getid3_lib::LittleEndian2Int(substr($BlockData, 1, 3));
$ThisBlock = array();
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.vqf.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.vqf.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.vqf.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.vqf.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_vqf extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.wavpack.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.wavpack.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.audio.wavpack.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.audio.wavpack.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,7 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
-
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_wavpack extends getid3_handler
{
/**
@@ -102,8 +104,8 @@
return false;
}
- $info['wavpack']['blockheader']['minor_version'] = ord($wavpackheader{8});
- $info['wavpack']['blockheader']['major_version'] = ord($wavpackheader{9});
+ $info['wavpack']['blockheader']['minor_version'] = ord($wavpackheader[8]);
+ $info['wavpack']['blockheader']['major_version'] = ord($wavpackheader[9]);
if (($info['wavpack']['blockheader']['major_version'] != 4) ||
(($info['wavpack']['blockheader']['minor_version'] < 4) &&
@@ -122,8 +124,8 @@
return false;
}
- $info['wavpack']['blockheader']['track_number'] = ord($wavpackheader{10}); // unused
- $info['wavpack']['blockheader']['index_number'] = ord($wavpackheader{11}); // unused
+ $info['wavpack']['blockheader']['track_number'] = ord($wavpackheader[10]); // unused
+ $info['wavpack']['blockheader']['index_number'] = ord($wavpackheader[11]); // unused
$info['wavpack']['blockheader']['total_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 12, 4));
$info['wavpack']['blockheader']['block_index'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 16, 4));
$info['wavpack']['blockheader']['block_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 20, 4));
@@ -153,7 +155,7 @@
if (feof($this->getid3->fp)) {
break;
}
- $metablock['id'] = ord($metablockheader{0});
+ $metablock['id'] = ord($metablockheader[0]);
$metablock['function_id'] = ($metablock['id'] & 0x3F);
$metablock['function_name'] = $this->WavPackMetablockNameLookup($metablock['function_id']);
@@ -173,6 +175,7 @@
}
$metablock['size'] = getid3_lib::LittleEndian2Int(substr($metablockheader, 1)) * 2; // size is stored in words
$metablock['data'] = null;
+ $metablock['comments'] = array();
if ($metablock['size'] > 0) {
@@ -221,7 +224,7 @@
$original_wav_filesize = getid3_lib::LittleEndian2Int(substr($metablock['data'], 4, 4));
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
$getid3_riff = new getid3_riff($getid3_temp);
$getid3_riff->ParseRIFFdata($metablock['data']);
$metablock['riff'] = $getid3_temp->info['riff'];
@@ -243,7 +246,7 @@
$startoffset = $metablock['offset'] + ($metablock['large_block'] ? 4 : 2);
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
$getid3_temp->info['avdataend'] = $info['avdataend'];
//$getid3_temp->info['fileformat'] = 'riff';
$getid3_riff = new getid3_riff($getid3_temp);
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.bmp.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.bmp.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.bmp.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.bmp.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_bmp extends getid3_handler
{
@@ -334,7 +337,7 @@
case 1:
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
- $paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++});
+ $paletteindexbyte = ord($BMPpixelData[$pixeldataoffset++]);
for ($i = 7; $i >= 0; $i--) {
$paletteindex = ($paletteindexbyte & (0x01 << $i)) >> $i;
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
@@ -351,7 +354,7 @@
case 4:
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
- $paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++});
+ $paletteindexbyte = ord($BMPpixelData[$pixeldataoffset++]);
for ($i = 1; $i >= 0; $i--) {
$paletteindex = ($paletteindexbyte & (0x0F << (4 * $i))) >> (4 * $i);
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
@@ -368,7 +371,7 @@
case 8:
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
- $paletteindex = ord($BMPpixelData{$pixeldataoffset++});
+ $paletteindex = ord($BMPpixelData[$pixeldataoffset++]);
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
}
while (($pixeldataoffset % 4) != 0) {
@@ -381,7 +384,7 @@
case 24:
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
- $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset});
+ $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData[$pixeldataoffset+2]) << 16) | (ord($BMPpixelData[$pixeldataoffset+1]) << 8) | ord($BMPpixelData[$pixeldataoffset]);
$pixeldataoffset += 3;
}
while (($pixeldataoffset % 4) != 0) {
@@ -394,7 +397,7 @@
case 32:
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
- $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset+3}) << 24) | (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset});
+ $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData[$pixeldataoffset+3]) << 24) | (ord($BMPpixelData[$pixeldataoffset+2]) << 16) | (ord($BMPpixelData[$pixeldataoffset+1]) << 8) | ord($BMPpixelData[$pixeldataoffset]);
$pixeldataoffset += 4;
}
while (($pixeldataoffset % 4) != 0) {
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.efax.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.efax.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.efax.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.efax.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_efax extends getid3_handler
{
@@ -46,8 +49,6 @@
$this->error('eFax parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
return false;
-
- return true;
}
}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.gif.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.gif.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.gif.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.gif.php 2022-05-20 16:59:18.000000000 +0100
@@ -18,6 +18,11 @@
* @link https://www.w3.org/Graphics/GIF/spec-gif89a.txt
* @link http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
*/
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
+
class getid3_gif extends getid3_handler
{
/**
@@ -46,6 +51,10 @@
return false;
}
+ //if (!$this->getid3->option_extra_info) {
+ // $this->warning('GIF Extensions and Global Color Table not returned due to !getid3->option_extra_info');
+ //}
+
$info['gif']['header']['raw']['version'] = substr($GIFheader, $offset, 3);
$offset += 3;
$info['gif']['header']['raw']['width'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2));
@@ -85,12 +94,15 @@
if ($info['gif']['header']['flags']['global_color_table']) {
$GIFcolorTable = $this->fread(3 * $info['gif']['header']['global_color_size']);
- $offset = 0;
- for ($i = 0; $i < $info['gif']['header']['global_color_size']; $i++) {
- $red = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
- $green = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
- $blue = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
- $info['gif']['global_color_table'][$i] = (($red << 16) | ($green << 8) | ($blue));
+ if ($this->getid3->option_extra_info) {
+ $offset = 0;
+ for ($i = 0; $i < $info['gif']['header']['global_color_size']; $i++) {
+ $red = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
+ $green = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
+ $blue = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
+ $info['gif']['global_color_table'][$i] = (($red << 16) | ($green << 8) | ($blue));
+ $info['gif']['global_color_table_rgb'][$i] = sprintf('%02X%02X%02X', $red, $green, $blue);
+ }
}
}
@@ -166,7 +178,9 @@
}
}
- $info['gif']['extension_blocks'][] = $ExtensionBlock;
+ if ($this->getid3->option_extra_info) {
+ $info['gif']['extension_blocks'][] = $ExtensionBlock;
+ }
break;
case ';':
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.jpg.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.jpg.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.jpg.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.jpg.php 2022-05-20 16:59:18.000000000 +0100
@@ -15,7 +15,9 @@
// ///
/////////////////////////////////////////////////////////////////
-
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_jpg extends getid3_handler
{
/**
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.pcd.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.pcd.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.pcd.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.pcd.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,7 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
-
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_pcd extends getid3_handler
{
public $ExtractData = 0;
@@ -48,6 +50,7 @@
if ($this->ExtractData > 3) {
$this->error('Cannot extract PSD image data for detail levels above BASE (level-3) because encrypted with Kodak-proprietary compression/encryption.');
+ return false;
} elseif ($this->ExtractData > 0) {
@@ -76,11 +79,11 @@
for ($x = 0; $x < $PCD_width; $x++) {
if ($PCDisVertical) {
- $info['pcd']['data'][$PCD_width - $x][$y] = $this->YCbCr2RGB(ord($PCD_data_Y1{$x}), ord($PCD_data_Cb{(int) floor($x / 2)}), ord($PCD_data_Cr{(int) floor($x / 2)}));
- $info['pcd']['data'][$PCD_width - $x][$y + 1] = $this->YCbCr2RGB(ord($PCD_data_Y2{$x}), ord($PCD_data_Cb{(int) floor($x / 2)}), ord($PCD_data_Cr{(int) floor($x / 2)}));
+ $info['pcd']['data'][$PCD_width - $x][$y] = $this->YCbCr2RGB(ord($PCD_data_Y1[$x]), ord($PCD_data_Cb[(int) floor($x / 2)]), ord($PCD_data_Cr[(int) floor($x / 2)]));
+ $info['pcd']['data'][$PCD_width - $x][$y + 1] = $this->YCbCr2RGB(ord($PCD_data_Y2[$x]), ord($PCD_data_Cb[(int) floor($x / 2)]), ord($PCD_data_Cr[(int) floor($x / 2)]));
} else {
- $info['pcd']['data'][$y][$x] = $this->YCbCr2RGB(ord($PCD_data_Y1{$x}), ord($PCD_data_Cb{(int) floor($x / 2)}), ord($PCD_data_Cr{(int) floor($x / 2)}));
- $info['pcd']['data'][$y + 1][$x] = $this->YCbCr2RGB(ord($PCD_data_Y2{$x}), ord($PCD_data_Cb{(int) floor($x / 2)}), ord($PCD_data_Cr{(int) floor($x / 2)}));
+ $info['pcd']['data'][$y][$x] = $this->YCbCr2RGB(ord($PCD_data_Y1[$x]), ord($PCD_data_Cb[(int) floor($x / 2)]), ord($PCD_data_Cr[(int) floor($x / 2)]));
+ $info['pcd']['data'][$y + 1][$x] = $this->YCbCr2RGB(ord($PCD_data_Y2[$x]), ord($PCD_data_Cb[(int) floor($x / 2)]), ord($PCD_data_Cr[(int) floor($x / 2)]));
}
}
}
@@ -100,6 +103,7 @@
}
+ return false;
}
/**
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.png.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.png.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.png.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.png.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_png extends getid3_handler
{
@@ -593,23 +596,18 @@
switch ($color_type) {
case 0: // Each pixel is a grayscale sample.
return $bit_depth;
- break;
case 2: // Each pixel is an R,G,B triple
return 3 * $bit_depth;
- break;
case 3: // Each pixel is a palette index; a PLTE chunk must appear.
return $bit_depth;
- break;
case 4: // Each pixel is a grayscale sample, followed by an alpha sample.
return 2 * $bit_depth;
- break;
case 6: // Each pixel is an R,G,B triple, followed by an alpha sample.
return 4 * $bit_depth;
- break;
}
return false;
}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.svg.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.svg.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.svg.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.svg.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_svg extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.tiff.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.tiff.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.graphic.tiff.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.graphic.tiff.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_tiff extends getid3_handler
{
@@ -36,14 +39,13 @@
default:
$this->error('Invalid TIFF byte order identifier ('.substr($TIFFheader, 0, 2).') at offset '.$info['avdataoffset']);
return false;
- break;
}
$info['fileformat'] = 'tiff';
$info['video']['dataformat'] = 'tiff';
$info['video']['lossless'] = true;
$info['tiff']['ifd'] = array();
- $CurrentIFD = array();
+ $CurrentIFD = array();
$FieldTypeByteLength = array(1=>1, 2=>1, 3=>2, 4=>4, 5=>8);
@@ -57,47 +59,61 @@
$CurrentIFD['fieldcount'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
for ($i = 0; $i < $CurrentIFD['fieldcount']; $i++) {
- $CurrentIFD['fields'][$i]['raw']['tag'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
- $CurrentIFD['fields'][$i]['raw']['type'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
- $CurrentIFD['fields'][$i]['raw']['length'] = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
- $CurrentIFD['fields'][$i]['raw']['offset'] = $this->fread(4);
-
+ $CurrentIFD['fields'][$i]['raw']['tag'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
+ $CurrentIFD['fields'][$i]['raw']['type'] = $this->TIFFendian2Int($this->fread(2), $info['tiff']['byte_order']);
+ $CurrentIFD['fields'][$i]['raw']['length'] = $this->TIFFendian2Int($this->fread(4), $info['tiff']['byte_order']);
+ $CurrentIFD['fields'][$i]['raw']['valoff'] = $this->fread(4); // To save time and space the Value Offset contains the Value instead of pointing to the Value if and only if the Value fits into 4 bytes. If the Value is shorter than 4 bytes, it is left-justified within the 4-byte Value Offset, i.e., stored in the lowernumbered bytes. Whether the Value fits within 4 bytes is determined by the Type and Count of the field.
$CurrentIFD['fields'][$i]['raw']['tag_name'] = $this->TIFFcommentName($CurrentIFD['fields'][$i]['raw']['tag']);
switch ($CurrentIFD['fields'][$i]['raw']['type']) {
case 1: // BYTE An 8-bit unsigned integer.
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
- $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 1), $info['tiff']['byte_order']);
+ $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['valoff'], 0, 1), $info['tiff']['byte_order']);
} else {
- $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
+ $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['valoff'], $info['tiff']['byte_order']);
}
break;
case 2: // ASCII 8-bit bytes that store ASCII codes; the last byte must be null.
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
- $CurrentIFD['fields'][$i]['value'] = substr($CurrentIFD['fields'][$i]['raw']['offset'], 3);
+ $CurrentIFD['fields'][$i]['value'] = substr($CurrentIFD['fields'][$i]['raw']['valoff'], 3);
} else {
- $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
+ $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['valoff'], $info['tiff']['byte_order']);
}
break;
case 3: // SHORT A 16-bit (2-byte) unsigned integer.
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 2) {
- $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 2), $info['tiff']['byte_order']);
+ $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['valoff'], 0, 2), $info['tiff']['byte_order']);
} else {
- $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
+ $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['valoff'], $info['tiff']['byte_order']);
}
break;
case 4: // LONG A 32-bit (4-byte) unsigned integer.
- if ($CurrentIFD['fields'][$i]['raw']['length'] <= 1) {
- $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
+ if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
+ $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['valoff'], $info['tiff']['byte_order']);
} else {
- $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']);
+ $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['valoff'], $info['tiff']['byte_order']);
}
break;
case 5: // RATIONAL Two LONG_s: the first represents the numerator of a fraction, the second the denominator.
+ case 7: // UNDEFINED An 8-bit byte that may contain anything, depending on the definition of the field.
+ $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['valoff'], $info['tiff']['byte_order']);
+ break;
+
+ // Warning: It is possible that other TIFF field types will be added in the future. Readers should skip over fields containing an unexpected field type.
+ // In TIFF 6.0, some new field types have been defined:
+ // These new field types are also governed by the byte order (II or MM) in the TIFF header.
+ case 6: // SBYTE An 8-bit signed (twos-complement) integer.
+ case 8: // SSHORT A 16-bit (2-byte) signed (twos-complement) integer.
+ case 9: // SLONG A 32-bit (4-byte) signed (twos-complement) integer.
+ case 10: // SRATIONAL Two SLONGs: the first represents the numerator of a fraction, the second the denominator.
+ case 11: // FLOAT Single precision (4-byte) IEEE format
+ case 12: // DOUBLE Double precision (8-byte) IEEE format
+ default:
+ $this->warning('unhandled IFD field type '.$CurrentIFD['fields'][$i]['raw']['type'].' for IFD entry '.$i);
break;
}
}
@@ -137,6 +153,16 @@
}
break;
+ case 700:
+ $XMPmagic = 'fseek($fieldarray['offset']);
+ $xmpkey = (isset($info['tiff']['XMP']) ? count($info['tiff']['XMP']) : 0);
+ $info['tiff']['XMP'][$xmpkey]['raw'] = $this->fread($fieldarray['raw']['length']);
+ if (substr($info['tiff']['XMP'][$xmpkey]['raw'], 0, strlen($XMPmagic)) != $XMPmagic) {
+ $this->warning('did not find expected XMP data at offset '.$fieldarray['offset']);
+ unset($info['tiff']['XMP'][$xmpkey]['raw']);
+ }
+ break;
}
switch ($fieldarray['raw']['tag']) {
case 256: // ImageWidth
@@ -207,14 +233,33 @@
* @return string
*/
public function TIFFcompressionMethod($id) {
+ // https://en.wikipedia.org/wiki/TIFF#TIFF_Compression_Tag
static $TIFFcompressionMethod = array();
if (empty($TIFFcompressionMethod)) {
$TIFFcompressionMethod = array(
- 1 => 'Uncompressed',
- 2 => 'Huffman',
- 3 => 'Fax - CCITT 3',
- 5 => 'LZW',
- 32773 => 'PackBits',
+ 0x0001 => 'Uncompressed',
+ 0x0002 => 'Huffman',
+ 0x0003 => 'CCITT T.4',
+ 0x0004 => 'CCITT T.6',
+ 0x0005 => 'LZW',
+ 0x0006 => 'JPEG-old',
+ 0x0007 => 'JPEG',
+ 0x0008 => 'deflate',
+ 0x0009 => 'JBIG ITU-T T.85',
+ 0x000A => 'JBIG ITU-T T.43',
+ 0x7FFE => 'NeXT RLE 2-bit',
+ 0x8005 => 'PackBits',
+ 0x8029 => 'ThunderScan RLE 4-bit',
+ 0x807F => 'RasterPadding',
+ 0x8080 => 'RLE-LW',
+ 0x8081 => 'RLE-CT',
+ 0x8082 => 'RLE-BL',
+ 0x80B2 => 'deflate-PK',
+ 0x80B3 => 'Kodak-DCS',
+ 0x8765 => 'JBIG',
+ 0x8798 => 'JPEG2000',
+ 0x8799 => 'Nikon NEF',
+ 0x879B => 'JBIG2',
);
}
return (isset($TIFFcompressionMethod[$id]) ? $TIFFcompressionMethod[$id] : 'unknown/invalid ('.$id.')');
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.misc.cue.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.misc.cue.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.misc.cue.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.misc.cue.php 2022-05-20 16:59:18.000000000 +0100
@@ -31,6 +31,11 @@
* A CueSheet class used to open and parse cuesheets.
*
*/
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
+
class getid3_cue extends getid3_handler
{
public $cuesheet = array();
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.misc.exe.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.misc.exe.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.misc.exe.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.misc.exe.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_exe extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.misc.iso.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.misc.iso.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.misc.iso.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.misc.iso.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_iso extends getid3_handler
{
@@ -29,7 +32,7 @@
$this->fseek(2048 * $i);
$ISOheader = $this->fread(2048);
if (substr($ISOheader, 1, 5) == 'CD001') {
- switch (ord($ISOheader{0})) {
+ switch (ord($ISOheader[0])) {
case 1:
$info['iso']['primary_volume_descriptor']['offset'] = 2048 * $i;
$this->ParsePrimaryVolumeDescriptor($ISOheader);
@@ -296,9 +299,9 @@
$DirectoryRecordData = $this->fread(1);
$DirectoryRecord = array();
- while (ord($DirectoryRecordData{0}) > 33) {
+ while (ord($DirectoryRecordData[0]) > 33) {
- $DirectoryRecordData .= $this->fread(ord($DirectoryRecordData{0}) - 1);
+ $DirectoryRecordData .= $this->fread(ord($DirectoryRecordData[0]) - 1);
$ThisDirectoryRecord = array();
@@ -389,13 +392,13 @@
// 6: second of the minute from 0 to 59
// 7: Offset from Greenwich Mean Time in number of 15 minute intervals from -48 (West) to +52 (East)
- $UNIXyear = ord($ISOtime{0}) + 1900;
- $UNIXmonth = ord($ISOtime{1});
- $UNIXday = ord($ISOtime{2});
- $UNIXhour = ord($ISOtime{3});
- $UNIXminute = ord($ISOtime{4});
- $UNIXsecond = ord($ISOtime{5});
- $GMToffset = $this->TwosCompliment2Decimal(ord($ISOtime{5}));
+ $UNIXyear = ord($ISOtime[0]) + 1900;
+ $UNIXmonth = ord($ISOtime[1]);
+ $UNIXday = ord($ISOtime[2]);
+ $UNIXhour = ord($ISOtime[3]);
+ $UNIXminute = ord($ISOtime[4]);
+ $UNIXsecond = ord($ISOtime[5]);
+ $GMToffset = $this->TwosCompliment2Decimal(ord($ISOtime[5]));
return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.misc.msoffice.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.misc.msoffice.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.misc.msoffice.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.misc.msoffice.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_msoffice extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.misc.par2.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.misc.par2.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.misc.par2.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.misc.par2.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_par2 extends getid3_handler
{
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.misc.pdf.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.misc.pdf.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.misc.pdf.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.misc.pdf.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,20 +14,134 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_pdf extends getid3_handler
{
+ public $returnXREF = false; // return full details of PDF Cross-Reference Table (XREF)
+
/**
* @return bool
*/
public function Analyze() {
$info = &$this->getid3->info;
- $info['fileformat'] = 'pdf';
-
- $this->error('PDF parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
+ $this->fseek(0);
+ if (preg_match('#^%PDF-([0-9\\.]+)$#', rtrim($this->fgets()), $matches)) {
+ $info['pdf']['header']['version'] = floatval($matches[1]);
+ $info['fileformat'] = 'pdf';
+
+ // the PDF Cross-Reference Table (XREF) is located near the end of the file
+ // the starting offset is specified in the penultimate section, on the two lines just before "%%EOF"
+ // the first line is "startxref", the second line is the byte offset of the XREF.
+ // We know the length of "%%EOF" and "startxref", but the offset could be 2-10 bytes,
+ // and we're not sure if the line ends are one or two bytes, so we might find "startxref" as little as 18(?) bytes
+ // from EOF, but it could 30 bytes, so we start 40 bytes back just to be safe and do a search for the data we want.
+ $this->fseek(-40, SEEK_END);
+ if (preg_match('#[\r\n]startxref[ \r\n]+([0-9]+)[ \r\n]+#', $this->fread(40), $matches)) {
+ $info['pdf']['trailer']['startxref'] = intval($matches[1]);
+ $this->parseXREF($info['pdf']['trailer']['startxref']);
+ if (!empty($info['pdf']['xref']['offset'])) {
+ while (!$this->feof() && (max(array_keys($info['pdf']['xref']['offset'])) > $info['pdf']['xref']['count'])) {
+ // suspect that there may be another XREF entry somewhere in the file, brute-force scan for it
+ /*
+ // starting at last known entry of main XREF table
+ $this->fseek(max($info['pdf']['xref']['offset']));
+ */
+ // starting at the beginning of the file
+ $this->fseek(0);
+ while (!$this->feof()) {
+ $XREFoffset = $this->ftell();
+ if (rtrim($this->fgets()) == 'xref') {
+ if (empty($info['pdf']['xref']['xref_offsets']) || !in_array($XREFoffset, $info['pdf']['xref']['xref_offsets'])) {
+ $this->parseXREF($XREFoffset);
+ break;
+ }
+ }
+ }
+ }
+ foreach ($info['pdf']['xref']['offset'] as $objectNumber => $offset) {
+ if ($info['pdf']['xref']['entry'][$objectNumber] == 'f') {
+ // "free" object means "deleted", ignore
+ continue;
+ }
+ $this->fseek($offset);
+ $line = rtrim($this->fgets());
+ if (preg_match('#^'.$objectNumber.' ([0-9]+) obj#', $line, $matches)) {
+ if (strlen($line) > strlen($matches[0])) {
+ // object header line not actually on its own line, rewind file pointer to start reading data
+ $this->fseek($offset + strlen($matches[0]));
+ }
+ $objectData = '';
+ while (true) {
+ $line = $this->fgets();
+ if (rtrim($line) == 'endobj') {
+ break;
+ }
+ $objectData .= $line;
+ }
+ if (preg_match('#^<<[\r\n\s]*(/Type|/Pages|/Parent [0-9]+ [0-9]+ [A-Z]|/Count [0-9]+|/Kids *\\[[0-9A-Z ]+\\]|[\r\n\s])+[\r\n\s]*>>#', $objectData, $matches)) {
+ if (preg_match('#/Count ([0-9]+)#', $objectData, $matches)) {
+ $info['pdf']['pages'] = (int) $matches[1];
+ break; // for now this is the only data we're looking for in the PDF not need to loop through every object in the file (and a large PDF may contain MANY objects). And it MAY be possible that there are other objects elsewhere in the file that define additional (or removed?) pages
+ }
+ }
+ } else {
+ $this->error('Unexpected structure "'.$line.'" at offset '.$offset);
+ break;
+ }
+ }
+ if (!$this->returnXREF) {
+ unset($info['pdf']['xref']['offset'], $info['pdf']['xref']['generation'], $info['pdf']['xref']['entry']);
+ }
+
+ } else {
+ $this->error('Did not find "xref" at offset '.$info['pdf']['trailer']['startxref']);
+ }
+ } else {
+ $this->error('Did not find "startxref" in the last 40 bytes of the PDF');
+ }
+
+ $this->warning('PDF parsing incomplete in this version of getID3() ['.$this->getid3->version().']');
+ return true;
+ }
+ $this->error('Did not find "%PDF" at the beginning of the PDF');
return false;
}
+ /**
+ * @return bool
+ */
+ private function parseXREF($XREFoffset) {
+ $info = &$this->getid3->info;
+
+ $this->fseek($XREFoffset);
+ if (rtrim($this->fgets()) == 'xref') {
+
+ $info['pdf']['xref']['xref_offsets'][$XREFoffset] = $XREFoffset;
+ list($firstObjectNumber, $XREFcount) = explode(' ', rtrim($this->fgets()));
+ $XREFcount = (int) $XREFcount;
+ $info['pdf']['xref']['count'] = $XREFcount + (!empty($info['pdf']['xref']['count']) ? $info['pdf']['xref']['count'] : 0);
+ for ($i = 0; $i < $XREFcount; $i++) {
+ $line = rtrim($this->fgets());
+ if (preg_match('#^([0-9]+) ([0-9]+) ([nf])$#', $line, $matches)) {
+ $info['pdf']['xref']['offset'][($firstObjectNumber + $i)] = (int) $matches[1];
+ $info['pdf']['xref']['generation'][($firstObjectNumber + $i)] = (int) $matches[2];
+ $info['pdf']['xref']['entry'][($firstObjectNumber + $i)] = $matches[3];
+ } else {
+ $this->error('failed to parse XREF entry #'.$i.' in XREF table at offset '.$XREFoffset);
+ return false;
+ }
+ }
+ sort($info['pdf']['xref']['xref_offsets']);
+ return true;
+
+ }
+ $this->warning('failed to find expected XREF structure at offset '.$XREFoffset);
+ return false;
+ }
+
}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.tag.apetag.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.tag.apetag.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.tag.apetag.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.tag.apetag.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,10 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
+
class getid3_apetag extends getid3_handler
{
/**
@@ -162,8 +166,8 @@
switch (strtolower($item_key)) {
// http://wiki.hydrogenaud.io/index.php?title=ReplayGain#MP3Gain
case 'replaygain_track_gain':
- if (preg_match('#^[\\-\\+][0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {
- $thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
+ if (preg_match('#^([\\-\\+][0-9\\.,]{8})( dB)?$#', $thisfile_ape_items_current['data'][0], $matches)) {
+ $thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $matches[1]); // float casting will see "0,95" as zero!
$thisfile_replaygain['track']['originator'] = 'unspecified';
} else {
$this->warning('MP3gainTrackGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"');
@@ -171,8 +175,8 @@
break;
case 'replaygain_track_peak':
- if (preg_match('#^[0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {
- $thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
+ if (preg_match('#^([0-9\\.,]{8})$#', $thisfile_ape_items_current['data'][0], $matches)) {
+ $thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $matches[1]); // float casting will see "0,95" as zero!
$thisfile_replaygain['track']['originator'] = 'unspecified';
if ($thisfile_replaygain['track']['peak'] <= 0) {
$this->warning('ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")');
@@ -183,8 +187,8 @@
break;
case 'replaygain_album_gain':
- if (preg_match('#^[\\-\\+][0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {
- $thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
+ if (preg_match('#^([\\-\\+][0-9\\.,]{8})( dB)?$#', $thisfile_ape_items_current['data'][0], $matches)) {
+ $thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $matches[1]); // float casting will see "0,95" as zero!
$thisfile_replaygain['album']['originator'] = 'unspecified';
} else {
$this->warning('MP3gainAlbumGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"');
@@ -192,8 +196,8 @@
break;
case 'replaygain_album_peak':
- if (preg_match('#^[0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {
- $thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
+ if (preg_match('#^([0-9\\.,]{8})$#', $thisfile_ape_items_current['data'][0], $matches)) {
+ $thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $matches[1]); // float casting will see "0,95" as zero!
$thisfile_replaygain['album']['originator'] = 'unspecified';
if ($thisfile_replaygain['album']['peak'] <= 0) {
$this->warning('ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")');
@@ -237,7 +241,7 @@
case 'tracknumber':
if (is_array($thisfile_ape_items_current['data'])) {
foreach ($thisfile_ape_items_current['data'] as $comment) {
- $thisfile_ape['comments']['track'][] = $comment;
+ $thisfile_ape['comments']['track_number'][] = $comment;
}
}
break;
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.tag.id3v1.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.tag.id3v1.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.tag.id3v1.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.tag.id3v1.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_id3v1 extends getid3_handler
{
@@ -45,9 +48,9 @@
// If second-last byte of comment field is null and last byte of comment field is non-null
// then this is ID3v1.1 and the comment field is 28 bytes long and the 30th byte is the track number
- if (($id3v1tag{125} === "\x00") && ($id3v1tag{126} !== "\x00")) {
- $ParsedID3v1['track'] = ord(substr($ParsedID3v1['comment'], 29, 1));
- $ParsedID3v1['comment'] = substr($ParsedID3v1['comment'], 0, 28);
+ if (($id3v1tag[125] === "\x00") && ($id3v1tag[126] !== "\x00")) {
+ $ParsedID3v1['track_number'] = ord(substr($ParsedID3v1['comment'], 29, 1));
+ $ParsedID3v1['comment'] = substr($ParsedID3v1['comment'], 0, 28);
}
$ParsedID3v1['comment'] = $this->cutfield($ParsedID3v1['comment']);
@@ -62,26 +65,30 @@
foreach ($ParsedID3v1 as $key => $value) {
$ParsedID3v1['comments'][$key][0] = $value;
}
- // ID3v1 encoding detection hack START
- // ID3v1 is defined as always using ISO-8859-1 encoding, but it is not uncommon to find files tagged with ID3v1 using Windows-1251 or other character sets
- // Since ID3v1 has no concept of character sets there is no certain way to know we have the correct non-ISO-8859-1 character set, but we can guess
- $ID3v1encoding = 'ISO-8859-1';
- foreach ($ParsedID3v1['comments'] as $tag_key => $valuearray) {
- foreach ($valuearray as $key => $value) {
- if (preg_match('#^[\\x00-\\x40\\xA8\\B8\\x80-\\xFF]+$#', $value)) {
- foreach (array('Windows-1251', 'KOI8-R') as $id3v1_bad_encoding) {
- if (function_exists('mb_convert_encoding') && @mb_convert_encoding($value, $id3v1_bad_encoding, $id3v1_bad_encoding) === $value) {
- $ID3v1encoding = $id3v1_bad_encoding;
- break 3;
- } elseif (function_exists('iconv') && @iconv($id3v1_bad_encoding, $id3v1_bad_encoding, $value) === $value) {
- $ID3v1encoding = $id3v1_bad_encoding;
- break 3;
+ $ID3v1encoding = $this->getid3->encoding_id3v1;
+ if ($this->getid3->encoding_id3v1_autodetect) {
+ // ID3v1 encoding detection hack START
+ // ID3v1 is defined as always using ISO-8859-1 encoding, but it is not uncommon to find files tagged with ID3v1 using Windows-1251 or other character sets
+ // Since ID3v1 has no concept of character sets there is no certain way to know we have the correct non-ISO-8859-1 character set, but we can guess
+ foreach ($ParsedID3v1['comments'] as $tag_key => $valuearray) {
+ foreach ($valuearray as $key => $value) {
+ if (preg_match('#^[\\x00-\\x40\\x80-\\xFF]+$#', $value) && !ctype_digit((string) $value)) { // check for strings with only characters above chr(128) and punctuation/numbers, but not just numeric strings (e.g. track numbers or years)
+ foreach (array('Windows-1251', 'KOI8-R') as $id3v1_bad_encoding) {
+ if (function_exists('mb_convert_encoding') && @mb_convert_encoding($value, $id3v1_bad_encoding, $id3v1_bad_encoding) === $value) {
+ $ID3v1encoding = $id3v1_bad_encoding;
+ $this->warning('ID3v1 detected as '.$id3v1_bad_encoding.' text encoding in '.$tag_key);
+ break 3;
+ } elseif (function_exists('iconv') && @iconv($id3v1_bad_encoding, $id3v1_bad_encoding, $value) === $value) {
+ $ID3v1encoding = $id3v1_bad_encoding;
+ $this->warning('ID3v1 detected as '.$id3v1_bad_encoding.' text encoding in '.$tag_key);
+ break 3;
+ }
}
}
}
}
+ // ID3v1 encoding detection hack END
}
- // ID3v1 encoding detection hack END
// ID3v1 data is supposed to be padded with NULL characters, but some taggers pad with spaces
$GoodFormatID3v1tag = $this->GenerateID3v1Tag(
@@ -91,7 +98,7 @@
$ParsedID3v1['year'],
(isset($ParsedID3v1['genre']) ? $this->LookupGenreID($ParsedID3v1['genre']) : false),
$ParsedID3v1['comment'],
- (!empty($ParsedID3v1['track']) ? $ParsedID3v1['track'] : ''));
+ (!empty($ParsedID3v1['track_number']) ? $ParsedID3v1['track_number'] : ''));
$ParsedID3v1['padding_valid'] = true;
if ($id3v1tag !== $GoodFormatID3v1tag) {
$ParsedID3v1['padding_valid'] = false;
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.tag.id3v2.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.tag.id3v2.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.tag.id3v2.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.tag.id3v2.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true);
class getid3_id3v2 extends getid3_handler
@@ -59,8 +62,8 @@
$header = $this->fread(10);
if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) {
- $thisfile_id3v2['majorversion'] = ord($header{3});
- $thisfile_id3v2['minorversion'] = ord($header{4});
+ $thisfile_id3v2['majorversion'] = ord($header[3]);
+ $thisfile_id3v2['minorversion'] = ord($header[4]);
// shortcut
$id3v2_majorversion = &$thisfile_id3v2['majorversion'];
@@ -79,7 +82,7 @@
}
- $id3_flags = ord($header{5});
+ $id3_flags = ord($header[5]);
switch ($id3v2_majorversion) {
case 2:
// %ab000000 in v2.2
@@ -260,7 +263,7 @@
$thisfile_id3v2['padding']['length'] = strlen($framedata);
$thisfile_id3v2['padding']['valid'] = true;
for ($i = 0; $i < $thisfile_id3v2['padding']['length']; $i++) {
- if ($framedata{$i} != "\x00") {
+ if ($framedata[$i] != "\x00") {
$thisfile_id3v2['padding']['valid'] = false;
$thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
$this->warning('Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)');
@@ -326,7 +329,7 @@
$len = strlen($framedata);
for ($i = 0; $i < $len; $i++) {
- if ($framedata{$i} != "\x00") {
+ if ($framedata[$i] != "\x00") {
$thisfile_id3v2['padding']['valid'] = false;
$thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
$this->warning('Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)');
@@ -434,11 +437,11 @@
$footer = $this->fread(10);
if (substr($footer, 0, 3) == '3DI') {
$thisfile_id3v2['footer'] = true;
- $thisfile_id3v2['majorversion_footer'] = ord($footer{3});
- $thisfile_id3v2['minorversion_footer'] = ord($footer{4});
+ $thisfile_id3v2['majorversion_footer'] = ord($footer[3]);
+ $thisfile_id3v2['minorversion_footer'] = ord($footer[4]);
}
if ($thisfile_id3v2['majorversion_footer'] <= 4) {
- $id3_flags = ord($footer{5});
+ $id3_flags = ord($footer[5]);
$thisfile_id3v2_flags['unsynch_footer'] = (bool) ($id3_flags & 0x80);
$thisfile_id3v2_flags['extfoot_footer'] = (bool) ($id3_flags & 0x40);
$thisfile_id3v2_flags['experim_footer'] = (bool) ($id3_flags & 0x20);
@@ -459,10 +462,10 @@
unset($key, $value, $genres, $genre);
}
- if (isset($thisfile_id3v2['comments']['track'])) {
- foreach ($thisfile_id3v2['comments']['track'] as $key => $value) {
+ if (isset($thisfile_id3v2['comments']['track_number'])) {
+ foreach ($thisfile_id3v2['comments']['track_number'] as $key => $value) {
if (strstr($value, '/')) {
- list($thisfile_id3v2['comments']['tracknum'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track'][$key]);
+ list($thisfile_id3v2['comments']['track_number'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track_number'][$key]);
}
}
}
@@ -520,14 +523,21 @@
if (($this->getid3->info['id3v2']['majorversion'] == 3) && !preg_match('#[\x00]#', $genrestring)) {
// note: MusicBrainz Picard incorrectly stores plaintext genres separated by "/" when writing in ID3v2.3 mode, hack-fix here:
// replace / with NULL, then replace back the two ID3v1 genres that legitimately have "/" as part of the single genre name
- if (preg_match('#/#', $genrestring)) {
+ if (strpos($genrestring, '/') !== false) {
+ $LegitimateSlashedGenreList = array( // https://github.com/JamesHeinrich/getID3/issues/223
+ 'Pop/Funk', // ID3v1 genre #62 - https://en.wikipedia.org/wiki/ID3#standard
+ 'Cut-up/DJ', // Discogs - https://www.discogs.com/style/cut-up/dj
+ 'RnB/Swing', // Discogs - https://www.discogs.com/style/rnb/swing
+ 'Funk / Soul', // Discogs (note spaces) - https://www.discogs.com/genre/funk+%2F+soul
+ );
$genrestring = str_replace('/', "\x00", $genrestring);
- $genrestring = str_replace('Pop'."\x00".'Funk', 'Pop/Funk', $genrestring);
- $genrestring = str_replace('Rock'."\x00".'Rock', 'Folk/Rock', $genrestring);
+ foreach ($LegitimateSlashedGenreList as $SlashedGenre) {
+ $genrestring = str_ireplace(str_replace('/', "\x00", $SlashedGenre), $SlashedGenre, $genrestring);
+ }
}
// some other taggers separate multiple genres with semicolon, e.g. "Heavy Metal;Thrash Metal;Metal"
- if (preg_match('#;#', $genrestring)) {
+ if (strpos($genrestring, ';') !== false) {
$genrestring = str_replace(';', "\x00", $genrestring);
}
}
@@ -672,16 +682,14 @@
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
}
- $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
- if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
- // if description only contains a BOM or terminator then make it blank
- $frame_description = '';
- }
+ $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
$parsedFrame['encodingid'] = $frame_textencoding;
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
- $parsedFrame['description'] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $frame_description));
+ $parsedFrame['description'] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['description']));
$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
+ $parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $frame_textencoding_terminator);
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
$commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0));
if (!isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) || !array_key_exists($commentkey, $info['id3v2']['comments'][$parsedFrame['framenameshort']])) {
@@ -693,7 +701,7 @@
//unset($parsedFrame['data']); do not unset, may be needed elsewhere, e.g. for replaygain
- } elseif ($parsedFrame['frame_name']{0} == 'T') { // 4.2. T??[?] Text information frame
+ } elseif ($parsedFrame['frame_name'][0] == 'T') { // 4.2. T??[?] Text information frame
// There may only be one text information frame of its kind in an tag.
//
@@ -707,10 +715,10 @@
}
$parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+ $parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding));
$parsedFrame['encodingid'] = $frame_textencoding;
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
-
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
// ID3v2.3 specs say that TPE1 (and others) can contain multiple artist values separated with /
// This of course breaks when an artist name contains slash character, e.g. "AC/DC"
@@ -766,38 +774,20 @@
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
}
- $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
- if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
- // if description only contains a BOM or terminator then make it blank
- $frame_description = '';
- }
- $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
-
- $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator);
- if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
- $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
- }
- if ($frame_terminatorpos) {
- // there are null bytes after the data - this is not according to spec
- // only use data up to first null byte
- $frame_urldata = (string) substr($parsedFrame['data'], 0, $frame_terminatorpos);
- } else {
- // no null bytes following data, just use all data
- $frame_urldata = (string) $parsedFrame['data'];
- }
-
$parsedFrame['encodingid'] = $frame_textencoding;
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+ $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); // according to the frame text encoding
+ $parsedFrame['url'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); // always ISO-8859-1
+ $parsedFrame['description'] = $this->RemoveStringTerminator($parsedFrame['description'], $frame_textencoding_terminator);
+ $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
- $parsedFrame['url'] = $frame_urldata; // always ISO-8859-1
- $parsedFrame['description'] = $frame_description; // according to the frame text encoding
if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback('ISO-8859-1', $info['id3v2']['encoding'], $parsedFrame['url']);
}
unset($parsedFrame['data']);
- } elseif ($parsedFrame['frame_name']{0} == 'W') { // 4.3. W??? URL link frames
+ } elseif ($parsedFrame['frame_name'][0] == 'W') { // 4.3. W??? URL link frames
// There may only be one URL link frame of its kind in a tag,
// except when stated otherwise in the frame description
// MakeUTF16emptyStringEmpty($parsedFrame['description']);
$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
+ $parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $frame_textencoding_terminator);
$parsedFrame['encodingid'] = $frame_textencoding;
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
$parsedFrame['language'] = $frame_language;
$parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
- $parsedFrame['description'] = $frame_description;
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
}
@@ -1077,7 +1064,7 @@
$parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
$frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator));
- if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0)) {
+ if (($timestampindex == 0) && (ord($frame_remainingdata[0]) != 0)) {
// timestamp probably omitted for first data item
} else {
$parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 4));
@@ -1118,19 +1105,16 @@
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
}
- $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
- if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
- // if description only contains a BOM or terminator then make it blank
- $frame_description = '';
- }
+ $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
$frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
+ $frame_text = $this->RemoveStringTerminator($frame_text, $frame_textencoding_terminator);
$parsedFrame['encodingid'] = $frame_textencoding;
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
$parsedFrame['language'] = $frame_language;
$parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
- $parsedFrame['description'] = $frame_description;
$parsedFrame['data'] = $frame_text;
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
$commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (!empty($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0));
@@ -1423,26 +1407,22 @@
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
}
- $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
- if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
- // if description only contains a BOM or terminator then make it blank
- $frame_description = '';
- }
- $parsedFrame['encodingid'] = $frame_textencoding;
- $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+ $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
if ($id3v2_majorversion == 2) {
- $parsedFrame['imagetype'] = isset($frame_imagetype) ? $frame_imagetype : null;
+ $parsedFrame['imagetype'] = isset($frame_imagetype) ? $frame_imagetype : null;
} else {
- $parsedFrame['mime'] = isset($frame_mimetype) ? $frame_mimetype : null;
+ $parsedFrame['mime'] = isset($frame_mimetype) ? $frame_mimetype : null;
}
- $parsedFrame['picturetypeid'] = $frame_picturetype;
- $parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype);
- $parsedFrame['description'] = $frame_description;
- $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
- $parsedFrame['datalength'] = strlen($parsedFrame['data']);
+ $parsedFrame['picturetypeid'] = $frame_picturetype;
+ $parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype);
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
+ $parsedFrame['datalength'] = strlen($parsedFrame['data']);
- $parsedFrame['image_mime'] = '';
+ $parsedFrame['image_mime'] = '';
$imageinfo = array();
if ($imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo)) {
if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
@@ -1550,11 +1530,8 @@
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
}
- $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
- if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
- // if description only contains a BOM or terminator then make it blank
- $frame_description = '';
- }
+ $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
$frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
$parsedFrame['objectdata'] = (string) substr($parsedFrame['data'], $frame_offset);
@@ -1563,7 +1540,6 @@
$parsedFrame['mime'] = $frame_mimetype;
$parsedFrame['filename'] = $frame_filename;
- $parsedFrame['description'] = $frame_description;
unset($parsedFrame['data']);
@@ -1633,16 +1609,12 @@
$frame_offset = $frame_terminatorpos + strlen("\x00");
$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
- $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
- if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
- // if description only contains a BOM or terminator then make it blank
- $frame_description = '';
- }
+ $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
$frame_offset = $frame_terminatorpos + strlen("\x00");
$parsedFrame['ownerid'] = $frame_ownerid;
$parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
- $parsedFrame['description'] = $frame_description;
unset($parsedFrame['data']);
@@ -1738,7 +1710,8 @@
$parsedFrame['encodingid'] = $frame_textencoding;
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
- $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+ $parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding));
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
}
@@ -1776,6 +1749,7 @@
$frame_offset += 8;
$parsedFrame['seller'] = (string) substr($parsedFrame['data'], $frame_offset);
+ $parsedFrame['seller'] = $this->RemoveStringTerminator($parsedFrame['seller'], $this->TextEncodingTerminatorLookup($frame_textencoding));
unset($parsedFrame['data']);
@@ -1834,11 +1808,8 @@
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
}
- $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
- if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
- // if description only contains a BOM or terminator then make it blank
- $frame_description = '';
- }
+ $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
$frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
@@ -1855,7 +1826,6 @@
$parsedFrame['receivedasid'] = $frame_receivedasid;
$parsedFrame['receivedas'] = $this->COMRReceivedAsLookup($frame_receivedasid);
$parsedFrame['sellername'] = $frame_sellername;
- $parsedFrame['description'] = $frame_description;
$parsedFrame['mime'] = $frame_mimetype;
$parsedFrame['logo'] = $frame_sellerlogo;
unset($parsedFrame['data']);
@@ -2019,9 +1989,9 @@
// Element ID $00
// Start time $xx xx xx xx
// End time $xx xx xx xx
- // Start offset $xx xx xx xx
- // End offset $xx xx xx xx
- //
+ // Start offset $xx xx xx xx
+ // End offset $xx xx xx xx
+ //
$frame_offset = 0;
@list($parsedFrame['element_id']) = explode("\x00", $parsedFrame['data'], 2);
@@ -2062,7 +2032,7 @@
$subframe['encodingid'] = ord(substr($subframe_rawdata, 0, 1));
$subframe['text'] = substr($subframe_rawdata, 1);
$subframe['encoding'] = $this->TextEncodingNameLookup($subframe['encodingid']);
- $encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text']));;
+ $encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text']));
switch (substr($encoding_converted_text, 0, 2)) {
case "\xFF\xFE":
case "\xFE\xFF":
@@ -2082,22 +2052,51 @@
break;
}
- if (($subframe['name'] == 'TIT2') || ($subframe['name'] == 'TIT3')) {
- if ($subframe['name'] == 'TIT2') {
+ switch ($subframe['name']) {
+ case 'TIT2':
$parsedFrame['chapter_name'] = $encoding_converted_text;
- } elseif ($subframe['name'] == 'TIT3') {
+ $parsedFrame['subframes'][] = $subframe;
+ break;
+ case 'TIT3':
$parsedFrame['chapter_description'] = $encoding_converted_text;
- }
- $parsedFrame['subframes'][] = $subframe;
- } else {
- $this->warning('ID3v2.CHAP subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)');
+ $parsedFrame['subframes'][] = $subframe;
+ break;
+ case 'WXXX':
+ list($subframe['chapter_url_description'], $subframe['chapter_url']) = explode("\x00", $encoding_converted_text, 2);
+ $parsedFrame['chapter_url'][$subframe['chapter_url_description']] = $subframe['chapter_url'];
+ $parsedFrame['subframes'][] = $subframe;
+ break;
+ case 'APIC':
+ if (preg_match('#^([^\\x00]+)*\\x00(.)([^\\x00]+)*\\x00(.+)$#s', $subframe['text'], $matches)) {
+ list($dummy, $subframe_apic_mime, $subframe_apic_picturetype, $subframe_apic_description, $subframe_apic_picturedata) = $matches;
+ $subframe['image_mime'] = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe_apic_mime));
+ $subframe['picture_type'] = $this->APICPictureTypeLookup($subframe_apic_picturetype);
+ $subframe['description'] = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe_apic_description));
+ if (strlen($this->TextEncodingTerminatorLookup($subframe['encoding'])) == 2) {
+ // the null terminator between "description" and "picture data" could be either 1 byte (ISO-8859-1, UTF-8) or two bytes (UTF-16)
+ // the above regex assumes one byte, if it's actually two then strip the second one here
+ $subframe_apic_picturedata = substr($subframe_apic_picturedata, 1);
+ }
+ $subframe['data'] = $subframe_apic_picturedata;
+ unset($dummy, $subframe_apic_mime, $subframe_apic_picturetype, $subframe_apic_description, $subframe_apic_picturedata);
+ unset($subframe['text'], $parsedFrame['text']);
+ $parsedFrame['subframes'][] = $subframe;
+ $parsedFrame['picture_present'] = true;
+ } else {
+ $this->warning('ID3v2.CHAP subframe #'.(count($parsedFrame['subframes']) + 1).' "'.$subframe['name'].'" not in expected format');
+ }
+ break;
+ default:
+ $this->warning('ID3v2.CHAP subframe "'.$subframe['name'].'" not handled (supported: TIT2, TIT3, WXXX, APIC)');
+ break;
}
}
unset($subframe_rawdata, $subframe, $encoding_converted_text);
+ unset($parsedFrame['data']); // debatable whether this this be here, without it the returned structure may contain a large amount of duplicate data if chapters contain APIC
}
$id3v2_chapter_entry = array();
- foreach (array('id', 'time_begin', 'time_end', 'offset_begin', 'offset_end', 'chapter_name', 'chapter_description') as $id3v2_chapter_key) {
+ foreach (array('id', 'time_begin', 'time_end', 'offset_begin', 'offset_end', 'chapter_name', 'chapter_description', 'chapter_url', 'picture_present') as $id3v2_chapter_key) {
if (isset($parsedFrame[$id3v2_chapter_key])) {
$id3v2_chapter_entry[$id3v2_chapter_key] = $parsedFrame[$id3v2_chapter_key];
}
@@ -2116,7 +2115,7 @@
// CTOC flags %xx
// Entry count $xx
// Child Element ID $00 /* zero or more child CHAP or CTOC entries */
- //
+ //
$frame_offset = 0;
@list($parsedFrame['element_id']) = explode("\x00", $parsedFrame['data'], 2);
@@ -3696,6 +3695,35 @@
}
/**
+ * @param string $string
+ * @param string $terminator
+ *
+ * @return string
+ */
+ public static function RemoveStringTerminator($string, $terminator) {
+ // Null terminator at end of comment string is somewhat ambiguous in the specification, may or may not be implemented by various taggers. Remove terminator only if present.
+ // https://github.com/JamesHeinrich/getID3/issues/121
+ // https://community.mp3tag.de/t/x-trailing-nulls-in-id3v2-comments/19227
+ if (substr($string, -strlen($terminator), strlen($terminator)) === $terminator) {
+ $string = substr($string, 0, -strlen($terminator));
+ }
+ return $string;
+ }
+
+ /**
+ * @param string $string
+ *
+ * @return string
+ */
+ public static function MakeUTF16emptyStringEmpty($string) {
+ if (in_array($string, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
+ // if string only contains a BOM or terminator then make it actually an empty string
+ $string = '';
+ }
+ return $string;
+ }
+
+ /**
* @param string $framename
* @param int $id3v2majorversion
*
@@ -3705,12 +3733,10 @@
switch ($id3v2majorversion) {
case 2:
return preg_match('#[A-Z][A-Z0-9]{2}#', $framename);
- break;
case 3:
case 4:
return preg_match('#[A-Z][A-Z0-9]{3}#', $framename);
- break;
}
return false;
}
@@ -3724,10 +3750,10 @@
*/
public static function IsANumber($numberstring, $allowdecimal=false, $allownegative=false) {
for ($i = 0; $i < strlen($numberstring); $i++) {
- if ((chr($numberstring{$i}) < chr('0')) || (chr($numberstring{$i}) > chr('9'))) {
- if (($numberstring{$i} == '.') && $allowdecimal) {
+ if ((chr($numberstring[$i]) < chr('0')) || (chr($numberstring[$i]) > chr('9'))) {
+ if (($numberstring[$i] == '.') && $allowdecimal) {
// allowed
- } elseif (($numberstring{$i} == '-') && $allownegative && ($i == 0)) {
+ } elseif (($numberstring[$i] == '-') && $allownegative && ($i == 0)) {
// allowed
} else {
return false;
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.tag.lyrics3.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.tag.lyrics3.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.tag.lyrics3.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.tag.lyrics3.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,7 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
-
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_lyrics3 extends getid3_handler
{
/**
@@ -32,7 +34,7 @@
$this->fseek((0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - "LYRICSEND" - [Lyrics3size]
$lyrics3_id3v1 = $this->fread(128 + 9 + 6);
- $lyrics3lsz = substr($lyrics3_id3v1, 0, 6); // Lyrics3size
+ $lyrics3lsz = (int) substr($lyrics3_id3v1, 0, 6); // Lyrics3size
$lyrics3end = substr($lyrics3_id3v1, 6, 9); // LYRICSEND or LYRICS200
$id3v1tag = substr($lyrics3_id3v1, 15, 128); // ID3v1
@@ -107,7 +109,7 @@
$GETID3_ERRORARRAY = &$info['warning'];
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true);
$getid3_temp = new getID3();
- $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
$getid3_apetag = new getid3_apetag($getid3_temp);
$getid3_apetag->overrideendoffset = $info['lyrics3']['tag_offset_start'];
$getid3_apetag->Analyze();
@@ -240,7 +242,6 @@
default:
$this->error('Cannot process Lyrics3 version '.$version.' (only v1 and v2)');
return false;
- break;
}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/module.tag.xmp.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.tag.xmp.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/module.tag.xmp.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/module.tag.xmp.php 2022-05-20 16:59:18.000000000 +0100
@@ -114,7 +114,7 @@
$data = fread($filehnd, 2);
// Check that the third character is 0xFF (Start of first segment header)
- if ($data{0} != "\xFF")
+ if ($data[0] != "\xFF")
{
// NO FF found - close file and return - JPEG is probably corrupted
fclose($filehnd);
@@ -124,16 +124,16 @@
// Flag that we havent yet hit the compressed image data
$hit_compressed_image_data = false;
- $headerdata = array();
+ $headerdata = array();
// Cycle through the file until, one of: 1) an EOI (End of image) marker is hit,
// 2) we have hit the compressed image data (no more headers are allowed after data)
// 3) or end of file is hit
- while (($data{1} != "\xD9") && (!$hit_compressed_image_data) && (!feof($filehnd)))
+ while (($data[1] != "\xD9") && (!$hit_compressed_image_data) && (!feof($filehnd)))
{
// Found a segment to look at.
// Check that the segment marker is not a Restart marker - restart markers don't have size or data after them
- if ((ord($data{1}) < 0xD0) || (ord($data{1}) > 0xD7))
+ if ((ord($data[1]) < 0xD0) || (ord($data[1]) > 0xD7))
{
// Segment isn't a Restart marker
// Read the next two bytes (size)
@@ -150,15 +150,15 @@
// Store the segment information in the output array
$headerdata[] = array(
- 'SegType' => ord($data{1}),
- 'SegName' => $GLOBALS['JPEG_Segment_Names'][ord($data{1})],
+ 'SegType' => ord($data[1]),
+ 'SegName' => $GLOBALS['JPEG_Segment_Names'][ord($data[1])],
'SegDataStart' => $segdatastart,
'SegData' => $segdata,
);
}
// If this is a SOS (Start Of Scan) segment, then there is no more header data - the compressed image data follows
- if ($data{1} == "\xDA")
+ if ($data[1] == "\xDA")
{
// Flag that we have hit the compressed image data - exit loop as no more headers available.
$hit_compressed_image_data = true;
@@ -169,7 +169,7 @@
$data = fread($filehnd, 2);
// Check that the first byte of the two is 0xFF as it should be for a marker
- if ($data{0} != "\xFF")
+ if ($data[0] != "\xFF")
{
// NO FF found - close file and return - JPEG is probably corrupted
fclose($filehnd);
@@ -305,11 +305,11 @@
{
// Check whether we want this details from this attribute
// if (in_array($key, $GLOBALS['XMP_tag_captions']))
- if (true)
- {
+// if (true)
+// {
// Attribute wanted
$xmp_array[$key] = $xml_elem['attributes'][$key];
- }
+// }
}
}
break;
@@ -365,8 +365,8 @@
default:
// Check whether we want the details from this attribute
// if (in_array($xml_elem['tag'], $GLOBALS['XMP_tag_captions']))
- if (true)
- {
+// if (true)
+// {
switch ($xml_elem['type'])
{
case 'open':
@@ -388,7 +388,7 @@
// ignore
break;
}
- }
+// }
break;
}
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/write.apetag.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/write.apetag.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/write.apetag.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/write.apetag.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,7 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
-
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true);
class getid3_write_apetag
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/write.id3v1.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/write.id3v1.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/write.id3v1.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/write.id3v1.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true);
class getid3_write_id3v1
@@ -68,16 +71,16 @@
} else {
fseek($fp_source, 0, SEEK_END); // append new ID3v1 tag
}
- $this->tag_data['track'] = (isset($this->tag_data['track']) ? $this->tag_data['track'] : (isset($this->tag_data['track_number']) ? $this->tag_data['track_number'] : (isset($this->tag_data['tracknumber']) ? $this->tag_data['tracknumber'] : '')));
+ $this->tag_data['track_number'] = (isset($this->tag_data['track_number']) ? $this->tag_data['track_number'] : '');
$new_id3v1_tag_data = getid3_id3v1::GenerateID3v1Tag(
- (isset($this->tag_data['title'] ) ? $this->tag_data['title'] : ''),
- (isset($this->tag_data['artist'] ) ? $this->tag_data['artist'] : ''),
- (isset($this->tag_data['album'] ) ? $this->tag_data['album'] : ''),
- (isset($this->tag_data['year'] ) ? $this->tag_data['year'] : ''),
- (isset($this->tag_data['genreid']) ? $this->tag_data['genreid'] : ''),
- (isset($this->tag_data['comment']) ? $this->tag_data['comment'] : ''),
- (isset($this->tag_data['track'] ) ? $this->tag_data['track'] : ''));
+ (isset($this->tag_data['title'] ) ? $this->tag_data['title'] : ''),
+ (isset($this->tag_data['artist'] ) ? $this->tag_data['artist'] : ''),
+ (isset($this->tag_data['album'] ) ? $this->tag_data['album'] : ''),
+ (isset($this->tag_data['year'] ) ? $this->tag_data['year'] : ''),
+ (isset($this->tag_data['genreid'] ) ? $this->tag_data['genreid'] : ''),
+ (isset($this->tag_data['comment'] ) ? $this->tag_data['comment'] : ''),
+ (isset($this->tag_data['track_number']) ? $this->tag_data['track_number'] : ''));
fwrite($fp_source, $new_id3v1_tag_data, 128);
fclose($fp_source);
return true;
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/write.id3v2.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/write.id3v2.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/write.id3v2.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/write.id3v2.php 2022-05-20 16:59:18.000000000 +0100
@@ -14,6 +14,9 @@
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
class getid3_write_id3v2
@@ -24,7 +27,7 @@
public $filename;
/**
- * @var array
+ * @var array|null
*/
public $tag_data;
@@ -325,7 +328,6 @@
default:
return false;
- break;
}
return chr(bindec($flag));
}
@@ -345,7 +347,7 @@
public function GenerateID3v2FrameFlags($TagAlter=false, $FileAlter=false, $ReadOnly=false, $Compression=false, $Encryption=false, $GroupingIdentity=false, $Unsynchronisation=false, $DataLengthIndicator=false) {
$flag1 = null;
$flag2 = null;
- switch ($this->majorversion) {
+ switch ($this->majorversion) {
case 4:
// %0abc0000 %0h00kmnp
$flag1 = '0';
@@ -378,7 +380,6 @@
default:
return false;
- break;
}
return chr(bindec($flag1)).chr(bindec($flag2));
@@ -852,7 +853,7 @@
$this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion;
} elseif (!$this->ID3v2IsValidAPICpicturetype($source_data_array['picturetypeid'])) {
$this->errors[] = 'Invalid Picture Type byte in '.$frame_name.' ('.$source_data_array['picturetypeid'].') for ID3v2.'.$this->majorversion;
- } elseif (($this->majorversion >= 3) && (!$this->ID3v2IsValidAPICimageformat($source_data_array['mime']))) {
+ } elseif ((!$this->ID3v2IsValidAPICimageformat($source_data_array['mime']))) {
$this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].') for ID3v2.'.$this->majorversion;
} elseif (($source_data_array['mime'] == '-->') && (!$this->IsValidURL($source_data_array['data'], false))) {
//$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')';
@@ -905,10 +906,14 @@
// Email to user $00
// Rating $xx
// Counter $xx xx xx xx (xx ...)
+ if (!$this->IsValidEmail($source_data_array['email'])) {
+ // https://github.com/JamesHeinrich/getID3/issues/216
+ // https://en.wikipedia.org/wiki/ID3#ID3v2_rating_tag_issue
+ // ID3v2 specs say it should be an email address, but Windows instead uses string like "Windows Media Player 9 Series"
+ $this->warnings[] = 'Invalid Email in '.$frame_name.' ('.$source_data_array['email'].')';
+ }
if (!$this->IsWithinBitRange($source_data_array['rating'], 8, false)) {
$this->errors[] = 'Invalid Rating byte in '.$frame_name.' ('.$source_data_array['rating'].') (range = 0 to 255)';
- } elseif (!$this->IsValidEmail($source_data_array['email'])) {
- $this->errors[] = 'Invalid Email in '.$frame_name.' ('.$source_data_array['email'].')';
} else {
$framedata .= str_replace("\x00", '', $source_data_array['email'])."\x00";
$framedata .= chr($source_data_array['rating']);
@@ -1095,7 +1100,6 @@
$this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].')';
} else {
$framedata .= chr($source_data_array['encodingid']);
- unset($pricestring);
$pricestrings = array();
foreach ($source_data_array['price'] as $key => $val) {
if ($this->ID3v2IsValidPriceString($key.$val['value'])) {
@@ -1233,9 +1237,9 @@
break;
default:
- if ((($this->majorversion == 2) && (strlen($frame_name) != 3)) || (($this->majorversion > 2) && (strlen($frame_name) != 4))) {
+ if (/*(($this->majorversion == 2) && (strlen($frame_name) != 3)) || (($this->majorversion > 2) && (*/strlen($frame_name) != 4/*))*/) {
$this->errors[] = 'Invalid frame name "'.$frame_name.'" for ID3v2.'.$this->majorversion;
- } elseif ($frame_name{0} == 'T') {
+ } elseif ($frame_name[0] == 'T') {
// 4.2. T??? Text information frames
// Text encoding $xx
// Information
@@ -1246,7 +1250,7 @@
$framedata .= chr($source_data_array['encodingid']);
$framedata .= $source_data_array['data'];
}
- } elseif ($frame_name{0} == 'W') {
+ } elseif ($frame_name[0] == 'W') {
// 4.3. W??? URL link frames
// URL
if (!$this->IsValidURL($source_data_array['data'], false)) {
@@ -1402,7 +1406,7 @@
break;
default:
- if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) {
+ if (($frame_name[0] != 'T') && ($frame_name[0] != 'W')) {
$this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name;
}
break;
@@ -1525,7 +1529,7 @@
break;
default:
- if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) {
+ if (($frame_name[0] != 'T') && ($frame_name[0] != 'W')) {
$this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name;
}
break;
@@ -1617,7 +1621,7 @@
break;
default:
- if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) {
+ if (($frame_name[0] != 'T') && ($frame_name[0] != 'W')) {
$this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name;
}
break;
@@ -1688,18 +1692,18 @@
if ($noerrorsonly) {
return false;
} else {
- unset($frame_name);
+ $frame_name = null;
}
}
} else {
// ignore any invalid frame names, including 'title', 'header', etc
$this->warnings[] = 'Ignoring invalid ID3v2 frame type: "'.$frame_name.'"';
- unset($frame_name);
+ $frame_name = null;
unset($frame_length);
unset($frame_flags);
unset($frame_data);
}
- if (isset($frame_name) && isset($frame_length) && isset($frame_flags) && isset($frame_data)) {
+ if (null !== $frame_name && isset($frame_length) && isset($frame_flags) && isset($frame_data)) {
$tagstring .= $frame_name.$frame_length.$frame_flags.$frame_data;
}
}
@@ -1723,7 +1727,7 @@
}
$footer = false; // ID3v2 footers not yet supported in getID3()
- if (!$footer && ($this->paddedlength > (strlen($tagstring) + getid3_id3v2::ID3v2HeaderLength($this->majorversion)))) {
+ if (/*!$footer && */($this->paddedlength > (strlen($tagstring) + getid3_id3v2::ID3v2HeaderLength($this->majorversion)))) {
// pad up to $paddedlength bytes if unpadded tag is shorter than $paddedlength
// "Furthermore it MUST NOT have any padding when a tag footer is added to the tag."
if (($this->paddedlength - strlen($tagstring) - getid3_id3v2::ID3v2HeaderLength($this->majorversion)) > 0) {
@@ -1791,11 +1795,9 @@
switch ($framename) {
case 'RGAD':
return false;
- break;
default:
return false;
- break;
}
}
@@ -1958,10 +1960,10 @@
$unsyncheddata = '';
$datalength = strlen($data);
for ($i = 0; $i < $datalength; $i++) {
- $thischar = $data{$i};
+ $thischar = $data[$i];
$unsyncheddata .= $thischar;
if ($thischar == "\xFF") {
- $nextchar = ord($data{$i + 1});
+ $nextchar = ord($data[$i + 1]);
if (($nextchar & 0xE0) == 0xE0) {
// previous byte = 11111111, this byte = 111?????
$unsyncheddata .= "\x00";
@@ -2316,6 +2318,7 @@
$ID3v2ShortFrameNameLookup[4]['performer_sort_order'] = 'TSOP';
$ID3v2ShortFrameNameLookup[4]['title_sort_order'] = 'TSOT';
$ID3v2ShortFrameNameLookup[4]['set_subtitle'] = 'TSST';
+ $ID3v2ShortFrameNameLookup[4]['year'] = 'TDRC'; // subset of ISO 8601: valid timestamps are yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddTHH, yyyy-MM-ddTHH:mm and yyyy-MM-ddTHH:mm:ss. All time stamps are UTC
}
return (isset($ID3v2ShortFrameNameLookup[$majorversion][strtolower($long_description)]) ? $ID3v2ShortFrameNameLookup[$majorversion][strtolower($long_description)] : '');
diff -Nru spip-3.2.7/plugins-dist/medias/lib/getid3/write.php spip-3.2.15.1/plugins-dist/medias/lib/getid3/write.php
--- spip-3.2.7/plugins-dist/medias/lib/getid3/write.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/lib/getid3/write.php 2022-05-20 16:59:18.000000000 +0100
@@ -205,14 +205,12 @@
//$AllowedTagFormats = array('metaflac');
$this->errors[] = 'metaflac is not (yet) compatible with OggFLAC files';
return false;
- break;
case 'vorbis':
$AllowedTagFormats = array('vorbiscomment');
break;
default:
$this->errors[] = 'metaflac is not (yet) compatible with Ogg files other than OggVorbis';
return false;
- break;
}
break;
@@ -282,7 +280,6 @@
default:
$this->errors[] = 'unknown tag format "'.$tagformat.'" in $tagformats in WriteTags()';
return false;
- break;
}
}
@@ -311,9 +308,9 @@
}
}
- // Convert "TRACK" to "TRACKNUMBER" (if needed) for compatability with all formats
- if (isset($this->tag_data['TRACK']) && !isset($this->tag_data['TRACKNUMBER'])) {
- $this->tag_data['TRACKNUMBER'] = $this->tag_data['TRACK'];
+ // Convert "TRACK" to "TRACK_NUMBER" (if needed) for compatability with all formats
+ if (isset($this->tag_data['TRACK']) && !isset($this->tag_data['TRACK_NUMBER'])) {
+ $this->tag_data['TRACK_NUMBER'] = $this->tag_data['TRACK'];
unset($this->tag_data['TRACK']);
}
@@ -408,7 +405,6 @@
default:
$this->errors[] = 'Invalid tag format to write: "'.$tagformat.'"';
return false;
- break;
}
if (!$success) {
return false;
@@ -486,7 +482,6 @@
default:
$this->errors[] = 'Invalid tag format to delete: "'.$DeleteTagFormat.'"';
return false;
- break;
}
if (!$success) {
return false;
@@ -508,10 +503,10 @@
// do nothing - ignore previous data
} else {
throw new Exception('$this->overwrite_tags=false is known to be buggy in this version of getID3. Check http://github.com/JamesHeinrich/getID3 for a newer version.');
- if (!isset($this->ThisFileInfo['tags'][$TagFormat])) {
- return false;
- }
- $tag_data = array_merge_recursive($tag_data, $this->ThisFileInfo['tags'][$TagFormat]);
+// if (!isset($this->ThisFileInfo['tags'][$TagFormat])) {
+// return false;
+// }
+// $tag_data = array_merge_recursive($tag_data, $this->ThisFileInfo['tags'][$TagFormat]);
}
return true;
}
@@ -559,14 +554,14 @@
}
}
}
- $tag_data_id3v1['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TITLE'] ) ? $this->tag_data['TITLE'] : array())));
- $tag_data_id3v1['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ARTIST'] ) ? $this->tag_data['ARTIST'] : array())));
- $tag_data_id3v1['album'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ALBUM'] ) ? $this->tag_data['ALBUM'] : array())));
- $tag_data_id3v1['year'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['YEAR'] ) ? $this->tag_data['YEAR'] : array())));
- $tag_data_id3v1['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['COMMENT'] ) ? $this->tag_data['COMMENT'] : array())));
- $tag_data_id3v1['track'] = intval(getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TRACKNUMBER']) ? $this->tag_data['TRACKNUMBER'] : array()))));
- if ($tag_data_id3v1['track'] <= 0) {
- $tag_data_id3v1['track'] = '';
+ $tag_data_id3v1['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TITLE'] ) ? $this->tag_data['TITLE'] : array())));
+ $tag_data_id3v1['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ARTIST'] ) ? $this->tag_data['ARTIST'] : array())));
+ $tag_data_id3v1['album'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ALBUM'] ) ? $this->tag_data['ALBUM'] : array())));
+ $tag_data_id3v1['year'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['YEAR'] ) ? $this->tag_data['YEAR'] : array())));
+ $tag_data_id3v1['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['COMMENT'] ) ? $this->tag_data['COMMENT'] : array())));
+ $tag_data_id3v1['track_number'] = intval(getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TRACK_NUMBER']) ? $this->tag_data['TRACK_NUMBER'] : array()))));
+ if ($tag_data_id3v1['track_number'] <= 0) {
+ $tag_data_id3v1['track_number'] = '';
}
$this->MergeExistingTagData('id3v1', $tag_data_id3v1);
@@ -665,7 +660,7 @@
// note: some software, notably Windows Media Player and iTunes are broken and treat files tagged with UTF-16BE (with BOM) as corrupt
// therefore we force data to UTF-16LE and manually prepend the BOM
$ID3v2_tag_data_converted = false;
- if (!$ID3v2_tag_data_converted && ($this->tag_encoding == 'ISO-8859-1')) {
+ if (/*!$ID3v2_tag_data_converted && */($this->tag_encoding == 'ISO-8859-1')) {
// great, leave data as-is for minimum compatability problems
$tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 0;
$tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value;
@@ -675,7 +670,7 @@
do {
// if UTF-8 string does not include any characters above chr(127) then it is identical to ISO-8859-1
for ($i = 0; $i < strlen($value); $i++) {
- if (ord($value{$i}) > 127) {
+ if (ord($value[$i]) > 127) {
break 2;
}
}
diff -Nru spip-3.2.7/plugins-dist/medias/medias_administrations.php spip-3.2.15.1/plugins-dist/medias/medias_administrations.php
--- spip-3.2.7/plugins-dist/medias/medias_administrations.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/medias_administrations.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/medias_autoriser.php spip-3.2.15.1/plugins-dist/medias/medias_autoriser.php
--- spip-3.2.7/plugins-dist/medias/medias_autoriser.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/medias_autoriser.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/medias_fonctions.php spip-3.2.15.1/plugins-dist/medias/medias_fonctions.php
--- spip-3.2.7/plugins-dist/medias/medias_fonctions.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/medias_fonctions.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/medias_pipelines.php spip-3.2.15.1/plugins-dist/medias/medias_pipelines.php
--- spip-3.2.7/plugins-dist/medias/medias_pipelines.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/medias_pipelines.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/metadata/html.php spip-3.2.15.1/plugins-dist/medias/metadata/html.php
--- spip-3.2.7/plugins-dist/medias/metadata/html.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/metadata/html.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/metadata/image.php spip-3.2.15.1/plugins-dist/medias/metadata/image.php
--- spip-3.2.7/plugins-dist/medias/metadata/image.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/metadata/image.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/metadata/svg.php spip-3.2.15.1/plugins-dist/medias/metadata/svg.php
--- spip-3.2.7/plugins-dist/medias/metadata/svg.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/metadata/svg.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/metadata/swf.php spip-3.2.15.1/plugins-dist/medias/metadata/swf.php
--- spip-3.2.7/plugins-dist/medias/metadata/swf.php 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/metadata/swf.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/modeles/document_case_fonctions.php spip-3.2.15.1/plugins-dist/medias/modeles/document_case_fonctions.php
--- spip-3.2.7/plugins-dist/medias/modeles/document_case_fonctions.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/modeles/document_case_fonctions.php 2022-05-20 16:59:18.000000000 +0100
@@ -1,12 +1,13 @@
#FORMULAIRE_RECHERCHE_ECRIRE{#GET{self},ajax}
-
+
[(#GET{editable})
diff -Nru spip-3.2.7/plugins-dist/medias/prive/squelettes/inclure/portfolio-documents.html spip-3.2.15.1/plugins-dist/medias/prive/squelettes/inclure/portfolio-documents.html
--- spip-3.2.7/plugins-dist/medias/prive/squelettes/inclure/portfolio-documents.html 2019-12-12 21:31:06.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/prive/squelettes/inclure/portfolio-documents.html 2022-05-20 16:59:18.000000000 +0100
@@ -11,7 +11,7 @@
[(#REM) D'abord les images illustration]
-
<:medias:info_illustrations:>
+
<:medias:info_illustrations:>
[
(#PAGINATION{prive})
]
@@ -32,7 +32,7 @@
[(#REM) puis les images du portfolio]
-
<:medias:info_portfolio:>
+
<:medias:info_portfolio:>
[
(#PAGINATION{prive})
]
@@ -53,7 +53,7 @@
[(#REM) puis les documents]
-
<:medias:info_documents:>
+
<:medias:info_documents:>
[
(#PAGINATION{prive})
]
diff -Nru spip-3.2.7/plugins-dist/medias/puce_statut/document.php spip-3.2.15.1/plugins-dist/medias/puce_statut/document.php
--- spip-3.2.7/plugins-dist/medias/puce_statut/document.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/puce_statut/document.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/urls/generer_url_document.php spip-3.2.15.1/plugins-dist/medias/urls/generer_url_document.php
--- spip-3.2.7/plugins-dist/medias/urls/generer_url_document.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/urls/generer_url_document.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/medias/urls/generer_url_ecrire_document.php spip-3.2.15.1/plugins-dist/medias/urls/generer_url_ecrire_document.php
--- spip-3.2.7/plugins-dist/medias/urls/generer_url_ecrire_document.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/medias/urls/generer_url_ecrire_document.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/mots/action/editer_groupe_mots.php spip-3.2.15.1/plugins-dist/mots/action/editer_groupe_mots.php
--- spip-3.2.7/plugins-dist/mots/action/editer_groupe_mots.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mots/action/editer_groupe_mots.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/mots/action/editer_mot.php spip-3.2.15.1/plugins-dist/mots/action/editer_mot.php
--- spip-3.2.7/plugins-dist/mots/action/editer_mot.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mots/action/editer_mot.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/mots/action/supprimer_groupe_mots.php spip-3.2.15.1/plugins-dist/mots/action/supprimer_groupe_mots.php
--- spip-3.2.7/plugins-dist/mots/action/supprimer_groupe_mots.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mots/action/supprimer_groupe_mots.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/mots/action/supprimer_mot.php spip-3.2.15.1/plugins-dist/mots/action/supprimer_mot.php
--- spip-3.2.7/plugins-dist/mots/action/supprimer_mot.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mots/action/supprimer_mot.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/mots/base/mots.php spip-3.2.15.1/plugins-dist/mots/base/mots.php
--- spip-3.2.7/plugins-dist/mots/base/mots.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mots/base/mots.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/mots/formulaires/configurer_mots.php spip-3.2.15.1/plugins-dist/mots/formulaires/configurer_mots.php
--- spip-3.2.7/plugins-dist/mots/formulaires/configurer_mots.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mots/formulaires/configurer_mots.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/mots/formulaires/editer_groupe_mot.php spip-3.2.15.1/plugins-dist/mots/formulaires/editer_groupe_mot.php
--- spip-3.2.7/plugins-dist/mots/formulaires/editer_groupe_mot.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mots/formulaires/editer_groupe_mot.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
@@ -47,6 +47,13 @@
) {
$valeurs = formulaires_editer_objet_charger('groupe_mots', $id_groupe, 0, '', $retour, $config_fonc, $row, $hidden);
+ if (test_formulaire_inclus_par_modele()) {
+ if (intval($id_groupe) and !autoriser('modifier', 'groupemots', intval($id_groupe))) {
+ $valeurs['editable'] = '';
+ }
+ }
+
+
$valeurs['tables_liees'] = explode(',', $valeurs['tables_liees']);
// par defaut a la creation de groupe
diff -Nru spip-3.2.7/plugins-dist/mots/formulaires/editer_mot.php spip-3.2.15.1/plugins-dist/mots/formulaires/editer_mot.php
--- spip-3.2.7/plugins-dist/mots/formulaires/editer_mot.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mots/formulaires/editer_mot.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
@@ -63,6 +63,13 @@
$valeurs['id_groupe'] = $valeurs['id_parent'];
}
+ if (test_formulaire_inclus_par_modele()) {
+ if (intval($id_mot) and !autoriser('modifier', 'mot', intval($id_mot))) {
+ $valeurs['editable'] = '';
+ }
+ }
+
+
if ($associer_objet) {
if (intval($associer_objet)) {
// compat avec l'appel de la forme ajouter_id_article
diff -Nru spip-3.2.7/plugins-dist/mots/inc/mots.php spip-3.2.15.1/plugins-dist/mots/inc/mots.php
--- spip-3.2.7/plugins-dist/mots/inc/mots.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mots/inc/mots.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/mots/mots_administrations.php spip-3.2.15.1/plugins-dist/mots/mots_administrations.php
--- spip-3.2.7/plugins-dist/mots/mots_administrations.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mots/mots_administrations.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/mots/mots_autoriser.php spip-3.2.15.1/plugins-dist/mots/mots_autoriser.php
--- spip-3.2.7/plugins-dist/mots/mots_autoriser.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mots/mots_autoriser.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/mots/mots_pipelines.php spip-3.2.15.1/plugins-dist/mots/mots_pipelines.php
--- spip-3.2.7/plugins-dist/mots/mots_pipelines.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mots/mots_pipelines.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/mots/paquet.xml spip-3.2.15.1/plugins-dist/mots/paquet.xml
--- spip-3.2.7/plugins-dist/mots/paquet.xml 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mots/paquet.xml 2022-05-20 16:59:18.000000000 +0100
@@ -1,7 +1,7 @@
diff -Nru spip-3.2.7/plugins-dist/mots/puce_statut/mot.php spip-3.2.15.1/plugins-dist/mots/puce_statut/mot.php
--- spip-3.2.7/plugins-dist/mots/puce_statut/mot.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/mots/puce_statut/mot.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/organiseur/action/effacer_messagerecu.php spip-3.2.15.1/plugins-dist/organiseur/action/effacer_messagerecu.php
--- spip-3.2.7/plugins-dist/organiseur/action/effacer_messagerecu.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/organiseur/action/effacer_messagerecu.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/organiseur/action/envoyer_message.php spip-3.2.15.1/plugins-dist/organiseur/action/envoyer_message.php
--- spip-3.2.7/plugins-dist/organiseur/action/envoyer_message.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/organiseur/action/envoyer_message.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/organiseur/action/quete_autocomplete.php spip-3.2.15.1/plugins-dist/organiseur/action/quete_autocomplete.php
--- spip-3.2.7/plugins-dist/organiseur/action/quete_autocomplete.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/organiseur/action/quete_autocomplete.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/organiseur/action/quete_calendrier_prive.php spip-3.2.15.1/plugins-dist/organiseur/action/quete_calendrier_prive.php
--- spip-3.2.7/plugins-dist/organiseur/action/quete_calendrier_prive.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/organiseur/action/quete_calendrier_prive.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/organiseur/action/supprimer_message.php spip-3.2.15.1/plugins-dist/organiseur/action/supprimer_message.php
--- spip-3.2.7/plugins-dist/organiseur/action/supprimer_message.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/organiseur/action/supprimer_message.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/organiseur/base/organiseur.php spip-3.2.15.1/plugins-dist/organiseur/base/organiseur.php
--- spip-3.2.7/plugins-dist/organiseur/base/organiseur.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/organiseur/base/organiseur.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/organiseur/formulaires/configurer_messagerie_agenda.php spip-3.2.15.1/plugins-dist/organiseur/formulaires/configurer_messagerie_agenda.php
--- spip-3.2.7/plugins-dist/organiseur/formulaires/configurer_messagerie_agenda.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/organiseur/formulaires/configurer_messagerie_agenda.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/organiseur/formulaires/editer_message.php spip-3.2.15.1/plugins-dist/organiseur/formulaires/editer_message.php
--- spip-3.2.7/plugins-dist/organiseur/formulaires/editer_message.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/organiseur/formulaires/editer_message.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/organiseur/inc/date_gestion.php spip-3.2.15.1/plugins-dist/organiseur/inc/date_gestion.php
--- spip-3.2.7/plugins-dist/organiseur/inc/date_gestion.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/organiseur/inc/date_gestion.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/organiseur/inc/messages.php spip-3.2.15.1/plugins-dist/organiseur/inc/messages.php
--- spip-3.2.7/plugins-dist/organiseur/inc/messages.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/organiseur/inc/messages.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/organiseur/inc/quete_calendrier.php spip-3.2.15.1/plugins-dist/organiseur/inc/quete_calendrier.php
--- spip-3.2.7/plugins-dist/organiseur/inc/quete_calendrier.php 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/organiseur/inc/quete_calendrier.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
@@ -169,14 +169,16 @@
} else {
$langues = array();
}
+
while ($row = sql_fetch($result)) {
$amj = date_anneemoisjour($row['date']);
$id = $row['id_article'];
if (autoriser('voir', 'article', $id)) {
+ $langue = isset($langues[$row['lang']]) ? $langues[$row['lang']] : "";
$evenements[$amj][] =
array(
'CATEGORIES' => calendrier_categories('spip_articles', $id, 'id_article'),
- 'DESCRIPTION' => $row['descriptif'] ? $row['descriptif'] : $langues[$row['lang']],
+ 'DESCRIPTION' => $row['descriptif'] ?: $langue,
'SUMMARY' => $row['titre'],
'URL' => generer_url_ecrire_objet('article', $id, '', '', 'prop')
);
@@ -343,7 +345,7 @@
'DESCRIPTION' => $row['texte'],
'SUMMARY' => $row['titre'],
'CATEGORIES' => $cat,
- 'ATTENDEE' => (count($auteurs) == 0) ? '' : join($auteurs, ', ')
+ 'ATTENDEE' => (count($auteurs) == 0) ? '' : implode(', ', $auteurs)
);
}
diff -Nru spip-3.2.7/plugins-dist/organiseur/lib/fullcalendar/fullcalendar.css spip-3.2.15.1/plugins-dist/organiseur/lib/fullcalendar/fullcalendar.css
--- spip-3.2.7/plugins-dist/organiseur/lib/fullcalendar/fullcalendar.css 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/organiseur/lib/fullcalendar/fullcalendar.css 2022-05-20 16:59:18.000000000 +0100
@@ -1,7 +1,7 @@
/*!
- * FullCalendar v3.9.0
+ * FullCalendar v3.10.2
* Docs & License: https://fullcalendar.io/
- * (c) 2018 Adam Shaw
+ * (c) 2019 Adam Shaw
*/
.fc {
direction: ltr;
@@ -582,7 +582,7 @@
-ms-user-select: none;
user-select: none;
-webkit-touch-callout: none;
- -webkit-tap-highlight-color: transparent; }
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0); }
/*
TODO: more distinction between this file and common.css
diff -Nru spip-3.2.7/plugins-dist/organiseur/lib/fullcalendar/fullcalendar.js spip-3.2.15.1/plugins-dist/organiseur/lib/fullcalendar/fullcalendar.js
--- spip-3.2.7/plugins-dist/organiseur/lib/fullcalendar/fullcalendar.js 2019-12-12 21:31:08.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/organiseur/lib/fullcalendar/fullcalendar.js 2022-05-20 16:59:18.000000000 +0100
@@ -1,7 +1,7 @@
/*!
- * FullCalendar v3.9.0
+ * FullCalendar v3.10.2
* Docs & License: https://fullcalendar.io/
- * (c) 2018 Adam Shaw
+ * (c) 2019 Adam Shaw
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
@@ -75,7 +75,7 @@
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
-/******/ return __webpack_require__(__webpack_require__.s = 236);
+/******/ return __webpack_require__(__webpack_require__.s = 256);
/******/ })
/************************************************************************/
/******/ ([
@@ -200,7 +200,7 @@
var naturalOffset = flexOffsets[i];
var naturalHeight = flexHeights[i];
var newHeight = minOffset - (naturalOffset - naturalHeight); // subtract the margin/padding
- if (naturalOffset < minOffset) {
+ if (naturalOffset < minOffset) { // we check this again because redistribution might have changed things
$(el).height(newHeight);
}
});
@@ -314,7 +314,7 @@
leftRightWidth = sanitizeScrollbarWidth(leftRightWidth);
bottomWidth = sanitizeScrollbarWidth(bottomWidth);
widths = { left: 0, right: 0, top: 0, bottom: bottomWidth };
- if (getIsLeftRtlScrollbars() && el.css('direction') === 'rtl') {
+ if (getIsLeftRtlScrollbars() && el.css('direction') === 'rtl') { // is the scrollbar on the left side?
widths.left = leftRightWidth;
}
else {
@@ -339,7 +339,7 @@
return _isLeftRtlScrollbars;
}
function computeIsLeftRtlScrollbars() {
- var el = $('
')
+ var el = $('
')
.css({
position: 'absolute',
top: -1000,
@@ -577,13 +577,13 @@
// Results are based on Moment's .as() and .diff() methods, so results can depend on internal handling
// of month-diffing logic (which tends to vary from version to version).
function computeRangeAs(unit, start, end) {
- if (end != null) {
+ if (end != null) { // given start, end
return end.diff(start, unit, true);
}
- else if (moment.isDuration(start)) {
+ else if (moment.isDuration(start)) { // given duration
return start.as(unit);
}
- else {
+ else { // given { start, end } range object
return start.end.diff(start.start, unit, true);
}
}
@@ -709,7 +709,7 @@
for (i = propObjs.length - 1; i >= 0; i--) {
props = propObjs[i];
for (name in props) {
- if (!(name in dest)) {
+ if (!(name in dest)) { // if already assigned by previous props or complex props, don't reassign
dest[name] = props[name];
}
}
@@ -747,7 +747,7 @@
var removeCnt = 0;
var i = 0;
while (i < array.length) {
- if (testFunc(array[i])) {
+ if (testFunc(array[i])) { // truthy value means *remove*
array.splice(i, 1);
removeCnt++;
}
@@ -776,7 +776,7 @@
function isArraysEqual(a0, a1) {
var len = a0.length;
var i;
- if (len == null || len !== a1.length) {
+ if (len == null || len !== a1.length) { // not array? or not same length?
return false;
}
for (i = 0; i < len; i++) {
@@ -805,7 +805,7 @@
.replace(/>/g, '>')
.replace(/'/g, ''')
.replace(/"/g, '"')
- .replace(/\n/g, ' ');
+ .replace(/\n/g, ' ');
}
exports.htmlEscape = htmlEscape;
function stripHtmlEntities(text) {
@@ -907,7 +907,7 @@
Object.defineProperty(exports, "__esModule", { value: true });
var moment = __webpack_require__(0);
-var moment_ext_1 = __webpack_require__(10);
+var moment_ext_1 = __webpack_require__(11);
var UnzonedRange = /** @class */ (function () {
function UnzonedRange(startInput, endInput) {
// TODO: move these into footprint.
@@ -942,7 +942,7 @@
for (i = 0; i < ranges.length; i++) {
dateRange = ranges[i];
// add the span of time before the event (if there is any)
- if (dateRange.startMs > startMs) {
+ if (dateRange.startMs > startMs) { // compare millisecond time (skip any ambig logic)
invertedRanges.push(new UnzonedRange(startMs, dateRange.startMs));
}
if (dateRange.endMs > startMs) {
@@ -950,7 +950,7 @@
}
}
// add the span of time after the last event (if there is any)
- if (startMs < constraintRange.endMs) {
+ if (startMs < constraintRange.endMs) { // compare millisecond time (skip any ambig logic)
invertedRanges.push(new UnzonedRange(startMs, constraintRange.endMs));
}
return invertedRanges;
@@ -1058,9 +1058,9 @@
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
-var ParsableModelMixin_1 = __webpack_require__(208);
-var Class_1 = __webpack_require__(33);
-var EventDefParser_1 = __webpack_require__(49);
+var ParsableModelMixin_1 = __webpack_require__(52);
+var Class_1 = __webpack_require__(35);
+var EventDefParser_1 = __webpack_require__(36);
var EventSource = /** @class */ (function (_super) {
tslib_1.__extends(EventSource, _super);
// can we do away with calendar? at least for the abstract?
@@ -1189,7 +1189,7 @@
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
-var Mixin_1 = __webpack_require__(14);
+var Mixin_1 = __webpack_require__(15);
var guid = 0;
var ListenerMixin = /** @class */ (function (_super) {
tslib_1.__extends(ListenerMixin, _super);
@@ -1208,7 +1208,7 @@
})
*/
ListenerMixin.prototype.listenTo = function (other, arg, callback) {
- if (typeof arg === 'object') {
+ if (typeof arg === 'object') { // given dictionary of callbacks
for (var eventName in arg) {
if (arg.hasOwnProperty(eventName)) {
this.listenTo(other, eventName, arg[eventName]);
@@ -1246,8 +1246,76 @@
/***/ }),
/* 8 */,
-/* 9 */,
-/* 10 */
+/* 9 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var EventDef_1 = __webpack_require__(37);
+var EventInstance_1 = __webpack_require__(53);
+var EventDateProfile_1 = __webpack_require__(16);
+var SingleEventDef = /** @class */ (function (_super) {
+ tslib_1.__extends(SingleEventDef, _super);
+ function SingleEventDef() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ /*
+ Will receive start/end params, but will be ignored.
+ */
+ SingleEventDef.prototype.buildInstances = function () {
+ return [this.buildInstance()];
+ };
+ SingleEventDef.prototype.buildInstance = function () {
+ return new EventInstance_1.default(this, // definition
+ this.dateProfile);
+ };
+ SingleEventDef.prototype.isAllDay = function () {
+ return this.dateProfile.isAllDay();
+ };
+ SingleEventDef.prototype.clone = function () {
+ var def = _super.prototype.clone.call(this);
+ def.dateProfile = this.dateProfile;
+ return def;
+ };
+ SingleEventDef.prototype.rezone = function () {
+ var calendar = this.source.calendar;
+ var dateProfile = this.dateProfile;
+ this.dateProfile = new EventDateProfile_1.default(calendar.moment(dateProfile.start), dateProfile.end ? calendar.moment(dateProfile.end) : null, calendar);
+ };
+ /*
+ NOTE: if super-method fails, should still attempt to apply
+ */
+ SingleEventDef.prototype.applyManualStandardProps = function (rawProps) {
+ var superSuccess = _super.prototype.applyManualStandardProps.call(this, rawProps);
+ var dateProfile = EventDateProfile_1.default.parse(rawProps, this.source); // returns null on failure
+ if (dateProfile) {
+ this.dateProfile = dateProfile;
+ // make sure `date` shows up in the legacy event objects as-is
+ if (rawProps.date != null) {
+ this.miscProps.date = rawProps.date;
+ }
+ return superSuccess;
+ }
+ else {
+ return false;
+ }
+ };
+ return SingleEventDef;
+}(EventDef_1.default));
+exports.default = SingleEventDef;
+// Parsing
+// ---------------------------------------------------------------------------------------------------------------------
+SingleEventDef.defineStandardProps({
+ start: false,
+ date: false,
+ end: false,
+ allDay: false
+});
+
+
+/***/ }),
+/* 10 */,
+/* 11 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
@@ -1287,7 +1355,7 @@
var mom = makeMoment(arguments, true);
// Force it into UTC because makeMoment doesn't guarantee it
// (if given a pre-existing moment for example)
- if (mom.hasTime()) {
+ if (mom.hasTime()) { // don't give ambiguously-timed moments a UTC zone
mom.utc();
}
return mom;
@@ -1314,7 +1382,7 @@
if (moment.isMoment(input) || util_1.isNativeDate(input) || input === undefined) {
mom = moment.apply(null, args);
}
- else {
+ else { // "parsing" is required
isAmbigTime = false;
isAmbigZone = false;
if (isSingleString) {
@@ -1345,7 +1413,7 @@
mom._ambigTime = true;
mom._ambigZone = true; // ambiguous time always means ambiguous zone
}
- else if (parseZone) {
+ else if (parseZone) { // let's record the inputted zone somehow
if (isAmbigZone) {
mom._ambigZone = true;
}
@@ -1363,7 +1431,7 @@
// `weeks` is an alias for `week`
newMomentProto.week = newMomentProto.weeks = function (input) {
var weekCalc = this._locale._fullCalendar_weekCalc;
- if (input == null && typeof weekCalc === 'function') {
+ if (input == null && typeof weekCalc === 'function') { // custom function only works for getter
return weekCalc(this);
}
else if (weekCalc === 'ISO') {
@@ -1386,7 +1454,7 @@
if (!this._fullCalendar) {
return oldMomentProto.time.apply(this, arguments);
}
- if (time == null) {
+ if (time == null) { // getter
return moment.duration({
hours: this.hours(),
minutes: this.minutes(),
@@ -1394,7 +1462,7 @@
milliseconds: this.milliseconds()
});
}
- else {
+ else { // setter
this._ambigTime = false; // mark that the moment now has a time
if (!moment.isDuration(time) && !moment.isMoment(time)) {
time = moment.duration(time);
@@ -1481,7 +1549,7 @@
};
// implicitly marks a zone (will probably get called upon .utc() and .local())
newMomentProto.utcOffset = function (tzo) {
- if (tzo != null) {
+ if (tzo != null) { // setter
// these assignments needs to happen before the original zone method is called.
// I forget why, something to do with a browser crash.
this._ambigTime = false;
@@ -1492,7 +1560,35 @@
/***/ }),
-/* 11 */
+/* 12 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+/*
+Meant to be immutable
+*/
+var ComponentFootprint = /** @class */ (function () {
+ function ComponentFootprint(unzonedRange, isAllDay) {
+ this.isAllDay = false; // component can choose to ignore this
+ this.unzonedRange = unzonedRange;
+ this.isAllDay = isAllDay;
+ }
+ /*
+ Only works for non-open-ended ranges.
+ */
+ ComponentFootprint.prototype.toLegacy = function (calendar) {
+ return {
+ start: calendar.msToMoment(this.unzonedRange.startMs, this.isAllDay),
+ end: calendar.msToMoment(this.unzonedRange.endMs, this.isAllDay)
+ };
+ };
+ return ComponentFootprint;
+}());
+exports.default = ComponentFootprint;
+
+
+/***/ }),
+/* 13 */
/***/ (function(module, exports, __webpack_require__) {
/*
@@ -1511,7 +1607,7 @@
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
-var Mixin_1 = __webpack_require__(14);
+var Mixin_1 = __webpack_require__(15);
var EmitterMixin = /** @class */ (function (_super) {
tslib_1.__extends(EmitterMixin, _super);
function EmitterMixin() {
@@ -1573,103 +1669,28 @@
/***/ }),
-/* 12 */
+/* 14 */
/***/ (function(module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
-/*
-Meant to be immutable
-*/
-var ComponentFootprint = /** @class */ (function () {
- function ComponentFootprint(unzonedRange, isAllDay) {
- this.isAllDay = false; // component can choose to ignore this
- this.unzonedRange = unzonedRange;
- this.isAllDay = isAllDay;
- }
- /*
- Only works for non-open-ended ranges.
- */
- ComponentFootprint.prototype.toLegacy = function (calendar) {
- return {
- start: calendar.msToMoment(this.unzonedRange.startMs, this.isAllDay),
- end: calendar.msToMoment(this.unzonedRange.endMs, this.isAllDay)
- };
- };
- return ComponentFootprint;
-}());
-exports.default = ComponentFootprint;
-
-
-/***/ }),
-/* 13 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var tslib_1 = __webpack_require__(2);
-var EventDef_1 = __webpack_require__(34);
-var EventInstance_1 = __webpack_require__(209);
-var EventDateProfile_1 = __webpack_require__(17);
-var SingleEventDef = /** @class */ (function (_super) {
- tslib_1.__extends(SingleEventDef, _super);
- function SingleEventDef() {
- return _super !== null && _super.apply(this, arguments) || this;
+var Interaction = /** @class */ (function () {
+ function Interaction(component) {
+ this.view = component._getView();
+ this.component = component;
}
- /*
- Will receive start/end params, but will be ignored.
- */
- SingleEventDef.prototype.buildInstances = function () {
- return [this.buildInstance()];
- };
- SingleEventDef.prototype.buildInstance = function () {
- return new EventInstance_1.default(this, // definition
- this.dateProfile);
- };
- SingleEventDef.prototype.isAllDay = function () {
- return this.dateProfile.isAllDay();
- };
- SingleEventDef.prototype.clone = function () {
- var def = _super.prototype.clone.call(this);
- def.dateProfile = this.dateProfile;
- return def;
- };
- SingleEventDef.prototype.rezone = function () {
- var calendar = this.source.calendar;
- var dateProfile = this.dateProfile;
- this.dateProfile = new EventDateProfile_1.default(calendar.moment(dateProfile.start), dateProfile.end ? calendar.moment(dateProfile.end) : null, calendar);
+ Interaction.prototype.opt = function (name) {
+ return this.view.opt(name);
};
- /*
- NOTE: if super-method fails, should still attempt to apply
- */
- SingleEventDef.prototype.applyManualStandardProps = function (rawProps) {
- var superSuccess = _super.prototype.applyManualStandardProps.call(this, rawProps);
- var dateProfile = EventDateProfile_1.default.parse(rawProps, this.source); // returns null on failure
- if (dateProfile) {
- this.dateProfile = dateProfile;
- // make sure `date` shows up in the legacy event objects as-is
- if (rawProps.date != null) {
- this.miscProps.date = rawProps.date;
- }
- return superSuccess;
- }
- else {
- return false;
- }
+ Interaction.prototype.end = function () {
+ // subclasses can implement
};
- return SingleEventDef;
-}(EventDef_1.default));
-exports.default = SingleEventDef;
-// Parsing
-// ---------------------------------------------------------------------------------------------------------------------
-SingleEventDef.defineStandardProps({
- start: false,
- date: false,
- end: false,
- allDay: false
-});
+ return Interaction;
+}());
+exports.default = Interaction;
/***/ }),
-/* 14 */
+/* 15 */
/***/ (function(module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
@@ -1679,7 +1700,7 @@
Mixin.mixInto = function (destClass) {
var _this = this;
Object.getOwnPropertyNames(this.prototype).forEach(function (name) {
- if (!destClass.prototype[name]) {
+ if (!destClass.prototype[name]) { // if destination class doesn't already define it
destClass.prototype[name] = _this.prototype[name];
}
});
@@ -1700,32 +1721,262 @@
/***/ }),
-/* 15 */
-/***/ (function(module, exports) {
+/* 16 */
+/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
-var Interaction = /** @class */ (function () {
- function Interaction(component) {
- this.view = component._getView();
- this.component = component;
+var UnzonedRange_1 = __webpack_require__(5);
+/*
+Meant to be immutable
+*/
+var EventDateProfile = /** @class */ (function () {
+ function EventDateProfile(start, end, calendar) {
+ this.start = start;
+ this.end = end || null;
+ this.unzonedRange = this.buildUnzonedRange(calendar);
}
- Interaction.prototype.opt = function (name) {
- return this.view.opt(name);
+ /*
+ Needs an EventSource object
+ */
+ EventDateProfile.parse = function (rawProps, source) {
+ var startInput = rawProps.start || rawProps.date;
+ var endInput = rawProps.end;
+ if (!startInput) {
+ return false;
+ }
+ var calendar = source.calendar;
+ var start = calendar.moment(startInput);
+ var end = endInput ? calendar.moment(endInput) : null;
+ var forcedAllDay = rawProps.allDay;
+ var forceEventDuration = calendar.opt('forceEventDuration');
+ if (!start.isValid()) {
+ return false;
+ }
+ if (forcedAllDay == null) {
+ forcedAllDay = source.allDayDefault;
+ if (forcedAllDay == null) {
+ forcedAllDay = calendar.opt('allDayDefault');
+ }
+ }
+ if (forcedAllDay === true) {
+ start.stripTime();
+ if (end) {
+ end.stripTime();
+ }
+ }
+ else if (forcedAllDay === false) {
+ if (!start.hasTime()) {
+ start.time(0);
+ }
+ if (end && !end.hasTime()) {
+ end.time(0);
+ }
+ }
+ if (end && (!end.isValid() || !end.isAfter(start))) {
+ end = null;
+ }
+ if (!end && forceEventDuration) {
+ end = calendar.getDefaultEventEnd(!start.hasTime(), start);
+ }
+ return new EventDateProfile(start, end, calendar);
};
- Interaction.prototype.end = function () {
- // subclasses can implement
+ EventDateProfile.isStandardProp = function (propName) {
+ return propName === 'start' || propName === 'date' || propName === 'end' || propName === 'allDay';
};
- return Interaction;
+ EventDateProfile.prototype.isAllDay = function () {
+ return !(this.start.hasTime() || (this.end && this.end.hasTime()));
+ };
+ /*
+ Needs a Calendar object
+ */
+ EventDateProfile.prototype.buildUnzonedRange = function (calendar) {
+ var startMs = this.start.clone().stripZone().valueOf();
+ var endMs = this.getEnd(calendar).stripZone().valueOf();
+ return new UnzonedRange_1.default(startMs, endMs);
+ };
+ /*
+ Needs a Calendar object
+ */
+ EventDateProfile.prototype.getEnd = function (calendar) {
+ return this.end ?
+ this.end.clone() :
+ // derive the end from the start and allDay. compute allDay if necessary
+ calendar.getDefaultEventEnd(this.isAllDay(), this.start);
+ };
+ return EventDateProfile;
}());
-exports.default = Interaction;
+exports.default = EventDateProfile;
/***/ }),
-/* 16 */
+/* 17 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
-exports.version = '3.9.0';
+var tslib_1 = __webpack_require__(2);
+var util_1 = __webpack_require__(4);
+var DragListener_1 = __webpack_require__(59);
+/* Tracks mouse movements over a component and raises events about which hit the mouse is over.
+------------------------------------------------------------------------------------------------------------------------
+options:
+- subjectEl
+- subjectCenter
+*/
+var HitDragListener = /** @class */ (function (_super) {
+ tslib_1.__extends(HitDragListener, _super);
+ function HitDragListener(component, options) {
+ var _this = _super.call(this, options) || this;
+ _this.component = component;
+ return _this;
+ }
+ // Called when drag listening starts (but a real drag has not necessarily began).
+ // ev might be undefined if dragging was started manually.
+ HitDragListener.prototype.handleInteractionStart = function (ev) {
+ var subjectEl = this.subjectEl;
+ var subjectRect;
+ var origPoint;
+ var point;
+ this.component.hitsNeeded();
+ this.computeScrollBounds(); // for autoscroll
+ if (ev) {
+ origPoint = { left: util_1.getEvX(ev), top: util_1.getEvY(ev) };
+ point = origPoint;
+ // constrain the point to bounds of the element being dragged
+ if (subjectEl) {
+ subjectRect = util_1.getOuterRect(subjectEl); // used for centering as well
+ point = util_1.constrainPoint(point, subjectRect);
+ }
+ this.origHit = this.queryHit(point.left, point.top);
+ // treat the center of the subject as the collision point?
+ if (subjectEl && this.options.subjectCenter) {
+ // only consider the area the subject overlaps the hit. best for large subjects.
+ // TODO: skip this if hit didn't supply left/right/top/bottom
+ if (this.origHit) {
+ subjectRect = util_1.intersectRects(this.origHit, subjectRect) ||
+ subjectRect; // in case there is no intersection
+ }
+ point = util_1.getRectCenter(subjectRect);
+ }
+ this.coordAdjust = util_1.diffPoints(point, origPoint); // point - origPoint
+ }
+ else {
+ this.origHit = null;
+ this.coordAdjust = null;
+ }
+ // call the super-method. do it after origHit has been computed
+ _super.prototype.handleInteractionStart.call(this, ev);
+ };
+ // Called when the actual drag has started
+ HitDragListener.prototype.handleDragStart = function (ev) {
+ var hit;
+ _super.prototype.handleDragStart.call(this, ev);
+ // might be different from this.origHit if the min-distance is large
+ hit = this.queryHit(util_1.getEvX(ev), util_1.getEvY(ev));
+ // report the initial hit the mouse is over
+ // especially important if no min-distance and drag starts immediately
+ if (hit) {
+ this.handleHitOver(hit);
+ }
+ };
+ // Called when the drag moves
+ HitDragListener.prototype.handleDrag = function (dx, dy, ev) {
+ var hit;
+ _super.prototype.handleDrag.call(this, dx, dy, ev);
+ hit = this.queryHit(util_1.getEvX(ev), util_1.getEvY(ev));
+ if (!isHitsEqual(hit, this.hit)) { // a different hit than before?
+ if (this.hit) {
+ this.handleHitOut();
+ }
+ if (hit) {
+ this.handleHitOver(hit);
+ }
+ }
+ };
+ // Called when dragging has been stopped
+ HitDragListener.prototype.handleDragEnd = function (ev) {
+ this.handleHitDone();
+ _super.prototype.handleDragEnd.call(this, ev);
+ };
+ // Called when a the mouse has just moved over a new hit
+ HitDragListener.prototype.handleHitOver = function (hit) {
+ var isOrig = isHitsEqual(hit, this.origHit);
+ this.hit = hit;
+ this.trigger('hitOver', this.hit, isOrig, this.origHit);
+ };
+ // Called when the mouse has just moved out of a hit
+ HitDragListener.prototype.handleHitOut = function () {
+ if (this.hit) {
+ this.trigger('hitOut', this.hit);
+ this.handleHitDone();
+ this.hit = null;
+ }
+ };
+ // Called after a hitOut. Also called before a dragStop
+ HitDragListener.prototype.handleHitDone = function () {
+ if (this.hit) {
+ this.trigger('hitDone', this.hit);
+ }
+ };
+ // Called when the interaction ends, whether there was a real drag or not
+ HitDragListener.prototype.handleInteractionEnd = function (ev, isCancelled) {
+ _super.prototype.handleInteractionEnd.call(this, ev, isCancelled);
+ this.origHit = null;
+ this.hit = null;
+ this.component.hitsNotNeeded();
+ };
+ // Called when scrolling has stopped, whether through auto scroll, or the user scrolling
+ HitDragListener.prototype.handleScrollEnd = function () {
+ _super.prototype.handleScrollEnd.call(this);
+ // hits' absolute positions will be in new places after a user's scroll.
+ // HACK for recomputing.
+ if (this.isDragging) {
+ this.component.releaseHits();
+ this.component.prepareHits();
+ }
+ };
+ // Gets the hit underneath the coordinates for the given mouse event
+ HitDragListener.prototype.queryHit = function (left, top) {
+ if (this.coordAdjust) {
+ left += this.coordAdjust.left;
+ top += this.coordAdjust.top;
+ }
+ return this.component.queryHit(left, top);
+ };
+ return HitDragListener;
+}(DragListener_1.default));
+exports.default = HitDragListener;
+// Returns `true` if the hits are identically equal. `false` otherwise. Must be from the same component.
+// Two null values will be considered equal, as two "out of the component" states are the same.
+function isHitsEqual(hit0, hit1) {
+ if (!hit0 && !hit1) {
+ return true;
+ }
+ if (hit0 && hit1) {
+ return hit0.component === hit1.component &&
+ isHitPropsWithin(hit0, hit1) &&
+ isHitPropsWithin(hit1, hit0); // ensures all props are identical
+ }
+ return false;
+}
+// Returns true if all of subHit's non-standard properties are within superHit
+function isHitPropsWithin(subHit, superHit) {
+ for (var propName in subHit) {
+ if (!/^(component|left|right|top|bottom)$/.test(propName)) {
+ if (subHit[propName] !== superHit[propName]) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+/***/ }),
+/* 18 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.version = '3.10.2';
// When introducing internal API incompatibilities (where fullcalendar plugins would break),
// the minor version of the calendar should be upped (ex: 2.7.2 -> 2.8.0)
// and the below integer should be incremented.
@@ -1756,210 +2007,259 @@
exports.warn = util_1.warn;
exports.removeExact = util_1.removeExact;
exports.intersectRects = util_1.intersectRects;
-var date_formatting_1 = __webpack_require__(47);
+exports.allowSelection = util_1.allowSelection;
+exports.attrsToStr = util_1.attrsToStr;
+exports.compareNumbers = util_1.compareNumbers;
+exports.compensateScroll = util_1.compensateScroll;
+exports.computeDurationGreatestUnit = util_1.computeDurationGreatestUnit;
+exports.constrainPoint = util_1.constrainPoint;
+exports.copyOwnProps = util_1.copyOwnProps;
+exports.diffByUnit = util_1.diffByUnit;
+exports.diffDay = util_1.diffDay;
+exports.diffDayTime = util_1.diffDayTime;
+exports.diffPoints = util_1.diffPoints;
+exports.disableCursor = util_1.disableCursor;
+exports.distributeHeight = util_1.distributeHeight;
+exports.enableCursor = util_1.enableCursor;
+exports.firstDefined = util_1.firstDefined;
+exports.getEvIsTouch = util_1.getEvIsTouch;
+exports.getEvX = util_1.getEvX;
+exports.getEvY = util_1.getEvY;
+exports.getRectCenter = util_1.getRectCenter;
+exports.getScrollParent = util_1.getScrollParent;
+exports.hasOwnProp = util_1.hasOwnProp;
+exports.isArraysEqual = util_1.isArraysEqual;
+exports.isNativeDate = util_1.isNativeDate;
+exports.isPrimaryMouseButton = util_1.isPrimaryMouseButton;
+exports.isTimeString = util_1.isTimeString;
+exports.matchCellWidths = util_1.matchCellWidths;
+exports.mergeProps = util_1.mergeProps;
+exports.preventSelection = util_1.preventSelection;
+exports.removeMatching = util_1.removeMatching;
+exports.stripHtmlEntities = util_1.stripHtmlEntities;
+exports.subtractInnerElHeight = util_1.subtractInnerElHeight;
+exports.uncompensateScroll = util_1.uncompensateScroll;
+exports.undistributeHeight = util_1.undistributeHeight;
+exports.dayIDs = util_1.dayIDs;
+exports.unitsDesc = util_1.unitsDesc;
+var date_formatting_1 = __webpack_require__(49);
exports.formatDate = date_formatting_1.formatDate;
exports.formatRange = date_formatting_1.formatRange;
exports.queryMostGranularFormatUnit = date_formatting_1.queryMostGranularFormatUnit;
-var locale_1 = __webpack_require__(31);
+var locale_1 = __webpack_require__(32);
exports.datepickerLocale = locale_1.datepickerLocale;
exports.locale = locale_1.locale;
-var moment_ext_1 = __webpack_require__(10);
+exports.getMomentLocaleData = locale_1.getMomentLocaleData;
+exports.populateInstanceComputableOptions = locale_1.populateInstanceComputableOptions;
+var util_2 = __webpack_require__(19);
+exports.eventDefsToEventInstances = util_2.eventDefsToEventInstances;
+exports.eventFootprintToComponentFootprint = util_2.eventFootprintToComponentFootprint;
+exports.eventInstanceToEventRange = util_2.eventInstanceToEventRange;
+exports.eventInstanceToUnzonedRange = util_2.eventInstanceToUnzonedRange;
+exports.eventRangeToEventFootprint = util_2.eventRangeToEventFootprint;
+var moment_ext_1 = __webpack_require__(11);
exports.moment = moment_ext_1.default;
-var EmitterMixin_1 = __webpack_require__(11);
+var EmitterMixin_1 = __webpack_require__(13);
exports.EmitterMixin = EmitterMixin_1.default;
var ListenerMixin_1 = __webpack_require__(7);
exports.ListenerMixin = ListenerMixin_1.default;
-var Model_1 = __webpack_require__(48);
+var Model_1 = __webpack_require__(51);
exports.Model = Model_1.default;
-var Constraints_1 = __webpack_require__(207);
+var Constraints_1 = __webpack_require__(217);
exports.Constraints = Constraints_1.default;
+var DateProfileGenerator_1 = __webpack_require__(55);
+exports.DateProfileGenerator = DateProfileGenerator_1.default;
var UnzonedRange_1 = __webpack_require__(5);
exports.UnzonedRange = UnzonedRange_1.default;
var ComponentFootprint_1 = __webpack_require__(12);
exports.ComponentFootprint = ComponentFootprint_1.default;
-var BusinessHourGenerator_1 = __webpack_require__(212);
+var BusinessHourGenerator_1 = __webpack_require__(218);
exports.BusinessHourGenerator = BusinessHourGenerator_1.default;
-var EventDef_1 = __webpack_require__(34);
+var EventPeriod_1 = __webpack_require__(219);
+exports.EventPeriod = EventPeriod_1.default;
+var EventManager_1 = __webpack_require__(220);
+exports.EventManager = EventManager_1.default;
+var EventDef_1 = __webpack_require__(37);
exports.EventDef = EventDef_1.default;
-var EventDefMutation_1 = __webpack_require__(37);
+var EventDefMutation_1 = __webpack_require__(39);
exports.EventDefMutation = EventDefMutation_1.default;
+var EventDefParser_1 = __webpack_require__(36);
+exports.EventDefParser = EventDefParser_1.default;
+var EventInstance_1 = __webpack_require__(53);
+exports.EventInstance = EventInstance_1.default;
+var EventRange_1 = __webpack_require__(50);
+exports.EventRange = EventRange_1.default;
+var RecurringEventDef_1 = __webpack_require__(54);
+exports.RecurringEventDef = RecurringEventDef_1.default;
+var SingleEventDef_1 = __webpack_require__(9);
+exports.SingleEventDef = SingleEventDef_1.default;
+var EventDefDateMutation_1 = __webpack_require__(40);
+exports.EventDefDateMutation = EventDefDateMutation_1.default;
+var EventDateProfile_1 = __webpack_require__(16);
+exports.EventDateProfile = EventDateProfile_1.default;
var EventSourceParser_1 = __webpack_require__(38);
exports.EventSourceParser = EventSourceParser_1.default;
var EventSource_1 = __webpack_require__(6);
exports.EventSource = EventSource_1.default;
-var ThemeRegistry_1 = __webpack_require__(51);
+var ThemeRegistry_1 = __webpack_require__(57);
exports.defineThemeSystem = ThemeRegistry_1.defineThemeSystem;
-var EventInstanceGroup_1 = __webpack_require__(18);
+exports.getThemeSystemClass = ThemeRegistry_1.getThemeSystemClass;
+var EventInstanceGroup_1 = __webpack_require__(20);
exports.EventInstanceGroup = EventInstanceGroup_1.default;
-var ArrayEventSource_1 = __webpack_require__(52);
+var ArrayEventSource_1 = __webpack_require__(56);
exports.ArrayEventSource = ArrayEventSource_1.default;
-var FuncEventSource_1 = __webpack_require__(215);
+var FuncEventSource_1 = __webpack_require__(223);
exports.FuncEventSource = FuncEventSource_1.default;
-var JsonFeedEventSource_1 = __webpack_require__(216);
+var JsonFeedEventSource_1 = __webpack_require__(224);
exports.JsonFeedEventSource = JsonFeedEventSource_1.default;
-var EventFootprint_1 = __webpack_require__(36);
+var EventFootprint_1 = __webpack_require__(34);
exports.EventFootprint = EventFootprint_1.default;
-var Class_1 = __webpack_require__(33);
+var Class_1 = __webpack_require__(35);
exports.Class = Class_1.default;
-var Mixin_1 = __webpack_require__(14);
+var Mixin_1 = __webpack_require__(15);
exports.Mixin = Mixin_1.default;
-var CoordCache_1 = __webpack_require__(53);
+var CoordCache_1 = __webpack_require__(58);
exports.CoordCache = CoordCache_1.default;
-var DragListener_1 = __webpack_require__(54);
+var Iterator_1 = __webpack_require__(225);
+exports.Iterator = Iterator_1.default;
+var DragListener_1 = __webpack_require__(59);
exports.DragListener = DragListener_1.default;
-var Promise_1 = __webpack_require__(20);
+var HitDragListener_1 = __webpack_require__(17);
+exports.HitDragListener = HitDragListener_1.default;
+var MouseFollower_1 = __webpack_require__(226);
+exports.MouseFollower = MouseFollower_1.default;
+var ParsableModelMixin_1 = __webpack_require__(52);
+exports.ParsableModelMixin = ParsableModelMixin_1.default;
+var Popover_1 = __webpack_require__(227);
+exports.Popover = Popover_1.default;
+var Promise_1 = __webpack_require__(21);
exports.Promise = Promise_1.default;
-var TaskQueue_1 = __webpack_require__(217);
+var TaskQueue_1 = __webpack_require__(228);
exports.TaskQueue = TaskQueue_1.default;
-var RenderQueue_1 = __webpack_require__(218);
+var RenderQueue_1 = __webpack_require__(229);
exports.RenderQueue = RenderQueue_1.default;
-var Scroller_1 = __webpack_require__(39);
+var Scroller_1 = __webpack_require__(41);
exports.Scroller = Scroller_1.default;
-var Theme_1 = __webpack_require__(19);
+var Theme_1 = __webpack_require__(22);
exports.Theme = Theme_1.default;
-var DateComponent_1 = __webpack_require__(219);
+var Component_1 = __webpack_require__(230);
+exports.Component = Component_1.default;
+var DateComponent_1 = __webpack_require__(231);
exports.DateComponent = DateComponent_1.default;
-var InteractiveDateComponent_1 = __webpack_require__(40);
+var InteractiveDateComponent_1 = __webpack_require__(42);
exports.InteractiveDateComponent = InteractiveDateComponent_1.default;
-var Calendar_1 = __webpack_require__(220);
+var Calendar_1 = __webpack_require__(232);
exports.Calendar = Calendar_1.default;
-var View_1 = __webpack_require__(41);
+var View_1 = __webpack_require__(43);
exports.View = View_1.default;
-var ViewRegistry_1 = __webpack_require__(22);
+var ViewRegistry_1 = __webpack_require__(24);
exports.defineView = ViewRegistry_1.defineView;
exports.getViewConfig = ViewRegistry_1.getViewConfig;
-var DayTableMixin_1 = __webpack_require__(55);
+var DayTableMixin_1 = __webpack_require__(60);
exports.DayTableMixin = DayTableMixin_1.default;
-var BusinessHourRenderer_1 = __webpack_require__(56);
+var BusinessHourRenderer_1 = __webpack_require__(61);
exports.BusinessHourRenderer = BusinessHourRenderer_1.default;
-var EventRenderer_1 = __webpack_require__(42);
+var EventRenderer_1 = __webpack_require__(44);
exports.EventRenderer = EventRenderer_1.default;
-var FillRenderer_1 = __webpack_require__(57);
+var FillRenderer_1 = __webpack_require__(62);
exports.FillRenderer = FillRenderer_1.default;
-var HelperRenderer_1 = __webpack_require__(58);
+var HelperRenderer_1 = __webpack_require__(63);
exports.HelperRenderer = HelperRenderer_1.default;
-var ExternalDropping_1 = __webpack_require__(222);
+var ExternalDropping_1 = __webpack_require__(233);
exports.ExternalDropping = ExternalDropping_1.default;
-var EventResizing_1 = __webpack_require__(223);
+var EventResizing_1 = __webpack_require__(234);
exports.EventResizing = EventResizing_1.default;
-var EventPointing_1 = __webpack_require__(59);
+var EventPointing_1 = __webpack_require__(64);
exports.EventPointing = EventPointing_1.default;
-var EventDragging_1 = __webpack_require__(224);
+var EventDragging_1 = __webpack_require__(235);
exports.EventDragging = EventDragging_1.default;
-var DateSelecting_1 = __webpack_require__(225);
+var DateSelecting_1 = __webpack_require__(236);
exports.DateSelecting = DateSelecting_1.default;
-var StandardInteractionsMixin_1 = __webpack_require__(60);
+var DateClicking_1 = __webpack_require__(237);
+exports.DateClicking = DateClicking_1.default;
+var Interaction_1 = __webpack_require__(14);
+exports.Interaction = Interaction_1.default;
+var StandardInteractionsMixin_1 = __webpack_require__(65);
exports.StandardInteractionsMixin = StandardInteractionsMixin_1.default;
-var AgendaView_1 = __webpack_require__(226);
+var AgendaView_1 = __webpack_require__(238);
exports.AgendaView = AgendaView_1.default;
-var TimeGrid_1 = __webpack_require__(227);
+var TimeGrid_1 = __webpack_require__(239);
exports.TimeGrid = TimeGrid_1.default;
-var DayGrid_1 = __webpack_require__(61);
+var TimeGridEventRenderer_1 = __webpack_require__(240);
+exports.TimeGridEventRenderer = TimeGridEventRenderer_1.default;
+var TimeGridFillRenderer_1 = __webpack_require__(242);
+exports.TimeGridFillRenderer = TimeGridFillRenderer_1.default;
+var TimeGridHelperRenderer_1 = __webpack_require__(241);
+exports.TimeGridHelperRenderer = TimeGridHelperRenderer_1.default;
+var DayGrid_1 = __webpack_require__(66);
exports.DayGrid = DayGrid_1.default;
-var BasicView_1 = __webpack_require__(62);
+var DayGridEventRenderer_1 = __webpack_require__(243);
+exports.DayGridEventRenderer = DayGridEventRenderer_1.default;
+var DayGridFillRenderer_1 = __webpack_require__(245);
+exports.DayGridFillRenderer = DayGridFillRenderer_1.default;
+var DayGridHelperRenderer_1 = __webpack_require__(244);
+exports.DayGridHelperRenderer = DayGridHelperRenderer_1.default;
+var BasicView_1 = __webpack_require__(67);
exports.BasicView = BasicView_1.default;
-var MonthView_1 = __webpack_require__(229);
+var BasicViewDateProfileGenerator_1 = __webpack_require__(68);
+exports.BasicViewDateProfileGenerator = BasicViewDateProfileGenerator_1.default;
+var MonthView_1 = __webpack_require__(246);
exports.MonthView = MonthView_1.default;
-var ListView_1 = __webpack_require__(230);
+var MonthViewDateProfileGenerator_1 = __webpack_require__(247);
+exports.MonthViewDateProfileGenerator = MonthViewDateProfileGenerator_1.default;
+var ListView_1 = __webpack_require__(248);
exports.ListView = ListView_1.default;
+var ListEventPointing_1 = __webpack_require__(250);
+exports.ListEventPointing = ListEventPointing_1.default;
+var ListEventRenderer_1 = __webpack_require__(249);
+exports.ListEventRenderer = ListEventRenderer_1.default;
/***/ }),
-/* 17 */
+/* 19 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
-var UnzonedRange_1 = __webpack_require__(5);
-/*
-Meant to be immutable
-*/
-var EventDateProfile = /** @class */ (function () {
- function EventDateProfile(start, end, calendar) {
- this.start = start;
- this.end = end || null;
- this.unzonedRange = this.buildUnzonedRange(calendar);
+var EventRange_1 = __webpack_require__(50);
+var EventFootprint_1 = __webpack_require__(34);
+var ComponentFootprint_1 = __webpack_require__(12);
+function eventDefsToEventInstances(eventDefs, unzonedRange) {
+ var eventInstances = [];
+ var i;
+ for (i = 0; i < eventDefs.length; i++) {
+ eventInstances.push.apply(eventInstances, // append
+ eventDefs[i].buildInstances(unzonedRange));
}
- /*
- Needs an EventSource object
- */
- EventDateProfile.parse = function (rawProps, source) {
- var startInput = rawProps.start || rawProps.date;
- var endInput = rawProps.end;
- if (!startInput) {
- return false;
- }
- var calendar = source.calendar;
- var start = calendar.moment(startInput);
- var end = endInput ? calendar.moment(endInput) : null;
- var forcedAllDay = rawProps.allDay;
- var forceEventDuration = calendar.opt('forceEventDuration');
- if (!start.isValid()) {
- return false;
- }
- if (end && (!end.isValid() || !end.isAfter(start))) {
- end = null;
- }
- if (forcedAllDay == null) {
- forcedAllDay = source.allDayDefault;
- if (forcedAllDay == null) {
- forcedAllDay = calendar.opt('allDayDefault');
- }
- }
- if (forcedAllDay === true) {
- start.stripTime();
- if (end) {
- end.stripTime();
- }
- }
- else if (forcedAllDay === false) {
- if (!start.hasTime()) {
- start.time(0);
- }
- if (end && !end.hasTime()) {
- end.time(0);
- }
- }
- if (!end && forceEventDuration) {
- end = calendar.getDefaultEventEnd(!start.hasTime(), start);
- }
- return new EventDateProfile(start, end, calendar);
- };
- EventDateProfile.isStandardProp = function (propName) {
- return propName === 'start' || propName === 'date' || propName === 'end' || propName === 'allDay';
- };
- EventDateProfile.prototype.isAllDay = function () {
- return !(this.start.hasTime() || (this.end && this.end.hasTime()));
- };
- /*
- Needs a Calendar object
- */
- EventDateProfile.prototype.buildUnzonedRange = function (calendar) {
- var startMs = this.start.clone().stripZone().valueOf();
- var endMs = this.getEnd(calendar).stripZone().valueOf();
- return new UnzonedRange_1.default(startMs, endMs);
- };
- /*
- Needs a Calendar object
- */
- EventDateProfile.prototype.getEnd = function (calendar) {
- return this.end ?
- this.end.clone() :
- // derive the end from the start and allDay. compute allDay if necessary
- calendar.getDefaultEventEnd(this.isAllDay(), this.start);
- };
- return EventDateProfile;
-}());
-exports.default = EventDateProfile;
+ return eventInstances;
+}
+exports.eventDefsToEventInstances = eventDefsToEventInstances;
+function eventInstanceToEventRange(eventInstance) {
+ return new EventRange_1.default(eventInstance.dateProfile.unzonedRange, eventInstance.def, eventInstance);
+}
+exports.eventInstanceToEventRange = eventInstanceToEventRange;
+function eventRangeToEventFootprint(eventRange) {
+ return new EventFootprint_1.default(new ComponentFootprint_1.default(eventRange.unzonedRange, eventRange.eventDef.isAllDay()), eventRange.eventDef, eventRange.eventInstance // might not exist
+ );
+}
+exports.eventRangeToEventFootprint = eventRangeToEventFootprint;
+function eventInstanceToUnzonedRange(eventInstance) {
+ return eventInstance.dateProfile.unzonedRange;
+}
+exports.eventInstanceToUnzonedRange = eventInstanceToUnzonedRange;
+function eventFootprintToComponentFootprint(eventFootprint) {
+ return eventFootprint.componentFootprint;
+}
+exports.eventFootprintToComponentFootprint = eventFootprintToComponentFootprint;
/***/ }),
-/* 18 */
+/* 20 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var UnzonedRange_1 = __webpack_require__(5);
-var util_1 = __webpack_require__(35);
-var EventRange_1 = __webpack_require__(211);
+var util_1 = __webpack_require__(19);
+var EventRange_1 = __webpack_require__(50);
/*
It's expected that there will be at least one EventInstance,
OR that an explicitEventDef is assigned.
@@ -2019,7 +2319,60 @@
/***/ }),
-/* 19 */
+/* 21 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var PromiseStub = {
+ construct: function (executor) {
+ var deferred = $.Deferred();
+ var promise = deferred.promise();
+ if (typeof executor === 'function') {
+ executor(function (val) {
+ deferred.resolve(val);
+ attachImmediatelyResolvingThen(promise, val);
+ }, function () {
+ deferred.reject();
+ attachImmediatelyRejectingThen(promise);
+ });
+ }
+ return promise;
+ },
+ resolve: function (val) {
+ var deferred = $.Deferred().resolve(val);
+ var promise = deferred.promise();
+ attachImmediatelyResolvingThen(promise, val);
+ return promise;
+ },
+ reject: function () {
+ var deferred = $.Deferred().reject();
+ var promise = deferred.promise();
+ attachImmediatelyRejectingThen(promise);
+ return promise;
+ }
+};
+exports.default = PromiseStub;
+function attachImmediatelyResolvingThen(promise, val) {
+ promise.then = function (onResolve) {
+ if (typeof onResolve === 'function') {
+ return PromiseStub.resolve(onResolve(val));
+ }
+ return promise;
+ };
+}
+function attachImmediatelyRejectingThen(promise) {
+ promise.then = function (onResolve, onReject) {
+ if (typeof onReject === 'function') {
+ onReject();
+ }
+ return promise;
+ };
+}
+
+
+/***/ }),
+/* 22 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
@@ -2050,7 +2403,7 @@
};
Theme.prototype.applyIconOverridePrefix = function (className) {
var prefix = this.iconOverridePrefix;
- if (prefix && className.indexOf(prefix) !== 0) {
+ if (prefix && className.indexOf(prefix) !== 0) { // if not already present
className = prefix + className;
}
return className;
@@ -2085,66 +2438,13 @@
/***/ }),
-/* 20 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var $ = __webpack_require__(3);
-var PromiseStub = {
- construct: function (executor) {
- var deferred = $.Deferred();
- var promise = deferred.promise();
- if (typeof executor === 'function') {
- executor(function (val) {
- deferred.resolve(val);
- attachImmediatelyResolvingThen(promise, val);
- }, function () {
- deferred.reject();
- attachImmediatelyRejectingThen(promise);
- });
- }
- return promise;
- },
- resolve: function (val) {
- var deferred = $.Deferred().resolve(val);
- var promise = deferred.promise();
- attachImmediatelyResolvingThen(promise, val);
- return promise;
- },
- reject: function () {
- var deferred = $.Deferred().reject();
- var promise = deferred.promise();
- attachImmediatelyRejectingThen(promise);
- return promise;
- }
-};
-exports.default = PromiseStub;
-function attachImmediatelyResolvingThen(promise, val) {
- promise.then = function (onResolve) {
- if (typeof onResolve === 'function') {
- return PromiseStub.resolve(onResolve(val));
- }
- return promise;
- };
-}
-function attachImmediatelyRejectingThen(promise) {
- promise.then = function (onResolve, onReject) {
- if (typeof onReject === 'function') {
- onReject();
- }
- return promise;
- };
-}
-
-
-/***/ }),
-/* 21 */
+/* 23 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var $ = __webpack_require__(3);
-var exportHooks = __webpack_require__(16);
-var EmitterMixin_1 = __webpack_require__(11);
+var exportHooks = __webpack_require__(18);
+var EmitterMixin_1 = __webpack_require__(13);
var ListenerMixin_1 = __webpack_require__(7);
exportHooks.touchMouseIgnoreWait = 500;
var globalEmitter = null;
@@ -2179,7 +2479,7 @@
// called when the object that originally called needed() doesn't need a GlobalEmitter anymore.
GlobalEmitter.unneeded = function () {
neededCount--;
- if (!neededCount) {
+ if (!neededCount) { // nobody else needs it
globalEmitter.unbind();
globalEmitter = null;
}
@@ -2214,7 +2514,8 @@
};
GlobalEmitter.prototype.unbind = function () {
this.stopListeningTo($(document));
- window.removeEventListener('touchmove', this.handleTouchMoveProxy);
+ window.removeEventListener('touchmove', this.handleTouchMoveProxy, { passive: false } // use same options as addEventListener
+ );
window.removeEventListener('scroll', this.handleScrollProxy, true // useCapture
);
};
@@ -2309,11 +2610,11 @@
/***/ }),
-/* 22 */
+/* 24 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
-var exportHooks = __webpack_require__(16);
+var exportHooks = __webpack_require__(18);
exports.viewHash = {};
exportHooks.views = exports.viewHash;
function defineView(viewName, viewConfig) {
@@ -2327,184 +2628,21 @@
/***/ }),
-/* 23 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var tslib_1 = __webpack_require__(2);
-var util_1 = __webpack_require__(4);
-var DragListener_1 = __webpack_require__(54);
-/* Tracks mouse movements over a component and raises events about which hit the mouse is over.
-------------------------------------------------------------------------------------------------------------------------
-options:
-- subjectEl
-- subjectCenter
-*/
-var HitDragListener = /** @class */ (function (_super) {
- tslib_1.__extends(HitDragListener, _super);
- function HitDragListener(component, options) {
- var _this = _super.call(this, options) || this;
- _this.component = component;
- return _this;
- }
- // Called when drag listening starts (but a real drag has not necessarily began).
- // ev might be undefined if dragging was started manually.
- HitDragListener.prototype.handleInteractionStart = function (ev) {
- var subjectEl = this.subjectEl;
- var subjectRect;
- var origPoint;
- var point;
- this.component.hitsNeeded();
- this.computeScrollBounds(); // for autoscroll
- if (ev) {
- origPoint = { left: util_1.getEvX(ev), top: util_1.getEvY(ev) };
- point = origPoint;
- // constrain the point to bounds of the element being dragged
- if (subjectEl) {
- subjectRect = util_1.getOuterRect(subjectEl); // used for centering as well
- point = util_1.constrainPoint(point, subjectRect);
- }
- this.origHit = this.queryHit(point.left, point.top);
- // treat the center of the subject as the collision point?
- if (subjectEl && this.options.subjectCenter) {
- // only consider the area the subject overlaps the hit. best for large subjects.
- // TODO: skip this if hit didn't supply left/right/top/bottom
- if (this.origHit) {
- subjectRect = util_1.intersectRects(this.origHit, subjectRect) ||
- subjectRect; // in case there is no intersection
- }
- point = util_1.getRectCenter(subjectRect);
- }
- this.coordAdjust = util_1.diffPoints(point, origPoint); // point - origPoint
- }
- else {
- this.origHit = null;
- this.coordAdjust = null;
- }
- // call the super-method. do it after origHit has been computed
- _super.prototype.handleInteractionStart.call(this, ev);
- };
- // Called when the actual drag has started
- HitDragListener.prototype.handleDragStart = function (ev) {
- var hit;
- _super.prototype.handleDragStart.call(this, ev);
- // might be different from this.origHit if the min-distance is large
- hit = this.queryHit(util_1.getEvX(ev), util_1.getEvY(ev));
- // report the initial hit the mouse is over
- // especially important if no min-distance and drag starts immediately
- if (hit) {
- this.handleHitOver(hit);
- }
- };
- // Called when the drag moves
- HitDragListener.prototype.handleDrag = function (dx, dy, ev) {
- var hit;
- _super.prototype.handleDrag.call(this, dx, dy, ev);
- hit = this.queryHit(util_1.getEvX(ev), util_1.getEvY(ev));
- if (!isHitsEqual(hit, this.hit)) {
- if (this.hit) {
- this.handleHitOut();
- }
- if (hit) {
- this.handleHitOver(hit);
- }
- }
- };
- // Called when dragging has been stopped
- HitDragListener.prototype.handleDragEnd = function (ev) {
- this.handleHitDone();
- _super.prototype.handleDragEnd.call(this, ev);
- };
- // Called when a the mouse has just moved over a new hit
- HitDragListener.prototype.handleHitOver = function (hit) {
- var isOrig = isHitsEqual(hit, this.origHit);
- this.hit = hit;
- this.trigger('hitOver', this.hit, isOrig, this.origHit);
- };
- // Called when the mouse has just moved out of a hit
- HitDragListener.prototype.handleHitOut = function () {
- if (this.hit) {
- this.trigger('hitOut', this.hit);
- this.handleHitDone();
- this.hit = null;
- }
- };
- // Called after a hitOut. Also called before a dragStop
- HitDragListener.prototype.handleHitDone = function () {
- if (this.hit) {
- this.trigger('hitDone', this.hit);
- }
- };
- // Called when the interaction ends, whether there was a real drag or not
- HitDragListener.prototype.handleInteractionEnd = function (ev, isCancelled) {
- _super.prototype.handleInteractionEnd.call(this, ev, isCancelled);
- this.origHit = null;
- this.hit = null;
- this.component.hitsNotNeeded();
- };
- // Called when scrolling has stopped, whether through auto scroll, or the user scrolling
- HitDragListener.prototype.handleScrollEnd = function () {
- _super.prototype.handleScrollEnd.call(this);
- // hits' absolute positions will be in new places after a user's scroll.
- // HACK for recomputing.
- if (this.isDragging) {
- this.component.releaseHits();
- this.component.prepareHits();
- }
- };
- // Gets the hit underneath the coordinates for the given mouse event
- HitDragListener.prototype.queryHit = function (left, top) {
- if (this.coordAdjust) {
- left += this.coordAdjust.left;
- top += this.coordAdjust.top;
- }
- return this.component.queryHit(left, top);
- };
- return HitDragListener;
-}(DragListener_1.default));
-exports.default = HitDragListener;
-// Returns `true` if the hits are identically equal. `false` otherwise. Must be from the same component.
-// Two null values will be considered equal, as two "out of the component" states are the same.
-function isHitsEqual(hit0, hit1) {
- if (!hit0 && !hit1) {
- return true;
- }
- if (hit0 && hit1) {
- return hit0.component === hit1.component &&
- isHitPropsWithin(hit0, hit1) &&
- isHitPropsWithin(hit1, hit0); // ensures all props are identical
- }
- return false;
-}
-// Returns true if all of subHit's non-standard properties are within superHit
-function isHitPropsWithin(subHit, superHit) {
- for (var propName in subHit) {
- if (!/^(component|left|right|top|bottom)$/.test(propName)) {
- if (subHit[propName] !== superHit[propName]) {
- return false;
- }
- }
- }
- return true;
-}
-
-
-/***/ }),
-/* 24 */,
/* 25 */,
/* 26 */,
/* 27 */,
/* 28 */,
/* 29 */,
/* 30 */,
-/* 31 */
+/* 31 */,
+/* 32 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var $ = __webpack_require__(3);
var moment = __webpack_require__(0);
-var exportHooks = __webpack_require__(16);
-var options_1 = __webpack_require__(32);
+var exportHooks = __webpack_require__(18);
+var options_1 = __webpack_require__(33);
var util_1 = __webpack_require__(4);
exports.localeOptionHash = {};
exportHooks.locales = exports.localeOptionHash;
@@ -2667,7 +2805,7 @@
/***/ }),
-/* 32 */
+/* 33 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
@@ -2781,7 +2919,28 @@
/***/ }),
-/* 33 */
+/* 34 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var EventFootprint = /** @class */ (function () {
+ function EventFootprint(componentFootprint, eventDef, eventInstance) {
+ this.componentFootprint = componentFootprint;
+ this.eventDef = eventDef;
+ if (eventInstance) {
+ this.eventInstance = eventInstance;
+ }
+ }
+ EventFootprint.prototype.getEventLegacy = function () {
+ return (this.eventInstance || this.eventDef).toLegacy();
+ };
+ return EventFootprint;
+}());
+exports.default = EventFootprint;
+
+
+/***/ }),
+/* 35 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
@@ -2815,12 +2974,34 @@
/***/ }),
-/* 34 */
+/* 36 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var moment = __webpack_require__(0);
+var util_1 = __webpack_require__(4);
+var SingleEventDef_1 = __webpack_require__(9);
+var RecurringEventDef_1 = __webpack_require__(54);
+exports.default = {
+ parse: function (eventInput, source) {
+ if (util_1.isTimeString(eventInput.start) || moment.isDuration(eventInput.start) ||
+ util_1.isTimeString(eventInput.end) || moment.isDuration(eventInput.end)) {
+ return RecurringEventDef_1.default.parse(eventInput, source);
+ }
+ else {
+ return SingleEventDef_1.default.parse(eventInput, source);
+ }
+ }
+};
+
+
+/***/ }),
+/* 37 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var $ = __webpack_require__(3);
-var ParsableModelMixin_1 = __webpack_require__(208);
+var ParsableModelMixin_1 = __webpack_require__(52);
var EventDef = /** @class */ (function () {
function EventDef(source) {
this.source = source;
@@ -2918,7 +3099,7 @@
else {
this.id = EventDef.generateId();
}
- if (rawProps._id != null) {
+ if (rawProps._id != null) { // accept this prop, even tho somewhat internal
this.uid = String(rawProps._id);
}
else {
@@ -2966,73 +3147,39 @@
/***/ }),
-/* 35 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var EventRange_1 = __webpack_require__(211);
-var EventFootprint_1 = __webpack_require__(36);
-var ComponentFootprint_1 = __webpack_require__(12);
-function eventDefsToEventInstances(eventDefs, unzonedRange) {
- var eventInstances = [];
- var i;
- for (i = 0; i < eventDefs.length; i++) {
- eventInstances.push.apply(eventInstances, // append
- eventDefs[i].buildInstances(unzonedRange));
- }
- return eventInstances;
-}
-exports.eventDefsToEventInstances = eventDefsToEventInstances;
-function eventInstanceToEventRange(eventInstance) {
- return new EventRange_1.default(eventInstance.dateProfile.unzonedRange, eventInstance.def, eventInstance);
-}
-exports.eventInstanceToEventRange = eventInstanceToEventRange;
-function eventRangeToEventFootprint(eventRange) {
- return new EventFootprint_1.default(new ComponentFootprint_1.default(eventRange.unzonedRange, eventRange.eventDef.isAllDay()), eventRange.eventDef, eventRange.eventInstance // might not exist
- );
-}
-exports.eventRangeToEventFootprint = eventRangeToEventFootprint;
-function eventInstanceToUnzonedRange(eventInstance) {
- return eventInstance.dateProfile.unzonedRange;
-}
-exports.eventInstanceToUnzonedRange = eventInstanceToUnzonedRange;
-function eventFootprintToComponentFootprint(eventFootprint) {
- return eventFootprint.componentFootprint;
-}
-exports.eventFootprintToComponentFootprint = eventFootprintToComponentFootprint;
-
-
-/***/ }),
-/* 36 */
+/* 38 */
/***/ (function(module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
-var EventFootprint = /** @class */ (function () {
- function EventFootprint(componentFootprint, eventDef, eventInstance) {
- this.componentFootprint = componentFootprint;
- this.eventDef = eventDef;
- if (eventInstance) {
- this.eventInstance = eventInstance;
+exports.default = {
+ sourceClasses: [],
+ registerClass: function (EventSourceClass) {
+ this.sourceClasses.unshift(EventSourceClass); // give highest priority
+ },
+ parse: function (rawInput, calendar) {
+ var sourceClasses = this.sourceClasses;
+ var i;
+ var eventSource;
+ for (i = 0; i < sourceClasses.length; i++) {
+ eventSource = sourceClasses[i].parse(rawInput, calendar);
+ if (eventSource) {
+ return eventSource;
+ }
}
}
- EventFootprint.prototype.getEventLegacy = function () {
- return (this.eventInstance || this.eventDef).toLegacy();
- };
- return EventFootprint;
-}());
-exports.default = EventFootprint;
+};
/***/ }),
-/* 37 */
+/* 39 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var util_1 = __webpack_require__(4);
-var EventDateProfile_1 = __webpack_require__(17);
-var EventDef_1 = __webpack_require__(34);
-var EventDefDateMutation_1 = __webpack_require__(50);
-var SingleEventDef_1 = __webpack_require__(13);
+var EventDateProfile_1 = __webpack_require__(16);
+var EventDef_1 = __webpack_require__(37);
+var EventDefDateMutation_1 = __webpack_require__(40);
+var SingleEventDef_1 = __webpack_require__(9);
var EventDefMutation = /** @class */ (function () {
function EventDefMutation() {
}
@@ -3055,12 +3202,12 @@
else if (eventDef.isStandardProp(propName)) {
standardProps[propName] = rawProps[propName];
}
- else if (eventDef.miscProps[propName] !== rawProps[propName]) {
+ else if (eventDef.miscProps[propName] !== rawProps[propName]) { // only if changed
miscProps[propName] = rawProps[propName];
}
}
dateProfile = EventDateProfile_1.default.parse(dateProps, eventDef.source);
- if (dateProfile) {
+ if (dateProfile) { // no failure?
dateMutation = EventDefDateMutation_1.default.createFromDiff(eventInstance.dateProfile, dateProfile, largeUnit);
}
if (standardProps.id !== eventDef.id) {
@@ -3138,38 +3285,152 @@
/***/ }),
-/* 38 */
-/***/ (function(module, exports) {
+/* 40 */
+/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
-exports.default = {
- sourceClasses: [],
- registerClass: function (EventSourceClass) {
- this.sourceClasses.unshift(EventSourceClass); // give highest priority
- },
- parse: function (rawInput, calendar) {
- var sourceClasses = this.sourceClasses;
- var i;
- var eventSource;
- for (i = 0; i < sourceClasses.length; i++) {
- eventSource = sourceClasses[i].parse(rawInput, calendar);
- if (eventSource) {
- return eventSource;
+var util_1 = __webpack_require__(4);
+var EventDateProfile_1 = __webpack_require__(16);
+var EventDefDateMutation = /** @class */ (function () {
+ function EventDefDateMutation() {
+ this.clearEnd = false;
+ this.forceTimed = false;
+ this.forceAllDay = false;
+ }
+ EventDefDateMutation.createFromDiff = function (dateProfile0, dateProfile1, largeUnit) {
+ var clearEnd = dateProfile0.end && !dateProfile1.end;
+ var forceTimed = dateProfile0.isAllDay() && !dateProfile1.isAllDay();
+ var forceAllDay = !dateProfile0.isAllDay() && dateProfile1.isAllDay();
+ var dateDelta;
+ var endDiff;
+ var endDelta;
+ var mutation;
+ // subtracts the dates in the appropriate way, returning a duration
+ function subtractDates(date1, date0) {
+ if (largeUnit) {
+ return util_1.diffByUnit(date1, date0, largeUnit); // poorly named
+ }
+ else if (dateProfile1.isAllDay()) {
+ return util_1.diffDay(date1, date0); // poorly named
+ }
+ else {
+ return util_1.diffDayTime(date1, date0); // poorly named
}
}
- }
-};
+ dateDelta = subtractDates(dateProfile1.start, dateProfile0.start);
+ if (dateProfile1.end) {
+ // use unzonedRanges because dateProfile0.end might be null
+ endDiff = subtractDates(dateProfile1.unzonedRange.getEnd(), dateProfile0.unzonedRange.getEnd());
+ endDelta = endDiff.subtract(dateDelta);
+ }
+ mutation = new EventDefDateMutation();
+ mutation.clearEnd = clearEnd;
+ mutation.forceTimed = forceTimed;
+ mutation.forceAllDay = forceAllDay;
+ mutation.setDateDelta(dateDelta);
+ mutation.setEndDelta(endDelta);
+ return mutation;
+ };
+ /*
+ returns an undo function.
+ */
+ EventDefDateMutation.prototype.buildNewDateProfile = function (eventDateProfile, calendar) {
+ var start = eventDateProfile.start.clone();
+ var end = null;
+ var shouldRezone = false;
+ if (eventDateProfile.end && !this.clearEnd) {
+ end = eventDateProfile.end.clone();
+ }
+ else if (this.endDelta && !end) {
+ end = calendar.getDefaultEventEnd(eventDateProfile.isAllDay(), start);
+ }
+ if (this.forceTimed) {
+ shouldRezone = true;
+ if (!start.hasTime()) {
+ start.time(0);
+ }
+ if (end && !end.hasTime()) {
+ end.time(0);
+ }
+ }
+ else if (this.forceAllDay) {
+ if (start.hasTime()) {
+ start.stripTime();
+ }
+ if (end && end.hasTime()) {
+ end.stripTime();
+ }
+ }
+ if (this.dateDelta) {
+ shouldRezone = true;
+ start.add(this.dateDelta);
+ if (end) {
+ end.add(this.dateDelta);
+ }
+ }
+ // do this before adding startDelta to start, so we can work off of start
+ if (this.endDelta) {
+ shouldRezone = true;
+ end.add(this.endDelta);
+ }
+ if (this.startDelta) {
+ shouldRezone = true;
+ start.add(this.startDelta);
+ }
+ if (shouldRezone) {
+ start = calendar.applyTimezone(start);
+ if (end) {
+ end = calendar.applyTimezone(end);
+ }
+ }
+ // TODO: okay to access calendar option?
+ if (!end && calendar.opt('forceEventDuration')) {
+ end = calendar.getDefaultEventEnd(eventDateProfile.isAllDay(), start);
+ }
+ return new EventDateProfile_1.default(start, end, calendar);
+ };
+ EventDefDateMutation.prototype.setDateDelta = function (dateDelta) {
+ if (dateDelta && dateDelta.valueOf()) {
+ this.dateDelta = dateDelta;
+ }
+ else {
+ this.dateDelta = null;
+ }
+ };
+ EventDefDateMutation.prototype.setStartDelta = function (startDelta) {
+ if (startDelta && startDelta.valueOf()) {
+ this.startDelta = startDelta;
+ }
+ else {
+ this.startDelta = null;
+ }
+ };
+ EventDefDateMutation.prototype.setEndDelta = function (endDelta) {
+ if (endDelta && endDelta.valueOf()) {
+ this.endDelta = endDelta;
+ }
+ else {
+ this.endDelta = null;
+ }
+ };
+ EventDefDateMutation.prototype.isEmpty = function () {
+ return !this.clearEnd && !this.forceTimed && !this.forceAllDay &&
+ !this.dateDelta && !this.startDelta && !this.endDelta;
+ };
+ return EventDefDateMutation;
+}());
+exports.default = EventDefDateMutation;
/***/ }),
-/* 39 */
+/* 41 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
var util_1 = __webpack_require__(4);
-var Class_1 = __webpack_require__(33);
+var Class_1 = __webpack_require__(35);
/*
Embodies a div that has potential scrollbars
*/
@@ -3215,12 +3476,16 @@
if (overflowX === 'auto') {
overflowX = (scrollbarWidths.top || scrollbarWidths.bottom || // horizontal scrollbars?
// OR scrolling pane with massless scrollbars?
- this.scrollEl[0].scrollWidth - 1 > this.scrollEl[0].clientWidth) ? 'scroll' : 'hidden';
+ this.scrollEl[0].scrollWidth - 1 > this.scrollEl[0].clientWidth
+ // subtract 1 because of IE off-by-one issue
+ ) ? 'scroll' : 'hidden';
}
if (overflowY === 'auto') {
overflowY = (scrollbarWidths.left || scrollbarWidths.right || // vertical scrollbars?
// OR scrolling pane with massless scrollbars?
- this.scrollEl[0].scrollHeight - 1 > this.scrollEl[0].clientHeight) ? 'scroll' : 'hidden';
+ this.scrollEl[0].scrollHeight - 1 > this.scrollEl[0].clientHeight
+ // subtract 1 because of IE off-by-one issue
+ ) ? 'scroll' : 'hidden';
}
this.scrollEl.css({ 'overflow-x': overflowX, 'overflow-y': overflowY });
};
@@ -3250,15 +3515,15 @@
/***/ }),
-/* 40 */
+/* 42 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
var util_1 = __webpack_require__(4);
-var DateComponent_1 = __webpack_require__(219);
-var GlobalEmitter_1 = __webpack_require__(21);
+var DateComponent_1 = __webpack_require__(231);
+var GlobalEmitter_1 = __webpack_require__(23);
var InteractiveDateComponent = /** @class */ (function (_super) {
tslib_1.__extends(InteractiveDateComponent, _super);
function InteractiveDateComponent(_view, _options) {
@@ -3505,7 +3770,7 @@
/***/ }),
-/* 41 */
+/* 43 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
@@ -3513,10 +3778,10 @@
var $ = __webpack_require__(3);
var moment = __webpack_require__(0);
var util_1 = __webpack_require__(4);
-var RenderQueue_1 = __webpack_require__(218);
-var DateProfileGenerator_1 = __webpack_require__(221);
-var InteractiveDateComponent_1 = __webpack_require__(40);
-var GlobalEmitter_1 = __webpack_require__(21);
+var RenderQueue_1 = __webpack_require__(229);
+var DateProfileGenerator_1 = __webpack_require__(55);
+var InteractiveDateComponent_1 = __webpack_require__(42);
+var GlobalEmitter_1 = __webpack_require__(23);
var UnzonedRange_1 = __webpack_require__(5);
/* An abstract class from which other views inherit from
----------------------------------------------------------------------------------------------------------------------*/
@@ -3566,7 +3831,7 @@
this.addScroll(this.queryScroll());
};
View.prototype.onRenderQueueStop = function () {
- if (this.calendar.updateViewSize()) {
+ if (this.calendar.updateViewSize()) { // success?
this.popScroll();
}
this.calendar.thawContentHeight();
@@ -3602,7 +3867,7 @@
if (/^(year|month)$/.test(dateProfile.currentRangeUnit)) {
unzonedRange = dateProfile.currentUnzonedRange;
}
- else {
+ else { // for day units or smaller, use the actual day range
unzonedRange = dateProfile.activeUnzonedRange;
}
return this.formatRange({
@@ -3828,7 +4093,7 @@
/* Dimensions
------------------------------------------------------------------------------------------------------------------*/
View.prototype.updateSize = function (totalHeight, isAuto, isResize) {
- if (this['setHeight']) {
+ if (this['setHeight']) { // for legacy API
this['setHeight'](totalHeight, isAuto);
}
else {
@@ -3945,15 +4210,16 @@
var undoFunc = eventManager.mutateEventsWithId(eventInstance.def.id, eventMutation);
// update the EventInstance, for handlers
eventInstance.dateProfile = eventMutation.dateMutation.buildNewDateProfile(eventInstance.dateProfile, this.calendar);
- this.triggerEventResize(eventInstance, eventMutation.dateMutation.endDelta, undoFunc, el, ev);
+ var resizeDelta = eventMutation.dateMutation.endDelta || eventMutation.dateMutation.startDelta;
+ this.triggerEventResize(eventInstance, resizeDelta, undoFunc, el, ev);
};
// Triggers event-resize handlers that have subscribed via the API
- View.prototype.triggerEventResize = function (eventInstance, durationDelta, undoFunc, el, ev) {
+ View.prototype.triggerEventResize = function (eventInstance, resizeDelta, undoFunc, el, ev) {
this.publiclyTrigger('eventResize', {
context: el[0],
args: [
eventInstance.toLegacy(),
- durationDelta,
+ resizeDelta,
undoFunc,
ev,
{},
@@ -3971,7 +4237,7 @@
this.reportSelection(footprint, ev);
};
View.prototype.renderSelectionFootprint = function (footprint) {
- if (this['renderSelection']) {
+ if (this['renderSelection']) { // legacy method in custom view classes
this['renderSelection'](footprint.toLegacy(this.calendar));
}
else {
@@ -4030,7 +4296,7 @@
View.prototype.unselectEventInstance = function () {
if (this.selectedEventInstance) {
this.getEventSegs().forEach(function (seg) {
- if (seg.el) {
+ if (seg.el) { // necessary?
seg.el.removeClass('fc-selected');
}
});
@@ -4218,7 +4484,7 @@
/***/ }),
-/* 42 */
+/* 44 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
@@ -4282,7 +4548,7 @@
// render an `.el` on each seg
// returns a subset of the segs. segs that were actually rendered
segs = this.renderFgSegEls(segs);
- if (this.renderFgSegs(segs) !== false) {
+ if (this.renderFgSegs(segs) !== false) { // no failure?
this.fgSegs = segs;
}
};
@@ -4293,7 +4559,7 @@
EventRenderer.prototype.renderBgRanges = function (eventRanges) {
var eventFootprints = this.component.eventRangesToEventFootprints(eventRanges);
var segs = this.component.eventFootprintsToSegs(eventFootprints);
- if (this.renderBgSegs(segs) !== false) {
+ if (this.renderBgSegs(segs) !== false) { // no failure?
this.bgSegs = segs;
}
};
@@ -4349,7 +4615,7 @@
var html = '';
var renderedSegs = [];
var i;
- if (segs.length) {
+ if (segs.length) { // don't build an empty html string
// build a large concatenation of event segment HTML
for (i = 0; i < segs.length; i++) {
this.beforeFgSegHtml(segs[i]);
@@ -4360,7 +4626,7 @@
$(html).each(function (i, node) {
var seg = segs[i];
var el = $(node);
- if (hasEventRenderHandlers) {
+ if (hasEventRenderHandlers) { // optimization
el = _this.filterEventRenderEl(seg.footprint, el);
}
if (el) {
@@ -4405,7 +4671,7 @@
context: legacy,
args: [legacy, el, this.view]
});
- if (custom === false) {
+ if (custom === false) { // means don't render at all
el = null;
}
else if (custom && custom !== true) {
@@ -4543,19 +4809,19 @@
/***/ }),
-/* 43 */,
-/* 44 */,
/* 45 */,
/* 46 */,
-/* 47 */
+/* 47 */,
+/* 48 */,
+/* 49 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
-var moment_ext_1 = __webpack_require__(10);
+var moment_ext_1 = __webpack_require__(11);
// Plugin
// -------------------------------------------------------------------------------------------------
moment_ext_1.newMomentProto.format = function () {
- if (this._fullCalendar && arguments[0]) {
+ if (this._fullCalendar && arguments[0]) { // an enhanced moment? and a format string provided?
return formatDate(this, arguments[0]); // our extended formatting
}
if (this._ambigTime) {
@@ -4564,7 +4830,7 @@
if (this._ambigZone) {
return moment_ext_1.oldMomentFormat(englishMoment(this), 'YYYY-MM-DD[T]HH:mm:ss');
}
- if (this._fullCalendar) {
+ if (this._fullCalendar) { // enhanced non-ambig moment?
// moment.format() doesn't ensure english, but we want to.
return moment_ext_1.oldMomentFormat(englishMoment(this));
}
@@ -4577,7 +4843,7 @@
if (this._ambigZone) {
return moment_ext_1.oldMomentFormat(englishMoment(this), 'YYYY-MM-DD[T]HH:mm:ss');
}
- if (this._fullCalendar) {
+ if (this._fullCalendar) { // enhanced non-ambig moment?
// depending on browser, moment might not output english. ensure english.
// https://github.com/moment/moment/blob/2.18.1/src/lib/moment/format.js#L22
return moment_ext_1.oldMomentProto.toISOString.apply(englishMoment(this), arguments);
@@ -4747,17 +5013,17 @@
// \4 is a backreference to the first character of a multi-character set.
var chunker = /\[([^\]]*)\]|\(([^\)]*)\)|(LTS|LT|(\w)\4*o?)|([^\w\[\(]+)/g;
while ((match = chunker.exec(formatStr))) {
- if (match[1]) {
+ if (match[1]) { // a literal string inside [ ... ]
chunks.push.apply(chunks, // append
splitStringLiteral(match[1]));
}
- else if (match[2]) {
+ else if (match[2]) { // non-zero formatting inside ( ... )
chunks.push({ maybe: chunkFormatString(match[2]) });
}
- else if (match[3]) {
+ else if (match[3]) { // a formatting token
chunks.push({ token: match[3] });
}
- else if (match[5]) {
+ else if (match[5]) { // an unenclosed literal string
chunks.push.apply(chunks, // append
splitStringLiteral(match[5]));
}
@@ -4868,7 +5134,7 @@
*/
function processMaybeMarkers(s) {
return s.replace(MAYBE_REGEXP, function (m0, m1) {
- if (m1.match(/[1-9]/)) {
+ if (m1.match(/[1-9]/)) { // any non-zero numeric characters?
return m1;
}
else {
@@ -4907,13 +5173,31 @@
/***/ }),
-/* 48 */
+/* 50 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var EventRange = /** @class */ (function () {
+ function EventRange(unzonedRange, eventDef, eventInstance) {
+ this.unzonedRange = unzonedRange;
+ this.eventDef = eventDef;
+ if (eventInstance) {
+ this.eventInstance = eventInstance;
+ }
+ }
+ return EventRange;
+}());
+exports.default = EventRange;
+
+
+/***/ }),
+/* 51 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
-var Class_1 = __webpack_require__(33);
-var EmitterMixin_1 = __webpack_require__(11);
+var Class_1 = __webpack_require__(35);
+var EmitterMixin_1 = __webpack_require__(13);
var ListenerMixin_1 = __webpack_require__(7);
var Model = /** @class */ (function (_super) {
tslib_1.__extends(Model, _super);
@@ -5069,8 +5353,8 @@
var isCallingStop = false;
var onBeforeDepChange = function (depName, val, isOptional) {
queuedChangeCnt++;
- if (queuedChangeCnt === 1) {
- if (satisfyCnt === depCnt) {
+ if (queuedChangeCnt === 1) { // first change to cause a "stop" ?
+ if (satisfyCnt === depCnt) { // all deps previously satisfied?
isCallingStop = true;
stopFunc(values);
isCallingStop = false;
@@ -5078,14 +5362,14 @@
}
};
var onDepChange = function (depName, val, isOptional) {
- if (val === undefined) {
+ if (val === undefined) { // unsetting a value?
// required dependency that was previously set?
if (!isOptional && values[depName] !== undefined) {
satisfyCnt--;
}
delete values[depName];
}
- else {
+ else { // setting a value?
// required dependency that was previously unset?
if (!isOptional && values[depName] === undefined) {
satisfyCnt++;
@@ -5093,7 +5377,7 @@
values[depName] = val;
}
queuedChangeCnt--;
- if (!queuedChangeCnt) {
+ if (!queuedChangeCnt) { // last change to cause a "start"?
// now finally satisfied or satisfied all along?
if (satisfyCnt === depCnt) {
// if the stopFunc initiated another value change, ignore it.
@@ -5112,7 +5396,7 @@
// listen to dependency changes
depList.forEach(function (depName) {
var isOptional = false;
- if (depName.charAt(0) === '?') {
+ if (depName.charAt(0) === '?') { // TODO: more DRY
depName = depName.substring(1);
isOptional = true;
}
@@ -5126,7 +5410,7 @@
// process current dependency values
depList.forEach(function (depName) {
var isOptional = false;
- if (depName.charAt(0) === '?') {
+ if (depName.charAt(0) === '?') { // TODO: more DRY
depName = depName.substring(1);
isOptional = true;
}
@@ -5177,202 +5461,509 @@
/***/ }),
-/* 49 */
+/* 52 */
/***/ (function(module, exports, __webpack_require__) {
+/*
+USAGE:
+ import { default as ParsableModelMixin, ParsableModelInterface } from './ParsableModelMixin'
+in class:
+ applyProps: ParsableModelInterface['applyProps']
+ applyManualStandardProps: ParsableModelInterface['applyManualStandardProps']
+ applyMiscProps: ParsableModelInterface['applyMiscProps']
+ isStandardProp: ParsableModelInterface['isStandardProp']
+ static defineStandardProps = ParsableModelMixin.defineStandardProps
+ static copyVerbatimStandardProps = ParsableModelMixin.copyVerbatimStandardProps
+after class:
+ ParsableModelMixin.mixInto(TheClass)
+*/
Object.defineProperty(exports, "__esModule", { value: true });
-var moment = __webpack_require__(0);
+var tslib_1 = __webpack_require__(2);
var util_1 = __webpack_require__(4);
-var SingleEventDef_1 = __webpack_require__(13);
-var RecurringEventDef_1 = __webpack_require__(210);
-exports.default = {
- parse: function (eventInput, source) {
- if (util_1.isTimeString(eventInput.start) || moment.isDuration(eventInput.start) ||
- util_1.isTimeString(eventInput.end) || moment.isDuration(eventInput.end)) {
- return RecurringEventDef_1.default.parse(eventInput, source);
+var Mixin_1 = __webpack_require__(15);
+var ParsableModelMixin = /** @class */ (function (_super) {
+ tslib_1.__extends(ParsableModelMixin, _super);
+ function ParsableModelMixin() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ ParsableModelMixin.defineStandardProps = function (propDefs) {
+ var proto = this.prototype;
+ if (!proto.hasOwnProperty('standardPropMap')) {
+ proto.standardPropMap = Object.create(proto.standardPropMap);
}
- else {
- return SingleEventDef_1.default.parse(eventInput, source);
+ util_1.copyOwnProps(propDefs, proto.standardPropMap);
+ };
+ ParsableModelMixin.copyVerbatimStandardProps = function (src, dest) {
+ var map = this.prototype.standardPropMap;
+ var propName;
+ for (propName in map) {
+ if (src[propName] != null && // in the src object?
+ map[propName] === true // false means "copy verbatim"
+ ) {
+ dest[propName] = src[propName];
+ }
+ }
+ };
+ /*
+ Returns true/false for success.
+ Meant to be only called ONCE, at object creation.
+ */
+ ParsableModelMixin.prototype.applyProps = function (rawProps) {
+ var standardPropMap = this.standardPropMap;
+ var manualProps = {};
+ var miscProps = {};
+ var propName;
+ for (propName in rawProps) {
+ if (standardPropMap[propName] === true) { // copy verbatim
+ this[propName] = rawProps[propName];
+ }
+ else if (standardPropMap[propName] === false) {
+ manualProps[propName] = rawProps[propName];
+ }
+ else {
+ miscProps[propName] = rawProps[propName];
+ }
}
+ this.applyMiscProps(miscProps);
+ return this.applyManualStandardProps(manualProps);
+ };
+ /*
+ If subclasses override, they must call this supermethod and return the boolean response.
+ Meant to be only called ONCE, at object creation.
+ */
+ ParsableModelMixin.prototype.applyManualStandardProps = function (rawProps) {
+ return true;
+ };
+ /*
+ Can be called even after initial object creation.
+ */
+ ParsableModelMixin.prototype.applyMiscProps = function (rawProps) {
+ // subclasses can implement
+ };
+ /*
+ TODO: why is this a method when defineStandardProps is static
+ */
+ ParsableModelMixin.prototype.isStandardProp = function (propName) {
+ return propName in this.standardPropMap;
+ };
+ return ParsableModelMixin;
+}(Mixin_1.default));
+exports.default = ParsableModelMixin;
+ParsableModelMixin.prototype.standardPropMap = {}; // will be cloned by defineStandardProps
+
+
+/***/ }),
+/* 53 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var EventInstance = /** @class */ (function () {
+ function EventInstance(def, dateProfile) {
+ this.def = def;
+ this.dateProfile = dateProfile;
}
+ EventInstance.prototype.toLegacy = function () {
+ var dateProfile = this.dateProfile;
+ var obj = this.def.toLegacy();
+ obj.start = dateProfile.start.clone();
+ obj.end = dateProfile.end ? dateProfile.end.clone() : null;
+ return obj;
+ };
+ return EventInstance;
+}());
+exports.default = EventInstance;
+
+
+/***/ }),
+/* 54 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var $ = __webpack_require__(3);
+var moment = __webpack_require__(0);
+var EventDef_1 = __webpack_require__(37);
+var EventInstance_1 = __webpack_require__(53);
+var EventDateProfile_1 = __webpack_require__(16);
+var RecurringEventDef = /** @class */ (function (_super) {
+ tslib_1.__extends(RecurringEventDef, _super);
+ function RecurringEventDef() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ RecurringEventDef.prototype.isAllDay = function () {
+ return !this.startTime && !this.endTime;
+ };
+ RecurringEventDef.prototype.buildInstances = function (unzonedRange) {
+ var calendar = this.source.calendar;
+ var unzonedDate = unzonedRange.getStart();
+ var unzonedEnd = unzonedRange.getEnd();
+ var zonedDayStart;
+ var instanceStart;
+ var instanceEnd;
+ var instances = [];
+ while (unzonedDate.isBefore(unzonedEnd)) {
+ // if everyday, or this particular day-of-week
+ if (!this.dowHash || this.dowHash[unzonedDate.day()]) {
+ zonedDayStart = calendar.applyTimezone(unzonedDate);
+ instanceStart = zonedDayStart.clone();
+ instanceEnd = null;
+ if (this.startTime) {
+ instanceStart.time(this.startTime);
+ }
+ else {
+ instanceStart.stripTime();
+ }
+ if (this.endTime) {
+ instanceEnd = zonedDayStart.clone().time(this.endTime);
+ }
+ instances.push(new EventInstance_1.default(this, // definition
+ new EventDateProfile_1.default(instanceStart, instanceEnd, calendar)));
+ }
+ unzonedDate.add(1, 'days');
+ }
+ return instances;
+ };
+ RecurringEventDef.prototype.setDow = function (dowNumbers) {
+ if (!this.dowHash) {
+ this.dowHash = {};
+ }
+ for (var i = 0; i < dowNumbers.length; i++) {
+ this.dowHash[dowNumbers[i]] = true;
+ }
+ };
+ RecurringEventDef.prototype.clone = function () {
+ var def = _super.prototype.clone.call(this);
+ if (def.startTime) {
+ def.startTime = moment.duration(this.startTime);
+ }
+ if (def.endTime) {
+ def.endTime = moment.duration(this.endTime);
+ }
+ if (this.dowHash) {
+ def.dowHash = $.extend({}, this.dowHash);
+ }
+ return def;
+ };
+ return RecurringEventDef;
+}(EventDef_1.default));
+exports.default = RecurringEventDef;
+/*
+HACK to work with TypeScript mixins
+NOTE: if super-method fails, should still attempt to apply
+*/
+RecurringEventDef.prototype.applyProps = function (rawProps) {
+ var superSuccess = EventDef_1.default.prototype.applyProps.call(this, rawProps);
+ if (rawProps.start) {
+ this.startTime = moment.duration(rawProps.start);
+ }
+ if (rawProps.end) {
+ this.endTime = moment.duration(rawProps.end);
+ }
+ if (rawProps.dow) {
+ this.setDow(rawProps.dow);
+ }
+ return superSuccess;
};
+// Parsing
+// ---------------------------------------------------------------------------------------------------------------------
+RecurringEventDef.defineStandardProps({
+ start: false,
+ end: false,
+ dow: false
+});
/***/ }),
-/* 50 */
+/* 55 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
+var moment = __webpack_require__(0);
var util_1 = __webpack_require__(4);
-var EventDateProfile_1 = __webpack_require__(17);
-var EventDefDateMutation = /** @class */ (function () {
- function EventDefDateMutation() {
- this.clearEnd = false;
- this.forceTimed = false;
- this.forceAllDay = false;
+var UnzonedRange_1 = __webpack_require__(5);
+var DateProfileGenerator = /** @class */ (function () {
+ function DateProfileGenerator(_view) {
+ this._view = _view;
}
- EventDefDateMutation.createFromDiff = function (dateProfile0, dateProfile1, largeUnit) {
- var clearEnd = dateProfile0.end && !dateProfile1.end;
- var forceTimed = dateProfile0.isAllDay() && !dateProfile1.isAllDay();
- var forceAllDay = !dateProfile0.isAllDay() && dateProfile1.isAllDay();
- var dateDelta;
- var endDiff;
- var endDelta;
- var mutation;
- // subtracts the dates in the appropriate way, returning a duration
- function subtractDates(date1, date0) {
- if (largeUnit) {
- return util_1.diffByUnit(date1, date0, largeUnit); // poorly named
- }
- else if (dateProfile1.isAllDay()) {
- return util_1.diffDay(date1, date0); // poorly named
- }
- else {
- return util_1.diffDayTime(date1, date0); // poorly named
- }
+ DateProfileGenerator.prototype.opt = function (name) {
+ return this._view.opt(name);
+ };
+ DateProfileGenerator.prototype.trimHiddenDays = function (unzonedRange) {
+ return this._view.trimHiddenDays(unzonedRange);
+ };
+ DateProfileGenerator.prototype.msToUtcMoment = function (ms, forceAllDay) {
+ return this._view.calendar.msToUtcMoment(ms, forceAllDay);
+ };
+ /* Date Range Computation
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Builds a structure with info about what the dates/ranges will be for the "prev" view.
+ DateProfileGenerator.prototype.buildPrev = function (currentDateProfile) {
+ var prevDate = currentDateProfile.date.clone()
+ .startOf(currentDateProfile.currentRangeUnit)
+ .subtract(currentDateProfile.dateIncrement);
+ return this.build(prevDate, -1);
+ };
+ // Builds a structure with info about what the dates/ranges will be for the "next" view.
+ DateProfileGenerator.prototype.buildNext = function (currentDateProfile) {
+ var nextDate = currentDateProfile.date.clone()
+ .startOf(currentDateProfile.currentRangeUnit)
+ .add(currentDateProfile.dateIncrement);
+ return this.build(nextDate, 1);
+ };
+ // Builds a structure holding dates/ranges for rendering around the given date.
+ // Optional direction param indicates whether the date is being incremented/decremented
+ // from its previous value. decremented = -1, incremented = 1 (default).
+ DateProfileGenerator.prototype.build = function (date, direction, forceToValid) {
+ if (forceToValid === void 0) { forceToValid = false; }
+ var isDateAllDay = !date.hasTime();
+ var validUnzonedRange;
+ var minTime = null;
+ var maxTime = null;
+ var currentInfo;
+ var isRangeAllDay;
+ var renderUnzonedRange;
+ var activeUnzonedRange;
+ var isValid;
+ validUnzonedRange = this.buildValidRange();
+ validUnzonedRange = this.trimHiddenDays(validUnzonedRange);
+ if (forceToValid) {
+ date = this.msToUtcMoment(validUnzonedRange.constrainDate(date), // returns MS
+ isDateAllDay);
}
- dateDelta = subtractDates(dateProfile1.start, dateProfile0.start);
- if (dateProfile1.end) {
- // use unzonedRanges because dateProfile0.end might be null
- endDiff = subtractDates(dateProfile1.unzonedRange.getEnd(), dateProfile0.unzonedRange.getEnd());
- endDelta = endDiff.subtract(dateDelta);
+ currentInfo = this.buildCurrentRangeInfo(date, direction);
+ isRangeAllDay = /^(year|month|week|day)$/.test(currentInfo.unit);
+ renderUnzonedRange = this.buildRenderRange(this.trimHiddenDays(currentInfo.unzonedRange), currentInfo.unit, isRangeAllDay);
+ renderUnzonedRange = this.trimHiddenDays(renderUnzonedRange);
+ activeUnzonedRange = renderUnzonedRange.clone();
+ if (!this.opt('showNonCurrentDates')) {
+ activeUnzonedRange = activeUnzonedRange.intersect(currentInfo.unzonedRange);
}
- mutation = new EventDefDateMutation();
- mutation.clearEnd = clearEnd;
- mutation.forceTimed = forceTimed;
- mutation.forceAllDay = forceAllDay;
- mutation.setDateDelta(dateDelta);
- mutation.setEndDelta(endDelta);
- return mutation;
+ minTime = moment.duration(this.opt('minTime'));
+ maxTime = moment.duration(this.opt('maxTime'));
+ activeUnzonedRange = this.adjustActiveRange(activeUnzonedRange, minTime, maxTime);
+ activeUnzonedRange = activeUnzonedRange.intersect(validUnzonedRange); // might return null
+ if (activeUnzonedRange) {
+ date = this.msToUtcMoment(activeUnzonedRange.constrainDate(date), // returns MS
+ isDateAllDay);
+ }
+ // it's invalid if the originally requested date is not contained,
+ // or if the range is completely outside of the valid range.
+ isValid = currentInfo.unzonedRange.intersectsWith(validUnzonedRange);
+ return {
+ // constraint for where prev/next operations can go and where events can be dragged/resized to.
+ // an object with optional start and end properties.
+ validUnzonedRange: validUnzonedRange,
+ // range the view is formally responsible for.
+ // for example, a month view might have 1st-31st, excluding padded dates
+ currentUnzonedRange: currentInfo.unzonedRange,
+ // name of largest unit being displayed, like "month" or "week"
+ currentRangeUnit: currentInfo.unit,
+ isRangeAllDay: isRangeAllDay,
+ // dates that display events and accept drag-n-drop
+ // will be `null` if no dates accept events
+ activeUnzonedRange: activeUnzonedRange,
+ // date range with a rendered skeleton
+ // includes not-active days that need some sort of DOM
+ renderUnzonedRange: renderUnzonedRange,
+ // Duration object that denotes the first visible time of any given day
+ minTime: minTime,
+ // Duration object that denotes the exclusive visible end time of any given day
+ maxTime: maxTime,
+ isValid: isValid,
+ date: date,
+ // how far the current date will move for a prev/next operation
+ dateIncrement: this.buildDateIncrement(currentInfo.duration)
+ // pass a fallback (might be null) ^
+ };
};
- /*
- returns an undo function.
- */
- EventDefDateMutation.prototype.buildNewDateProfile = function (eventDateProfile, calendar) {
- var start = eventDateProfile.start.clone();
- var end = null;
- var shouldRezone = false;
- if (eventDateProfile.end && !this.clearEnd) {
- end = eventDateProfile.end.clone();
+ // Builds an object with optional start/end properties.
+ // Indicates the minimum/maximum dates to display.
+ // not responsible for trimming hidden days.
+ DateProfileGenerator.prototype.buildValidRange = function () {
+ return this._view.getUnzonedRangeOption('validRange', this._view.calendar.getNow()) ||
+ new UnzonedRange_1.default(); // completely open-ended
+ };
+ // Builds a structure with info about the "current" range, the range that is
+ // highlighted as being the current month for example.
+ // See build() for a description of `direction`.
+ // Guaranteed to have `range` and `unit` properties. `duration` is optional.
+ // TODO: accept a MS-time instead of a moment `date`?
+ DateProfileGenerator.prototype.buildCurrentRangeInfo = function (date, direction) {
+ var viewSpec = this._view.viewSpec;
+ var duration = null;
+ var unit = null;
+ var unzonedRange = null;
+ var dayCount;
+ if (viewSpec.duration) {
+ duration = viewSpec.duration;
+ unit = viewSpec.durationUnit;
+ unzonedRange = this.buildRangeFromDuration(date, direction, duration, unit);
}
- else if (this.endDelta && !end) {
- end = calendar.getDefaultEventEnd(eventDateProfile.isAllDay(), start);
+ else if ((dayCount = this.opt('dayCount'))) {
+ unit = 'day';
+ unzonedRange = this.buildRangeFromDayCount(date, direction, dayCount);
}
- if (this.forceTimed) {
- shouldRezone = true;
- if (!start.hasTime()) {
- start.time(0);
+ else if ((unzonedRange = this.buildCustomVisibleRange(date))) {
+ unit = util_1.computeGreatestUnit(unzonedRange.getStart(), unzonedRange.getEnd());
+ }
+ else {
+ duration = this.getFallbackDuration();
+ unit = util_1.computeGreatestUnit(duration);
+ unzonedRange = this.buildRangeFromDuration(date, direction, duration, unit);
+ }
+ return { duration: duration, unit: unit, unzonedRange: unzonedRange };
+ };
+ DateProfileGenerator.prototype.getFallbackDuration = function () {
+ return moment.duration({ days: 1 });
+ };
+ // Returns a new activeUnzonedRange to have time values (un-ambiguate)
+ // minTime or maxTime causes the range to expand.
+ DateProfileGenerator.prototype.adjustActiveRange = function (unzonedRange, minTime, maxTime) {
+ var start = unzonedRange.getStart();
+ var end = unzonedRange.getEnd();
+ if (this._view.usesMinMaxTime) {
+ if (minTime < 0) {
+ start.time(0).add(minTime);
}
- if (end && !end.hasTime()) {
- end.time(0);
+ if (maxTime > 24 * 60 * 60 * 1000) { // beyond 24 hours?
+ end.time(maxTime - (24 * 60 * 60 * 1000));
}
}
- else if (this.forceAllDay) {
- if (start.hasTime()) {
- start.stripTime();
+ return new UnzonedRange_1.default(start, end);
+ };
+ // Builds the "current" range when it is specified as an explicit duration.
+ // `unit` is the already-computed computeGreatestUnit value of duration.
+ // TODO: accept a MS-time instead of a moment `date`?
+ DateProfileGenerator.prototype.buildRangeFromDuration = function (date, direction, duration, unit) {
+ var alignment = this.opt('dateAlignment');
+ var dateIncrementInput;
+ var dateIncrementDuration;
+ var start;
+ var end;
+ var res;
+ // compute what the alignment should be
+ if (!alignment) {
+ dateIncrementInput = this.opt('dateIncrement');
+ if (dateIncrementInput) {
+ dateIncrementDuration = moment.duration(dateIncrementInput);
+ // use the smaller of the two units
+ if (dateIncrementDuration < duration) {
+ alignment = util_1.computeDurationGreatestUnit(dateIncrementDuration, dateIncrementInput);
+ }
+ else {
+ alignment = unit;
+ }
}
- if (end && end.hasTime()) {
- end.stripTime();
+ else {
+ alignment = unit;
}
}
- if (this.dateDelta) {
- shouldRezone = true;
- start.add(this.dateDelta);
- if (end) {
- end.add(this.dateDelta);
+ // if the view displays a single day or smaller
+ if (duration.as('days') <= 1) {
+ if (this._view.isHiddenDay(start)) {
+ start = this._view.skipHiddenDays(start, direction);
+ start.startOf('day');
}
}
- // do this before adding startDelta to start, so we can work off of start
- if (this.endDelta) {
- shouldRezone = true;
- end.add(this.endDelta);
- }
- if (this.startDelta) {
- shouldRezone = true;
- start.add(this.startDelta);
- }
- if (shouldRezone) {
- start = calendar.applyTimezone(start);
- if (end) {
- end = calendar.applyTimezone(end);
- }
+ function computeRes() {
+ start = date.clone().startOf(alignment);
+ end = start.clone().add(duration);
+ res = new UnzonedRange_1.default(start, end);
}
- // TODO: okay to access calendar option?
- if (!end && calendar.opt('forceEventDuration')) {
- end = calendar.getDefaultEventEnd(eventDateProfile.isAllDay(), start);
+ computeRes();
+ // if range is completely enveloped by hidden days, go past the hidden days
+ if (!this.trimHiddenDays(res)) {
+ date = this._view.skipHiddenDays(date, direction);
+ computeRes();
}
- return new EventDateProfile_1.default(start, end, calendar);
+ return res;
};
- EventDefDateMutation.prototype.setDateDelta = function (dateDelta) {
- if (dateDelta && dateDelta.valueOf()) {
- this.dateDelta = dateDelta;
+ // Builds the "current" range when a dayCount is specified.
+ // TODO: accept a MS-time instead of a moment `date`?
+ DateProfileGenerator.prototype.buildRangeFromDayCount = function (date, direction, dayCount) {
+ var customAlignment = this.opt('dateAlignment');
+ var runningCount = 0;
+ var start;
+ var end;
+ if (customAlignment || direction !== -1) {
+ start = date.clone();
+ if (customAlignment) {
+ start.startOf(customAlignment);
+ }
+ start.startOf('day');
+ start = this._view.skipHiddenDays(start);
+ end = start.clone();
+ do {
+ end.add(1, 'day');
+ if (!this._view.isHiddenDay(end)) {
+ runningCount++;
+ }
+ } while (runningCount < dayCount);
+ }
+ else {
+ end = date.clone().startOf('day').add(1, 'day');
+ end = this._view.skipHiddenDays(end, -1, true);
+ start = end.clone();
+ do {
+ start.add(-1, 'day');
+ if (!this._view.isHiddenDay(start)) {
+ runningCount++;
+ }
+ } while (runningCount < dayCount);
}
- else {
- this.dateDelta = null;
+ return new UnzonedRange_1.default(start, end);
+ };
+ // Builds a normalized range object for the "visible" range,
+ // which is a way to define the currentUnzonedRange and activeUnzonedRange at the same time.
+ // TODO: accept a MS-time instead of a moment `date`?
+ DateProfileGenerator.prototype.buildCustomVisibleRange = function (date) {
+ var visibleUnzonedRange = this._view.getUnzonedRangeOption('visibleRange', this._view.calendar.applyTimezone(date) // correct zone. also generates new obj that avoids mutations
+ );
+ if (visibleUnzonedRange && (visibleUnzonedRange.startMs == null || visibleUnzonedRange.endMs == null)) {
+ return null;
}
+ return visibleUnzonedRange;
};
- EventDefDateMutation.prototype.setStartDelta = function (startDelta) {
- if (startDelta && startDelta.valueOf()) {
- this.startDelta = startDelta;
+ // Computes the range that will represent the element/cells for *rendering*,
+ // but which may have voided days/times.
+ // not responsible for trimming hidden days.
+ DateProfileGenerator.prototype.buildRenderRange = function (currentUnzonedRange, currentRangeUnit, isRangeAllDay) {
+ return currentUnzonedRange.clone();
+ };
+ // Compute the duration value that should be added/substracted to the current date
+ // when a prev/next operation happens.
+ DateProfileGenerator.prototype.buildDateIncrement = function (fallback) {
+ var dateIncrementInput = this.opt('dateIncrement');
+ var customAlignment;
+ if (dateIncrementInput) {
+ return moment.duration(dateIncrementInput);
}
- else {
- this.startDelta = null;
+ else if ((customAlignment = this.opt('dateAlignment'))) {
+ return moment.duration(1, customAlignment);
}
- };
- EventDefDateMutation.prototype.setEndDelta = function (endDelta) {
- if (endDelta && endDelta.valueOf()) {
- this.endDelta = endDelta;
+ else if (fallback) {
+ return fallback;
}
else {
- this.endDelta = null;
+ return moment.duration({ days: 1 });
}
};
- EventDefDateMutation.prototype.isEmpty = function () {
- return !this.clearEnd && !this.forceTimed && !this.forceAllDay &&
- !this.dateDelta && !this.startDelta && !this.endDelta;
- };
- return EventDefDateMutation;
+ return DateProfileGenerator;
}());
-exports.default = EventDefDateMutation;
-
-
-/***/ }),
-/* 51 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var StandardTheme_1 = __webpack_require__(213);
-var JqueryUiTheme_1 = __webpack_require__(214);
-var themeClassHash = {};
-function defineThemeSystem(themeName, themeClass) {
- themeClassHash[themeName] = themeClass;
-}
-exports.defineThemeSystem = defineThemeSystem;
-function getThemeSystemClass(themeSetting) {
- if (!themeSetting) {
- return StandardTheme_1.default;
- }
- else if (themeSetting === true) {
- return JqueryUiTheme_1.default;
- }
- else {
- return themeClassHash[themeSetting];
- }
-}
-exports.getThemeSystemClass = getThemeSystemClass;
+exports.default = DateProfileGenerator;
/***/ }),
-/* 52 */
+/* 56 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
var util_1 = __webpack_require__(4);
-var Promise_1 = __webpack_require__(20);
+var Promise_1 = __webpack_require__(21);
var EventSource_1 = __webpack_require__(6);
-var SingleEventDef_1 = __webpack_require__(13);
+var SingleEventDef_1 = __webpack_require__(9);
var ArrayEventSource = /** @class */ (function (_super) {
tslib_1.__extends(ArrayEventSource, _super);
function ArrayEventSource(calendar) {
@@ -5383,10 +5974,10 @@
ArrayEventSource.parse = function (rawInput, calendar) {
var rawProps;
// normalize raw input
- if ($.isArray(rawInput.events)) {
+ if ($.isArray(rawInput.events)) { // extended form
rawProps = rawInput;
}
- else if ($.isArray(rawInput)) {
+ else if ($.isArray(rawInput)) { // short form
rawProps = { events: rawInput };
}
if (rawProps) {
@@ -5443,7 +6034,33 @@
/***/ }),
-/* 53 */
+/* 57 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var StandardTheme_1 = __webpack_require__(221);
+var JqueryUiTheme_1 = __webpack_require__(222);
+var themeClassHash = {};
+function defineThemeSystem(themeName, themeClass) {
+ themeClassHash[themeName] = themeClass;
+}
+exports.defineThemeSystem = defineThemeSystem;
+function getThemeSystemClass(themeSetting) {
+ if (!themeSetting) {
+ return StandardTheme_1.default;
+ }
+ else if (themeSetting === true) {
+ return JqueryUiTheme_1.default;
+ }
+ else {
+ return themeClassHash[themeSetting];
+ }
+}
+exports.getThemeSystemClass = getThemeSystemClass;
+
+
+/***/ }),
+/* 58 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
@@ -5619,7 +6236,9 @@
var scrollParentEl;
if (this.els.length > 0) {
scrollParentEl = util_1.getScrollParent(this.els.eq(0));
- if (!scrollParentEl.is(document)) {
+ if (!scrollParentEl.is(document) &&
+ !scrollParentEl.is('html,body') // don't consider these bounding rects. solves issue 3615
+ ) {
return util_1.getClientRect(scrollParentEl);
}
}
@@ -5640,14 +6259,14 @@
/***/ }),
-/* 54 */
+/* 59 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var $ = __webpack_require__(3);
var util_1 = __webpack_require__(4);
var ListenerMixin_1 = __webpack_require__(7);
-var GlobalEmitter_1 = __webpack_require__(21);
+var GlobalEmitter_1 = __webpack_require__(23);
/* Tracks a drag's mouse movement, firing various handlers
----------------------------------------------------------------------------------------------------------------------*/
// TODO: use Emitter
@@ -5780,7 +6399,7 @@
var distanceSq; // current distance from the origin, squared
if (!this.isDistanceSurpassed) {
distanceSq = dx * dx + dy * dy;
- if (distanceSq >= minDistance * minDistance) {
+ if (distanceSq >= minDistance * minDistance) { // use pythagorean theorem
this.handleDistanceSurpassed(ev);
}
}
@@ -5905,7 +6524,7 @@
var rightCloseness;
var topVel = 0;
var leftVel = 0;
- if (bounds) {
+ if (bounds) { // only scroll if scrollEl exists
// compute closeness to edges. valid range is from 0.0 - 1.0
topCloseness = (sensitivity - (util_1.getEvY(ev) - bounds.top)) / sensitivity;
bottomCloseness = (sensitivity - (bounds.bottom - util_1.getEvY(ev))) / sensitivity;
@@ -5943,23 +6562,23 @@
// Forces scrollTopVel and scrollLeftVel to be zero if scrolling has already gone all the way
DragListener.prototype.constrainScrollVel = function () {
var el = this.scrollEl;
- if (this.scrollTopVel < 0) {
- if (el.scrollTop() <= 0) {
+ if (this.scrollTopVel < 0) { // scrolling up?
+ if (el.scrollTop() <= 0) { // already scrolled all the way up?
this.scrollTopVel = 0;
}
}
- else if (this.scrollTopVel > 0) {
- if (el.scrollTop() + el[0].clientHeight >= el[0].scrollHeight) {
+ else if (this.scrollTopVel > 0) { // scrolling down?
+ if (el.scrollTop() + el[0].clientHeight >= el[0].scrollHeight) { // already scrolled all the way down?
this.scrollTopVel = 0;
}
}
- if (this.scrollLeftVel < 0) {
- if (el.scrollLeft() <= 0) {
+ if (this.scrollLeftVel < 0) { // scrolling left?
+ if (el.scrollLeft() <= 0) { // already scrolled all the left?
this.scrollLeftVel = 0;
}
}
- else if (this.scrollLeftVel > 0) {
- if (el.scrollLeft() + el[0].clientWidth >= el[0].scrollWidth) {
+ else if (this.scrollLeftVel > 0) { // scrolling right?
+ if (el.scrollLeft() + el[0].clientWidth >= el[0].scrollWidth) { // already scrolled all the way right?
this.scrollLeftVel = 0;
}
}
@@ -6006,13 +6625,13 @@
/***/ }),
-/* 55 */
+/* 60 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var util_1 = __webpack_require__(4);
-var Mixin_1 = __webpack_require__(14);
+var Mixin_1 = __webpack_require__(15);
/*
A set of rendering and date-related methods for a visual component comprised of one or more rows of day columns.
Prerequisite: the object being mixed into needs to be a *Grid*
@@ -6035,7 +6654,7 @@
var daysPerRow;
var firstDay;
var rowCnt;
- while (date.isBefore(end)) {
+ while (date.isBefore(end)) { // loop each day from start to end
if (view.isHiddenDay(date)) {
dayIndices.push(dayIndex + 0.5); // mark that it's between indices
}
@@ -6158,7 +6777,7 @@
// deal with in-between indices
segFirst = Math.ceil(segFirst); // in-between starts round to next cell
segLast = Math.floor(segLast); // in-between ends round to prev cell
- if (segFirst <= segLast) {
+ if (segFirst <= segLast) { // was there any intersection with the current row?
segs.push({
row: row,
// normalize to start of row
@@ -6196,7 +6815,7 @@
// deal with in-between indices
segFirst = Math.ceil(segFirst); // in-between starts round to next cell
segLast = Math.floor(segLast); // in-between ends round to prev cell
- if (segFirst <= segLast) {
+ if (segFirst <= segLast) { // was there any intersection with the current row?
segs.push({
row: row,
// normalize to start of row
@@ -6361,7 +6980,7 @@
/***/ }),
-/* 56 */
+/* 61 */
/***/ (function(module, exports) {
Object.defineProperty(exports, "__esModule", { value: true });
@@ -6413,7 +7032,7 @@
/***/ }),
-/* 57 */
+/* 62 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
@@ -6466,7 +7085,7 @@
if (props.filterEl) {
el = props.filterEl(seg, el);
}
- if (el) {
+ if (el) { // custom filters did not cancel the render
el = $(el); // allow custom filter to return raw DOM node
// correct element type? (would be bad if a non-TD were inserted into a table for example)
if (el.is(_this.fillSegTag)) {
@@ -6486,7 +7105,7 @@
return '<' + this.fillSegTag +
(classes.length ? ' class="' + classes.join(' ') + '"' : '') +
(css ? ' style="' + css + '"' : '') +
- ' />';
+ '>' + this.fillSegTag + '>';
};
// Should return wrapping DOM structure
FillRenderer.prototype.attachSegEls = function (type, segs) {
@@ -6506,12 +7125,12 @@
/***/ }),
-/* 58 */
+/* 63 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
-var SingleEventDef_1 = __webpack_require__(13);
-var EventFootprint_1 = __webpack_require__(36);
+var SingleEventDef_1 = __webpack_require__(9);
+var EventFootprint_1 = __webpack_require__(34);
var EventSource_1 = __webpack_require__(6);
var HelperRenderer = /** @class */ (function () {
function HelperRenderer(component, eventRenderer) {
@@ -6573,13 +7192,13 @@
/***/ }),
-/* 59 */
+/* 64 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
-var GlobalEmitter_1 = __webpack_require__(21);
-var Interaction_1 = __webpack_require__(15);
+var GlobalEmitter_1 = __webpack_require__(23);
+var Interaction_1 = __webpack_require__(14);
var EventPointing = /** @class */ (function (_super) {
tslib_1.__extends(EventPointing, _super);
function EventPointing() {
@@ -6649,18 +7268,18 @@
/***/ }),
-/* 60 */
+/* 65 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
-var Mixin_1 = __webpack_require__(14);
-var DateClicking_1 = __webpack_require__(245);
-var DateSelecting_1 = __webpack_require__(225);
-var EventPointing_1 = __webpack_require__(59);
-var EventDragging_1 = __webpack_require__(224);
-var EventResizing_1 = __webpack_require__(223);
-var ExternalDropping_1 = __webpack_require__(222);
+var Mixin_1 = __webpack_require__(15);
+var DateClicking_1 = __webpack_require__(237);
+var DateSelecting_1 = __webpack_require__(236);
+var EventPointing_1 = __webpack_require__(64);
+var EventDragging_1 = __webpack_require__(235);
+var EventResizing_1 = __webpack_require__(234);
+var ExternalDropping_1 = __webpack_require__(233);
var StandardInteractionsMixin = /** @class */ (function (_super) {
tslib_1.__extends(StandardInteractionsMixin, _super);
function StandardInteractionsMixin() {
@@ -6678,25 +7297,25 @@
/***/ }),
-/* 61 */
+/* 66 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
var util_1 = __webpack_require__(4);
-var CoordCache_1 = __webpack_require__(53);
-var Popover_1 = __webpack_require__(249);
+var CoordCache_1 = __webpack_require__(58);
+var Popover_1 = __webpack_require__(227);
var UnzonedRange_1 = __webpack_require__(5);
var ComponentFootprint_1 = __webpack_require__(12);
-var EventFootprint_1 = __webpack_require__(36);
-var BusinessHourRenderer_1 = __webpack_require__(56);
-var StandardInteractionsMixin_1 = __webpack_require__(60);
-var InteractiveDateComponent_1 = __webpack_require__(40);
-var DayTableMixin_1 = __webpack_require__(55);
-var DayGridEventRenderer_1 = __webpack_require__(250);
-var DayGridHelperRenderer_1 = __webpack_require__(251);
-var DayGridFillRenderer_1 = __webpack_require__(252);
+var EventFootprint_1 = __webpack_require__(34);
+var BusinessHourRenderer_1 = __webpack_require__(61);
+var StandardInteractionsMixin_1 = __webpack_require__(65);
+var InteractiveDateComponent_1 = __webpack_require__(42);
+var DayTableMixin_1 = __webpack_require__(60);
+var DayGridEventRenderer_1 = __webpack_require__(243);
+var DayGridHelperRenderer_1 = __webpack_require__(244);
+var DayGridFillRenderer_1 = __webpack_require__(245);
/* A component that renders a grid of whole-days that runs horizontally. There can be multiple rows, one per week.
----------------------------------------------------------------------------------------------------------------------*/
var DayGrid = /** @class */ (function (_super) {
@@ -6844,7 +7463,7 @@
var weekCalcFirstDoW;
if (!isDayNumberVisible && !this.cellWeekNumbersVisible) {
// no numbers in day cell (week number must be along the side)
- return '
'; // will create an empty space above events :(
+ return '
'; // will create an empty space above events :(
}
classes = this.getDayClasses(date);
classes.unshift('fc-day-top');
@@ -7054,14 +7673,14 @@
if (segsBelow.length) {
td = cellMatrix[levelLimit - 1][col];
moreLink = _this.renderMoreLink(row, col, segsBelow);
- moreWrap = $('').append(moreLink);
+ moreWrap = $('
').append(moreLink);
td.append(moreWrap);
moreNodes.push(moreWrap[0]);
}
col++;
}
};
- if (levelLimit && levelLimit < rowStruct.segLevels.length) {
+ if (levelLimit && levelLimit < rowStruct.segLevels.length) { // is it actually over the limit?
levelSegs = rowStruct.segLevels[levelLimit - 1];
cellMatrix = rowStruct.cellMatrix;
limitedNodes = rowStruct.tbodyEl.children().slice(levelLimit) // get level
elements past the limit
@@ -7079,17 +7698,17 @@
totalSegsBelow += segsBelow.length;
col++;
}
- if (totalSegsBelow) {
+ if (totalSegsBelow) { // do we need to replace this segment with one or many "more" links?
td = cellMatrix[levelLimit - 1][seg.leftCol]; // the segment's parent cell
rowspan = td.attr('rowspan') || 1;
segMoreNodes = [];
// make a replacement
for each column the segment occupies. will be one for each colspan
for (j = 0; j < colSegsBelow.length; j++) {
- moreTd = $('
').attr('rowspan', rowspan);
+ moreTd = $('
').attr('rowspan', rowspan);
segsBelow = colSegsBelow[j];
moreLink = this.renderMoreLink(row, seg.leftCol + j, [seg].concat(segsBelow) // count seg as hidden too
);
- moreWrap = $('').append(moreLink);
+ moreWrap = $('
' +
'' +
@@ -7296,17 +7915,17 @@
/***/ }),
-/* 62 */
+/* 67 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
var util_1 = __webpack_require__(4);
-var Scroller_1 = __webpack_require__(39);
-var View_1 = __webpack_require__(41);
-var BasicViewDateProfileGenerator_1 = __webpack_require__(228);
-var DayGrid_1 = __webpack_require__(61);
+var Scroller_1 = __webpack_require__(41);
+var View_1 = __webpack_require__(43);
+var BasicViewDateProfileGenerator_1 = __webpack_require__(68);
+var DayGrid_1 = __webpack_require__(66);
/* An abstract class for the "basic" views, as well as month view. Renders one or more rows of day cells.
----------------------------------------------------------------------------------------------------------------------*/
// It is a manager for a DayGrid subcomponent, which does most of the heavy lifting.
@@ -7351,7 +7970,7 @@
this.el.addClass('fc-basic-view').html(this.renderSkeletonHtml());
this.scroller.render();
dayGridContainerEl = this.scroller.el.addClass('fc-day-grid-container');
- dayGridEl = $('').appendTo(dayGridContainerEl);
+ dayGridEl = $('
').appendTo(dayGridContainerEl);
this.el.find('.fc-body > tr > td').append(dayGridContainerEl);
this.dayGrid.headContainerEl = this.el.find('.fc-head-container');
this.dayGrid.setElement(dayGridEl);
@@ -7431,10 +8050,10 @@
if (eventLimit && typeof eventLimit !== 'number') {
this.dayGrid.limitRows(eventLimit); // limit the levels after the grid's row heights have been set
}
- if (!isAuto) {
+ if (!isAuto) { // should we force dimensions of the scroll container?
this.scroller.setHeight(scrollerHeight);
scrollbarWidths = this.scroller.getScrollbarWidths();
- if (scrollbarWidths.left || scrollbarWidths.right) {
+ if (scrollbarWidths.left || scrollbarWidths.right) { // using scrollbars?
util_1.compensateScroll(headRowEl, scrollbarWidths);
// doing the scrollbar compensation might have created text overflow which created more height. redo
scrollerHeight = this.computeScrollerHeight(totalHeight);
@@ -7539,12 +8158,39 @@
/***/ }),
-/* 63 */,
-/* 64 */,
-/* 65 */,
-/* 66 */,
-/* 67 */,
-/* 68 */,
+/* 68 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var UnzonedRange_1 = __webpack_require__(5);
+var DateProfileGenerator_1 = __webpack_require__(55);
+var BasicViewDateProfileGenerator = /** @class */ (function (_super) {
+ tslib_1.__extends(BasicViewDateProfileGenerator, _super);
+ function BasicViewDateProfileGenerator() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ // Computes the date range that will be rendered.
+ BasicViewDateProfileGenerator.prototype.buildRenderRange = function (currentUnzonedRange, currentRangeUnit, isRangeAllDay) {
+ var renderUnzonedRange = _super.prototype.buildRenderRange.call(this, currentUnzonedRange, currentRangeUnit, isRangeAllDay); // an UnzonedRange
+ var start = this.msToUtcMoment(renderUnzonedRange.startMs, isRangeAllDay);
+ var end = this.msToUtcMoment(renderUnzonedRange.endMs, isRangeAllDay);
+ // year and month views should be aligned with weeks. this is already done for week
+ if (/^(year|month)$/.test(currentRangeUnit)) {
+ start.startOf('week');
+ // make end-of-week if not already
+ if (end.weekday()) {
+ end.add(1, 'week').startOf('week'); // exclusively move backwards
+ }
+ }
+ return new UnzonedRange_1.default(start, end);
+ };
+ return BasicViewDateProfileGenerator;
+}(DateProfileGenerator_1.default));
+exports.default = BasicViewDateProfileGenerator;
+
+
+/***/ }),
/* 69 */,
/* 70 */,
/* 71 */,
@@ -7683,15 +8329,25 @@
/* 204 */,
/* 205 */,
/* 206 */,
-/* 207 */
+/* 207 */,
+/* 208 */,
+/* 209 */,
+/* 210 */,
+/* 211 */,
+/* 212 */,
+/* 213 */,
+/* 214 */,
+/* 215 */,
+/* 216 */,
+/* 217 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var UnzonedRange_1 = __webpack_require__(5);
var ComponentFootprint_1 = __webpack_require__(12);
-var EventDefParser_1 = __webpack_require__(49);
+var EventDefParser_1 = __webpack_require__(36);
var EventSource_1 = __webpack_require__(6);
-var util_1 = __webpack_require__(35);
+var util_1 = __webpack_require__(19);
var Constraints = /** @class */ (function () {
function Constraints(eventManager, _calendar) {
this.eventManager = eventManager;
@@ -7793,14 +8449,14 @@
}
else if (typeof constraintVal === 'object') {
eventInstances = this.parseEventDefToInstances(constraintVal); // handles recurring events
- if (!eventInstances) {
+ if (!eventInstances) { // invalid input. fallback to parsing footprint directly
return this.parseFootprints(constraintVal);
}
else {
return this.eventInstancesToFootprints(eventInstances);
}
}
- else if (constraintVal != null) {
+ else if (constraintVal != null) { // an ID
eventInstances = this.eventManager.getEventInstancesWithId(constraintVal);
return this.eventInstancesToFootprints(eventInstances);
}
@@ -7849,7 +8505,7 @@
Constraints.prototype.parseEventDefToInstances = function (eventInput) {
var eventManager = this.eventManager;
var eventDef = EventDefParser_1.default.parse(eventInput, new EventSource_1.default(this._calendar));
- if (!eventDef) {
+ if (!eventDef) { // invalid
return false;
}
return eventDef.buildInstances(eventManager.currentPeriod.unzonedRange);
@@ -7937,245 +8593,14 @@
/***/ }),
-/* 208 */
-/***/ (function(module, exports, __webpack_require__) {
-
-/*
-USAGE:
- import { default as ParsableModelMixin, ParsableModelInterface } from './ParsableModelMixin'
-in class:
- applyProps: ParsableModelInterface['applyProps']
- applyManualStandardProps: ParsableModelInterface['applyManualStandardProps']
- applyMiscProps: ParsableModelInterface['applyMiscProps']
- isStandardProp: ParsableModelInterface['isStandardProp']
- static defineStandardProps = ParsableModelMixin.defineStandardProps
- static copyVerbatimStandardProps = ParsableModelMixin.copyVerbatimStandardProps
-after class:
- ParsableModelMixin.mixInto(TheClass)
-*/
-Object.defineProperty(exports, "__esModule", { value: true });
-var tslib_1 = __webpack_require__(2);
-var util_1 = __webpack_require__(4);
-var Mixin_1 = __webpack_require__(14);
-var ParsableModelMixin = /** @class */ (function (_super) {
- tslib_1.__extends(ParsableModelMixin, _super);
- function ParsableModelMixin() {
- return _super !== null && _super.apply(this, arguments) || this;
- }
- ParsableModelMixin.defineStandardProps = function (propDefs) {
- var proto = this.prototype;
- if (!proto.hasOwnProperty('standardPropMap')) {
- proto.standardPropMap = Object.create(proto.standardPropMap);
- }
- util_1.copyOwnProps(propDefs, proto.standardPropMap);
- };
- ParsableModelMixin.copyVerbatimStandardProps = function (src, dest) {
- var map = this.prototype.standardPropMap;
- var propName;
- for (propName in map) {
- if (src[propName] != null && // in the src object?
- map[propName] === true // false means "copy verbatim"
- ) {
- dest[propName] = src[propName];
- }
- }
- };
- /*
- Returns true/false for success.
- Meant to be only called ONCE, at object creation.
- */
- ParsableModelMixin.prototype.applyProps = function (rawProps) {
- var standardPropMap = this.standardPropMap;
- var manualProps = {};
- var miscProps = {};
- var propName;
- for (propName in rawProps) {
- if (standardPropMap[propName] === true) {
- this[propName] = rawProps[propName];
- }
- else if (standardPropMap[propName] === false) {
- manualProps[propName] = rawProps[propName];
- }
- else {
- miscProps[propName] = rawProps[propName];
- }
- }
- this.applyMiscProps(miscProps);
- return this.applyManualStandardProps(manualProps);
- };
- /*
- If subclasses override, they must call this supermethod and return the boolean response.
- Meant to be only called ONCE, at object creation.
- */
- ParsableModelMixin.prototype.applyManualStandardProps = function (rawProps) {
- return true;
- };
- /*
- Can be called even after initial object creation.
- */
- ParsableModelMixin.prototype.applyMiscProps = function (rawProps) {
- // subclasses can implement
- };
- /*
- TODO: why is this a method when defineStandardProps is static
- */
- ParsableModelMixin.prototype.isStandardProp = function (propName) {
- return propName in this.standardPropMap;
- };
- return ParsableModelMixin;
-}(Mixin_1.default));
-exports.default = ParsableModelMixin;
-ParsableModelMixin.prototype.standardPropMap = {}; // will be cloned by defineStandardProps
-
-
-/***/ }),
-/* 209 */
-/***/ (function(module, exports) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var EventInstance = /** @class */ (function () {
- function EventInstance(def, dateProfile) {
- this.def = def;
- this.dateProfile = dateProfile;
- }
- EventInstance.prototype.toLegacy = function () {
- var dateProfile = this.dateProfile;
- var obj = this.def.toLegacy();
- obj.start = dateProfile.start.clone();
- obj.end = dateProfile.end ? dateProfile.end.clone() : null;
- return obj;
- };
- return EventInstance;
-}());
-exports.default = EventInstance;
-
-
-/***/ }),
-/* 210 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var tslib_1 = __webpack_require__(2);
-var $ = __webpack_require__(3);
-var moment = __webpack_require__(0);
-var EventDef_1 = __webpack_require__(34);
-var EventInstance_1 = __webpack_require__(209);
-var EventDateProfile_1 = __webpack_require__(17);
-var RecurringEventDef = /** @class */ (function (_super) {
- tslib_1.__extends(RecurringEventDef, _super);
- function RecurringEventDef() {
- return _super !== null && _super.apply(this, arguments) || this;
- }
- RecurringEventDef.prototype.isAllDay = function () {
- return !this.startTime && !this.endTime;
- };
- RecurringEventDef.prototype.buildInstances = function (unzonedRange) {
- var calendar = this.source.calendar;
- var unzonedDate = unzonedRange.getStart();
- var unzonedEnd = unzonedRange.getEnd();
- var zonedDayStart;
- var instanceStart;
- var instanceEnd;
- var instances = [];
- while (unzonedDate.isBefore(unzonedEnd)) {
- // if everyday, or this particular day-of-week
- if (!this.dowHash || this.dowHash[unzonedDate.day()]) {
- zonedDayStart = calendar.applyTimezone(unzonedDate);
- instanceStart = zonedDayStart.clone();
- instanceEnd = null;
- if (this.startTime) {
- instanceStart.time(this.startTime);
- }
- else {
- instanceStart.stripTime();
- }
- if (this.endTime) {
- instanceEnd = zonedDayStart.clone().time(this.endTime);
- }
- instances.push(new EventInstance_1.default(this, // definition
- new EventDateProfile_1.default(instanceStart, instanceEnd, calendar)));
- }
- unzonedDate.add(1, 'days');
- }
- return instances;
- };
- RecurringEventDef.prototype.setDow = function (dowNumbers) {
- if (!this.dowHash) {
- this.dowHash = {};
- }
- for (var i = 0; i < dowNumbers.length; i++) {
- this.dowHash[dowNumbers[i]] = true;
- }
- };
- RecurringEventDef.prototype.clone = function () {
- var def = _super.prototype.clone.call(this);
- if (def.startTime) {
- def.startTime = moment.duration(this.startTime);
- }
- if (def.endTime) {
- def.endTime = moment.duration(this.endTime);
- }
- if (this.dowHash) {
- def.dowHash = $.extend({}, this.dowHash);
- }
- return def;
- };
- return RecurringEventDef;
-}(EventDef_1.default));
-exports.default = RecurringEventDef;
-/*
-HACK to work with TypeScript mixins
-NOTE: if super-method fails, should still attempt to apply
-*/
-RecurringEventDef.prototype.applyProps = function (rawProps) {
- var superSuccess = EventDef_1.default.prototype.applyProps.call(this, rawProps);
- if (rawProps.start) {
- this.startTime = moment.duration(rawProps.start);
- }
- if (rawProps.end) {
- this.endTime = moment.duration(rawProps.end);
- }
- if (rawProps.dow) {
- this.setDow(rawProps.dow);
- }
- return superSuccess;
-};
-// Parsing
-// ---------------------------------------------------------------------------------------------------------------------
-RecurringEventDef.defineStandardProps({
- start: false,
- end: false,
- dow: false
-});
-
-
-/***/ }),
-/* 211 */
-/***/ (function(module, exports) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var EventRange = /** @class */ (function () {
- function EventRange(unzonedRange, eventDef, eventInstance) {
- this.unzonedRange = unzonedRange;
- this.eventDef = eventDef;
- if (eventInstance) {
- this.eventInstance = eventInstance;
- }
- }
- return EventRange;
-}());
-exports.default = EventRange;
-
-
-/***/ }),
-/* 212 */
+/* 218 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var $ = __webpack_require__(3);
-var util_1 = __webpack_require__(35);
-var EventInstanceGroup_1 = __webpack_require__(18);
-var RecurringEventDef_1 = __webpack_require__(210);
+var util_1 = __webpack_require__(19);
+var EventInstanceGroup_1 = __webpack_require__(20);
+var RecurringEventDef_1 = __webpack_require__(54);
var EventSource_1 = __webpack_require__(6);
var BUSINESS_HOUR_EVENT_DEFAULTS = {
start: '09:00',
@@ -8237,12 +8662,521 @@
/***/ }),
-/* 213 */
+/* 219 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var Promise_1 = __webpack_require__(21);
+var EmitterMixin_1 = __webpack_require__(13);
+var UnzonedRange_1 = __webpack_require__(5);
+var EventInstanceGroup_1 = __webpack_require__(20);
+var EventPeriod = /** @class */ (function () {
+ function EventPeriod(start, end, timezone) {
+ this.pendingCnt = 0;
+ this.freezeDepth = 0;
+ this.stuntedReleaseCnt = 0;
+ this.releaseCnt = 0;
+ this.start = start;
+ this.end = end;
+ this.timezone = timezone;
+ this.unzonedRange = new UnzonedRange_1.default(start.clone().stripZone(), end.clone().stripZone());
+ this.requestsByUid = {};
+ this.eventDefsByUid = {};
+ this.eventDefsById = {};
+ this.eventInstanceGroupsById = {};
+ }
+ EventPeriod.prototype.isWithinRange = function (start, end) {
+ // TODO: use a range util function?
+ return !start.isBefore(this.start) && !end.isAfter(this.end);
+ };
+ // Requesting and Purging
+ // -----------------------------------------------------------------------------------------------------------------
+ EventPeriod.prototype.requestSources = function (sources) {
+ this.freeze();
+ for (var i = 0; i < sources.length; i++) {
+ this.requestSource(sources[i]);
+ }
+ this.thaw();
+ };
+ EventPeriod.prototype.requestSource = function (source) {
+ var _this = this;
+ var request = { source: source, status: 'pending', eventDefs: null };
+ this.requestsByUid[source.uid] = request;
+ this.pendingCnt += 1;
+ source.fetch(this.start, this.end, this.timezone).then(function (eventDefs) {
+ if (request.status !== 'cancelled') {
+ request.status = 'completed';
+ request.eventDefs = eventDefs;
+ _this.addEventDefs(eventDefs);
+ _this.pendingCnt--;
+ _this.tryRelease();
+ }
+ }, function () {
+ if (request.status !== 'cancelled') {
+ request.status = 'failed';
+ _this.pendingCnt--;
+ _this.tryRelease();
+ }
+ });
+ };
+ EventPeriod.prototype.purgeSource = function (source) {
+ var request = this.requestsByUid[source.uid];
+ if (request) {
+ delete this.requestsByUid[source.uid];
+ if (request.status === 'pending') {
+ request.status = 'cancelled';
+ this.pendingCnt--;
+ this.tryRelease();
+ }
+ else if (request.status === 'completed') {
+ request.eventDefs.forEach(this.removeEventDef.bind(this));
+ }
+ }
+ };
+ EventPeriod.prototype.purgeAllSources = function () {
+ var requestsByUid = this.requestsByUid;
+ var uid;
+ var request;
+ var completedCnt = 0;
+ for (uid in requestsByUid) {
+ request = requestsByUid[uid];
+ if (request.status === 'pending') {
+ request.status = 'cancelled';
+ }
+ else if (request.status === 'completed') {
+ completedCnt++;
+ }
+ }
+ this.requestsByUid = {};
+ this.pendingCnt = 0;
+ if (completedCnt) {
+ this.removeAllEventDefs(); // might release
+ }
+ };
+ // Event Definitions
+ // -----------------------------------------------------------------------------------------------------------------
+ EventPeriod.prototype.getEventDefByUid = function (eventDefUid) {
+ return this.eventDefsByUid[eventDefUid];
+ };
+ EventPeriod.prototype.getEventDefsById = function (eventDefId) {
+ var a = this.eventDefsById[eventDefId];
+ if (a) {
+ return a.slice(); // clone
+ }
+ return [];
+ };
+ EventPeriod.prototype.addEventDefs = function (eventDefs) {
+ for (var i = 0; i < eventDefs.length; i++) {
+ this.addEventDef(eventDefs[i]);
+ }
+ };
+ EventPeriod.prototype.addEventDef = function (eventDef) {
+ var eventDefsById = this.eventDefsById;
+ var eventDefId = eventDef.id;
+ var eventDefs = eventDefsById[eventDefId] || (eventDefsById[eventDefId] = []);
+ var eventInstances = eventDef.buildInstances(this.unzonedRange);
+ var i;
+ eventDefs.push(eventDef);
+ this.eventDefsByUid[eventDef.uid] = eventDef;
+ for (i = 0; i < eventInstances.length; i++) {
+ this.addEventInstance(eventInstances[i], eventDefId);
+ }
+ };
+ EventPeriod.prototype.removeEventDefsById = function (eventDefId) {
+ var _this = this;
+ this.getEventDefsById(eventDefId).forEach(function (eventDef) {
+ _this.removeEventDef(eventDef);
+ });
+ };
+ EventPeriod.prototype.removeAllEventDefs = function () {
+ var isEmpty = $.isEmptyObject(this.eventDefsByUid);
+ this.eventDefsByUid = {};
+ this.eventDefsById = {};
+ this.eventInstanceGroupsById = {};
+ if (!isEmpty) {
+ this.tryRelease();
+ }
+ };
+ EventPeriod.prototype.removeEventDef = function (eventDef) {
+ var eventDefsById = this.eventDefsById;
+ var eventDefs = eventDefsById[eventDef.id];
+ delete this.eventDefsByUid[eventDef.uid];
+ if (eventDefs) {
+ util_1.removeExact(eventDefs, eventDef);
+ if (!eventDefs.length) {
+ delete eventDefsById[eventDef.id];
+ }
+ this.removeEventInstancesForDef(eventDef);
+ }
+ };
+ // Event Instances
+ // -----------------------------------------------------------------------------------------------------------------
+ EventPeriod.prototype.getEventInstances = function () {
+ var eventInstanceGroupsById = this.eventInstanceGroupsById;
+ var eventInstances = [];
+ var id;
+ for (id in eventInstanceGroupsById) {
+ eventInstances.push.apply(eventInstances, // append
+ eventInstanceGroupsById[id].eventInstances);
+ }
+ return eventInstances;
+ };
+ EventPeriod.prototype.getEventInstancesWithId = function (eventDefId) {
+ var eventInstanceGroup = this.eventInstanceGroupsById[eventDefId];
+ if (eventInstanceGroup) {
+ return eventInstanceGroup.eventInstances.slice(); // clone
+ }
+ return [];
+ };
+ EventPeriod.prototype.getEventInstancesWithoutId = function (eventDefId) {
+ var eventInstanceGroupsById = this.eventInstanceGroupsById;
+ var matchingInstances = [];
+ var id;
+ for (id in eventInstanceGroupsById) {
+ if (id !== eventDefId) {
+ matchingInstances.push.apply(matchingInstances, // append
+ eventInstanceGroupsById[id].eventInstances);
+ }
+ }
+ return matchingInstances;
+ };
+ EventPeriod.prototype.addEventInstance = function (eventInstance, eventDefId) {
+ var eventInstanceGroupsById = this.eventInstanceGroupsById;
+ var eventInstanceGroup = eventInstanceGroupsById[eventDefId] ||
+ (eventInstanceGroupsById[eventDefId] = new EventInstanceGroup_1.default());
+ eventInstanceGroup.eventInstances.push(eventInstance);
+ this.tryRelease();
+ };
+ EventPeriod.prototype.removeEventInstancesForDef = function (eventDef) {
+ var eventInstanceGroupsById = this.eventInstanceGroupsById;
+ var eventInstanceGroup = eventInstanceGroupsById[eventDef.id];
+ var removeCnt;
+ if (eventInstanceGroup) {
+ removeCnt = util_1.removeMatching(eventInstanceGroup.eventInstances, function (currentEventInstance) {
+ return currentEventInstance.def === eventDef;
+ });
+ if (!eventInstanceGroup.eventInstances.length) {
+ delete eventInstanceGroupsById[eventDef.id];
+ }
+ if (removeCnt) {
+ this.tryRelease();
+ }
+ }
+ };
+ // Releasing and Freezing
+ // -----------------------------------------------------------------------------------------------------------------
+ EventPeriod.prototype.tryRelease = function () {
+ if (!this.pendingCnt) {
+ if (!this.freezeDepth) {
+ this.release();
+ }
+ else {
+ this.stuntedReleaseCnt++;
+ }
+ }
+ };
+ EventPeriod.prototype.release = function () {
+ this.releaseCnt++;
+ this.trigger('release', this.eventInstanceGroupsById);
+ };
+ EventPeriod.prototype.whenReleased = function () {
+ var _this = this;
+ if (this.releaseCnt) {
+ return Promise_1.default.resolve(this.eventInstanceGroupsById);
+ }
+ else {
+ return Promise_1.default.construct(function (onResolve) {
+ _this.one('release', onResolve);
+ });
+ }
+ };
+ EventPeriod.prototype.freeze = function () {
+ if (!(this.freezeDepth++)) {
+ this.stuntedReleaseCnt = 0;
+ }
+ };
+ EventPeriod.prototype.thaw = function () {
+ if (!(--this.freezeDepth) && this.stuntedReleaseCnt && !this.pendingCnt) {
+ this.release();
+ }
+ };
+ return EventPeriod;
+}());
+exports.default = EventPeriod;
+EmitterMixin_1.default.mixInto(EventPeriod);
+
+
+/***/ }),
+/* 220 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var EventPeriod_1 = __webpack_require__(219);
+var ArrayEventSource_1 = __webpack_require__(56);
+var EventSource_1 = __webpack_require__(6);
+var EventSourceParser_1 = __webpack_require__(38);
+var SingleEventDef_1 = __webpack_require__(9);
+var EventInstanceGroup_1 = __webpack_require__(20);
+var EmitterMixin_1 = __webpack_require__(13);
+var ListenerMixin_1 = __webpack_require__(7);
+var EventManager = /** @class */ (function () {
+ function EventManager(calendar) {
+ this.calendar = calendar;
+ this.stickySource = new ArrayEventSource_1.default(calendar);
+ this.otherSources = [];
+ }
+ EventManager.prototype.requestEvents = function (start, end, timezone, force) {
+ if (force ||
+ !this.currentPeriod ||
+ !this.currentPeriod.isWithinRange(start, end) ||
+ timezone !== this.currentPeriod.timezone) {
+ this.setPeriod(// will change this.currentPeriod
+ new EventPeriod_1.default(start, end, timezone));
+ }
+ return this.currentPeriod.whenReleased();
+ };
+ // Source Adding/Removing
+ // -----------------------------------------------------------------------------------------------------------------
+ EventManager.prototype.addSource = function (eventSource) {
+ this.otherSources.push(eventSource);
+ if (this.currentPeriod) {
+ this.currentPeriod.requestSource(eventSource); // might release
+ }
+ };
+ EventManager.prototype.removeSource = function (doomedSource) {
+ util_1.removeExact(this.otherSources, doomedSource);
+ if (this.currentPeriod) {
+ this.currentPeriod.purgeSource(doomedSource); // might release
+ }
+ };
+ EventManager.prototype.removeAllSources = function () {
+ this.otherSources = [];
+ if (this.currentPeriod) {
+ this.currentPeriod.purgeAllSources(); // might release
+ }
+ };
+ // Source Refetching
+ // -----------------------------------------------------------------------------------------------------------------
+ EventManager.prototype.refetchSource = function (eventSource) {
+ var currentPeriod = this.currentPeriod;
+ if (currentPeriod) {
+ currentPeriod.freeze();
+ currentPeriod.purgeSource(eventSource);
+ currentPeriod.requestSource(eventSource);
+ currentPeriod.thaw();
+ }
+ };
+ EventManager.prototype.refetchAllSources = function () {
+ var currentPeriod = this.currentPeriod;
+ if (currentPeriod) {
+ currentPeriod.freeze();
+ currentPeriod.purgeAllSources();
+ currentPeriod.requestSources(this.getSources());
+ currentPeriod.thaw();
+ }
+ };
+ // Source Querying
+ // -----------------------------------------------------------------------------------------------------------------
+ EventManager.prototype.getSources = function () {
+ return [this.stickySource].concat(this.otherSources);
+ };
+ // like querySources, but accepts multple match criteria (like multiple IDs)
+ EventManager.prototype.multiQuerySources = function (matchInputs) {
+ // coerce into an array
+ if (!matchInputs) {
+ matchInputs = [];
+ }
+ else if (!$.isArray(matchInputs)) {
+ matchInputs = [matchInputs];
+ }
+ var matchingSources = [];
+ var i;
+ // resolve raw inputs to real event source objects
+ for (i = 0; i < matchInputs.length; i++) {
+ matchingSources.push.apply(// append
+ matchingSources, this.querySources(matchInputs[i]));
+ }
+ return matchingSources;
+ };
+ // matchInput can either by a real event source object, an ID, or the function/URL for the source.
+ // returns an array of matching source objects.
+ EventManager.prototype.querySources = function (matchInput) {
+ var sources = this.otherSources;
+ var i;
+ var source;
+ // given a proper event source object
+ for (i = 0; i < sources.length; i++) {
+ source = sources[i];
+ if (source === matchInput) {
+ return [source];
+ }
+ }
+ // an ID match
+ source = this.getSourceById(EventSource_1.default.normalizeId(matchInput));
+ if (source) {
+ return [source];
+ }
+ // parse as an event source
+ matchInput = EventSourceParser_1.default.parse(matchInput, this.calendar);
+ if (matchInput) {
+ return $.grep(sources, function (source) {
+ return isSourcesEquivalent(matchInput, source);
+ });
+ }
+ };
+ /*
+ ID assumed to already be normalized
+ */
+ EventManager.prototype.getSourceById = function (id) {
+ return $.grep(this.otherSources, function (source) {
+ return source.id && source.id === id;
+ })[0];
+ };
+ // Event-Period
+ // -----------------------------------------------------------------------------------------------------------------
+ EventManager.prototype.setPeriod = function (eventPeriod) {
+ if (this.currentPeriod) {
+ this.unbindPeriod(this.currentPeriod);
+ this.currentPeriod = null;
+ }
+ this.currentPeriod = eventPeriod;
+ this.bindPeriod(eventPeriod);
+ eventPeriod.requestSources(this.getSources());
+ };
+ EventManager.prototype.bindPeriod = function (eventPeriod) {
+ this.listenTo(eventPeriod, 'release', function (eventsPayload) {
+ this.trigger('release', eventsPayload);
+ });
+ };
+ EventManager.prototype.unbindPeriod = function (eventPeriod) {
+ this.stopListeningTo(eventPeriod);
+ };
+ // Event Getting/Adding/Removing
+ // -----------------------------------------------------------------------------------------------------------------
+ EventManager.prototype.getEventDefByUid = function (uid) {
+ if (this.currentPeriod) {
+ return this.currentPeriod.getEventDefByUid(uid);
+ }
+ };
+ EventManager.prototype.addEventDef = function (eventDef, isSticky) {
+ if (isSticky) {
+ this.stickySource.addEventDef(eventDef);
+ }
+ if (this.currentPeriod) {
+ this.currentPeriod.addEventDef(eventDef); // might release
+ }
+ };
+ EventManager.prototype.removeEventDefsById = function (eventId) {
+ this.getSources().forEach(function (eventSource) {
+ eventSource.removeEventDefsById(eventId);
+ });
+ if (this.currentPeriod) {
+ this.currentPeriod.removeEventDefsById(eventId); // might release
+ }
+ };
+ EventManager.prototype.removeAllEventDefs = function () {
+ this.getSources().forEach(function (eventSource) {
+ eventSource.removeAllEventDefs();
+ });
+ if (this.currentPeriod) {
+ this.currentPeriod.removeAllEventDefs();
+ }
+ };
+ // Event Mutating
+ // -----------------------------------------------------------------------------------------------------------------
+ /*
+ Returns an undo function.
+ */
+ EventManager.prototype.mutateEventsWithId = function (eventDefId, eventDefMutation) {
+ var currentPeriod = this.currentPeriod;
+ var eventDefs;
+ var undoFuncs = [];
+ if (currentPeriod) {
+ currentPeriod.freeze();
+ eventDefs = currentPeriod.getEventDefsById(eventDefId);
+ eventDefs.forEach(function (eventDef) {
+ // add/remove esp because id might change
+ currentPeriod.removeEventDef(eventDef);
+ undoFuncs.push(eventDefMutation.mutateSingle(eventDef));
+ currentPeriod.addEventDef(eventDef);
+ });
+ currentPeriod.thaw();
+ return function () {
+ currentPeriod.freeze();
+ for (var i = 0; i < eventDefs.length; i++) {
+ currentPeriod.removeEventDef(eventDefs[i]);
+ undoFuncs[i]();
+ currentPeriod.addEventDef(eventDefs[i]);
+ }
+ currentPeriod.thaw();
+ };
+ }
+ return function () { };
+ };
+ /*
+ copies and then mutates
+ */
+ EventManager.prototype.buildMutatedEventInstanceGroup = function (eventDefId, eventDefMutation) {
+ var eventDefs = this.getEventDefsById(eventDefId);
+ var i;
+ var defCopy;
+ var allInstances = [];
+ for (i = 0; i < eventDefs.length; i++) {
+ defCopy = eventDefs[i].clone();
+ if (defCopy instanceof SingleEventDef_1.default) {
+ eventDefMutation.mutateSingle(defCopy);
+ allInstances.push.apply(allInstances, // append
+ defCopy.buildInstances());
+ }
+ }
+ return new EventInstanceGroup_1.default(allInstances);
+ };
+ // Freezing
+ // -----------------------------------------------------------------------------------------------------------------
+ EventManager.prototype.freeze = function () {
+ if (this.currentPeriod) {
+ this.currentPeriod.freeze();
+ }
+ };
+ EventManager.prototype.thaw = function () {
+ if (this.currentPeriod) {
+ this.currentPeriod.thaw();
+ }
+ };
+ // methods that simply forward to EventPeriod
+ EventManager.prototype.getEventDefsById = function (eventDefId) {
+ return this.currentPeriod.getEventDefsById(eventDefId);
+ };
+ EventManager.prototype.getEventInstances = function () {
+ return this.currentPeriod.getEventInstances();
+ };
+ EventManager.prototype.getEventInstancesWithId = function (eventDefId) {
+ return this.currentPeriod.getEventInstancesWithId(eventDefId);
+ };
+ EventManager.prototype.getEventInstancesWithoutId = function (eventDefId) {
+ return this.currentPeriod.getEventInstancesWithoutId(eventDefId);
+ };
+ return EventManager;
+}());
+exports.default = EventManager;
+EmitterMixin_1.default.mixInto(EventManager);
+ListenerMixin_1.default.mixInto(EventManager);
+function isSourcesEquivalent(source0, source1) {
+ return source0.getPrimitive() === source1.getPrimitive();
+}
+
+
+/***/ }),
+/* 221 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
-var Theme_1 = __webpack_require__(19);
+var Theme_1 = __webpack_require__(22);
var StandardTheme = /** @class */ (function (_super) {
tslib_1.__extends(StandardTheme, _super);
function StandardTheme() {
@@ -8286,12 +9220,12 @@
/***/ }),
-/* 214 */
+/* 222 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
-var Theme_1 = __webpack_require__(19);
+var Theme_1 = __webpack_require__(22);
var JqueryUiTheme = /** @class */ (function (_super) {
tslib_1.__extends(JqueryUiTheme, _super);
function JqueryUiTheme() {
@@ -8336,13 +9270,13 @@
/***/ }),
-/* 215 */
+/* 223 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
-var Promise_1 = __webpack_require__(20);
+var Promise_1 = __webpack_require__(21);
var EventSource_1 = __webpack_require__(6);
var FuncEventSource = /** @class */ (function (_super) {
tslib_1.__extends(FuncEventSource, _super);
@@ -8352,10 +9286,10 @@
FuncEventSource.parse = function (rawInput, calendar) {
var rawProps;
// normalize raw input
- if ($.isFunction(rawInput.events)) {
+ if ($.isFunction(rawInput.events)) { // extended form
rawProps = rawInput;
}
- else if ($.isFunction(rawInput)) {
+ else if ($.isFunction(rawInput)) { // short form
rawProps = { events: rawInput };
}
if (rawProps) {
@@ -8390,14 +9324,14 @@
/***/ }),
-/* 216 */
+/* 224 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
var util_1 = __webpack_require__(4);
-var Promise_1 = __webpack_require__(20);
+var Promise_1 = __webpack_require__(21);
var EventSource_1 = __webpack_require__(6);
var JsonFeedEventSource = /** @class */ (function (_super) {
tslib_1.__extends(JsonFeedEventSource, _super);
@@ -8407,10 +9341,10 @@
JsonFeedEventSource.parse = function (rawInput, calendar) {
var rawProps;
// normalize raw input
- if (typeof rawInput.url === 'string') {
+ if (typeof rawInput.url === 'string') { // extended form
rawProps = rawInput;
}
- else if (typeof rawInput === 'string') {
+ else if (typeof rawInput === 'string') { // short form
rawProps = { url: rawInput };
}
if (rawProps) {
@@ -8515,11 +9449,333 @@
/***/ }),
-/* 217 */
+/* 225 */
+/***/ (function(module, exports) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var Iterator = /** @class */ (function () {
+ function Iterator(items) {
+ this.items = items || [];
+ }
+ /* Calls a method on every item passing the arguments through */
+ Iterator.prototype.proxyCall = function (methodName) {
+ var args = [];
+ for (var _i = 1; _i < arguments.length; _i++) {
+ args[_i - 1] = arguments[_i];
+ }
+ var results = [];
+ this.items.forEach(function (item) {
+ results.push(item[methodName].apply(item, args));
+ });
+ return results;
+ };
+ return Iterator;
+}());
+exports.default = Iterator;
+
+
+/***/ }),
+/* 226 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
-var EmitterMixin_1 = __webpack_require__(11);
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var ListenerMixin_1 = __webpack_require__(7);
+/* Creates a clone of an element and lets it track the mouse as it moves
+----------------------------------------------------------------------------------------------------------------------*/
+var MouseFollower = /** @class */ (function () {
+ function MouseFollower(sourceEl, options) {
+ this.isFollowing = false;
+ this.isHidden = false;
+ this.isAnimating = false; // doing the revert animation?
+ this.options = options = options || {};
+ this.sourceEl = sourceEl;
+ this.parentEl = options.parentEl ? $(options.parentEl) : sourceEl.parent(); // default to sourceEl's parent
+ }
+ // Causes the element to start following the mouse
+ MouseFollower.prototype.start = function (ev) {
+ if (!this.isFollowing) {
+ this.isFollowing = true;
+ this.y0 = util_1.getEvY(ev);
+ this.x0 = util_1.getEvX(ev);
+ this.topDelta = 0;
+ this.leftDelta = 0;
+ if (!this.isHidden) {
+ this.updatePosition();
+ }
+ if (util_1.getEvIsTouch(ev)) {
+ this.listenTo($(document), 'touchmove', this.handleMove);
+ }
+ else {
+ this.listenTo($(document), 'mousemove', this.handleMove);
+ }
+ }
+ };
+ // Causes the element to stop following the mouse. If shouldRevert is true, will animate back to original position.
+ // `callback` gets invoked when the animation is complete. If no animation, it is invoked immediately.
+ MouseFollower.prototype.stop = function (shouldRevert, callback) {
+ var _this = this;
+ var revertDuration = this.options.revertDuration;
+ var complete = function () {
+ _this.isAnimating = false;
+ _this.removeElement();
+ _this.top0 = _this.left0 = null; // reset state for future updatePosition calls
+ if (callback) {
+ callback();
+ }
+ };
+ if (this.isFollowing && !this.isAnimating) { // disallow more than one stop animation at a time
+ this.isFollowing = false;
+ this.stopListeningTo($(document));
+ if (shouldRevert && revertDuration && !this.isHidden) { // do a revert animation?
+ this.isAnimating = true;
+ this.el.animate({
+ top: this.top0,
+ left: this.left0
+ }, {
+ duration: revertDuration,
+ complete: complete
+ });
+ }
+ else {
+ complete();
+ }
+ }
+ };
+ // Gets the tracking element. Create it if necessary
+ MouseFollower.prototype.getEl = function () {
+ var el = this.el;
+ if (!el) {
+ el = this.el = this.sourceEl.clone()
+ .addClass(this.options.additionalClass || '')
+ .css({
+ position: 'absolute',
+ visibility: '',
+ display: this.isHidden ? 'none' : '',
+ margin: 0,
+ right: 'auto',
+ bottom: 'auto',
+ width: this.sourceEl.width(),
+ height: this.sourceEl.height(),
+ opacity: this.options.opacity || '',
+ zIndex: this.options.zIndex
+ });
+ // we don't want long taps or any mouse interaction causing selection/menus.
+ // would use preventSelection(), but that prevents selectstart, causing problems.
+ el.addClass('fc-unselectable');
+ el.appendTo(this.parentEl);
+ }
+ return el;
+ };
+ // Removes the tracking element if it has already been created
+ MouseFollower.prototype.removeElement = function () {
+ if (this.el) {
+ this.el.remove();
+ this.el = null;
+ }
+ };
+ // Update the CSS position of the tracking element
+ MouseFollower.prototype.updatePosition = function () {
+ var sourceOffset;
+ var origin;
+ this.getEl(); // ensure this.el
+ // make sure origin info was computed
+ if (this.top0 == null) {
+ sourceOffset = this.sourceEl.offset();
+ origin = this.el.offsetParent().offset();
+ this.top0 = sourceOffset.top - origin.top;
+ this.left0 = sourceOffset.left - origin.left;
+ }
+ this.el.css({
+ top: this.top0 + this.topDelta,
+ left: this.left0 + this.leftDelta
+ });
+ };
+ // Gets called when the user moves the mouse
+ MouseFollower.prototype.handleMove = function (ev) {
+ this.topDelta = util_1.getEvY(ev) - this.y0;
+ this.leftDelta = util_1.getEvX(ev) - this.x0;
+ if (!this.isHidden) {
+ this.updatePosition();
+ }
+ };
+ // Temporarily makes the tracking element invisible. Can be called before following starts
+ MouseFollower.prototype.hide = function () {
+ if (!this.isHidden) {
+ this.isHidden = true;
+ if (this.el) {
+ this.el.hide();
+ }
+ }
+ };
+ // Show the tracking element after it has been temporarily hidden
+ MouseFollower.prototype.show = function () {
+ if (this.isHidden) {
+ this.isHidden = false;
+ this.updatePosition();
+ this.getEl().show();
+ }
+ };
+ return MouseFollower;
+}());
+exports.default = MouseFollower;
+ListenerMixin_1.default.mixInto(MouseFollower);
+
+
+/***/ }),
+/* 227 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/* A rectangular panel that is absolutely positioned over other content
+------------------------------------------------------------------------------------------------------------------------
+Options:
+ - className (string)
+ - content (HTML string or jQuery element set)
+ - parentEl
+ - top
+ - left
+ - right (the x coord of where the right edge should be. not a "CSS" right)
+ - autoHide (boolean)
+ - show (callback)
+ - hide (callback)
+*/
+Object.defineProperty(exports, "__esModule", { value: true });
+var $ = __webpack_require__(3);
+var util_1 = __webpack_require__(4);
+var ListenerMixin_1 = __webpack_require__(7);
+var Popover = /** @class */ (function () {
+ function Popover(options) {
+ this.isHidden = true;
+ this.margin = 10; // the space required between the popover and the edges of the scroll container
+ this.options = options || {};
+ }
+ // Shows the popover on the specified position. Renders it if not already
+ Popover.prototype.show = function () {
+ if (this.isHidden) {
+ if (!this.el) {
+ this.render();
+ }
+ this.el.show();
+ this.position();
+ this.isHidden = false;
+ this.trigger('show');
+ }
+ };
+ // Hides the popover, through CSS, but does not remove it from the DOM
+ Popover.prototype.hide = function () {
+ if (!this.isHidden) {
+ this.el.hide();
+ this.isHidden = true;
+ this.trigger('hide');
+ }
+ };
+ // Creates `this.el` and renders content inside of it
+ Popover.prototype.render = function () {
+ var _this = this;
+ var options = this.options;
+ this.el = $('
')
+ .addClass(options.className || '')
+ .css({
+ // position initially to the top left to avoid creating scrollbars
+ top: 0,
+ left: 0
+ })
+ .append(options.content)
+ .appendTo(options.parentEl);
+ // when a click happens on anything inside with a 'fc-close' className, hide the popover
+ this.el.on('click', '.fc-close', function () {
+ _this.hide();
+ });
+ if (options.autoHide) {
+ this.listenTo($(document), 'mousedown', this.documentMousedown);
+ }
+ };
+ // Triggered when the user clicks *anywhere* in the document, for the autoHide feature
+ Popover.prototype.documentMousedown = function (ev) {
+ // only hide the popover if the click happened outside the popover
+ if (this.el && !$(ev.target).closest(this.el).length) {
+ this.hide();
+ }
+ };
+ // Hides and unregisters any handlers
+ Popover.prototype.removeElement = function () {
+ this.hide();
+ if (this.el) {
+ this.el.remove();
+ this.el = null;
+ }
+ this.stopListeningTo($(document), 'mousedown');
+ };
+ // Positions the popover optimally, using the top/left/right options
+ Popover.prototype.position = function () {
+ var options = this.options;
+ var origin = this.el.offsetParent().offset();
+ var width = this.el.outerWidth();
+ var height = this.el.outerHeight();
+ var windowEl = $(window);
+ var viewportEl = util_1.getScrollParent(this.el);
+ var viewportTop;
+ var viewportLeft;
+ var viewportOffset;
+ var top; // the "position" (not "offset") values for the popover
+ var left; //
+ // compute top and left
+ top = options.top || 0;
+ if (options.left !== undefined) {
+ left = options.left;
+ }
+ else if (options.right !== undefined) {
+ left = options.right - width; // derive the left value from the right value
+ }
+ else {
+ left = 0;
+ }
+ if (viewportEl.is(window) || viewportEl.is(document)) { // normalize getScrollParent's result
+ viewportEl = windowEl;
+ viewportTop = 0; // the window is always at the top left
+ viewportLeft = 0; // (and .offset() won't work if called here)
+ }
+ else {
+ viewportOffset = viewportEl.offset();
+ viewportTop = viewportOffset.top;
+ viewportLeft = viewportOffset.left;
+ }
+ // if the window is scrolled, it causes the visible area to be further down
+ viewportTop += windowEl.scrollTop();
+ viewportLeft += windowEl.scrollLeft();
+ // constrain to the view port. if constrained by two edges, give precedence to top/left
+ if (options.viewportConstrain !== false) {
+ top = Math.min(top, viewportTop + viewportEl.outerHeight() - height - this.margin);
+ top = Math.max(top, viewportTop + this.margin);
+ left = Math.min(left, viewportLeft + viewportEl.outerWidth() - width - this.margin);
+ left = Math.max(left, viewportLeft + this.margin);
+ }
+ this.el.css({
+ top: top - origin.top,
+ left: left - origin.left
+ });
+ };
+ // Triggers a callback. Calls a function in the option hash of the same name.
+ // Arguments beyond the first `name` are forwarded on.
+ // TODO: better code reuse for this. Repeat code
+ Popover.prototype.trigger = function (name) {
+ if (this.options[name]) {
+ this.options[name].apply(this, Array.prototype.slice.call(arguments, 1));
+ }
+ };
+ return Popover;
+}());
+exports.default = Popover;
+ListenerMixin_1.default.mixInto(Popover);
+
+
+/***/ }),
+/* 228 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var EmitterMixin_1 = __webpack_require__(13);
var TaskQueue = /** @class */ (function () {
function TaskQueue() {
this.q = [];
@@ -8585,12 +9841,12 @@
/***/ }),
-/* 218 */
+/* 229 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
-var TaskQueue_1 = __webpack_require__(217);
+var TaskQueue_1 = __webpack_require__(228);
var RenderQueue = /** @class */ (function (_super) {
tslib_1.__extends(RenderQueue, _super);
function RenderQueue(waitsByNamespace) {
@@ -8617,7 +9873,7 @@
this.tryStart();
}
}
- if (this.compoundTask(task)) {
+ if (this.compoundTask(task)) { // appended to queue?
if (!this.waitNamespace && waitMs != null) {
this.startWait(namespace, waitMs);
}
@@ -8679,15 +9935,17 @@
// remove all init/add/remove ops with same namespace, regardless of order
for (i = q.length - 1; i >= 0; i--) {
task = q[i];
- switch (task.type) {
- case 'init':
- shouldAppend = false;
- // the latest destroy is cancelled out by not doing the init
- /* falls through */
- case 'add':
- /* falls through */
- case 'remove':
- q.splice(i, 1); // remove task
+ if (task.namespace === newTask.namespace) {
+ switch (task.type) {
+ case 'init':
+ shouldAppend = false;
+ // the latest destroy is cancelled out by not doing the init
+ /* falls through */
+ case 'add':
+ /* falls through */
+ case 'remove':
+ q.splice(i, 1); // remove task
+ }
}
}
}
@@ -8702,7 +9960,56 @@
/***/ }),
-/* 219 */
+/* 230 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var Model_1 = __webpack_require__(51);
+var Component = /** @class */ (function (_super) {
+ tslib_1.__extends(Component, _super);
+ function Component() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ Component.prototype.setElement = function (el) {
+ this.el = el;
+ this.bindGlobalHandlers();
+ this.renderSkeleton();
+ this.set('isInDom', true);
+ };
+ Component.prototype.removeElement = function () {
+ this.unset('isInDom');
+ this.unrenderSkeleton();
+ this.unbindGlobalHandlers();
+ this.el.remove();
+ // NOTE: don't null-out this.el in case the View was destroyed within an API callback.
+ // We don't null-out the View's other jQuery element references upon destroy,
+ // so we shouldn't kill this.el either.
+ };
+ Component.prototype.bindGlobalHandlers = function () {
+ // subclasses can override
+ };
+ Component.prototype.unbindGlobalHandlers = function () {
+ // subclasses can override
+ };
+ /*
+ NOTE: Can't have a `render` method. Read the deprecation notice in View::executeDateRender
+ */
+ // Renders the basic structure of the view before any content is rendered
+ Component.prototype.renderSkeleton = function () {
+ // subclasses should implement
+ };
+ // Unrenders the basic structure of the view
+ Component.prototype.unrenderSkeleton = function () {
+ // subclasses should implement
+ };
+ return Component;
+}(Model_1.default));
+exports.default = Component;
+
+
+/***/ }),
+/* 231 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
@@ -8710,10 +10017,10 @@
var $ = __webpack_require__(3);
var moment = __webpack_require__(0);
var util_1 = __webpack_require__(4);
-var moment_ext_1 = __webpack_require__(10);
-var date_formatting_1 = __webpack_require__(47);
-var Component_1 = __webpack_require__(237);
-var util_2 = __webpack_require__(35);
+var moment_ext_1 = __webpack_require__(11);
+var date_formatting_1 = __webpack_require__(49);
+var Component_1 = __webpack_require__(230);
+var util_2 = __webpack_require__(19);
var DateComponent = /** @class */ (function (_super) {
tslib_1.__extends(DateComponent, _super);
function DateComponent(_view, _options) {
@@ -8736,7 +10043,7 @@
if (_this.fillRendererClass) {
_this.fillRenderer = new _this.fillRendererClass(_this);
}
- if (_this.eventRendererClass) {
+ if (_this.eventRendererClass) { // fillRenderer is optional -----v
_this.eventRenderer = new _this.eventRendererClass(_this, _this.fillRenderer);
}
if (_this.helperRendererClass && _this.eventRenderer) {
@@ -8846,7 +10153,7 @@
this.eventRenderer.rangeUpdated(); // poorly named now
this.eventRenderer.render(eventsPayload);
}
- else if (this['renderEvents']) {
+ else if (this['renderEvents']) { // legacy
this['renderEvents'](convertEventsPayloadToLegacyArray(eventsPayload));
}
this.callChildren('executeEventRender', arguments);
@@ -8856,7 +10163,7 @@
if (this.eventRenderer) {
this.eventRenderer.unrender();
}
- else if (this['destroyEvents']) {
+ else if (this['destroyEvents']) { // legacy
this['destroyEvents']();
}
};
@@ -8901,7 +10208,7 @@
if (this.hasPublicHandlers('eventAfterRender')) {
segs.forEach(function (seg) {
var legacy;
- if (seg.el) {
+ if (seg.el) { // necessary?
legacy = seg.footprint.getEventLegacy();
_this.publiclyTrigger('eventAfterRender', {
context: legacy,
@@ -8919,7 +10226,7 @@
if (this.hasPublicHandlers('eventDestroy')) {
segs.forEach(function (seg) {
var legacy;
- if (seg.el) {
+ if (seg.el) { // necessary?
legacy = seg.footprint.getEventLegacy();
_this.publiclyTrigger('eventDestroy', {
context: legacy,
@@ -9197,7 +10504,7 @@
}
else {
classes.push('fc-' + util_1.dayIDs[date.day()]);
- if (view.isDateInOtherMonth(date, this.dateProfile)) {
+ if (view.isDateInOtherMonth(date, this.dateProfile)) { // TODO: use DateComponent subclass somehow
classes.push('fc-other-month');
}
today = view.calendar.getNow();
@@ -9277,35 +10584,35 @@
/***/ }),
-/* 220 */
+/* 232 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var $ = __webpack_require__(3);
var moment = __webpack_require__(0);
var util_1 = __webpack_require__(4);
-var options_1 = __webpack_require__(32);
-var Iterator_1 = __webpack_require__(238);
-var GlobalEmitter_1 = __webpack_require__(21);
-var EmitterMixin_1 = __webpack_require__(11);
+var options_1 = __webpack_require__(33);
+var Iterator_1 = __webpack_require__(225);
+var GlobalEmitter_1 = __webpack_require__(23);
+var EmitterMixin_1 = __webpack_require__(13);
var ListenerMixin_1 = __webpack_require__(7);
-var Toolbar_1 = __webpack_require__(239);
-var OptionsManager_1 = __webpack_require__(240);
-var ViewSpecManager_1 = __webpack_require__(241);
-var Constraints_1 = __webpack_require__(207);
-var locale_1 = __webpack_require__(31);
-var moment_ext_1 = __webpack_require__(10);
+var Toolbar_1 = __webpack_require__(257);
+var OptionsManager_1 = __webpack_require__(258);
+var ViewSpecManager_1 = __webpack_require__(259);
+var Constraints_1 = __webpack_require__(217);
+var locale_1 = __webpack_require__(32);
+var moment_ext_1 = __webpack_require__(11);
var UnzonedRange_1 = __webpack_require__(5);
var ComponentFootprint_1 = __webpack_require__(12);
-var EventDateProfile_1 = __webpack_require__(17);
-var EventManager_1 = __webpack_require__(242);
-var BusinessHourGenerator_1 = __webpack_require__(212);
+var EventDateProfile_1 = __webpack_require__(16);
+var EventManager_1 = __webpack_require__(220);
+var BusinessHourGenerator_1 = __webpack_require__(218);
var EventSourceParser_1 = __webpack_require__(38);
-var EventDefParser_1 = __webpack_require__(49);
-var SingleEventDef_1 = __webpack_require__(13);
-var EventDefMutation_1 = __webpack_require__(37);
+var EventDefParser_1 = __webpack_require__(36);
+var SingleEventDef_1 = __webpack_require__(9);
+var EventDefMutation_1 = __webpack_require__(39);
var EventSource_1 = __webpack_require__(6);
-var ThemeRegistry_1 = __webpack_require__(51);
+var ThemeRegistry_1 = __webpack_require__(57);
var Calendar = /** @class */ (function () {
function Calendar(el, overrides) {
this.loadingLevel = 0; // number of simultaneous loading tasks
@@ -9362,16 +10669,16 @@
Calendar.prototype.option = function (name, value) {
var newOptionHash;
if (typeof name === 'string') {
- if (value === undefined) {
+ if (value === undefined) { // getter
return this.optionsManager.get(name);
}
- else {
+ else { // setter for individual option
newOptionHash = {};
newOptionHash[name] = value;
this.optionsManager.add(newOptionHash);
}
}
- else if (typeof name === 'object') {
+ else if (typeof name === 'object') { // compound setter with object input
this.optionsManager.add(name);
}
};
@@ -9395,12 +10702,12 @@
};
Calendar.prototype.changeView = function (viewName, dateOrRange) {
if (dateOrRange) {
- if (dateOrRange.start && dateOrRange.end) {
+ if (dateOrRange.start && dateOrRange.end) { // a range
this.optionsManager.recordOverrides({
visibleRange: dateOrRange
});
}
- else {
+ else { // a date
this.currentDate = this.moment(dateOrRange).stripZone(); // just like gotoDate
}
}
@@ -9546,7 +10853,7 @@
el.toggleClass('fc-ltr', !opts.isRTL);
el.toggleClass('fc-rtl', opts.isRTL);
});
- this.contentEl = $("").prependTo(el);
+ this.contentEl = $("
").prependTo(el);
this.initToolbars();
this.renderHeader();
this.renderFooter();
@@ -9581,12 +10888,12 @@
Calendar.prototype.bindViewHandlers = function (view) {
var _this = this;
view.watch('titleForCalendar', ['title'], function (deps) {
- if (view === _this.view) {
+ if (view === _this.view) { // hack
_this.setToolbarsTitle(deps.title);
}
});
view.watch('dateProfileForCalendar', ['dateProfile'], function (deps) {
- if (view === _this.view) {
+ if (view === _this.view) { // hack
_this.currentDate = deps.dateProfile.date; // might have been constrained by view dates
_this.updateToolbarButtons(deps.dateProfile);
}
@@ -9615,7 +10922,7 @@
(this.viewsByType[viewType] = this.instantiateView(viewType));
this.bindViewHandlers(newView);
newView.startBatchRender(); // so that setElement+setDate rendering are joined
- newView.setElement($("").appendTo(this.contentEl));
+ newView.setElement($("
").appendTo(this.contentEl));
this.toolbarsManager.proxyCall('activateButton', viewType);
}
if (this.view) {
@@ -9690,19 +10997,19 @@
Calendar.prototype._calcSize = function () {
var contentHeightInput = this.opt('contentHeight');
var heightInput = this.opt('height');
- if (typeof contentHeightInput === 'number') {
+ if (typeof contentHeightInput === 'number') { // exists and not 'auto'
this.suggestedViewHeight = contentHeightInput;
}
- else if (typeof contentHeightInput === 'function') {
+ else if (typeof contentHeightInput === 'function') { // exists and is a function
this.suggestedViewHeight = contentHeightInput();
}
- else if (typeof heightInput === 'number') {
+ else if (typeof heightInput === 'number') { // exists and not 'auto'
this.suggestedViewHeight = heightInput - this.queryToolbarsHeight();
}
- else if (typeof heightInput === 'function') {
+ else if (typeof heightInput === 'function') { // exists and is a function
this.suggestedViewHeight = heightInput() - this.queryToolbarsHeight();
}
- else if (heightInput === 'parent') {
+ else if (heightInput === 'parent') { // set to height of parent element
this.suggestedViewHeight = this.el.parent().height() - this.queryToolbarsHeight();
}
else {
@@ -9717,7 +11024,7 @@
ev.target === window &&
this.view &&
this.view.isDatesRendered) {
- if (this.updateViewSize(true)) {
+ if (this.updateViewSize(true)) { // isResize=true, returns true on success
this.publiclyTrigger('windowResize', [this.view]);
}
}
@@ -9879,7 +11186,8 @@
_week.dow = firstDay;
localeData._week = _week;
}
- if (weekNumberCalculation === 'ISO' ||
+ if ( // whitelist certain kinds of input
+ weekNumberCalculation === 'ISO' ||
weekNumberCalculation === 'local' ||
typeof weekNumberCalculation === 'function') {
localeData._fullCalendar_weekCalc = weekNumberCalculation; // moment-ext will know what to do with it
@@ -9903,7 +11211,7 @@
if (this.opt('timezone') === 'local') {
mom = moment_ext_1.default.apply(null, args);
// Force the moment to be local, because momentExt doesn't guarantee it.
- if (mom.hasTime()) {
+ if (mom.hasTime()) { // don't give ambiguously-timed moments a local zone
mom.local();
}
}
@@ -9953,9 +11261,9 @@
var timeAdjust = date.time().asMilliseconds() - zonedDate.time().asMilliseconds();
var adjustedZonedDate;
// Safari sometimes has problems with this coersion when near DST. Adjust if necessary. (bug #2396)
- if (timeAdjust) {
+ if (timeAdjust) { // is the time result different than expected?
adjustedZonedDate = zonedDate.clone().add(timeAdjust); // add milliseconds
- if (date.time().asMilliseconds() - adjustedZonedDate.time().asMilliseconds() === 0) {
+ if (date.time().asMilliseconds() - adjustedZonedDate.time().asMilliseconds() === 0) { // does it match perfectly now?
zonedDate = adjustedZonedDate;
}
}
@@ -9983,6 +11291,10 @@
end = this.applyTimezone(end);
}
}
+ this.localizeMoment(start);
+ if (end) {
+ this.localizeMoment(end);
+ }
return new EventDateProfile_1.default(start, end, this);
};
// Returns a moment for the current date, as defined by the client's computer or from the `now` option.
@@ -10097,7 +11409,7 @@
var idMap = {};
var eventDef;
var i;
- if (legacyQuery == null) {
+ if (legacyQuery == null) { // shortcut for removing all
eventManager.removeAllEventDefs(); // persist=true
}
else {
@@ -10111,7 +11423,7 @@
idMap[eventDef.id] = true;
}
eventManager.freeze();
- for (i in idMap) {
+ for (i in idMap) { // reuse `i` as an "id"
eventManager.removeEventDefsById(i); // persist=true
}
eventManager.thaw();
@@ -10210,7 +11522,7 @@
else if ($.isFunction(legacyQuery)) {
return legacyEventInstances.filter(legacyQuery);
}
- else {
+ else { // an event ID
legacyQuery += ''; // normalize to string
return legacyEventInstances.filter(function (legacyEventInstance) {
// soft comparison because id not be normalized to string
@@ -10223,288 +11535,22 @@
/***/ }),
-/* 221 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var moment = __webpack_require__(0);
-var util_1 = __webpack_require__(4);
-var UnzonedRange_1 = __webpack_require__(5);
-var DateProfileGenerator = /** @class */ (function () {
- function DateProfileGenerator(_view) {
- this._view = _view;
- }
- DateProfileGenerator.prototype.opt = function (name) {
- return this._view.opt(name);
- };
- DateProfileGenerator.prototype.trimHiddenDays = function (unzonedRange) {
- return this._view.trimHiddenDays(unzonedRange);
- };
- DateProfileGenerator.prototype.msToUtcMoment = function (ms, forceAllDay) {
- return this._view.calendar.msToUtcMoment(ms, forceAllDay);
- };
- /* Date Range Computation
- ------------------------------------------------------------------------------------------------------------------*/
- // Builds a structure with info about what the dates/ranges will be for the "prev" view.
- DateProfileGenerator.prototype.buildPrev = function (currentDateProfile) {
- var prevDate = currentDateProfile.date.clone()
- .startOf(currentDateProfile.currentRangeUnit)
- .subtract(currentDateProfile.dateIncrement);
- return this.build(prevDate, -1);
- };
- // Builds a structure with info about what the dates/ranges will be for the "next" view.
- DateProfileGenerator.prototype.buildNext = function (currentDateProfile) {
- var nextDate = currentDateProfile.date.clone()
- .startOf(currentDateProfile.currentRangeUnit)
- .add(currentDateProfile.dateIncrement);
- return this.build(nextDate, 1);
- };
- // Builds a structure holding dates/ranges for rendering around the given date.
- // Optional direction param indicates whether the date is being incremented/decremented
- // from its previous value. decremented = -1, incremented = 1 (default).
- DateProfileGenerator.prototype.build = function (date, direction, forceToValid) {
- if (forceToValid === void 0) { forceToValid = false; }
- var isDateAllDay = !date.hasTime();
- var validUnzonedRange;
- var minTime = null;
- var maxTime = null;
- var currentInfo;
- var isRangeAllDay;
- var renderUnzonedRange;
- var activeUnzonedRange;
- var isValid;
- validUnzonedRange = this.buildValidRange();
- validUnzonedRange = this.trimHiddenDays(validUnzonedRange);
- if (forceToValid) {
- date = this.msToUtcMoment(validUnzonedRange.constrainDate(date), // returns MS
- isDateAllDay);
- }
- currentInfo = this.buildCurrentRangeInfo(date, direction);
- isRangeAllDay = /^(year|month|week|day)$/.test(currentInfo.unit);
- renderUnzonedRange = this.buildRenderRange(this.trimHiddenDays(currentInfo.unzonedRange), currentInfo.unit, isRangeAllDay);
- renderUnzonedRange = this.trimHiddenDays(renderUnzonedRange);
- activeUnzonedRange = renderUnzonedRange.clone();
- if (!this.opt('showNonCurrentDates')) {
- activeUnzonedRange = activeUnzonedRange.intersect(currentInfo.unzonedRange);
- }
- minTime = moment.duration(this.opt('minTime'));
- maxTime = moment.duration(this.opt('maxTime'));
- activeUnzonedRange = this.adjustActiveRange(activeUnzonedRange, minTime, maxTime);
- activeUnzonedRange = activeUnzonedRange.intersect(validUnzonedRange); // might return null
- if (activeUnzonedRange) {
- date = this.msToUtcMoment(activeUnzonedRange.constrainDate(date), // returns MS
- isDateAllDay);
- }
- // it's invalid if the originally requested date is not contained,
- // or if the range is completely outside of the valid range.
- isValid = currentInfo.unzonedRange.intersectsWith(validUnzonedRange);
- return {
- // constraint for where prev/next operations can go and where events can be dragged/resized to.
- // an object with optional start and end properties.
- validUnzonedRange: validUnzonedRange,
- // range the view is formally responsible for.
- // for example, a month view might have 1st-31st, excluding padded dates
- currentUnzonedRange: currentInfo.unzonedRange,
- // name of largest unit being displayed, like "month" or "week"
- currentRangeUnit: currentInfo.unit,
- isRangeAllDay: isRangeAllDay,
- // dates that display events and accept drag-n-drop
- // will be `null` if no dates accept events
- activeUnzonedRange: activeUnzonedRange,
- // date range with a rendered skeleton
- // includes not-active days that need some sort of DOM
- renderUnzonedRange: renderUnzonedRange,
- // Duration object that denotes the first visible time of any given day
- minTime: minTime,
- // Duration object that denotes the exclusive visible end time of any given day
- maxTime: maxTime,
- isValid: isValid,
- date: date,
- // how far the current date will move for a prev/next operation
- dateIncrement: this.buildDateIncrement(currentInfo.duration)
- // pass a fallback (might be null) ^
- };
- };
- // Builds an object with optional start/end properties.
- // Indicates the minimum/maximum dates to display.
- // not responsible for trimming hidden days.
- DateProfileGenerator.prototype.buildValidRange = function () {
- return this._view.getUnzonedRangeOption('validRange', this._view.calendar.getNow()) ||
- new UnzonedRange_1.default(); // completely open-ended
- };
- // Builds a structure with info about the "current" range, the range that is
- // highlighted as being the current month for example.
- // See build() for a description of `direction`.
- // Guaranteed to have `range` and `unit` properties. `duration` is optional.
- // TODO: accept a MS-time instead of a moment `date`?
- DateProfileGenerator.prototype.buildCurrentRangeInfo = function (date, direction) {
- var viewSpec = this._view.viewSpec;
- var duration = null;
- var unit = null;
- var unzonedRange = null;
- var dayCount;
- if (viewSpec.duration) {
- duration = viewSpec.duration;
- unit = viewSpec.durationUnit;
- unzonedRange = this.buildRangeFromDuration(date, direction, duration, unit);
- }
- else if ((dayCount = this.opt('dayCount'))) {
- unit = 'day';
- unzonedRange = this.buildRangeFromDayCount(date, direction, dayCount);
- }
- else if ((unzonedRange = this.buildCustomVisibleRange(date))) {
- unit = util_1.computeGreatestUnit(unzonedRange.getStart(), unzonedRange.getEnd());
- }
- else {
- duration = this.getFallbackDuration();
- unit = util_1.computeGreatestUnit(duration);
- unzonedRange = this.buildRangeFromDuration(date, direction, duration, unit);
- }
- return { duration: duration, unit: unit, unzonedRange: unzonedRange };
- };
- DateProfileGenerator.prototype.getFallbackDuration = function () {
- return moment.duration({ days: 1 });
- };
- // Returns a new activeUnzonedRange to have time values (un-ambiguate)
- // minTime or maxTime causes the range to expand.
- DateProfileGenerator.prototype.adjustActiveRange = function (unzonedRange, minTime, maxTime) {
- var start = unzonedRange.getStart();
- var end = unzonedRange.getEnd();
- if (this._view.usesMinMaxTime) {
- if (minTime < 0) {
- start.time(0).add(minTime);
- }
- if (maxTime > 24 * 60 * 60 * 1000) {
- end.time(maxTime - (24 * 60 * 60 * 1000));
- }
- }
- return new UnzonedRange_1.default(start, end);
- };
- // Builds the "current" range when it is specified as an explicit duration.
- // `unit` is the already-computed computeGreatestUnit value of duration.
- // TODO: accept a MS-time instead of a moment `date`?
- DateProfileGenerator.prototype.buildRangeFromDuration = function (date, direction, duration, unit) {
- var alignment = this.opt('dateAlignment');
- var dateIncrementInput;
- var dateIncrementDuration;
- var start;
- var end;
- var res;
- // compute what the alignment should be
- if (!alignment) {
- dateIncrementInput = this.opt('dateIncrement');
- if (dateIncrementInput) {
- dateIncrementDuration = moment.duration(dateIncrementInput);
- // use the smaller of the two units
- if (dateIncrementDuration < duration) {
- alignment = util_1.computeDurationGreatestUnit(dateIncrementDuration, dateIncrementInput);
- }
- else {
- alignment = unit;
- }
- }
- else {
- alignment = unit;
- }
- }
- // if the view displays a single day or smaller
- if (duration.as('days') <= 1) {
- if (this._view.isHiddenDay(start)) {
- start = this._view.skipHiddenDays(start, direction);
- start.startOf('day');
- }
- }
- function computeRes() {
- start = date.clone().startOf(alignment);
- end = start.clone().add(duration);
- res = new UnzonedRange_1.default(start, end);
- }
- computeRes();
- // if range is completely enveloped by hidden days, go past the hidden days
- if (!this.trimHiddenDays(res)) {
- date = this._view.skipHiddenDays(date, direction);
- computeRes();
- }
- return res;
- };
- // Builds the "current" range when a dayCount is specified.
- // TODO: accept a MS-time instead of a moment `date`?
- DateProfileGenerator.prototype.buildRangeFromDayCount = function (date, direction, dayCount) {
- var customAlignment = this.opt('dateAlignment');
- var runningCount = 0;
- var start = date.clone();
- var end;
- if (customAlignment) {
- start.startOf(customAlignment);
- }
- start.startOf('day');
- start = this._view.skipHiddenDays(start, direction);
- end = start.clone();
- do {
- end.add(1, 'day');
- if (!this._view.isHiddenDay(end)) {
- runningCount++;
- }
- } while (runningCount < dayCount);
- return new UnzonedRange_1.default(start, end);
- };
- // Builds a normalized range object for the "visible" range,
- // which is a way to define the currentUnzonedRange and activeUnzonedRange at the same time.
- // TODO: accept a MS-time instead of a moment `date`?
- DateProfileGenerator.prototype.buildCustomVisibleRange = function (date) {
- var visibleUnzonedRange = this._view.getUnzonedRangeOption('visibleRange', this._view.calendar.applyTimezone(date) // correct zone. also generates new obj that avoids mutations
- );
- if (visibleUnzonedRange && (visibleUnzonedRange.startMs == null || visibleUnzonedRange.endMs == null)) {
- return null;
- }
- return visibleUnzonedRange;
- };
- // Computes the range that will represent the element/cells for *rendering*,
- // but which may have voided days/times.
- // not responsible for trimming hidden days.
- DateProfileGenerator.prototype.buildRenderRange = function (currentUnzonedRange, currentRangeUnit, isRangeAllDay) {
- return currentUnzonedRange.clone();
- };
- // Compute the duration value that should be added/substracted to the current date
- // when a prev/next operation happens.
- DateProfileGenerator.prototype.buildDateIncrement = function (fallback) {
- var dateIncrementInput = this.opt('dateIncrement');
- var customAlignment;
- if (dateIncrementInput) {
- return moment.duration(dateIncrementInput);
- }
- else if ((customAlignment = this.opt('dateAlignment'))) {
- return moment.duration(1, customAlignment);
- }
- else if (fallback) {
- return fallback;
- }
- else {
- return moment.duration({ days: 1 });
- }
- };
- return DateProfileGenerator;
-}());
-exports.default = DateProfileGenerator;
-
-
-/***/ }),
-/* 222 */
+/* 233 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
var moment = __webpack_require__(0);
-var exportHooks = __webpack_require__(16);
+var exportHooks = __webpack_require__(18);
var util_1 = __webpack_require__(4);
-var moment_ext_1 = __webpack_require__(10);
+var moment_ext_1 = __webpack_require__(11);
var ListenerMixin_1 = __webpack_require__(7);
-var HitDragListener_1 = __webpack_require__(23);
-var SingleEventDef_1 = __webpack_require__(13);
-var EventInstanceGroup_1 = __webpack_require__(18);
+var HitDragListener_1 = __webpack_require__(17);
+var SingleEventDef_1 = __webpack_require__(9);
+var EventInstanceGroup_1 = __webpack_require__(20);
var EventSource_1 = __webpack_require__(6);
-var Interaction_1 = __webpack_require__(15);
+var Interaction_1 = __webpack_require__(14);
var ExternalDropping = /** @class */ (function (_super) {
tslib_1.__extends(ExternalDropping, _super);
function ExternalDropping() {
@@ -10538,13 +11584,13 @@
ExternalDropping.prototype.handleDragStart = function (ev, ui) {
var el;
var accept;
- if (this.opt('droppable')) {
+ if (this.opt('droppable')) { // only listen if this setting is on
el = $((ui ? ui.item : null) || ev.target);
// Test that the dragged element passes the dropAccept selector or filter function.
// FYI, the default is "*" (matches all)
accept = this.opt('dropAccept');
if ($.isFunction(accept) ? accept.call(el[0], el) : el.is(accept)) {
- if (!this.isDragging) {
+ if (!this.isDragging) { // prevent double-listening if fired twice
this.listenToExternalDrag(el, ev, ui);
}
}
@@ -10598,7 +11644,7 @@
component.unrenderDrag();
},
interactionEnd: function (ev) {
- if (singleEventDef) {
+ if (singleEventDef) { // element was dropped on a valid hit
view.reportExternalDrop(singleEventDef, Boolean(meta.eventProps), // isEvent
Boolean(meta.stick), // isSticky
el, ev, ui);
@@ -10667,7 +11713,7 @@
if (typeof eventProps === 'object') {
eventProps = $.extend({}, eventProps); // make a copy
}
- else {
+ else { // something like 1 or true. still signal event creation
eventProps = {};
}
// pluck special-cased date/time properties
@@ -10704,17 +11750,17 @@
/***/ }),
-/* 223 */
+/* 234 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
var util_1 = __webpack_require__(4);
-var EventDefMutation_1 = __webpack_require__(37);
-var EventDefDateMutation_1 = __webpack_require__(50);
-var HitDragListener_1 = __webpack_require__(23);
-var Interaction_1 = __webpack_require__(15);
+var EventDefMutation_1 = __webpack_require__(39);
+var EventDefDateMutation_1 = __webpack_require__(40);
+var HitDragListener_1 = __webpack_require__(17);
+var Interaction_1 = __webpack_require__(14);
var EventResizing = /** @class */ (function (_super) {
tslib_1.__extends(EventResizing, _super);
/*
@@ -10825,7 +11871,7 @@
if (isDragging) {
_this.segResizeStop(seg, ev);
}
- if (resizeMutation) {
+ if (resizeMutation) { // valid date to resize to?
// no need to re-show original, will rerender all anyways. esp important if eventRenderWait
view.reportEventResize(eventInstance, resizeMutation, el, ev);
}
@@ -10896,18 +11942,18 @@
/***/ }),
-/* 224 */
+/* 235 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var util_1 = __webpack_require__(4);
-var EventDefMutation_1 = __webpack_require__(37);
-var EventDefDateMutation_1 = __webpack_require__(50);
-var DragListener_1 = __webpack_require__(54);
-var HitDragListener_1 = __webpack_require__(23);
-var MouseFollower_1 = __webpack_require__(244);
-var Interaction_1 = __webpack_require__(15);
+var EventDefMutation_1 = __webpack_require__(39);
+var EventDefDateMutation_1 = __webpack_require__(40);
+var DragListener_1 = __webpack_require__(59);
+var HitDragListener_1 = __webpack_require__(17);
+var MouseFollower_1 = __webpack_require__(226);
+var Interaction_1 = __webpack_require__(14);
var EventDragging = /** @class */ (function (_super) {
tslib_1.__extends(EventDragging, _super);
/*
@@ -11170,16 +12216,16 @@
/***/ }),
-/* 225 */
+/* 236 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var util_1 = __webpack_require__(4);
-var HitDragListener_1 = __webpack_require__(23);
+var HitDragListener_1 = __webpack_require__(17);
var ComponentFootprint_1 = __webpack_require__(12);
var UnzonedRange_1 = __webpack_require__(5);
-var Interaction_1 = __webpack_require__(15);
+var Interaction_1 = __webpack_require__(14);
var DateSelecting = /** @class */ (function (_super) {
tslib_1.__extends(DateSelecting, _super);
/*
@@ -11240,7 +12286,7 @@
hitOver: function (hit, isOrig, origHit) {
var origHitFootprint;
var hitFootprint;
- if (origHit) {
+ if (origHit) { // click needs to have started on a hit
origHitFootprint = component.getSafeHitFootprint(origHit);
hitFootprint = component.getSafeHitFootprint(hit);
if (origHitFootprint && hitFootprint) {
@@ -11307,7 +12353,85 @@
/***/ }),
-/* 226 */
+/* 237 */
+/***/ (function(module, exports, __webpack_require__) {
+
+Object.defineProperty(exports, "__esModule", { value: true });
+var tslib_1 = __webpack_require__(2);
+var HitDragListener_1 = __webpack_require__(17);
+var Interaction_1 = __webpack_require__(14);
+var DateClicking = /** @class */ (function (_super) {
+ tslib_1.__extends(DateClicking, _super);
+ /*
+ component must implement:
+ - bindDateHandlerToEl
+ - getSafeHitFootprint
+ - getHitEl
+ */
+ function DateClicking(component) {
+ var _this = _super.call(this, component) || this;
+ _this.dragListener = _this.buildDragListener();
+ return _this;
+ }
+ DateClicking.prototype.end = function () {
+ this.dragListener.endInteraction();
+ };
+ DateClicking.prototype.bindToEl = function (el) {
+ var component = this.component;
+ var dragListener = this.dragListener;
+ component.bindDateHandlerToEl(el, 'mousedown', function (ev) {
+ if (!component.shouldIgnoreMouse()) {
+ dragListener.startInteraction(ev);
+ }
+ });
+ component.bindDateHandlerToEl(el, 'touchstart', function (ev) {
+ if (!component.shouldIgnoreTouch()) {
+ dragListener.startInteraction(ev);
+ }
+ });
+ };
+ // Creates a listener that tracks the user's drag across day elements, for day clicking.
+ DateClicking.prototype.buildDragListener = function () {
+ var _this = this;
+ var component = this.component;
+ var dayClickHit; // null if invalid dayClick
+ var dragListener = new HitDragListener_1.default(component, {
+ scroll: this.opt('dragScroll'),
+ interactionStart: function () {
+ dayClickHit = dragListener.origHit;
+ },
+ hitOver: function (hit, isOrig, origHit) {
+ // if user dragged to another cell at any point, it can no longer be a dayClick
+ if (!isOrig) {
+ dayClickHit = null;
+ }
+ },
+ hitOut: function () {
+ dayClickHit = null;
+ },
+ interactionEnd: function (ev, isCancelled) {
+ var componentFootprint;
+ if (!isCancelled && dayClickHit) {
+ componentFootprint = component.getSafeHitFootprint(dayClickHit);
+ if (componentFootprint) {
+ _this.view.triggerDayClick(componentFootprint, component.getHitEl(dayClickHit), ev);
+ }
+ }
+ }
+ });
+ // because dragListener won't be called with any time delay, "dragging" will begin immediately,
+ // which will kill any touchmoving/scrolling. Prevent this.
+ dragListener.shouldCancelTouchScroll = false;
+ dragListener.scrollAlwaysKills = true;
+ return dragListener;
+ };
+ return DateClicking;
+}(Interaction_1.default));
+exports.default = DateClicking;
+
+
+/***/ }),
+/* 238 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
@@ -11315,10 +12439,10 @@
var moment = __webpack_require__(0);
var $ = __webpack_require__(3);
var util_1 = __webpack_require__(4);
-var Scroller_1 = __webpack_require__(39);
-var View_1 = __webpack_require__(41);
-var TimeGrid_1 = __webpack_require__(227);
-var DayGrid_1 = __webpack_require__(61);
+var Scroller_1 = __webpack_require__(41);
+var View_1 = __webpack_require__(43);
+var TimeGrid_1 = __webpack_require__(239);
+var DayGrid_1 = __webpack_require__(66);
var AGENDA_ALL_DAY_EVENT_LIMIT = 5;
var agendaTimeGridMethods;
var agendaDayGridMethods;
@@ -11333,7 +12457,7 @@
_this.usesMinMaxTime = true; // indicates that minTime/maxTime affects rendering
_this.timeGrid = _this.instantiateTimeGrid();
_this.addChild(_this.timeGrid);
- if (_this.opt('allDaySlot')) {
+ if (_this.opt('allDaySlot')) { // should we display the "all-day" area?
_this.dayGrid = _this.instantiateDayGrid(); // the all-day subcomponent of this view
_this.addChild(_this.dayGrid);
}
@@ -11363,7 +12487,7 @@
this.el.addClass('fc-agenda-view').html(this.renderSkeletonHtml());
this.scroller.render();
timeGridWrapEl = this.scroller.el.addClass('fc-time-grid-container');
- timeGridEl = $('').appendTo(timeGridWrapEl);
+ timeGridEl = $('
');
- };
- // render the event segments in the view
- ListView.prototype.renderSegList = function (allSegs) {
- var segsByDay = this.groupSegsByDay(allSegs); // sparse array
- var dayIndex;
- var daySegs;
- var i;
- var tableEl = $('
');
- var tbodyEl = tableEl.find('tbody');
- for (dayIndex = 0; dayIndex < segsByDay.length; dayIndex++) {
- daySegs = segsByDay[dayIndex];
- if (daySegs) {
- // append a day header
- tbodyEl.append(this.dayHeaderHtml(this.dayDates[dayIndex]));
- this.eventRenderer.sortEventSegs(daySegs);
- for (i = 0; i < daySegs.length; i++) {
- tbodyEl.append(daySegs[i].el); // append event row
- }
- }
- }
- this.contentEl.empty().append(tableEl);
- };
- // Returns a sparse array of arrays, segs grouped by their dayIndex
- ListView.prototype.groupSegsByDay = function (segs) {
- var segsByDay = []; // sparse array
- var i;
- var seg;
- for (i = 0; i < segs.length; i++) {
- seg = segs[i];
- (segsByDay[seg.dayIndex] || (segsByDay[seg.dayIndex] = []))
- .push(seg);
- }
- return segsByDay;
- };
- // generates the HTML for the day headers that live amongst the event rows
- ListView.prototype.dayHeaderHtml = function (dayDate) {
- var mainFormat = this.opt('listDayFormat');
- var altFormat = this.opt('listDayAltFormat');
- return '
';
- };
- return ListView;
-}(View_1.default));
-exports.default = ListView;
-ListView.prototype.eventRendererClass = ListEventRenderer_1.default;
-ListView.prototype.eventPointingClass = ListEventPointing_1.default;
-
-
-/***/ }),
-/* 231 */,
-/* 232 */,
-/* 233 */,
-/* 234 */,
-/* 235 */,
-/* 236 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var $ = __webpack_require__(3);
-var exportHooks = __webpack_require__(16);
-var util_1 = __webpack_require__(4);
-var Calendar_1 = __webpack_require__(220);
-// for intentional side-effects
-__webpack_require__(10);
-__webpack_require__(47);
-__webpack_require__(256);
-__webpack_require__(257);
-__webpack_require__(260);
-__webpack_require__(261);
-__webpack_require__(262);
-__webpack_require__(263);
-$.fullCalendar = exportHooks;
-$.fn.fullCalendar = function (options) {
- var args = Array.prototype.slice.call(arguments, 1); // for a possible method call
- var res = this; // what this function will return (this jQuery object by default)
- this.each(function (i, _element) {
- var element = $(_element);
- var calendar = element.data('fullCalendar'); // get the existing calendar object (if any)
- var singleRes; // the returned value of this single method call
- // a method call
- if (typeof options === 'string') {
- if (options === 'getCalendar') {
- if (!i) {
- res = calendar;
- }
- }
- else if (options === 'destroy') {
- if (calendar) {
- calendar.destroy();
- element.removeData('fullCalendar');
- }
- }
- else if (!calendar) {
- util_1.warn('Attempting to call a FullCalendar method on an element with no calendar.');
- }
- else if ($.isFunction(calendar[options])) {
- singleRes = calendar[options].apply(calendar, args);
- if (!i) {
- res = singleRes; // record the first method call result
- }
- if (options === 'destroy') {
- element.removeData('fullCalendar');
- }
- }
- else {
- util_1.warn("'" + options + "' is an unknown FullCalendar method.");
- }
- }
- else if (!calendar) {
- calendar = new Calendar_1.default(element, options);
- element.data('fullCalendar', calendar);
- calendar.render();
- }
- });
- return res;
-};
-module.exports = exportHooks;
-
-
-/***/ }),
-/* 237 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var tslib_1 = __webpack_require__(2);
-var Model_1 = __webpack_require__(48);
-var Component = /** @class */ (function (_super) {
- tslib_1.__extends(Component, _super);
- function Component() {
- return _super !== null && _super.apply(this, arguments) || this;
- }
- Component.prototype.setElement = function (el) {
- this.el = el;
- this.bindGlobalHandlers();
- this.renderSkeleton();
- this.set('isInDom', true);
- };
- Component.prototype.removeElement = function () {
- this.unset('isInDom');
- this.unrenderSkeleton();
- this.unbindGlobalHandlers();
- this.el.remove();
- // NOTE: don't null-out this.el in case the View was destroyed within an API callback.
- // We don't null-out the View's other jQuery element references upon destroy,
- // so we shouldn't kill this.el either.
- };
- Component.prototype.bindGlobalHandlers = function () {
- // subclasses can override
- };
- Component.prototype.unbindGlobalHandlers = function () {
- // subclasses can override
- };
- /*
- NOTE: Can't have a `render` method. Read the deprecation notice in View::executeDateRender
- */
- // Renders the basic structure of the view before any content is rendered
- Component.prototype.renderSkeleton = function () {
- // subclasses should implement
- };
- // Unrenders the basic structure of the view
- Component.prototype.unrenderSkeleton = function () {
- // subclasses should implement
- };
- return Component;
-}(Model_1.default));
-exports.default = Component;
-
-
-/***/ }),
-/* 238 */
-/***/ (function(module, exports) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var Iterator = /** @class */ (function () {
- function Iterator(items) {
- this.items = items || [];
- }
- /* Calls a method on every item passing the arguments through */
- Iterator.prototype.proxyCall = function (methodName) {
- var args = [];
- for (var _i = 1; _i < arguments.length; _i++) {
- args[_i - 1] = arguments[_i];
- }
- var results = [];
- this.items.forEach(function (item) {
- results.push(item[methodName].apply(item, args));
- });
- return results;
- };
- return Iterator;
-}());
-exports.default = Iterator;
-
-
-/***/ }),
-/* 239 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var $ = __webpack_require__(3);
-var util_1 = __webpack_require__(4);
-/* Toolbar with buttons and title
-----------------------------------------------------------------------------------------------------------------------*/
-var Toolbar = /** @class */ (function () {
- function Toolbar(calendar, toolbarOptions) {
- this.el = null; // mirrors local `el`
- this.viewsWithButtons = [];
- this.calendar = calendar;
- this.toolbarOptions = toolbarOptions;
- }
- // method to update toolbar-specific options, not calendar-wide options
- Toolbar.prototype.setToolbarOptions = function (newToolbarOptions) {
- this.toolbarOptions = newToolbarOptions;
- };
- // can be called repeatedly and will rerender
- Toolbar.prototype.render = function () {
- var sections = this.toolbarOptions.layout;
- var el = this.el;
- if (sections) {
- if (!el) {
- el = this.el = $("");
- }
- else {
- el.empty();
- }
- el.append(this.renderSection('left'))
- .append(this.renderSection('right'))
- .append(this.renderSection('center'))
- .append('');
- }
- else {
- this.removeElement();
- }
- };
- Toolbar.prototype.removeElement = function () {
- if (this.el) {
- this.el.remove();
- this.el = null;
- }
- };
- Toolbar.prototype.renderSection = function (position) {
- var _this = this;
- var calendar = this.calendar;
- var theme = calendar.theme;
- var optionsManager = calendar.optionsManager;
- var viewSpecManager = calendar.viewSpecManager;
- var sectionEl = $('');
- var buttonStr = this.toolbarOptions.layout[position];
- var calendarCustomButtons = optionsManager.get('customButtons') || {};
- var calendarButtonTextOverrides = optionsManager.overrides.buttonText || {};
- var calendarButtonText = optionsManager.get('buttonText') || {};
- if (buttonStr) {
- $.each(buttonStr.split(' '), function (i, buttonGroupStr) {
- var groupChildren = $();
- var isOnlyButtons = true;
- var groupEl;
- $.each(buttonGroupStr.split(','), function (j, buttonName) {
- var customButtonProps;
- var viewSpec;
- var buttonClick;
- var buttonIcon; // only one of these will be set
- var buttonText; // "
- var buttonInnerHtml;
- var buttonClasses;
- var buttonEl;
- var buttonAriaAttr;
- if (buttonName === 'title') {
- groupChildren = groupChildren.add($('
')); // we always want it to take up height
- isOnlyButtons = false;
- }
- else {
- if ((customButtonProps = calendarCustomButtons[buttonName])) {
- buttonClick = function (ev) {
- if (customButtonProps.click) {
- customButtonProps.click.call(buttonEl[0], ev);
- }
- };
- (buttonIcon = theme.getCustomButtonIconClass(customButtonProps)) ||
- (buttonIcon = theme.getIconClass(buttonName)) ||
- (buttonText = customButtonProps.text);
- }
- else if ((viewSpec = viewSpecManager.getViewSpec(buttonName))) {
- _this.viewsWithButtons.push(buttonName);
- buttonClick = function () {
- calendar.changeView(buttonName);
- };
- (buttonText = viewSpec.buttonTextOverride) ||
- (buttonIcon = theme.getIconClass(buttonName)) ||
- (buttonText = viewSpec.buttonTextDefault);
- }
- else if (calendar[buttonName]) {
- buttonClick = function () {
- calendar[buttonName]();
- };
- (buttonText = calendarButtonTextOverrides[buttonName]) ||
- (buttonIcon = theme.getIconClass(buttonName)) ||
- (buttonText = calendarButtonText[buttonName]);
- // ^ everything else is considered default
- }
- if (buttonClick) {
- buttonClasses = [
- 'fc-' + buttonName + '-button',
- theme.getClass('button'),
- theme.getClass('stateDefault')
- ];
- if (buttonText) {
- buttonInnerHtml = util_1.htmlEscape(buttonText);
- buttonAriaAttr = '';
- }
- else if (buttonIcon) {
- buttonInnerHtml = "";
- buttonAriaAttr = ' aria-label="' + buttonName + '"';
- }
- buttonEl = $(// type="button" so that it doesn't submit a form
- '')
- .click(function (ev) {
- // don't process clicks for disabled buttons
- if (!buttonEl.hasClass(theme.getClass('stateDisabled'))) {
- buttonClick(ev);
- // after the click action, if the button becomes the "active" tab, or disabled,
- // it should never have a hover class, so remove it now.
- if (buttonEl.hasClass(theme.getClass('stateActive')) ||
- buttonEl.hasClass(theme.getClass('stateDisabled'))) {
- buttonEl.removeClass(theme.getClass('stateHover'));
- }
- }
- })
- .mousedown(function () {
- // the *down* effect (mouse pressed in).
- // only on buttons that are not the "active" tab, or disabled
- buttonEl
- .not('.' + theme.getClass('stateActive'))
- .not('.' + theme.getClass('stateDisabled'))
- .addClass(theme.getClass('stateDown'));
- })
- .mouseup(function () {
- // undo the *down* effect
- buttonEl.removeClass(theme.getClass('stateDown'));
- })
- .hover(function () {
- // the *hover* effect.
- // only on buttons that are not the "active" tab, or disabled
- buttonEl
- .not('.' + theme.getClass('stateActive'))
- .not('.' + theme.getClass('stateDisabled'))
- .addClass(theme.getClass('stateHover'));
- }, function () {
- // undo the *hover* effect
- buttonEl
- .removeClass(theme.getClass('stateHover'))
- .removeClass(theme.getClass('stateDown')); // if mouseleave happens before mouseup
- });
- groupChildren = groupChildren.add(buttonEl);
- }
- }
- });
- if (isOnlyButtons) {
- groupChildren
- .first().addClass(theme.getClass('cornerLeft')).end()
- .last().addClass(theme.getClass('cornerRight')).end();
- }
- if (groupChildren.length > 1) {
- groupEl = $('');
- if (isOnlyButtons) {
- groupEl.addClass(theme.getClass('buttonGroup'));
- }
- groupEl.append(groupChildren);
- sectionEl.append(groupEl);
- }
- else {
- sectionEl.append(groupChildren); // 1 or 0 children
- }
- });
- }
- return sectionEl;
- };
- Toolbar.prototype.updateTitle = function (text) {
- if (this.el) {
- this.el.find('h2').text(text);
- }
- };
- Toolbar.prototype.activateButton = function (buttonName) {
- if (this.el) {
- this.el.find('.fc-' + buttonName + '-button')
- .addClass(this.calendar.theme.getClass('stateActive'));
- }
- };
- Toolbar.prototype.deactivateButton = function (buttonName) {
- if (this.el) {
- this.el.find('.fc-' + buttonName + '-button')
- .removeClass(this.calendar.theme.getClass('stateActive'));
- }
- };
- Toolbar.prototype.disableButton = function (buttonName) {
- if (this.el) {
- this.el.find('.fc-' + buttonName + '-button')
- .prop('disabled', true)
- .addClass(this.calendar.theme.getClass('stateDisabled'));
- }
- };
- Toolbar.prototype.enableButton = function (buttonName) {
- if (this.el) {
- this.el.find('.fc-' + buttonName + '-button')
- .prop('disabled', false)
- .removeClass(this.calendar.theme.getClass('stateDisabled'));
- }
- };
- Toolbar.prototype.getViewsWithButtons = function () {
- return this.viewsWithButtons;
- };
- return Toolbar;
-}());
-exports.default = Toolbar;
-
-
-/***/ }),
/* 240 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
-var $ = __webpack_require__(3);
-var util_1 = __webpack_require__(4);
-var options_1 = __webpack_require__(32);
-var locale_1 = __webpack_require__(31);
-var Model_1 = __webpack_require__(48);
-var OptionsManager = /** @class */ (function (_super) {
- tslib_1.__extends(OptionsManager, _super);
- function OptionsManager(_calendar, overrides) {
- var _this = _super.call(this) || this;
- _this._calendar = _calendar;
- _this.overrides = $.extend({}, overrides); // make a copy
- _this.dynamicOverrides = {};
- _this.compute();
- return _this;
- }
- OptionsManager.prototype.add = function (newOptionHash) {
- var optionCnt = 0;
- var optionName;
- this.recordOverrides(newOptionHash); // will trigger this model's watchers
- for (optionName in newOptionHash) {
- optionCnt++;
- }
- // special-case handling of single option change.
- // if only one option change, `optionName` will be its name.
- if (optionCnt === 1) {
- if (optionName === 'height' || optionName === 'contentHeight' || optionName === 'aspectRatio') {
- this._calendar.updateViewSize(true); // isResize=true
- return;
- }
- else if (optionName === 'defaultDate') {
- return; // can't change date this way. use gotoDate instead
- }
- else if (optionName === 'businessHours') {
- return; // this model already reacts to this
- }
- else if (/^(event|select)(Overlap|Constraint|Allow)$/.test(optionName)) {
- return; // doesn't affect rendering. only interactions.
- }
- else if (optionName === 'timezone') {
- this._calendar.view.flash('initialEvents');
- return;
- }
- }
- // catch-all. rerender the header and footer and rebuild/rerender the current view
- this._calendar.renderHeader();
- this._calendar.renderFooter();
- // even non-current views will be affected by this option change. do before rerender
- // TODO: detangle
- this._calendar.viewsByType = {};
- this._calendar.reinitView();
- };
- // Computes the flattened options hash for the calendar and assigns to `this.options`.
- // Assumes this.overrides and this.dynamicOverrides have already been initialized.
- OptionsManager.prototype.compute = function () {
- var locale;
- var localeDefaults;
- var isRTL;
- var dirDefaults;
- var rawOptions;
- locale = util_1.firstDefined(// explicit locale option given?
- this.dynamicOverrides.locale, this.overrides.locale);
- localeDefaults = locale_1.localeOptionHash[locale];
- if (!localeDefaults) {
- locale = options_1.globalDefaults.locale;
- localeDefaults = locale_1.localeOptionHash[locale] || {};
- }
- isRTL = util_1.firstDefined(// based on options computed so far, is direction RTL?
- this.dynamicOverrides.isRTL, this.overrides.isRTL, localeDefaults.isRTL, options_1.globalDefaults.isRTL);
- dirDefaults = isRTL ? options_1.rtlDefaults : {};
- this.dirDefaults = dirDefaults;
- this.localeDefaults = localeDefaults;
- rawOptions = options_1.mergeOptions([
- options_1.globalDefaults,
- dirDefaults,
- localeDefaults,
- this.overrides,
- this.dynamicOverrides
- ]);
- locale_1.populateInstanceComputableOptions(rawOptions); // fill in gaps with computed options
- this.reset(rawOptions);
- };
- // stores the new options internally, but does not rerender anything.
- OptionsManager.prototype.recordOverrides = function (newOptionHash) {
- var optionName;
- for (optionName in newOptionHash) {
- this.dynamicOverrides[optionName] = newOptionHash[optionName];
- }
- this._calendar.viewSpecManager.clearCache(); // the dynamic override invalidates the options in this cache, so just clear it
- this.compute(); // this.options needs to be recomputed after the dynamic override
- };
- return OptionsManager;
-}(Model_1.default));
-exports.default = OptionsManager;
-
-
-/***/ }),
-/* 241 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var moment = __webpack_require__(0);
-var $ = __webpack_require__(3);
-var ViewRegistry_1 = __webpack_require__(22);
-var util_1 = __webpack_require__(4);
-var options_1 = __webpack_require__(32);
-var locale_1 = __webpack_require__(31);
-var ViewSpecManager = /** @class */ (function () {
- function ViewSpecManager(optionsManager, _calendar) {
- this.optionsManager = optionsManager;
- this._calendar = _calendar;
- this.clearCache();
- }
- ViewSpecManager.prototype.clearCache = function () {
- this.viewSpecCache = {};
- };
- // Gets information about how to create a view. Will use a cache.
- ViewSpecManager.prototype.getViewSpec = function (viewType) {
- var cache = this.viewSpecCache;
- return cache[viewType] || (cache[viewType] = this.buildViewSpec(viewType));
- };
- // Given a duration singular unit, like "week" or "day", finds a matching view spec.
- // Preference is given to views that have corresponding buttons.
- ViewSpecManager.prototype.getUnitViewSpec = function (unit) {
- var viewTypes;
- var i;
- var spec;
- if ($.inArray(unit, util_1.unitsDesc) !== -1) {
- // put views that have buttons first. there will be duplicates, but oh well
- viewTypes = this._calendar.header.getViewsWithButtons(); // TODO: include footer as well?
- $.each(ViewRegistry_1.viewHash, function (viewType) {
- viewTypes.push(viewType);
- });
- for (i = 0; i < viewTypes.length; i++) {
- spec = this.getViewSpec(viewTypes[i]);
- if (spec) {
- if (spec.singleUnit === unit) {
- return spec;
- }
- }
- }
- }
- };
- // Builds an object with information on how to create a given view
- ViewSpecManager.prototype.buildViewSpec = function (requestedViewType) {
- var viewOverrides = this.optionsManager.overrides.views || {};
- var specChain = []; // for the view. lowest to highest priority
- var defaultsChain = []; // for the view. lowest to highest priority
- var overridesChain = []; // for the view. lowest to highest priority
- var viewType = requestedViewType;
- var spec; // for the view
- var overrides; // for the view
- var durationInput;
- var duration;
- var unit;
- // iterate from the specific view definition to a more general one until we hit an actual View class
- while (viewType) {
- spec = ViewRegistry_1.viewHash[viewType];
- overrides = viewOverrides[viewType];
- viewType = null; // clear. might repopulate for another iteration
- if (typeof spec === 'function') {
- spec = { 'class': spec };
- }
- if (spec) {
- specChain.unshift(spec);
- defaultsChain.unshift(spec.defaults || {});
- durationInput = durationInput || spec.duration;
- viewType = viewType || spec.type;
- }
- if (overrides) {
- overridesChain.unshift(overrides); // view-specific option hashes have options at zero-level
- durationInput = durationInput || overrides.duration;
- viewType = viewType || overrides.type;
- }
- }
- spec = util_1.mergeProps(specChain);
- spec.type = requestedViewType;
- if (!spec['class']) {
- return false;
- }
- // fall back to top-level `duration` option
- durationInput = durationInput ||
- this.optionsManager.dynamicOverrides.duration ||
- this.optionsManager.overrides.duration;
- if (durationInput) {
- duration = moment.duration(durationInput);
- if (duration.valueOf()) {
- unit = util_1.computeDurationGreatestUnit(duration, durationInput);
- spec.duration = duration;
- spec.durationUnit = unit;
- // view is a single-unit duration, like "week" or "day"
- // incorporate options for this. lowest priority
- if (duration.as(unit) === 1) {
- spec.singleUnit = unit;
- overridesChain.unshift(viewOverrides[unit] || {});
- }
- }
- }
- spec.defaults = options_1.mergeOptions(defaultsChain);
- spec.overrides = options_1.mergeOptions(overridesChain);
- this.buildViewSpecOptions(spec);
- this.buildViewSpecButtonText(spec, requestedViewType);
- return spec;
- };
- // Builds and assigns a view spec's options object from its already-assigned defaults and overrides
- ViewSpecManager.prototype.buildViewSpecOptions = function (spec) {
- var optionsManager = this.optionsManager;
- spec.options = options_1.mergeOptions([
- options_1.globalDefaults,
- spec.defaults,
- optionsManager.dirDefaults,
- optionsManager.localeDefaults,
- optionsManager.overrides,
- spec.overrides,
- optionsManager.dynamicOverrides // dynamically set via setter. highest precedence
- ]);
- locale_1.populateInstanceComputableOptions(spec.options);
- };
- // Computes and assigns a view spec's buttonText-related options
- ViewSpecManager.prototype.buildViewSpecButtonText = function (spec, requestedViewType) {
- var optionsManager = this.optionsManager;
- // given an options object with a possible `buttonText` hash, lookup the buttonText for the
- // requested view, falling back to a generic unit entry like "week" or "day"
- function queryButtonText(options) {
- var buttonText = options.buttonText || {};
- return buttonText[requestedViewType] ||
- // view can decide to look up a certain key
- (spec.buttonTextKey ? buttonText[spec.buttonTextKey] : null) ||
- // a key like "month"
- (spec.singleUnit ? buttonText[spec.singleUnit] : null);
- }
- // highest to lowest priority
- spec.buttonTextOverride =
- queryButtonText(optionsManager.dynamicOverrides) ||
- queryButtonText(optionsManager.overrides) || // constructor-specified buttonText lookup hash takes precedence
- spec.overrides.buttonText; // `buttonText` for view-specific options is a string
- // highest to lowest priority. mirrors buildViewSpecOptions
- spec.buttonTextDefault =
- queryButtonText(optionsManager.localeDefaults) ||
- queryButtonText(optionsManager.dirDefaults) ||
- spec.defaults.buttonText || // a single string. from ViewSubclass.defaults
- queryButtonText(options_1.globalDefaults) ||
- (spec.duration ? this._calendar.humanizeDuration(spec.duration) : null) || // like "3 days"
- requestedViewType; // fall back to given view name
- };
- return ViewSpecManager;
-}());
-exports.default = ViewSpecManager;
-
-
-/***/ }),
-/* 242 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var $ = __webpack_require__(3);
-var util_1 = __webpack_require__(4);
-var EventPeriod_1 = __webpack_require__(243);
-var ArrayEventSource_1 = __webpack_require__(52);
-var EventSource_1 = __webpack_require__(6);
-var EventSourceParser_1 = __webpack_require__(38);
-var SingleEventDef_1 = __webpack_require__(13);
-var EventInstanceGroup_1 = __webpack_require__(18);
-var EmitterMixin_1 = __webpack_require__(11);
-var ListenerMixin_1 = __webpack_require__(7);
-var EventManager = /** @class */ (function () {
- function EventManager(calendar) {
- this.calendar = calendar;
- this.stickySource = new ArrayEventSource_1.default(calendar);
- this.otherSources = [];
- }
- EventManager.prototype.requestEvents = function (start, end, timezone, force) {
- if (force ||
- !this.currentPeriod ||
- !this.currentPeriod.isWithinRange(start, end) ||
- timezone !== this.currentPeriod.timezone) {
- this.setPeriod(// will change this.currentPeriod
- new EventPeriod_1.default(start, end, timezone));
- }
- return this.currentPeriod.whenReleased();
- };
- // Source Adding/Removing
- // -----------------------------------------------------------------------------------------------------------------
- EventManager.prototype.addSource = function (eventSource) {
- this.otherSources.push(eventSource);
- if (this.currentPeriod) {
- this.currentPeriod.requestSource(eventSource); // might release
- }
- };
- EventManager.prototype.removeSource = function (doomedSource) {
- util_1.removeExact(this.otherSources, doomedSource);
- if (this.currentPeriod) {
- this.currentPeriod.purgeSource(doomedSource); // might release
- }
- };
- EventManager.prototype.removeAllSources = function () {
- this.otherSources = [];
- if (this.currentPeriod) {
- this.currentPeriod.purgeAllSources(); // might release
- }
- };
- // Source Refetching
- // -----------------------------------------------------------------------------------------------------------------
- EventManager.prototype.refetchSource = function (eventSource) {
- var currentPeriod = this.currentPeriod;
- if (currentPeriod) {
- currentPeriod.freeze();
- currentPeriod.purgeSource(eventSource);
- currentPeriod.requestSource(eventSource);
- currentPeriod.thaw();
- }
- };
- EventManager.prototype.refetchAllSources = function () {
- var currentPeriod = this.currentPeriod;
- if (currentPeriod) {
- currentPeriod.freeze();
- currentPeriod.purgeAllSources();
- currentPeriod.requestSources(this.getSources());
- currentPeriod.thaw();
- }
- };
- // Source Querying
- // -----------------------------------------------------------------------------------------------------------------
- EventManager.prototype.getSources = function () {
- return [this.stickySource].concat(this.otherSources);
- };
- // like querySources, but accepts multple match criteria (like multiple IDs)
- EventManager.prototype.multiQuerySources = function (matchInputs) {
- // coerce into an array
- if (!matchInputs) {
- matchInputs = [];
- }
- else if (!$.isArray(matchInputs)) {
- matchInputs = [matchInputs];
- }
- var matchingSources = [];
- var i;
- // resolve raw inputs to real event source objects
- for (i = 0; i < matchInputs.length; i++) {
- matchingSources.push.apply(// append
- matchingSources, this.querySources(matchInputs[i]));
- }
- return matchingSources;
- };
- // matchInput can either by a real event source object, an ID, or the function/URL for the source.
- // returns an array of matching source objects.
- EventManager.prototype.querySources = function (matchInput) {
- var sources = this.otherSources;
- var i;
- var source;
- // given a proper event source object
- for (i = 0; i < sources.length; i++) {
- source = sources[i];
- if (source === matchInput) {
- return [source];
- }
- }
- // an ID match
- source = this.getSourceById(EventSource_1.default.normalizeId(matchInput));
- if (source) {
- return [source];
- }
- // parse as an event source
- matchInput = EventSourceParser_1.default.parse(matchInput, this.calendar);
- if (matchInput) {
- return $.grep(sources, function (source) {
- return isSourcesEquivalent(matchInput, source);
- });
- }
- };
- /*
- ID assumed to already be normalized
- */
- EventManager.prototype.getSourceById = function (id) {
- return $.grep(this.otherSources, function (source) {
- return source.id && source.id === id;
- })[0];
- };
- // Event-Period
- // -----------------------------------------------------------------------------------------------------------------
- EventManager.prototype.setPeriod = function (eventPeriod) {
- if (this.currentPeriod) {
- this.unbindPeriod(this.currentPeriod);
- this.currentPeriod = null;
- }
- this.currentPeriod = eventPeriod;
- this.bindPeriod(eventPeriod);
- eventPeriod.requestSources(this.getSources());
- };
- EventManager.prototype.bindPeriod = function (eventPeriod) {
- this.listenTo(eventPeriod, 'release', function (eventsPayload) {
- this.trigger('release', eventsPayload);
- });
- };
- EventManager.prototype.unbindPeriod = function (eventPeriod) {
- this.stopListeningTo(eventPeriod);
- };
- // Event Getting/Adding/Removing
- // -----------------------------------------------------------------------------------------------------------------
- EventManager.prototype.getEventDefByUid = function (uid) {
- if (this.currentPeriod) {
- return this.currentPeriod.getEventDefByUid(uid);
- }
- };
- EventManager.prototype.addEventDef = function (eventDef, isSticky) {
- if (isSticky) {
- this.stickySource.addEventDef(eventDef);
- }
- if (this.currentPeriod) {
- this.currentPeriod.addEventDef(eventDef); // might release
- }
- };
- EventManager.prototype.removeEventDefsById = function (eventId) {
- this.getSources().forEach(function (eventSource) {
- eventSource.removeEventDefsById(eventId);
- });
- if (this.currentPeriod) {
- this.currentPeriod.removeEventDefsById(eventId); // might release
- }
- };
- EventManager.prototype.removeAllEventDefs = function () {
- this.getSources().forEach(function (eventSource) {
- eventSource.removeAllEventDefs();
- });
- if (this.currentPeriod) {
- this.currentPeriod.removeAllEventDefs();
- }
- };
- // Event Mutating
- // -----------------------------------------------------------------------------------------------------------------
- /*
- Returns an undo function.
- */
- EventManager.prototype.mutateEventsWithId = function (eventDefId, eventDefMutation) {
- var currentPeriod = this.currentPeriod;
- var eventDefs;
- var undoFuncs = [];
- if (currentPeriod) {
- currentPeriod.freeze();
- eventDefs = currentPeriod.getEventDefsById(eventDefId);
- eventDefs.forEach(function (eventDef) {
- // add/remove esp because id might change
- currentPeriod.removeEventDef(eventDef);
- undoFuncs.push(eventDefMutation.mutateSingle(eventDef));
- currentPeriod.addEventDef(eventDef);
- });
- currentPeriod.thaw();
- return function () {
- currentPeriod.freeze();
- for (var i = 0; i < eventDefs.length; i++) {
- currentPeriod.removeEventDef(eventDefs[i]);
- undoFuncs[i]();
- currentPeriod.addEventDef(eventDefs[i]);
- }
- currentPeriod.thaw();
- };
- }
- return function () { };
- };
- /*
- copies and then mutates
- */
- EventManager.prototype.buildMutatedEventInstanceGroup = function (eventDefId, eventDefMutation) {
- var eventDefs = this.getEventDefsById(eventDefId);
- var i;
- var defCopy;
- var allInstances = [];
- for (i = 0; i < eventDefs.length; i++) {
- defCopy = eventDefs[i].clone();
- if (defCopy instanceof SingleEventDef_1.default) {
- eventDefMutation.mutateSingle(defCopy);
- allInstances.push.apply(allInstances, // append
- defCopy.buildInstances());
- }
- }
- return new EventInstanceGroup_1.default(allInstances);
- };
- // Freezing
- // -----------------------------------------------------------------------------------------------------------------
- EventManager.prototype.freeze = function () {
- if (this.currentPeriod) {
- this.currentPeriod.freeze();
- }
- };
- EventManager.prototype.thaw = function () {
- if (this.currentPeriod) {
- this.currentPeriod.thaw();
- }
- };
- // methods that simply forward to EventPeriod
- EventManager.prototype.getEventDefsById = function (eventDefId) {
- return this.currentPeriod.getEventDefsById(eventDefId);
- };
- EventManager.prototype.getEventInstances = function () {
- return this.currentPeriod.getEventInstances();
- };
- EventManager.prototype.getEventInstancesWithId = function (eventDefId) {
- return this.currentPeriod.getEventInstancesWithId(eventDefId);
- };
- EventManager.prototype.getEventInstancesWithoutId = function (eventDefId) {
- return this.currentPeriod.getEventInstancesWithoutId(eventDefId);
- };
- return EventManager;
-}());
-exports.default = EventManager;
-EmitterMixin_1.default.mixInto(EventManager);
-ListenerMixin_1.default.mixInto(EventManager);
-function isSourcesEquivalent(source0, source1) {
- return source0.getPrimitive() === source1.getPrimitive();
-}
-
-
-/***/ }),
-/* 243 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var $ = __webpack_require__(3);
-var util_1 = __webpack_require__(4);
-var Promise_1 = __webpack_require__(20);
-var EmitterMixin_1 = __webpack_require__(11);
-var UnzonedRange_1 = __webpack_require__(5);
-var EventInstanceGroup_1 = __webpack_require__(18);
-var EventPeriod = /** @class */ (function () {
- function EventPeriod(start, end, timezone) {
- this.pendingCnt = 0;
- this.freezeDepth = 0;
- this.stuntedReleaseCnt = 0;
- this.releaseCnt = 0;
- this.start = start;
- this.end = end;
- this.timezone = timezone;
- this.unzonedRange = new UnzonedRange_1.default(start.clone().stripZone(), end.clone().stripZone());
- this.requestsByUid = {};
- this.eventDefsByUid = {};
- this.eventDefsById = {};
- this.eventInstanceGroupsById = {};
- }
- EventPeriod.prototype.isWithinRange = function (start, end) {
- // TODO: use a range util function?
- return !start.isBefore(this.start) && !end.isAfter(this.end);
- };
- // Requesting and Purging
- // -----------------------------------------------------------------------------------------------------------------
- EventPeriod.prototype.requestSources = function (sources) {
- this.freeze();
- for (var i = 0; i < sources.length; i++) {
- this.requestSource(sources[i]);
- }
- this.thaw();
- };
- EventPeriod.prototype.requestSource = function (source) {
- var _this = this;
- var request = { source: source, status: 'pending', eventDefs: null };
- this.requestsByUid[source.uid] = request;
- this.pendingCnt += 1;
- source.fetch(this.start, this.end, this.timezone).then(function (eventDefs) {
- if (request.status !== 'cancelled') {
- request.status = 'completed';
- request.eventDefs = eventDefs;
- _this.addEventDefs(eventDefs);
- _this.pendingCnt--;
- _this.tryRelease();
- }
- }, function () {
- if (request.status !== 'cancelled') {
- request.status = 'failed';
- _this.pendingCnt--;
- _this.tryRelease();
- }
- });
- };
- EventPeriod.prototype.purgeSource = function (source) {
- var request = this.requestsByUid[source.uid];
- if (request) {
- delete this.requestsByUid[source.uid];
- if (request.status === 'pending') {
- request.status = 'cancelled';
- this.pendingCnt--;
- this.tryRelease();
- }
- else if (request.status === 'completed') {
- request.eventDefs.forEach(this.removeEventDef.bind(this));
- }
- }
- };
- EventPeriod.prototype.purgeAllSources = function () {
- var requestsByUid = this.requestsByUid;
- var uid;
- var request;
- var completedCnt = 0;
- for (uid in requestsByUid) {
- request = requestsByUid[uid];
- if (request.status === 'pending') {
- request.status = 'cancelled';
- }
- else if (request.status === 'completed') {
- completedCnt++;
- }
- }
- this.requestsByUid = {};
- this.pendingCnt = 0;
- if (completedCnt) {
- this.removeAllEventDefs(); // might release
- }
- };
- // Event Definitions
- // -----------------------------------------------------------------------------------------------------------------
- EventPeriod.prototype.getEventDefByUid = function (eventDefUid) {
- return this.eventDefsByUid[eventDefUid];
- };
- EventPeriod.prototype.getEventDefsById = function (eventDefId) {
- var a = this.eventDefsById[eventDefId];
- if (a) {
- return a.slice(); // clone
- }
- return [];
- };
- EventPeriod.prototype.addEventDefs = function (eventDefs) {
- for (var i = 0; i < eventDefs.length; i++) {
- this.addEventDef(eventDefs[i]);
- }
- };
- EventPeriod.prototype.addEventDef = function (eventDef) {
- var eventDefsById = this.eventDefsById;
- var eventDefId = eventDef.id;
- var eventDefs = eventDefsById[eventDefId] || (eventDefsById[eventDefId] = []);
- var eventInstances = eventDef.buildInstances(this.unzonedRange);
- var i;
- eventDefs.push(eventDef);
- this.eventDefsByUid[eventDef.uid] = eventDef;
- for (i = 0; i < eventInstances.length; i++) {
- this.addEventInstance(eventInstances[i], eventDefId);
- }
- };
- EventPeriod.prototype.removeEventDefsById = function (eventDefId) {
- var _this = this;
- this.getEventDefsById(eventDefId).forEach(function (eventDef) {
- _this.removeEventDef(eventDef);
- });
- };
- EventPeriod.prototype.removeAllEventDefs = function () {
- var isEmpty = $.isEmptyObject(this.eventDefsByUid);
- this.eventDefsByUid = {};
- this.eventDefsById = {};
- this.eventInstanceGroupsById = {};
- if (!isEmpty) {
- this.tryRelease();
- }
- };
- EventPeriod.prototype.removeEventDef = function (eventDef) {
- var eventDefsById = this.eventDefsById;
- var eventDefs = eventDefsById[eventDef.id];
- delete this.eventDefsByUid[eventDef.uid];
- if (eventDefs) {
- util_1.removeExact(eventDefs, eventDef);
- if (!eventDefs.length) {
- delete eventDefsById[eventDef.id];
- }
- this.removeEventInstancesForDef(eventDef);
- }
- };
- // Event Instances
- // -----------------------------------------------------------------------------------------------------------------
- EventPeriod.prototype.getEventInstances = function () {
- var eventInstanceGroupsById = this.eventInstanceGroupsById;
- var eventInstances = [];
- var id;
- for (id in eventInstanceGroupsById) {
- eventInstances.push.apply(eventInstances, // append
- eventInstanceGroupsById[id].eventInstances);
- }
- return eventInstances;
- };
- EventPeriod.prototype.getEventInstancesWithId = function (eventDefId) {
- var eventInstanceGroup = this.eventInstanceGroupsById[eventDefId];
- if (eventInstanceGroup) {
- return eventInstanceGroup.eventInstances.slice(); // clone
- }
- return [];
- };
- EventPeriod.prototype.getEventInstancesWithoutId = function (eventDefId) {
- var eventInstanceGroupsById = this.eventInstanceGroupsById;
- var matchingInstances = [];
- var id;
- for (id in eventInstanceGroupsById) {
- if (id !== eventDefId) {
- matchingInstances.push.apply(matchingInstances, // append
- eventInstanceGroupsById[id].eventInstances);
- }
- }
- return matchingInstances;
- };
- EventPeriod.prototype.addEventInstance = function (eventInstance, eventDefId) {
- var eventInstanceGroupsById = this.eventInstanceGroupsById;
- var eventInstanceGroup = eventInstanceGroupsById[eventDefId] ||
- (eventInstanceGroupsById[eventDefId] = new EventInstanceGroup_1.default());
- eventInstanceGroup.eventInstances.push(eventInstance);
- this.tryRelease();
- };
- EventPeriod.prototype.removeEventInstancesForDef = function (eventDef) {
- var eventInstanceGroupsById = this.eventInstanceGroupsById;
- var eventInstanceGroup = eventInstanceGroupsById[eventDef.id];
- var removeCnt;
- if (eventInstanceGroup) {
- removeCnt = util_1.removeMatching(eventInstanceGroup.eventInstances, function (currentEventInstance) {
- return currentEventInstance.def === eventDef;
- });
- if (!eventInstanceGroup.eventInstances.length) {
- delete eventInstanceGroupsById[eventDef.id];
- }
- if (removeCnt) {
- this.tryRelease();
- }
- }
- };
- // Releasing and Freezing
- // -----------------------------------------------------------------------------------------------------------------
- EventPeriod.prototype.tryRelease = function () {
- if (!this.pendingCnt) {
- if (!this.freezeDepth) {
- this.release();
- }
- else {
- this.stuntedReleaseCnt++;
- }
- }
- };
- EventPeriod.prototype.release = function () {
- this.releaseCnt++;
- this.trigger('release', this.eventInstanceGroupsById);
- };
- EventPeriod.prototype.whenReleased = function () {
- var _this = this;
- if (this.releaseCnt) {
- return Promise_1.default.resolve(this.eventInstanceGroupsById);
- }
- else {
- return Promise_1.default.construct(function (onResolve) {
- _this.one('release', onResolve);
- });
- }
- };
- EventPeriod.prototype.freeze = function () {
- if (!(this.freezeDepth++)) {
- this.stuntedReleaseCnt = 0;
- }
- };
- EventPeriod.prototype.thaw = function () {
- if (!(--this.freezeDepth) && this.stuntedReleaseCnt && !this.pendingCnt) {
- this.release();
- }
- };
- return EventPeriod;
-}());
-exports.default = EventPeriod;
-EmitterMixin_1.default.mixInto(EventPeriod);
-
-
-/***/ }),
-/* 244 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var $ = __webpack_require__(3);
-var util_1 = __webpack_require__(4);
-var ListenerMixin_1 = __webpack_require__(7);
-/* Creates a clone of an element and lets it track the mouse as it moves
-----------------------------------------------------------------------------------------------------------------------*/
-var MouseFollower = /** @class */ (function () {
- function MouseFollower(sourceEl, options) {
- this.isFollowing = false;
- this.isHidden = false;
- this.isAnimating = false; // doing the revert animation?
- this.options = options = options || {};
- this.sourceEl = sourceEl;
- this.parentEl = options.parentEl ? $(options.parentEl) : sourceEl.parent(); // default to sourceEl's parent
- }
- // Causes the element to start following the mouse
- MouseFollower.prototype.start = function (ev) {
- if (!this.isFollowing) {
- this.isFollowing = true;
- this.y0 = util_1.getEvY(ev);
- this.x0 = util_1.getEvX(ev);
- this.topDelta = 0;
- this.leftDelta = 0;
- if (!this.isHidden) {
- this.updatePosition();
- }
- if (util_1.getEvIsTouch(ev)) {
- this.listenTo($(document), 'touchmove', this.handleMove);
- }
- else {
- this.listenTo($(document), 'mousemove', this.handleMove);
- }
- }
- };
- // Causes the element to stop following the mouse. If shouldRevert is true, will animate back to original position.
- // `callback` gets invoked when the animation is complete. If no animation, it is invoked immediately.
- MouseFollower.prototype.stop = function (shouldRevert, callback) {
- var _this = this;
- var revertDuration = this.options.revertDuration;
- var complete = function () {
- _this.isAnimating = false;
- _this.removeElement();
- _this.top0 = _this.left0 = null; // reset state for future updatePosition calls
- if (callback) {
- callback();
- }
- };
- if (this.isFollowing && !this.isAnimating) {
- this.isFollowing = false;
- this.stopListeningTo($(document));
- if (shouldRevert && revertDuration && !this.isHidden) {
- this.isAnimating = true;
- this.el.animate({
- top: this.top0,
- left: this.left0
- }, {
- duration: revertDuration,
- complete: complete
- });
- }
- else {
- complete();
- }
- }
- };
- // Gets the tracking element. Create it if necessary
- MouseFollower.prototype.getEl = function () {
- var el = this.el;
- if (!el) {
- el = this.el = this.sourceEl.clone()
- .addClass(this.options.additionalClass || '')
- .css({
- position: 'absolute',
- visibility: '',
- display: this.isHidden ? 'none' : '',
- margin: 0,
- right: 'auto',
- bottom: 'auto',
- width: this.sourceEl.width(),
- height: this.sourceEl.height(),
- opacity: this.options.opacity || '',
- zIndex: this.options.zIndex
- });
- // we don't want long taps or any mouse interaction causing selection/menus.
- // would use preventSelection(), but that prevents selectstart, causing problems.
- el.addClass('fc-unselectable');
- el.appendTo(this.parentEl);
- }
- return el;
- };
- // Removes the tracking element if it has already been created
- MouseFollower.prototype.removeElement = function () {
- if (this.el) {
- this.el.remove();
- this.el = null;
- }
- };
- // Update the CSS position of the tracking element
- MouseFollower.prototype.updatePosition = function () {
- var sourceOffset;
- var origin;
- this.getEl(); // ensure this.el
- // make sure origin info was computed
- if (this.top0 == null) {
- sourceOffset = this.sourceEl.offset();
- origin = this.el.offsetParent().offset();
- this.top0 = sourceOffset.top - origin.top;
- this.left0 = sourceOffset.left - origin.left;
- }
- this.el.css({
- top: this.top0 + this.topDelta,
- left: this.left0 + this.leftDelta
- });
- };
- // Gets called when the user moves the mouse
- MouseFollower.prototype.handleMove = function (ev) {
- this.topDelta = util_1.getEvY(ev) - this.y0;
- this.leftDelta = util_1.getEvX(ev) - this.x0;
- if (!this.isHidden) {
- this.updatePosition();
- }
- };
- // Temporarily makes the tracking element invisible. Can be called before following starts
- MouseFollower.prototype.hide = function () {
- if (!this.isHidden) {
- this.isHidden = true;
- if (this.el) {
- this.el.hide();
- }
- }
- };
- // Show the tracking element after it has been temporarily hidden
- MouseFollower.prototype.show = function () {
- if (this.isHidden) {
- this.isHidden = false;
- this.updatePosition();
- this.getEl().show();
- }
- };
- return MouseFollower;
-}());
-exports.default = MouseFollower;
-ListenerMixin_1.default.mixInto(MouseFollower);
-
-
-/***/ }),
-/* 245 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var tslib_1 = __webpack_require__(2);
-var HitDragListener_1 = __webpack_require__(23);
-var Interaction_1 = __webpack_require__(15);
-var DateClicking = /** @class */ (function (_super) {
- tslib_1.__extends(DateClicking, _super);
- /*
- component must implement:
- - bindDateHandlerToEl
- - getSafeHitFootprint
- - getHitEl
- */
- function DateClicking(component) {
- var _this = _super.call(this, component) || this;
- _this.dragListener = _this.buildDragListener();
- return _this;
- }
- DateClicking.prototype.end = function () {
- this.dragListener.endInteraction();
- };
- DateClicking.prototype.bindToEl = function (el) {
- var component = this.component;
- var dragListener = this.dragListener;
- component.bindDateHandlerToEl(el, 'mousedown', function (ev) {
- if (!component.shouldIgnoreMouse()) {
- dragListener.startInteraction(ev);
- }
- });
- component.bindDateHandlerToEl(el, 'touchstart', function (ev) {
- if (!component.shouldIgnoreTouch()) {
- dragListener.startInteraction(ev);
- }
- });
- };
- // Creates a listener that tracks the user's drag across day elements, for day clicking.
- DateClicking.prototype.buildDragListener = function () {
- var _this = this;
- var component = this.component;
- var dayClickHit; // null if invalid dayClick
- var dragListener = new HitDragListener_1.default(component, {
- scroll: this.opt('dragScroll'),
- interactionStart: function () {
- dayClickHit = dragListener.origHit;
- },
- hitOver: function (hit, isOrig, origHit) {
- // if user dragged to another cell at any point, it can no longer be a dayClick
- if (!isOrig) {
- dayClickHit = null;
- }
- },
- hitOut: function () {
- dayClickHit = null;
- },
- interactionEnd: function (ev, isCancelled) {
- var componentFootprint;
- if (!isCancelled && dayClickHit) {
- componentFootprint = component.getSafeHitFootprint(dayClickHit);
- if (componentFootprint) {
- _this.view.triggerDayClick(componentFootprint, component.getHitEl(dayClickHit), ev);
- }
- }
- }
- });
- // because dragListener won't be called with any time delay, "dragging" will begin immediately,
- // which will kill any touchmoving/scrolling. Prevent this.
- dragListener.shouldCancelTouchScroll = false;
- dragListener.scrollAlwaysKills = true;
- return dragListener;
- };
- return DateClicking;
-}(Interaction_1.default));
-exports.default = DateClicking;
-
-
-/***/ }),
-/* 246 */
-/***/ (function(module, exports, __webpack_require__) {
-
-Object.defineProperty(exports, "__esModule", { value: true });
-var tslib_1 = __webpack_require__(2);
var util_1 = __webpack_require__(4);
-var EventRenderer_1 = __webpack_require__(42);
+var EventRenderer_1 = __webpack_require__(44);
/*
Only handles foreground segs.
Does not own rendering. Use for low-level util methods by TimeGrid.
@@ -13759,7 +13296,7 @@
this.timeGrid.attachSegsByCol(segsByCol, containerEls);
};
TimeGridEventRenderer.prototype.unrenderFgSegs = function () {
- if (this.fgSegs) {
+ if (this.fgSegs) { // hack
this.fgSegs.forEach(function (seg) {
seg.el.remove();
});
@@ -13831,15 +13368,15 @@
'
' :
'') +
'
' +
- '' +
+ '' +
/* TODO: write CSS for this
(isResizableFromStart ?
- '' :
+ '' :
''
) +
*/
(isResizableFromEnd ?
- '' :
+ '' :
'') +
'';
};
@@ -13880,7 +13417,7 @@
TimeGridEventRenderer.prototype.computeFgSegForwardBack = function (seg, seriesBackwardPressure, seriesBackwardCoord) {
var forwardSegs = seg.forwardSegs;
var i;
- if (seg.forwardCoord === undefined) {
+ if (seg.forwardCoord === undefined) { // not already computed
if (!forwardSegs.length) {
// if there are no forward segments, this segment should butt up against the edge
seg.forwardCoord = 1;
@@ -13924,9 +13461,10 @@
for (i = 0; i < segs.length; i++) {
seg = segs[i];
seg.el.css(this.generateFgSegHorizontalCss(seg));
- // if the height is short, add a className for alternate styling
- if (seg.bottom - seg.top < 30) {
- seg.el.addClass('fc-short');
+ // if the event is short that the title will be cut off,
+ // attach a className that condenses the title into the time area.
+ if (seg.footprint.eventDef.title && seg.bottom - seg.top < 30) {
+ seg.el.addClass('fc-short'); // TODO: "condensed" is a better name
}
}
};
@@ -14010,7 +13548,7 @@
var forwardPressure = 0;
var i;
var forwardSeg;
- if (seg.forwardPressure === undefined) {
+ if (seg.forwardPressure === undefined) { // not already computed
for (i = 0; i < forwardSegs.length; i++) {
forwardSeg = forwardSegs[i];
// figure out the child's maximum forward path
@@ -14040,13 +13578,13 @@
/***/ }),
-/* 247 */
+/* 241 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
-var HelperRenderer_1 = __webpack_require__(58);
+var HelperRenderer_1 = __webpack_require__(63);
var TimeGridHelperRenderer = /** @class */ (function (_super) {
tslib_1.__extends(TimeGridHelperRenderer, _super);
function TimeGridHelperRenderer() {
@@ -14081,12 +13619,12 @@
/***/ }),
-/* 248 */
+/* 242 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
-var FillRenderer_1 = __webpack_require__(57);
+var FillRenderer_1 = __webpack_require__(62);
var TimeGridFillRenderer = /** @class */ (function (_super) {
tslib_1.__extends(TimeGridFillRenderer, _super);
function TimeGridFillRenderer() {
@@ -14117,161 +13655,14 @@
/***/ }),
-/* 249 */
-/***/ (function(module, exports, __webpack_require__) {
-
-/* A rectangular panel that is absolutely positioned over other content
-------------------------------------------------------------------------------------------------------------------------
-Options:
- - className (string)
- - content (HTML string or jQuery element set)
- - parentEl
- - top
- - left
- - right (the x coord of where the right edge should be. not a "CSS" right)
- - autoHide (boolean)
- - show (callback)
- - hide (callback)
-*/
-Object.defineProperty(exports, "__esModule", { value: true });
-var $ = __webpack_require__(3);
-var util_1 = __webpack_require__(4);
-var ListenerMixin_1 = __webpack_require__(7);
-var Popover = /** @class */ (function () {
- function Popover(options) {
- this.isHidden = true;
- this.margin = 10; // the space required between the popover and the edges of the scroll container
- this.options = options || {};
- }
- // Shows the popover on the specified position. Renders it if not already
- Popover.prototype.show = function () {
- if (this.isHidden) {
- if (!this.el) {
- this.render();
- }
- this.el.show();
- this.position();
- this.isHidden = false;
- this.trigger('show');
- }
- };
- // Hides the popover, through CSS, but does not remove it from the DOM
- Popover.prototype.hide = function () {
- if (!this.isHidden) {
- this.el.hide();
- this.isHidden = true;
- this.trigger('hide');
- }
- };
- // Creates `this.el` and renders content inside of it
- Popover.prototype.render = function () {
- var _this = this;
- var options = this.options;
- this.el = $('')
- .addClass(options.className || '')
- .css({
- // position initially to the top left to avoid creating scrollbars
- top: 0,
- left: 0
- })
- .append(options.content)
- .appendTo(options.parentEl);
- // when a click happens on anything inside with a 'fc-close' className, hide the popover
- this.el.on('click', '.fc-close', function () {
- _this.hide();
- });
- if (options.autoHide) {
- this.listenTo($(document), 'mousedown', this.documentMousedown);
- }
- };
- // Triggered when the user clicks *anywhere* in the document, for the autoHide feature
- Popover.prototype.documentMousedown = function (ev) {
- // only hide the popover if the click happened outside the popover
- if (this.el && !$(ev.target).closest(this.el).length) {
- this.hide();
- }
- };
- // Hides and unregisters any handlers
- Popover.prototype.removeElement = function () {
- this.hide();
- if (this.el) {
- this.el.remove();
- this.el = null;
- }
- this.stopListeningTo($(document), 'mousedown');
- };
- // Positions the popover optimally, using the top/left/right options
- Popover.prototype.position = function () {
- var options = this.options;
- var origin = this.el.offsetParent().offset();
- var width = this.el.outerWidth();
- var height = this.el.outerHeight();
- var windowEl = $(window);
- var viewportEl = util_1.getScrollParent(this.el);
- var viewportTop;
- var viewportLeft;
- var viewportOffset;
- var top; // the "position" (not "offset") values for the popover
- var left; //
- // compute top and left
- top = options.top || 0;
- if (options.left !== undefined) {
- left = options.left;
- }
- else if (options.right !== undefined) {
- left = options.right - width; // derive the left value from the right value
- }
- else {
- left = 0;
- }
- if (viewportEl.is(window) || viewportEl.is(document)) {
- viewportEl = windowEl;
- viewportTop = 0; // the window is always at the top left
- viewportLeft = 0; // (and .offset() won't work if called here)
- }
- else {
- viewportOffset = viewportEl.offset();
- viewportTop = viewportOffset.top;
- viewportLeft = viewportOffset.left;
- }
- // if the window is scrolled, it causes the visible area to be further down
- viewportTop += windowEl.scrollTop();
- viewportLeft += windowEl.scrollLeft();
- // constrain to the view port. if constrained by two edges, give precedence to top/left
- if (options.viewportConstrain !== false) {
- top = Math.min(top, viewportTop + viewportEl.outerHeight() - height - this.margin);
- top = Math.max(top, viewportTop + this.margin);
- left = Math.min(left, viewportLeft + viewportEl.outerWidth() - width - this.margin);
- left = Math.max(left, viewportLeft + this.margin);
- }
- this.el.css({
- top: top - origin.top,
- left: left - origin.left
- });
- };
- // Triggers a callback. Calls a function in the option hash of the same name.
- // Arguments beyond the first `name` are forwarded on.
- // TODO: better code reuse for this. Repeat code
- Popover.prototype.trigger = function (name) {
- if (this.options[name]) {
- this.options[name].apply(this, Array.prototype.slice.call(arguments, 1));
- }
- };
- return Popover;
-}());
-exports.default = Popover;
-ListenerMixin_1.default.mixInto(Popover);
-
-
-/***/ }),
-/* 250 */
+/* 243 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
var util_1 = __webpack_require__(4);
-var EventRenderer_1 = __webpack_require__(42);
+var EventRenderer_1 = __webpack_require__(44);
/* Event-rendering methods for the DayGrid class
----------------------------------------------------------------------------------------------------------------------*/
var DayGridEventRenderer = /** @class */ (function (_super) {
@@ -14326,7 +13717,7 @@
var colCnt = this.dayGrid.colCnt;
var segLevels = this.buildSegLevels(rowSegs); // group into sub-arrays of levels
var levelCnt = Math.max(1, segLevels.length); // ensure at least one level
- var tbody = $('');
+ var tbody = $('');
var segMatrix = []; // lookup for which segments are rendered into which level+col cells
var cellMatrix = []; // lookup for all
elements of the level+col matrix
var loneCellMatrix = []; // lookup for
elements that only take up a single column
@@ -14346,7 +13737,7 @@
td.attr('rowspan', parseInt(td.attr('rowspan') || 1, 10) + 1);
}
else {
- td = $('
');
+ td = $('
');
tr.append(td);
}
cellMatrix[i][col] = td;
@@ -14354,25 +13745,25 @@
col++;
}
}
- for (i = 0; i < levelCnt; i++) {
+ for (i = 0; i < levelCnt; i++) { // iterate through all levels
levelSegs = segLevels[i];
col = 0;
- tr = $('
');
+ tr = $('
');
segMatrix.push([]);
cellMatrix.push([]);
loneCellMatrix.push([]);
// levelCnt might be 1 even though there are no actual levels. protect against this.
// this single empty row is useful for styling.
if (levelSegs) {
- for (j = 0; j < levelSegs.length; j++) {
+ for (j = 0; j < levelSegs.length; j++) { // iterate through segments in level
seg = levelSegs[j];
emptyCellsUntil(seg.leftCol);
// create a container that occupies or more columns. append the event element.
- td = $('
'); // will be absolutely positioned
+ var skeletonEl = $('
'); // will be absolutely positioned
var skeletonTopEl;
var skeletonTop;
// If there is an original segment, match the top position. Otherwise, put it at the row's top level
@@ -14547,7 +13938,7 @@
}
else {
skeletonTopEl = rowEl.find('.fc-content-skeleton tbody');
- if (!skeletonTopEl.length) {
+ if (!skeletonTopEl.length) { // when no events
skeletonTopEl = rowEl.find('.fc-content-skeleton table');
}
skeletonTop = skeletonTopEl.position().top;
@@ -14566,13 +13957,13 @@
/***/ }),
-/* 252 */
+/* 245 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = __webpack_require__(2);
var $ = __webpack_require__(3);
-var FillRenderer_1 = __webpack_require__(57);
+var FillRenderer_1 = __webpack_require__(62);
var DayGridFillRenderer = /** @class */ (function (_super) {
tslib_1.__extends(DayGridFillRenderer, _super);
function DayGridFillRenderer() {
@@ -14608,15 +13999,19 @@
className = type.toLowerCase();
}
skeletonEl = $('
');
+ };
+ // render the event segments in the view
+ ListView.prototype.renderSegList = function (allSegs) {
+ var segsByDay = this.groupSegsByDay(allSegs); // sparse array
+ var dayIndex;
+ var daySegs;
+ var i;
+ var tableEl = $('
');
+ var tbodyEl = tableEl.find('tbody');
+ for (dayIndex = 0; dayIndex < segsByDay.length; dayIndex++) {
+ daySegs = segsByDay[dayIndex];
+ if (daySegs) { // sparse array, so might be undefined
+ // append a day header
+ tbodyEl.append(this.dayHeaderHtml(this.dayDates[dayIndex]));
+ this.eventRenderer.sortEventSegs(daySegs);
+ for (i = 0; i < daySegs.length; i++) {
+ tbodyEl.append(daySegs[i].el); // append event row
+ }
+ }
+ }
+ this.contentEl.empty().append(tableEl);
+ };
+ // Returns a sparse array of arrays, segs grouped by their dayIndex
+ ListView.prototype.groupSegsByDay = function (segs) {
+ var segsByDay = []; // sparse array
+ var i;
+ var seg;
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ (segsByDay[seg.dayIndex] || (segsByDay[seg.dayIndex] = []))
+ .push(seg);
+ }
+ return segsByDay;
+ };
+ // generates the HTML for the day headers that live amongst the event rows
+ ListView.prototype.dayHeaderHtml = function (dayDate) {
+ var mainFormat = this.opt('listDayFormat');
+ var altFormat = this.opt('listDayAltFormat');
+ return '
"},e}(a.default);e.default=c,c.prototype.eventRendererClass=u.default,c.prototype.eventPointingClass=d.default},,,,,,function(t,e,n){var i=n(3),r=n(16),o=n(4),s=n(220);n(10),n(47),n(256),n(257),n(260),n(261),n(262),n(263),i.fullCalendar=r,i.fn.fullCalendar=function(t){var e=Array.prototype.slice.call(arguments,1),n=this;return this.each(function(r,a){var l,u=i(a),d=u.data("fullCalendar");"string"==typeof t?"getCalendar"===t?r||(n=d):"destroy"===t?d&&(d.destroy(),u.removeData("fullCalendar")):d?i.isFunction(d[t])?(l=d[t].apply(d,e),r||(n=l),"destroy"===t&&u.removeData("fullCalendar")):o.warn("'"+t+"' is an unknown FullCalendar method."):o.warn("Attempting to call a FullCalendar method on an element with no calendar."):d||(d=new s.default(u,t),u.data("fullCalendar",d),d.render())}),n},t.exports=r},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),r=n(48),o=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return i.__extends(e,t),e.prototype.setElement=function(t){this.el=t,this.bindGlobalHandlers(),this.renderSkeleton(),this.set("isInDom",!0)},e.prototype.removeElement=function(){this.unset("isInDom"),this.unrenderSkeleton(),this.unbindGlobalHandlers(),this.el.remove()},e.prototype.bindGlobalHandlers=function(){},e.prototype.unbindGlobalHandlers=function(){},e.prototype.renderSkeleton=function(){},e.prototype.unrenderSkeleton=function(){},e}(r.default);e.default=o},function(t,e){Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t){this.items=t||[]}return t.prototype.proxyCall=function(t){for(var e=[],n=1;n"),e.append(this.renderSection("left")).append(this.renderSection("right")).append(this.renderSection("center")).append('')):this.removeElement()},t.prototype.removeElement=function(){this.el&&(this.el.remove(),this.el=null)},t.prototype.renderSection=function(t){var e=this,n=this.calendar,o=n.theme,s=n.optionsManager,a=n.viewSpecManager,l=i(''),u=this.toolbarOptions.layout[t],d=s.get("customButtons")||{},c=s.overrides.buttonText||{},p=s.get("buttonText")||{};return u&&i.each(u.split(" "),function(t,s){var u,h=i(),f=!0;i.each(s.split(","),function(t,s){var l,u,g,v,y,m,b,w,D;"title"===s?(h=h.add(i("
"},e.prototype.computeEventTimeFormat=function(){return this.opt("mediumTimeFormat")},e}(o.default);e.default=s},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var r=n(2),i=n(3),o=n(64),s=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return r.__extends(e,t),e.prototype.handleClick=function(e,n){var r;t.prototype.handleClick.call(this,e,n),i(n.target).closest("a[href]").length||(r=e.footprint.eventDef.url)&&!n.isDefaultPrevented()&&(window.location.href=r)},e}(o.default);e.default=s},,,,,,function(t,e,n){var r=n(3),i=n(18),o=n(4),s=n(232);n(11),n(49),n(260),n(261),n(264),n(265),n(266),n(267),r.fullCalendar=i,r.fn.fullCalendar=function(t){var e=Array.prototype.slice.call(arguments,1),n=this;return this.each(function(i,a){var l,u=r(a),d=u.data("fullCalendar");"string"==typeof t?"getCalendar"===t?i||(n=d):"destroy"===t?d&&(d.destroy(),u.removeData("fullCalendar")):d?r.isFunction(d[t])?(l=d[t].apply(d,e),i||(n=l),"destroy"===t&&u.removeData("fullCalendar")):o.warn("'"+t+"' is an unknown FullCalendar method."):o.warn("Attempting to call a FullCalendar method on an element with no calendar."):d||(d=new s.default(u,t),u.data("fullCalendar",d),d.render())}),n},t.exports=i},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var r=n(3),i=n(4),o=function(){function t(t,e){this.el=null,this.viewsWithButtons=[],this.calendar=t,this.toolbarOptions=e}return t.prototype.setToolbarOptions=function(t){this.toolbarOptions=t},t.prototype.render=function(){var t=this.toolbarOptions.layout,e=this.el;t?(e?e.empty():e=this.el=r("
-
+
-
+
+
+
\n";
-
+ include_spip('inc/autoriser');
+ if (autoriser('afficher_prive', 'porteplume')){
+ $js = timestamp(find_in_path('javascript/porte_plume_forcer_hauteur.js'));
+ $flux = porte_plume_inserer_head($flux, $GLOBALS['spip_lang'], true)
+ . "\n";
+ }
return $flux;
}
@@ -104,11 +125,14 @@
* @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'));
$hash = md5(porte_plume_creer_json_markitup());
- $js_start = produire_fond_statique('javascript/porte_plume_start.js', array('lang' => $lang, 'hash' => $hash));
+ $inserer_auto_name_texte = defined('_PORTE_PLUME_INSERER_AUTO_NAME_TEXTE') ? _PORTE_PLUME_INSERER_AUTO_NAME_TEXTE : true;
+ $js_start = produire_fond_statique('javascript/porte_plume_start.js', array('lang' => $lang, 'hash' => $hash, 'inserer_auto_name_texte' => $inserer_auto_name_texte));
$flux .=
"\n"
@@ -141,14 +165,14 @@
*/
function porte_plume_insert_head_css($flux = '', $prive = false) {
include_spip('inc/autoriser');
- // toujours autoriser pour le prive.
- if ($prive or autoriser('afficher_public', 'porteplume')) {
+ if (autoriser($prive ? 'afficher_prive' : 'afficher_public', 'porteplume')) {
if ($prive) {
$cssprive = timestamp(find_in_path('css/barre_outils_prive.css'));
$flux .= "\n";
}
$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));
diff -Nru spip-3.2.7/plugins-dist/revisions/afficher_diff/champ.php spip-3.2.15.1/plugins-dist/revisions/afficher_diff/champ.php
--- spip-3.2.7/plugins-dist/revisions/afficher_diff/champ.php 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/revisions/afficher_diff/champ.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/revisions/afficher_diff/id_rubrique.php spip-3.2.15.1/plugins-dist/revisions/afficher_diff/id_rubrique.php
--- spip-3.2.7/plugins-dist/revisions/afficher_diff/id_rubrique.php 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/revisions/afficher_diff/id_rubrique.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/revisions/afficher_diff/jointure.php spip-3.2.15.1/plugins-dist/revisions/afficher_diff/jointure.php
--- spip-3.2.7/plugins-dist/revisions/afficher_diff/jointure.php 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/revisions/afficher_diff/jointure.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/revisions/base/revisions.php spip-3.2.15.1/plugins-dist/revisions/base/revisions.php
--- spip-3.2.7/plugins-dist/revisions/base/revisions.php 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/revisions/base/revisions.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/revisions/formulaires/configurer_revisions_objets.php spip-3.2.15.1/plugins-dist/revisions/formulaires/configurer_revisions_objets.php
--- spip-3.2.7/plugins-dist/revisions/formulaires/configurer_revisions_objets.php 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/revisions/formulaires/configurer_revisions_objets.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/revisions/formulaires/reviser.php spip-3.2.15.1/plugins-dist/revisions/formulaires/reviser.php
--- spip-3.2.7/plugins-dist/revisions/formulaires/reviser.php 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/revisions/formulaires/reviser.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/revisions/genie/optimiser_revisions.php spip-3.2.15.1/plugins-dist/revisions/genie/optimiser_revisions.php
--- spip-3.2.7/plugins-dist/revisions/genie/optimiser_revisions.php 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/revisions/genie/optimiser_revisions.php 2022-05-20 16:59:18.000000000 +0100
@@ -2,7 +2,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/revisions/inc/diff.php spip-3.2.15.1/plugins-dist/revisions/inc/diff.php
--- spip-3.2.7/plugins-dist/revisions/inc/diff.php 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/revisions/inc/diff.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
@@ -194,7 +194,9 @@
if (!$fin_old) {
// Paragraphes supprimes jusqu'au paragraphe courant
if (!isset($i_old)) {
- list($i_old, $p_old) = each($paras_old);
+ $i_old = key($paras_old);
+ $p_old = current($paras_old);
+ next($paras_old);
if (!$p_old) {
$fin_old = true;
}
@@ -204,7 +206,9 @@
$this->diff->supprimer($p_old);
}
unset($i_old);
- list($i_old, $p_old) = each($paras_old);
+ $i_old = key($paras_old);
+ $p_old = current($paras_old);
+ next($paras_old);
if (!$p_old) {
$fin_old = true;
}
@@ -216,7 +220,9 @@
// Paragraphes supprimes a la fin du texte
if (!$fin_old) {
if (!isset($i_old)) {
- list($i_old, $p_old) = each($paras_old);
+ $i_old = key($paras_old);
+ $p_old = current($paras_old);
+ next($paras_old);
if (!strlen($p_old)) {
$fin_old = true;
}
@@ -225,7 +231,9 @@
if (!isset($trans_rev[$i_old])) {
$this->diff->supprimer($p_old);
}
- list($i_old, $p_old) = each($paras_old);
+ $i_old = key($paras_old);
+ $p_old = current($paras_old);
+ next($paras_old);
if (!$p_old) {
$fin_old = true;
}
diff -Nru spip-3.2.7/plugins-dist/revisions/inc/revisions_autoriser.php spip-3.2.15.1/plugins-dist/revisions/inc/revisions_autoriser.php
--- spip-3.2.7/plugins-dist/revisions/inc/revisions_autoriser.php 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/revisions/inc/revisions_autoriser.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/revisions/inc/revisions.php spip-3.2.15.1/plugins-dist/revisions/inc/revisions.php
--- spip-3.2.7/plugins-dist/revisions/inc/revisions.php 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/revisions/inc/revisions.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
@@ -561,8 +561,8 @@
// distinctif (pour eviter la violation d'unicite)
// et un titre contenant en fait le moment de l'insertion
list($ms, $sec) = explode(' ', microtime());
- $date = $sec . substr($ms, 1,
- 4) - 20; // SQL ne ramene que 4 chiffres significatifs apres la virgule pour 0.0+titre_version
+ // SQL ne ramene que 4 chiffres significatifs apres la virgule pour 0.0+titre_version
+ $date = ($sec . substr($ms, 1, 4)) - 20;
$datediff = ($sec - mktime(0, 0, 0, 9, 1, 2007)) * 1000000 + substr($ms, 2, strlen($ms) - 4);
$valeurs = array(
@@ -653,7 +653,8 @@
for ($i = 0; $i < $n; $i++) {
while ($i >= $paras_champ[$nom]) {
- list($nom, ) = each($champs);
+ $nom = key($champs);
+ next($champs);
}
// Lier au fragment existant si possible, sinon creer un nouveau fragment
$id_fragment = isset($trans[$i]) ? $trans[$i] : $next++;
diff -Nru spip-3.2.7/plugins-dist/revisions/inc/revisions_pipeline.php spip-3.2.15.1/plugins-dist/revisions/inc/revisions_pipeline.php
--- spip-3.2.7/plugins-dist/revisions/inc/revisions_pipeline.php 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/revisions/inc/revisions_pipeline.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
@@ -301,6 +301,7 @@
$table = table_objet_sql($x['args']['objet']);
$id_objet = $x['args']['id_objet'];
include_spip('inc/revisions');
+ include_spip('inc/session');
// si c'est une creation de lien qui arrive aussitot apres l'insertion on ne cree pas de revision
// (au cas ou pre_edition_lien n'aurait pas ete appele ?)
if (isset($GLOBALS['premiere_revision']["$table:0"])) {
@@ -316,7 +317,7 @@
$champs = array(
$j => recuperer_valeur_champ_jointure($x['args']['objet'], $id_objet, $x['args']['objet_source'])
);
- ajouter_version($id_objet, $x['args']['objet'], $champs, '', $GLOBALS['visiteur_session']['id_auteur']);
+ ajouter_version($id_objet, $x['args']['objet'], $champs, '', session_get('id_auteur'));
}
$table = table_objet_sql($x['args']['objet_source']);
@@ -336,7 +337,7 @@
$champs = array(
$j => recuperer_valeur_champ_jointure($x['args']['objet_source'], $id_objet, $x['args']['objet'])
);
- ajouter_version($id_objet, $x['args']['objet_source'], $champs, '', $GLOBALS['visiteur_session']['id_auteur']);
+ ajouter_version($id_objet, $x['args']['objet_source'], $champs, '', session_get('id_auteur'));
}
}
diff -Nru spip-3.2.7/plugins-dist/revisions/inc/suivi_versions.php spip-3.2.15.1/plugins-dist/revisions/inc/suivi_versions.php
--- spip-3.2.7/plugins-dist/revisions/inc/suivi_versions.php 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/revisions/inc/suivi_versions.php 2022-05-20 16:59:18.000000000 +0100
@@ -3,7 +3,7 @@
/***************************************************************************\
* SPIP, Systeme de publication pour l'internet *
* *
- * Copyright (c) 2001-2019 *
+ * Copyright (c) 2001-2020 *
* Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
* *
* Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
diff -Nru spip-3.2.7/plugins-dist/revisions/paquet.xml spip-3.2.15.1/plugins-dist/revisions/paquet.xml
--- spip-3.2.7/plugins-dist/revisions/paquet.xml 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/revisions/paquet.xml 2022-05-20 16:59:18.000000000 +0100
@@ -1,7 +1,7 @@
- * @author Miguel Vazquez Gocobachi
- * @copyright 2004-2009 Roman Ivanov, Miguel Vazquez Gocobachi
- * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
- * @version 1.3.10
- * @link https://wackowiki.org/doc/Dev/Projects/SafeHTML
+ * PHP version 7
+ *
+ * @category HTML
+ * @package SafeHTML
+ * @author Roman Ivanov
+ * @author Miguel Vazquez Gocobachi
+ * @copyright 2004-2020 Roman Ivanov, Miguel Vazquez Gocobachi, WackoWiki Team
+ * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
+ * @version 1.3.12
+ * @link https://wackowiki.org/doc/Dev/Projects/SafeHTML
*/
-
-if (!defined('_ECRIRE_INC_VERSION')) return;
-
+/**
+ * This package requires HTMLSax3 package
+ */
require_once(XML_HTMLSAX3 . 'HTMLSax3.php');
/**
- *
- * SafeHTML Parser
+ * HTML_Safe Parser
*
* This parser strips down all potentially dangerous content within HTML:
*
*
opening tag without its closing tag
*
closing tag without its opening tag
- *
any of these tags: "base", "basefont", "head", "html", "body", "applet",
- * "object", "iframe", "frame", "frameset", "script", "layer", "ilayer", "embed",
+ *
any of these tags: "base", "basefont", "head", "html", "body", "applet",
+ * "object", "iframe", "frame", "frameset", "script", "layer", "ilayer", "embed",
* "bgsound", "link", "meta", "style", "title", "blink", "xml" etc.
*
any of these attributes: on*, data*, dynsrc
*
javascript:/vbscript:/about: etc. protocols
*
expression/behavior etc. in styles
*
any other active content
*
- * It also tries to convert code to XHTML valid, but htmltidy is far better
+ * It also tries to convert code to XHTML valid, but htmltidy is far better
* solution for this task.
*
* Example:
*
- * $parser =& new SafeHTML();
+ * $parser = new SafeHTML;
* $result = $parser->parse($doc);
*
- *
- * @category HTML
- * @package SafeHTML
- * @author Roman Ivanov
- * @copyright 1997-2005 Roman Ivanov
- * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
- * @version Release: @package_version@
- * @link http://pear.php.net/package/SafeHTML
*/
-class SafeHTML
+class SafeHTML
{
- /**
- * Storage for resulting HTML output
- *
- * @var string
- */
- protected $xhtml = '';
-
- /**
- * Array of counters for each tag
- *
- * @var array
- */
- protected $counter = array();
-
- /**
- * Stack of unclosed tags
- *
- * @var array
- */
- protected $stack = array();
-
- /**
- * Array of counters for tags that must be deleted with all content
- *
- * @var array
- */
- protected $dcCounter = array();
-
- /**
- * Stack of unclosed tags that must be deleted with all content
- *
- * @var array
- */
- protected $dcStack = array();
-
- /**
- * Stores level of list (ol/ul) nesting
- *
- * @var int
- */
- protected $listScope = 0;
-
- /**
- * Stack of unclosed list tags
- *
- * @var array
- */
- protected $liStack = array();
-
- /**
- * Array of prepared regular expressions for protocols (schemas) matching
- *
- * @var array
- */
- protected $protoRegexps = array();
-
- /**
- * Array of prepared regular expressions for CSS matching
- *
- * @var array
- */
- protected $cssRegexps = array();
-
- /**
- * Should we perform UTF7 repacking or not?
- *
- * This repacking might replace completely normal strings such as "+31-" by illegal sequences,
- * which cause the document to be truncated on saving to MySQL
- *
- * @var boolean
- * @access public
- */
- var $repackUTF7 = true;
-
- /**
- * Allowed tags
- *
- * @var array
- */
- protected $allowTags = array();
-
-
- /**
- * List of single tags ("")
- *
- * @var array
- */
- public $singleTags = array('area', 'br', 'img', 'input', 'hr', 'wbr', );
-
- /**
- * List of dangerous tags (such tags will be deleted)
- *
- * @var array
- */
- public $deleteTags = array(
- 'applet', 'base', 'basefont', 'bgsound', 'blink', 'body',
- 'embed', 'frame', 'frameset', 'head', 'html', 'ilayer',
- 'iframe', 'layer', 'link', 'meta', 'object', 'style',
- 'title', 'script',
- );
-
- /**
- * List of dangerous tags (such tags will be deleted, and all content
- * inside this tags will be also removed)
- *
- * @var array
- */
- public $deleteTagsContent = array('script', 'style', 'title', 'xml', );
-
- /**
- * Type of protocols filtering ('white' or 'black')
- *
- * @var string
- */
- public $protocolFiltering = 'white';
-
- /**
- * List of "dangerous" protocols (used for blacklist-filtering)
- *
- * @var array
- */
- public $blackProtocols = array(
- 'about', 'chrome', 'data', 'disk', 'hcp',
- 'help', 'javascript', 'livescript', 'lynxcgi', 'lynxexec',
- 'ms-help', 'ms-its', 'mhtml', 'mocha', 'opera',
- 'res', 'resource', 'shell', 'vbscript', 'view-source',
- 'vnd.ms.radio', 'wysiwyg',
- );
-
- /**
- * List of "safe" protocols (used for whitelist-filtering)
- *
- * @var array
- */
- public $whiteProtocols = array(
- 'ed2k', 'file', 'ftp', 'gopher', 'http', 'https',
- 'irc', 'mailto', 'news', 'nntp', 'telnet', 'webcal',
- 'xmpp', 'callto',
- );
-
- /**
- * List of attributes that can contain protocols
- *
- * @var array
- */
- public $protocolAttributes = array(
- 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc', 'src', 'formaction',
- );
-
- /**
- * List of dangerous CSS keywords
- *
- * Whole style="" attribute will be removed, if parser will find one of
- * these keywords
- *
- * @var array
- */
- public $cssKeywords = array(
- 'absolute', 'behavior', 'behaviour', 'content', 'expression',
- 'fixed', 'include-source', 'moz-binding',
- );
-
- /**
- * List of tags that can have no "closing tag"
- *
- * @var array
- * @deprecated XHTML does not allow such tags
- */
- public $noClose = array();
-
- /**
- * List of block-level tags that terminates paragraph
- *
- * Paragraph will be closed when this tags opened
- *
- * @var array
- */
- public $closeParagraph = array(
- 'address', 'article', 'aside', 'audio', 'blockquote', 'canvas',
- 'center', 'dd', 'dir', 'div', 'dl', 'dt',
- 'figure', 'figcaption', 'footer', 'h1', 'h2', 'h3',
- 'h4', 'h5', 'h6', 'header', 'hr', 'isindex',
- 'listing', 'main', 'marquee', 'menu', 'multicol', 'nav',
- 'ol', 'output', 'p', 'plaintext', 'pre', 'section',
- 'table', 'ul', 'video', 'xmp',
- );
-
- /**
- * List of table tags, all table tags outside a table will be removed
- *
- * @var array
- */
- public $tableTags = array(
- 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
- 'thead', 'tr',
- );
-
- /**
- * List of list tags
- *
- * @var array
- */
- public $listTags = array('dir', 'menu', 'ol', 'ul', 'dl', );
-
- /**
- * List of dangerous attributes
- *
- * @var array
- */
- public $attributes = array('dynsrc', 'id', 'name', );
-
- /**
- * List of allowed "namespaced" attributes
- *
- * @var array
- */
- public $attributesNS = array('xml:lang', );
-
- /**
- * Constructs class
- *
- * @access public
- */
- public function __construct()
- {
- //making regular expressions based on Proto & CSS arrays
- foreach ($this->blackProtocols as $proto) {
- $preg = "/[\s\x01-\x1F]*";
- for ($i=0; $iprotoRegexps[] = $preg;
- }
-
- foreach ($this->cssKeywords as $css) {
- $this->cssRegexps[] = '/' . $css . '/i';
- }
- return true;
- }
-
- /**
- * Handles the writing of attributes - called from $this->openHandler()
- *
- * @param array $attrs array of attributes $name => $value
- * @param string|null $tag
- * @return boolean
- */
- protected function writeAttrs ($attrs, $tag = null)
- {
- if (is_array($attrs)) {
- foreach ($attrs as $name => $value) {
- $name = strtolower($name);
-
- if (strpos($name, 'on') === 0) {
- continue;
- }
-
- if (strpos($name, 'data') === 0) {
- continue;
- }
-
- if ($tag != 'a' and in_array($name, $this->attributes)) {
- continue;
- }
-
- if (!preg_match('/^[a-z0-9]+$/i', $name)) {
- if (!in_array($name, $this->attributesNS)) {
- continue;
- }
- }
-
- if (($value === true) || (is_null($value))) {
- $value = $name;
- }
-
- if ($name == 'style') {
- // removes insignificant backslahes
- $value = str_replace("\\", '', $value);
-
- // removes CSS comments
- while (1) {
- $_value = preg_replace('!/\*.*?\*/!s', '', $value);
-
- if ($_value == $value) {
- break;
- }
-
- $value = $_value;
- }
-
- // replace all & to &
- $value = str_replace('&', '&', $value);
- $value = str_replace('&', '&', $value);
-
- foreach ($this->cssRegexps as $css) {
- if (preg_match($css, $value)) {
- continue 2;
- }
- }
-
- foreach ($this->protoRegexps as $proto) {
- if (preg_match($proto, $value)) {
- continue 2;
- }
- }
- }
-
- $tempval = preg_replace_callback('/(\d+);?/m', function ($matches) { return chr($matches[1]); }, $value); //"'
- $tempval = preg_replace_callback(
- '/([0-9a-f]+);?/mi',
- function ($matches) { return chr(hexdec($matches[1])); },
- $tempval
- );
-
- if ((in_array($name, $this->protocolAttributes))
- && (strpos($tempval, ':') !== false)
- ) {
- if ($this->protocolFiltering == 'black') {
- foreach ($this->protoRegexps as $proto) {
- if (preg_match($proto, $tempval)) {
- continue 2;
- }
- }
- } else {
- $_tempval = explode(':', $tempval);
- $proto = $_tempval[0];
-
- if (!in_array($proto, $this->whiteProtocols)) {
- continue;
- }
- }
- }
-
- $value = str_replace("\"", '"', $value);
- $this->xhtml .= ' ' . $name . '="' . $value . '"';
- }
- }
-
- return true;
- }
-
- /**
- * Opening tag handler - called from HTMLSax
- *
- * @param object &$parser HTML Parser
- * @param string $name tag name
- * @param array $attrs tag attributes
- *
- * @return boolean
- */
- public function openHandler(&$parser, $name, $attrs)
- {
- $name = strtolower($name);
-
- if (in_array($name, $this->deleteTagsContent)) {
- array_push($this->dcStack, $name);
- $this->dcCounter[$name] = isset($this->dcCounter[$name])
- ? $this->dcCounter[$name]+1 : 1;
- }
- if (count($this->dcStack) != 0) {
- return true;
- }
-
- if (in_array($name, $this->deleteTags)
- && !in_array($name, $this->allowTags)
- ) {
- return true;
- }
-
- if (!preg_match('/^[a-z0-9]+$/i', $name)) {
- if (preg_match('!(?:\@|://)!i', $name)) {
- $this->xhtml .= '<' . $name . '>';
- }
- return true;
- }
-
- if (in_array($name, $this->singleTags)) {
- $this->xhtml .= '<' . $name;
- $this->writeAttrs($attrs, $name);
- $this->xhtml .= ' />';
- return true;
- }
-
- // TABLES: cannot open table elements when we are not inside table
- if ((isset($this->counter['table']))
- && ($this->counter['table'] <= 0)
- && (in_array($name, $this->tableTags))
- ) {
- return true;
- }
-
- // PARAGRAPHS: close paragraph when closeParagraph tags opening
- if ((in_array($name, $this->closeParagraph))
- && (in_array('p', $this->stack))
- ) {
- $this->closeHandler($parser, 'p');
- }
-
- // LISTS: we should close
if
of the same level opening
- if (($name == 'li') && count($this->liStack)
- && ($this->listScope == $this->liStack[count($this->liStack) - 1])
- ) {
- $this->closeHandler($parser, 'li');
- }
-
- // LISTS: we want to know on what nesting level of lists we are
- if (in_array($name, $this->listTags)) {
- ++$this->listScope;
- }
-
- if ($name == 'li') {
- array_push($this->liStack, $this->listScope);
- }
-
- $this->xhtml .= '<' . $name;
- $this->writeAttrs($attrs, $name);
- $this->xhtml .= '>';
- array_push($this->stack,$name);
- $this->counter[$name] = isset($this->counter[$name])
- ? ($this->counter[$name] + 1) : 1;
-
- return true;
- }
-
- /**
- * Closing tag handler - called from HTMLSax
- *
- * @param object &$parser HTML parser
- * @param string $name tag name
- *
- * @return boolean
- */
- public function closeHandler(&$parser, $name)
- {
- $name = strtolower($name);
-
- if (isset($this->dcCounter[$name])
- && ($this->dcCounter[$name] > 0)
- && (in_array($name, $this->deleteTagsContent))
- ) {
- while ($name != ($tag = array_pop($this->dcStack))) {
- --$this->dcCounter[$tag];
- }
-
- --$this->dcCounter[$name];
- }
-
- if (count($this->dcStack) != 0) {
- return true;
- }
-
- if ((isset($this->counter[$name])) && ($this->counter[$name] > 0)) {
- while ($name != ($tag = array_pop($this->stack))) {
- $this->closeTag($tag);
- }
-
- $this->closeTag($name);
- }
- return true;
- }
-
- /**
- * Closes tag
- *
- * @param string $tag tag name
- *
- * @return boolean
- */
- protected function closeTag($tag)
- {
- if (!in_array($tag, $this->noClose)) {
- $this->xhtml .= '' . $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:
- *
+ *
+ * @param array $tags Tags to allow
+ *
+ * @return void
+ */
+ public function setAllowTags($tags = [])
+ {
+ if (is_array($tags))
+ {
+ $this->allowTags = $tags;
+ }
+ }
+
+ /**
+ * Returns the allowed tags
+ *
+ * @return array
+ */
+ public function getAllowTags()
+ {
+ return $this->allowTags;
+ }
+
+ /**
+ * Reset the allowed tags
+ *
+ * @return void
+ */
+ public function resetAllowTags()
+ {
+ $this->allowTags = [];
+ }
+
+ /**
+ * Returns the XHTML document
+ *
+ * @return string Processed (X)HTML document
+ */
+ public function getXHTML()
+ {
+ while ($tag = array_pop($this->stack))
+ {
+ $this->closeTag($tag);
+ }
+
+ return $this->xhtml;
+ }
+
+ /**
+ * Clears current document data
+ *
+ * @return boolean
+ */
+ public function clear()
+ {
+ $this->xhtml = '';
+
+ return true;
+ }
+
+ /**
+ * Main parsing function
+ *
+ * @param string $doc HTML document for processing
+ *
+ * @return string Processed (X)HTML document
+ */
+ public function parse($doc)
+ {
+ $result = '';
+
+ // Save all '<' symbols
+ $doc = preg_replace('/<(?=[^a-zA-Z\/\!\?\%])/', '<', $doc);
+
+ // UTF7 pack
+ $doc = $this->repackUTF7($doc);
+
+ // Instantiate the parser
+ $parser = new XML_HTMLSax3;
+
+ // Set up the parser
+ $parser->set_object($this);
+
+ $parser->set_element_handler('openHandler', 'closeHandler');
+ $parser->set_data_handler('dataHandler');
+ $parser->set_escape_handler('escapeHandler');
+
+ $parser->parse($doc);
+
+ $result = $this->getXHTML();
+
+ $this->clear();
+
+ return $result;
+ }
+
+ /**
+ * UTF-7 decoding function
+ *
+ * @param string $str HTML document for recode ASCII part of UTF-7 back to ASCII
+ * @return string Decoded document
+ * @access private
+ */
+ function repackUTF7($str)
+ {
+ return preg_replace_callback('!\+([0-9a-zA-Z/]+)\-!', [$this, 'repackUTF7Callback'], $str);
+ }
+
+ /**
+ * Additional UTF-7 decoding function
+ *
+ * @param string $str String for recode ASCII part of UTF-7 back to ASCII
+ * @return string Recoded string
+ * @access private
+ */
+ function repackUTF7Callback($str)
+ {
+ $str = base64_decode($str[1]);
+ $str = preg_replace_callback('/^((?:\x00.)*)((?:[^\x00].)+)/', [$this, 'repackUTF7Back'], $str);
+
+ return preg_replace('/\x00(.)/', '$1', $str);
+ }
+
+ /**
+ * Additional UTF-7 encoding function
+ *
+ * @param string $str String for recode ASCII part of UTF-7 back to ASCII
+ * @return string Recoded string
+ * @access private
+ */
+ function repackUTF7Back($str)
+ {
+ return $str[1] . '+' . rtrim(base64_encode($str[2]), '=') . '-';
+ }
}
+
diff -Nru spip-3.2.7/plugins-dist/safehtml/lib/safehtml/license.txt spip-3.2.15.1/plugins-dist/safehtml/lib/safehtml/license.txt
--- spip-3.2.7/plugins-dist/safehtml/lib/safehtml/license.txt 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/safehtml/lib/safehtml/license.txt 2022-05-20 16:59:18.000000000 +0100
@@ -1,27 +1,27 @@
-(c) Miguel Vazquez Gocobachi, WackoWiki Team, 2005-2017
-(c) Roman Ivanov, 2004-2005
-(c) Pixel-Apes ( http://pixel-apes.com/ ), 2004-2005
-(c) JetStyle ( http://jetstyle.ru/ ), 2004-2005
-Maintainer -- Roman Ivanov
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-3. The name of the author may not be used to endorse or promote products
- derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+(c) Miguel Vazquez Gocobachi, WackoWiki Team, 2006-2020
+(c) Roman Ivanov, 2004-2005
+(c) Pixel-Apes ( http://pixel-apes.com/ ), 2004-2005
+(c) JetStyle ( http://jetstyle.ru/ ), 2004-2005
+Maintainer -- Roman Ivanov
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff -Nru spip-3.2.7/plugins-dist/safehtml/lib/safehtml/readme.txt spip-3.2.15.1/plugins-dist/safehtml/lib/safehtml/readme.txt
--- spip-3.2.7/plugins-dist/safehtml/lib/safehtml/readme.txt 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/safehtml/lib/safehtml/readme.txt 2022-05-20 16:59:18.000000000 +0100
@@ -1,87 +1,93 @@
-SafeHTML
---------
-Version 1.3.10.
-https://wackowiki.org/doc/Dev/Projects/SafeHTML
---------
-
-This parser strips down all potentially dangerous content within HTML:
- * opening tag without its closing tag
- * closing tag without its opening tag
- * any of these tags: "base", "basefont", "head", "html", "body", "applet", "object",
- "iframe", "frame", "frameset", "script", "layer", "ilayer", "embed", "bgsound",
- "link", "meta", "style", "title", "blink", "xml" etc.
- * any of these attributes: on*, data*, dynsrc
- * javascript:/vbscript:/about: etc. protocols
- * expression/behavior etc. in styles
- * any other active content
-It also tries to convert code to XHTML valid, but htmltidy is far better solution for this task.
-
-If you found any bugs in this parser, please file an issue -- https://wackowiki.org/bugs/
-
-Please, subscribe to https://wackowiki.org/doc/Dev/Projects/SafeHTML in order to receive notices
-when SAFEHTML will be updated.
-
--- Roman Ivanov.
--- Pixel-Apes ( http://pixel-apes.com ).
--- JetStyle ( http://jetstyle.ru/ ).
-
-
-
---------
-Version history:
---------
-1.3.10.
- * added HTML5 Block-level elements
-1.3.9.
- * Replaced preg_replace() e modifier with preg_replace_callback
-1.3.8.
- * UTF-7 XSS vulnerability fixed
-1.3.7.
- * Added 'dl' to the list of 'lists' tags.
- * Added 'callto' to the white list of protocols.
- * Added white list of "namespaced" attributes.
-1.3.6.
- * More accurate UTF-7 decoding.
-1.3.5.
- * Two serious security flaws fixed: UTF-7 XSS and CSS comments handling.
-1.3.2.
- * Security flaw (improper quotes handling in attributes' values) fixed. Big thanks to Nick Cleaton.
-1.3.1.
- * Dumb bug fixed (some closing tags were ignored).
-1.3.0.
- * Two holes (with decimal HTML entities and with \x00 symbol) fixed.
- * Class rewritten under PEAR coding standarts.
- * Class now uses unmodified HTMLSax3 from PEAR.
- * To the list of table tags added: "caption", "col", "colgroup".
-1.2.1.
- * It was possible to create XSS with hexadecimal HTML entities. Fixed. Big thanks to Christian Stocker.
-1.2.0.
- * "id" and "name" attributes added to dangerous attributes list, because malefactor can broke legal javascript by spoofing ID or NAME of some element.
- * New method parse() allows to do all parsing process in two lines of code. Examples also updated.
- * New array, closeParagraph, contains list of block-level elements. When we open such elemet, we should close paragraph before. . It allows SafeHTML to produce more XHTML compliant code.
- * Added "webcal" to white list of protocols for those who uses calendar programs (Mozilla/iCal/etc).
- * Now SafeHTML strips down table elements when we are not inside table.
- * Now SafeHTML correctly closes unclosed "li" tags: before opening "li" of the same nesting level.
-1.1.0.
- * New "dangerous" protocols: hcp, ms-help, help, disk, vnd.ms.radio, opera, res, resource, chrome, mocha, livescript.
- * tag was moved from "tags for deletion" to "tags for deletion with content".
- * New "dangerous" CSS instruction "include-source" (NN4 specific).
- * New array, Attributes, contains list of attributes for removal. If you need to remove "id" or "name" attribute,
- just add it to this array.
- * Now it is possible to choose between white-list and black-list filtering of protocols. Defaults are "white-list".
- This list is: "http", "https", "ftp", "telnet", "news", "nntp", "gopher", "mailto", "file".
- * For speed purposes, we now filter protocols only from these attributes: src, href, action, lowsrc, dynsrc,
- background, codebase.
- * Opera6 XSS bug ([\xC0][\xBC]script>alert(1)[\xC0][\xBC]/script> [UTF-8] workarounded.
-1.0.4.
- New "dangerous" tag: plaintext.
-1.0.3.
- Added array of elements that can have no closing tag.
-1.0.2.
- Bug fix: attack.
- Thanks to shmel.
-1.0.1.
- Bug fix: safehtml hangs on code.
- Thanks to lj user=electrocat.
-1.0.0.
- First public release
+SafeHTML
+--------
+Version 1.3.12.
+https://wackowiki.org/doc/Dev/Projects/SafeHTML
+--------
+
+This parser strips down all potentially dangerous content within HTML:
+ * opening tag without its closing tag
+ * closing tag without its opening tag
+ * any of these tags: "base", "basefont", "head", "html", "body", "applet", "object",
+ "iframe", "frame", "frameset", "script", "layer", "ilayer", "embed", "bgsound",
+ "link", "meta", "style", "title", "blink", "xml" etc.
+ * any of these attributes: on*, data*, dynsrc
+ * javascript:/vbscript:/about: etc. protocols
+ * expression/behavior etc. in styles
+ * any other active content
+It also tries to convert code to XHTML valid, but htmltidy is far better solution for this task.
+
+If you found any bugs in this parser, please file an issue -- https://wackowiki.org/bugs/
+
+Please, subscribe to https://wackowiki.org/doc/Dev/Projects/SafeHTML in order to receive notices
+when SAFEHTML will be updated.
+
+-- Roman Ivanov.
+-- Pixel-Apes ( http://pixel-apes.com ).
+-- JetStyle ( http://jetstyle.ru/ ).
+
+
+
+--------
+Version history:
+--------
+1.3.12
+ * added missing HTML5 tag terminators for paragraph
+ * removed obsolete and deprecated HTML elements
+1.3.11.
+ * added new HTML5 Block-level elements
+1.3.10.
+ * Replaced preg_replace() e modifier with preg_replace_callback
+1.3.9.
+ * UTF-7 XSS vulnerability fixed
+1.3.8.
+ * Allowed tags with setAllowTags() method.
+ * AllowTags can be disabled using resetAllowTags()
+1.3.7.
+ * Added 'dl' to the list of 'lists' tags.
+ * Added 'callto' to the white list of protocols.
+ * Added white list of "namespaced" attributes.
+1.3.6.
+ * More accurate UTF-7 decoding.
+1.3.5.
+ * Two serious security flaws fixed: UTF-7 XSS and CSS comments handling.
+1.3.2.
+ * Security flaw (improper quotes handling in attributes' values) fixed. Big thanks to Nick Cleaton.
+1.3.1.
+ * Dumb bug fixed (some closing tags were ignored).
+1.3.0.
+ * Two holes (with decimal HTML entities and with \x00 symbol) fixed.
+ * Class rewritten under PEAR coding standards.
+ * Class now uses unmodified HTMLSax3 from PEAR.
+ * To the list of table tags added: "caption", "col", "colgroup".
+1.2.1.
+ * It was possible to create XSS with hexadecimal HTML entities. Fixed. Big thanks to Christian Stocker.
+1.2.0.
+ * "id" and "name" attributes added to dangerous attributes list, because malefactor can broke legal javascript by spoofing ID or NAME of some element.
+ * New method parse() allows to do all parsing process in two lines of code. Examples also updated.
+ * New array, closeParagraph, contains list of block-level elements. When we open such element, we should close paragraph before. . It allows SafeHTML to produce more XHTML compliant code.
+ * Added "webcal" to white list of protocols for those who uses calendar programs (Mozilla/iCal/etc).
+ * Now SafeHTML strips down table elements when we are not inside table.
+ * Now SafeHTML correctly closes unclosed "li" tags: before opening "li" of the same nesting level.
+1.1.0.
+ * New "dangerous" protocols: hcp, ms-help, help, disk, vnd.ms.radio, opera, res, resource, chrome, mocha, livescript.
+ * tag was moved from "tags for deletion" to "tags for deletion with content".
+ * New "dangerous" CSS instruction "include-source" (NN4 specific).
+ * New array, Attributes, contains list of attributes for removal. If you need to remove "id" or "name" attribute,
+ just add it to this array.
+ * Now it is possible to choose between white-list and black-list filtering of protocols. Defaults are "white-list".
+ This list is: "http", "https", "ftp", "telnet", "news", "nntp", "gopher", "mailto", "file".
+ * For speed purposes, we now filter protocols only from these attributes: src, href, action, lowsrc, dynsrc,
+ background, codebase.
+ * Opera6 XSS bug ([\xC0][\xBC]script>alert(1)[\xC0][\xBC]/script> [UTF-8] workarounded.
+1.0.4.
+ New "dangerous" tag: plaintext.
+1.0.3.
+ Added array of elements that can have no closing tag.
+1.0.2.
+ Bug fix: attack.
+ Thanks to shmel.
+1.0.1.
+ Bug fix: safehtml hangs on code.
+ Thanks to lj user=electrocat.
+1.0.0.
+ First public release
diff -Nru spip-3.2.7/plugins-dist/safehtml/paquet.xml spip-3.2.15.1/plugins-dist/safehtml/paquet.xml
--- spip-3.2.7/plugins-dist/safehtml/paquet.xml 2019-12-12 21:31:10.000000000 +0000
+++ spip-3.2.15.1/plugins-dist/safehtml/paquet.xml 2022-05-20 16:59:18.000000000 +0100
@@ -1,7 +1,7 @@
Roman Ivanov
Pixel-ApesJetStyle
+ https://wackowiki.org/doc/Dev/Projects/SafeHTMLGPL
+
+
diff -Nru spip-3.2.7/plugins-dist/safehtml/tests/safehtml.php spip-3.2.15.1/plugins-dist/safehtml/tests/safehtml.php
--- spip-3.2.7/plugins-dist/safehtml/tests/safehtml.php 1970-01-01 01:00:00.000000000 +0100
+++ spip-3.2.15.1/plugins-dist/safehtml/tests/safehtml.php 2022-05-20 16:59:18.000000000 +0100
@@ -0,0 +1,853 @@
+' . join('', $err) . '');
+ }
+
+ echo "OK";
+
+
+ function essais_safehtml(){
+ $essais = array (
+ 0 =>
+ array (
+ 0 => '',
+ 1 => '',
+ ),
+ 1 =>
+ array (
+ 0 => '0',
+ 1 => '0',
+ ),
+ 2 =>
+ array (
+ 0 => 'Un texte avec des liens [Article 1->art1] [spip->https://www.spip.net] https://www.spip.net',
+ 1 => 'Un texte avec des liens [Article 1->art1] [spip->https://www.spip.net] https://www.spip.net',
+ ),
+ 3 =>
+ array (
+ 0 => 'Un texte avec des entités &<>"',
+ 1 => 'Un texte avec des entités &<>"',
+ ),
+ 4 =>
+ array (
+ 0 => 'Un texte avec des entités echapé &<>"',
+ 1 => 'Un texte avec des entités echapé &<>"',
+ ),
+ 5 =>
+ array (
+ 0 => 'Un texte avec des entités numériques &<>"',
+ 1 => 'Un texte avec des entités numériques &<>"',
+ ),
+ 6 =>
+ array (
+ 0 => 'Un texte avec des entités numériques echapées &<>"',
+ 1 => 'Un texte avec des entités numériques echapées &<>"',
+ ),
+ 7 =>
+ array (
+ 0 => 'Un texte sans entites &<>"\'',
+ 1 => 'Un texte sans entites &<>"\'',
+ ),
+ 8 =>
+ array (
+ 0 => '{{{Des raccourcis}}} {italique} {{gras}} du code',
+ 1 => '{{{Des raccourcis}}} {italique} {{gras}} du code',
+ ),
+ 9 =>
+ array (
+ 0 => 'Un modele https://www.spip.net]>',
+ 1 => 'Un modele https://www.spip.net]>',
+ ),
+ 10 =>
+ array (
+ 0 => 'Un texte avec des retour
+a la ligne et meme des
+
+paragraphes',
+ 1 => 'Un texte avec des retour
+a la ligne et meme des
+
+paragraphes',
+ ),
+ 11 =>
+ array (
+ 0 => '\';alert(String.fromCharCode(88,83,83))//\\\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\\";alert(String.fromCharCode(88,83,83))//-->">\'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>=&{}',
+ 1 => '\';alert(String.fromCharCode(88,83,83))//\\\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\\";alert(String.fromCharCode(88,83,83))//-->">\'>=&{}',
+ ),
+ 12 =>
+ array (
+ 0 => '\'\';!--"=&{()}',
+ 1 => '\'\';!--"=&{()}',
+ ),
+ 13 =>
+ array (
+ 0 => '<SCRIPT>alert(\'XSS\')</SCRIPT>',
+ 1 => '',
+ ),
+ 14 =>
+ array (
+ 0 => '<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>',
+ 1 => '',
+ ),
+ 15 =>
+ array (
+ 0 => '<SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>',
+ 1 => '',
+ ),
+ 16 =>
+ array (
+ 0 => '<base HREF="javascript:alert(\'XSS\');//">',
+ 1 => '',
+ ),
+ 17 =>
+ array (
+ 0 => '<BGSOUND SRC="javascript:alert(\'XSS\');">',
+ 1 => '',
+ ),
+ 18 =>
+ array (
+ 0 => '<BODY BACKGROUND="javascript:alert(\'XSS\');">',
+ 1 => '',
+ ),
+ 19 =>
+ array (
+ 0 => '<BODY ONLOAD=alert(\'XSS\')>',
+ 1 => '',
+ ),
+ 20 =>
+ array (
+ 0 => '',
+ 1 => '