From: Ludovic CHEVALIER Date: Thu, 8 Apr 2021 09:36:41 +0000 (+0200) Subject: [SPIP] ~maj v3.2.9-->v3.2.11 X-Git-Tag: production~9 X-Git-Url: http://git.cyclocoop.org/?p=lhc%2Fweb%2Fwww.git;a=commitdiff_plain;h=fd181064435bb60f1664ba4d8836fefce6ab0e0a [SPIP] ~maj v3.2.9-->v3.2.11 --- diff --git a/www/CHANGELOG.TXT b/www/CHANGELOG.TXT index d9db953d..f69be25c 100644 --- a/www/CHANGELOG.TXT +++ b/www/CHANGELOG.TXT @@ -1,42 +1,138 @@ - 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.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) diff --git a/www/config/ecran_securite.php b/www/config/ecran_securite.php index b4711566..773ae6c1 100644 --- a/www/config/ecran_securite.php +++ b/www/config/ecran_securite.php @@ -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 @@ define('_ECRAN_SECURITE', '1.3.13'); // 2019-12-04 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')){ 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 @@ if (isset($ecran_securite_raison)) { 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)

"); } @@ -598,5 +606,6 @@ if ( header("Cache-Control: no-cache, must-revalidate"); header("Pragma: no-cache"); header("Content-Type: text/html"); + header("Connection: close"); die("Status 429: Too Many Requests

Status 429

Too Many Requests (try again soon)

"); } diff --git a/www/ecrire/auth/sha256.inc.php b/www/ecrire/auth/sha256.inc.php index 3b9c49be..887bc49b 100644 --- a/www/ecrire/auth/sha256.inc.php +++ b/www/ecrire/auth/sha256.inc.php @@ -258,7 +258,7 @@ if (!class_exists('nanoSha2')) { return false; } - $h = ord($c{$index}); + $h = ord($c[$index]); if ($h <= 0x7F) { $bytes = 1; @@ -274,20 +274,20 @@ if (!class_exists('nanoSha2')) { 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 --git a/www/ecrire/balise/url_.php b/www/ecrire/balise/url_.php index 3f16b2c4..a3bb55c7 100644 --- a/www/ecrire/balise/url_.php +++ b/www/ecrire/balise/url_.php @@ -277,7 +277,7 @@ function balise_URL_PAGE_dist($p) { $code .= ", $args"; } $code = $f('page', $code, $s); - + $p->code = $code; return $p; } $s = 'connect=' . addslashes($s); diff --git a/www/ecrire/base/connect_sql.php b/www/ecrire/base/connect_sql.php index 1ec79e6c..ba1fa377 100644 --- a/www/ecrire/base/connect_sql.php +++ b/www/ecrire/base/connect_sql.php @@ -525,6 +525,7 @@ function query_reinjecte_textes($query, $textes) { * - 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 --git a/www/ecrire/base/upgrade.php b/www/ecrire/base/upgrade.php index 41ad9582..72f8dd49 100644 --- a/www/ecrire/base/upgrade.php +++ b/www/ecrire/base/upgrade.php @@ -92,7 +92,7 @@ function base_upgrade_dist($titre = '', $reprise = '') { * @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 @@ function maj_base($version_cible = 0, $redirect = '') { 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 @@ function maj_while($installee, $cible, $maj, $meta = '', $table = 'meta', $redir 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 @@ function maj_while($installee, $cible, $maj, $meta = '', $table = 'meta', $redir 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 --git a/www/ecrire/genie/optimiser.php b/www/ecrire/genie/optimiser.php index 639aad06..455d969f 100644 --- a/www/ecrire/genie/optimiser.php +++ b/www/ecrire/genie/optimiser.php @@ -155,12 +155,13 @@ function optimiser_sansref($table, $id, $sel, $and = '') { 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 @@ -173,12 +174,12 @@ function optimiser_base_disparus($attente = 86400) { 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 @@ -195,7 +196,7 @@ function optimiser_base_disparus($attente = 86400) { 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); diff --git a/www/ecrire/inc/charsets.php b/www/ecrire/inc/charsets.php index 7dbd178e..98036d60 100644 --- a/www/ecrire/inc/charsets.php +++ b/www/ecrire/inc/charsets.php @@ -404,20 +404,26 @@ function charset2unicode($texte, $charset = 'AUTO' /* $forcer: obsolete*/) { 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 @@ function charset2unicode($texte, $charset = 'AUTO' /* $forcer: obsolete*/) { } } } - 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 @@ function javascript_to_binary($texte) { * @return string */ function translitteration_rapide($texte, $charset = 'AUTO', $complexe = '') { - static $trans; + static $trans = []; if ($charset == 'AUTO') { $charset = $GLOBALS['meta']['charset']; } @@ -842,7 +848,8 @@ function translitteration_rapide($texte, $charset = 'AUTO', $complexe = '') { $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 @@ function translitteration_complexe($texte, $chiffres = false) { $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 @@ function transcoder_page($texte, $headers = '') { 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 --git a/www/ecrire/inc/config.php b/www/ecrire/inc/config.php index ede9c12f..d5d4113c 100644 --- a/www/ecrire/inc/config.php +++ b/www/ecrire/inc/config.php @@ -544,8 +544,8 @@ function actualise_metas($liste_meta) { // 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); } } diff --git a/www/ecrire/inc/filtres.php b/www/ecrire/inc/filtres.php index 3b37483e..064a44e7 100644 --- a/www/ecrire/inc/filtres.php +++ b/www/ecrire/inc/filtres.php @@ -1916,11 +1916,13 @@ function alterner($i) { **/ 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; } @@ -2361,7 +2363,7 @@ function microformat2enclosure($tags) { 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"; @@ -2400,7 +2402,9 @@ function extraire_balise($texte, $tag = 'a') { 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 ); @@ -2442,7 +2446,9 @@ function extraire_balises($texte, $tag = 'a') { 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 ); @@ -2846,9 +2852,11 @@ function urls_absolues_css($contenu, $source) { 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 + ); } @@ -4273,12 +4281,16 @@ function bouton_action($libelle, $url, $class = "", $confirm = "", $title = "", /** * 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); } /** diff --git a/www/ecrire/inc/filtres_images_lib_mini.php b/www/ecrire/inc/filtres_images_lib_mini.php index d93acc1e..b45889b4 100644 --- a/www/ecrire/inc/filtres_images_lib_mini.php +++ b/www/ecrire/inc/filtres_images_lib_mini.php @@ -853,7 +853,7 @@ function _image_tag_changer_taille($tag, $width, $height, $style = false) { // 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 --git a/www/ecrire/inc/idna_convert.class.php b/www/ecrire/inc/idna_convert.class.php index 5407a998..5e4e4fd2 100644 --- a/www/ecrire/inc/idna_convert.class.php +++ b/www/ecrire/inc/idna_convert.class.php @@ -423,7 +423,7 @@ class idna_convert { $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 @@ class idna_convert { 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 @@ class idna_convert { $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 @@ class idna_convert { $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 --git a/www/ecrire/inc/math.php b/www/ecrire/inc/math.php index a134c579..ce841dcb 100644 --- a/www/ecrire/inc/math.php +++ b/www/ecrire/inc/math.php @@ -60,7 +60,7 @@ function produire_image_math($tex) { // MathML if ($GLOBALS['traiter_math'] == 'mathml') { - return join(file("$fichier"), ""); + return implode("", file($fichier)); } // TeX else { list(, , , $size) = @getimagesize($fichier); diff --git a/www/ecrire/inc/plonger.php b/www/ecrire/inc/plonger.php index fc93da4a..1f55eb49 100644 --- a/www/ecrire/inc/plonger.php +++ b/www/ecrire/inc/plonger.php @@ -57,8 +57,8 @@ function inc_plonger_dist($id_rubrique, $idom = "", $list = array(), $col = 1, $ $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 --git a/www/ecrire/inc/plugin.php b/www/ecrire/inc/plugin.php index 417cb9f3..1da2f363 100644 --- a/www/ecrire/inc/plugin.php +++ b/www/ecrire/inc/plugin.php @@ -209,7 +209,7 @@ function plugin_version_compatible($intervalle, $version, $avec_quoi = '') { // 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 @@ function plugin_message_incompatibilite($intervalle, $version, $nom, $balise) { $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 @@ function plugins_precompile_chemin($plugin_valides, $ordre) { $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 --git a/www/ecrire/inc/session.php b/www/ecrire/inc/session.php index a7596502..2e331bf4 100644 --- a/www/ecrire/inc/session.php +++ b/www/ecrire/inc/session.php @@ -77,16 +77,26 @@ function inc_session_dist($auteur = false) { */ 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 --git a/www/ecrire/inc/utils.php b/www/ecrire/inc/utils.php index a89658a6..afc4fbc2 100644 --- a/www/ecrire/inc/utils.php +++ b/www/ecrire/inc/utils.php @@ -328,9 +328,12 @@ function spip_log($message = null, $name = null) { 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) { @@ -2741,9 +2744,11 @@ function spip_initialisation_suite() { // 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', ''); + } } diff --git a/www/ecrire/inc/xml.php b/www/ecrire/inc/xml.php index 26c80773..a9a55eeb 100644 --- a/www/ecrire/inc/xml.php +++ b/www/ecrire/inc/xml.php @@ -212,13 +212,12 @@ function spip_xml_tagname($tag) { 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 --git a/www/ecrire/inc_version.php b/www/ecrire/inc_version.php index 6d45f328..a4f5006e 100644 --- a/www/ecrire/inc_version.php +++ b/www/ecrire/inc_version.php @@ -374,8 +374,8 @@ $liste_des_authentifications = array( // ex : 2.0.0, 2.0.0-dev, 2.0.0-beta, 2.0.0-beta2 // le _SPIP_VERSION_ID est un nombre entier représentant le numéro de version (2 chiffres pour chaque 03 + 02 + 06 = 30206 // le _SPIP_EXTRA_VERSION sert à repérer les version dev, beta etc. Pour une version stable il est vide. -$spip_version_branche = "3.2.9"; -define('_SPIP_VERSION_ID', 30209); +$spip_version_branche = "3.2.11"; +define('_SPIP_VERSION_ID', 30211); define('_SPIP_EXTRA_VERSION', ''); // cette version dev accepte tous les plugins compatible avec la version ci-dessous diff --git a/www/ecrire/install/etape_chmod.php b/www/ecrire/install/etape_chmod.php index 0021f74a..15e7d765 100644 --- a/www/ecrire/install/etape_chmod.php +++ b/www/ecrire/install/etape_chmod.php @@ -93,7 +93,7 @@ function install_etape_chmod_dist() { $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 --git a/www/ecrire/iterateur/data.php b/www/ecrire/iterateur/data.php index 55367888..616bfc8a 100644 --- a/www/ecrire/iterateur/data.php +++ b/www/ecrire/iterateur/data.php @@ -127,7 +127,9 @@ class IterateurDATA implements Iterator { */ 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 @@ class IterateurDATA implements Iterator { * **/ 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 @@ class IterateurDATA implements Iterator { $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 @@ class IterateurDATA implements Iterator { */ 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); } } diff --git a/www/ecrire/paquet.xml b/www/ecrire/paquet.xml index d62467ff..b441cd09 100644 --- a/www/ecrire/paquet.xml +++ b/www/ecrire/paquet.xml @@ -1,7 +1,7 @@ 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); diff --git a/www/ecrire/public/compiler.php b/www/ecrire/public/compiler.php index 42ab5da7..47ac7eb9 100644 --- a/www/ecrire/public/compiler.php +++ b/www/ecrire/public/compiler.php @@ -1194,7 +1194,13 @@ function public_compiler_dist($squelette, $nom, $gram, $sourcefile, $connect = ' $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 @@ function public_compiler_dist($squelette, $nom, $gram, $sourcefile, $connect = ' // 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 --git a/www/ecrire/public/composer.php b/www/ecrire/public/composer.php index c3d11749..62b476fe 100644 --- a/www/ecrire/public/composer.php +++ b/www/ecrire/public/composer.php @@ -979,7 +979,8 @@ function calculer_select( // penser a regarder aussi la clause groubpy pour ne pas simplifier abusivement // #TOTAL_BOUCLE - 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 @@ -991,8 +992,8 @@ function calculer_select( 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 --git a/www/ecrire/public/iterateur.php b/www/ecrire/public/iterateur.php index 1e274d59..b5c2e35c 100644 --- a/www/ecrire/public/iterateur.php +++ b/www/ecrire/public/iterateur.php @@ -300,7 +300,10 @@ class IterDecorator extends FilterIterator { // 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 @@ class IterDecorator extends FilterIterator { # if (!in_array($cle, array('cle', 'valeur'))) # return; - $a = '$me->get_select(\'' . $cle . '\')'; + $a = '$this->get_select(\'' . $cle . '\')'; $filtre = ''; @@ -566,7 +569,7 @@ class IterDecorator extends FilterIterator { **/ public function accept() { if ($f = $this->func_filtre) { - return $f($this); + return $f(); } return true; diff --git a/www/ecrire/public/quete.php b/www/ecrire/public/quete.php index 09a4b1d9..f8f406d7 100644 --- a/www/ecrire/public/quete.php +++ b/www/ecrire/public/quete.php @@ -669,7 +669,7 @@ function quete_debut_pagination($primary, $valeur, $pas, $iter) { $pos++; } // si on a pas trouve - if ($row[$primary] != $valeur) { + if (!$row or $row[$primary] != $valeur) { return 0; } diff --git a/www/ecrire/public/references.php b/www/ecrire/public/references.php index 218f2903..6a6116a8 100644 --- a/www/ecrire/public/references.php +++ b/www/ecrire/public/references.php @@ -704,13 +704,18 @@ function champs_traitements($p) { $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_requete = $GLOBALS['table_des_tables'][$type_requete]; + } + // 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 indifféremment quelle que soit la boucle elseif (isset($ps[0])) { $ps = $ps[0]; } else { diff --git a/www/ecrire/req/mysql.php b/www/ecrire/req/mysql.php index 5cd2c0d2..4c78e1c6 100644 --- a/www/ecrire/req/mysql.php +++ b/www/ecrire/req/mysql.php @@ -243,7 +243,7 @@ function spip_mysql_query($query, $serveur = '', $requeter = true) { 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)) . ' */'; @@ -1681,7 +1681,8 @@ function spip_get_lock($nom, $timeout = 0) { $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 --git a/www/ecrire/req/sqlite_generique.php b/www/ecrire/req/sqlite_generique.php index 64f5016e..294df176 100644 --- a/www/ecrire/req/sqlite_generique.php +++ b/www/ecrire/req/sqlite_generique.php @@ -2298,16 +2298,14 @@ function _sqlite_charger_version($version = '') { 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; } diff --git a/www/plugins-dist/breves/breves_pipelines.php b/www/plugins-dist/breves/breves_pipelines.php index 4a296275..6286fd5c 100644 --- a/www/plugins-dist/breves/breves_pipelines.php +++ b/www/plugins-dist/breves/breves_pipelines.php @@ -285,8 +285,7 @@ function breves_accueil_encours($flux) { */ function breves_optimiser_base_disparus($flux) { $n = &$flux['data']; - $mydate = $flux['args']['date']; - + $mydate = sql_quote($flux['args']['date']); # les breves qui sont dans une id_rubrique inexistante $res = sql_select( @@ -295,7 +294,7 @@ function breves_optimiser_base_disparus($flux) { LEFT JOIN spip_rubriques AS R ON B.id_rubrique=R.id_rubrique', 'R.id_rubrique IS NULL - AND B.maj < ' . sql_quote($mydate) + AND B.maj < ' . $mydate ); $n += optimiser_sansref('spip_breves', 'id_breve', $res); diff --git a/www/plugins-dist/compresseur/inc/compresseur_embarquer.php b/www/plugins-dist/compresseur/inc/compresseur_embarquer.php index 85d940d4..891c7b8e 100644 --- a/www/plugins-dist/compresseur/inc/compresseur_embarquer.php +++ b/www/plugins-dist/compresseur/inc/compresseur_embarquer.php @@ -47,10 +47,9 @@ function compresseur_embarquer_images_css($contenu, $source, $source_file = null 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 --git a/www/plugins-dist/compresseur/lib/csstidy/NEWS b/www/plugins-dist/compresseur/lib/csstidy/NEWS deleted file mode 100644 index 4862c658..00000000 --- a/www/plugins-dist/compresseur/lib/csstidy/NEWS +++ /dev/null @@ -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 --git a/www/plugins-dist/compresseur/lib/csstidy/README.md b/www/plugins-dist/compresseur/lib/csstidy/README.md index 31d06757..3e780f8a 100644 --- a/www/plugins-dist/compresseur/lib/csstidy/README.md +++ b/www/plugins-dist/compresseur/lib/csstidy/README.md @@ -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 @@ here is the import of https://csstidy.svn.sourceforge.net/svnroot/csstidy on 201 Only PHP version is here maintained ---- +## Licence -## CSSTidy + Copyright 2005-2007 Florian Schmitz + Copyright 2010-2019 Cedric Morin -Original Tracker : -http://sourceforge.net/tracker/?group_id=148404&atid=771415 - -css_optimiser.php is the web-interface, css_parser.php contains the PHP class (CSSTidy). - -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 --git a/www/plugins-dist/compresseur/lib/csstidy/class.csstidy.php b/www/plugins-dist/compresseur/lib/csstidy/class.csstidy.php index d29068a0..b09373d4 100644 --- a/www/plugins-dist/compresseur/lib/csstidy/class.csstidy.php +++ b/www/plugins-dist/compresseur/lib/csstidy/class.csstidy.php @@ -32,31 +32,6 @@ * @author Mark Scherer (remove $GLOBALS once and for all + PHP5.4 comp) 2012 */ -/** - * 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 @@ require('class.csstidy_optimise.php'); * 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 @@ class csstidy { * @var string * @access private */ - public $version = '1.6.5'; + public $version = '1.7.3'; /** * Stores the settings * @var array @@ -416,7 +391,17 @@ class csstidy { */ 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 @@ class csstidy { $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 @@ class csstidy { $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 @@ class csstidy { * @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 @@ class csstidy { $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 @@ class csstidy { /* 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 @@ class csstidy { /* 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 @@ class csstidy { $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 @@ class csstidy { /* 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 @@ class csstidy { $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 @@ class csstidy { } 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 @@ class csstidy { $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 @@ class csstidy { $_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 @@ class csstidy { /* 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 @@ class csstidy { } $cur_comment = ''; } else { - $cur_comment .= $string{$i}; + $cur_comment .= $string[$i]; } break; } @@ -1044,7 +1034,7 @@ class csstidy { * @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 @@ class csstidy { } /** - * 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++; @@ -1122,6 +1110,56 @@ class csstidy { return $media; } + /** + * 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, @@ -1255,7 +1293,7 @@ class csstidy { /** * Checks if a property is valid * @param string $property - * @return bool; + * @return bool * @access public * @version 1.0 */ @@ -1279,7 +1317,6 @@ class csstidy { * @param string * @return array */ - public function parse_string_list($value) { $value = trim($value); @@ -1292,26 +1329,26 @@ class csstidy { $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 --git a/www/plugins-dist/compresseur/lib/csstidy/class.csstidy_optimise.php b/www/plugins-dist/compresseur/lib/csstidy/class.csstidy_optimise.php index 49724369..e4971f6e 100644 --- a/www/plugins-dist/compresseur/lib/csstidy/class.csstidy_optimise.php +++ b/www/plugins-dist/compresseur/lib/csstidy/class.csstidy_optimise.php @@ -358,8 +358,8 @@ class csstidy_optimise { // #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 @@ class csstidy_optimise { */ 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 @@ class csstidy_optimise { 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 @@ class csstidy_optimise { $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 @@ class csstidy_optimise { } 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 @@ class csstidy_optimise { // 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 @@ class csstidy_optimise { $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 @@ class csstidy_optimise { 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 --git a/www/plugins-dist/compresseur/lib/csstidy/class.csstidy_print.php b/www/plugins-dist/compresseur/lib/csstidy/class.csstidy_print.php index f4ea07c7..e5011074 100644 --- a/www/plugins-dist/compresseur/lib/csstidy/class.csstidy_print.php +++ b/www/plugins-dist/compresseur/lib/csstidy/class.csstidy_print.php @@ -219,20 +219,25 @@ class csstidy_print { $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 @@ class csstidy_print { 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 @@ class csstidy_print { 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 @@ class csstidy_print { 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 --git a/www/plugins-dist/compresseur/lib/csstidy/data.inc.php b/www/plugins-dist/compresseur/lib/csstidy/data.inc.php index 5bbc2ae5..63eeae8c 100644 --- a/www/plugins-dist/compresseur/lib/csstidy/data.inc.php +++ b/www/plugins-dist/compresseur/lib/csstidy/data.inc.php @@ -55,7 +55,7 @@ $data['csstidy']['units'] = array('in','cm','mm','pt','pc','px','rem','em','%',' * @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 @@ $data['csstidy']['multiple_properties'] = array('background', 'background-image' * @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 --git a/www/plugins-dist/compresseur/paquet.xml b/www/plugins-dist/compresseur/paquet.xml index 151e8e9b..36eea2e1 100644 --- a/www/plugins-dist/compresseur/paquet.xml +++ b/www/plugins-dist/compresseur/paquet.xml @@ -12,6 +12,8 @@ Collectif SPIP + Cerdic/CSSTidy + GPL @@ -24,4 +26,6 @@ + +
diff --git a/www/plugins-dist/medias/action/editer_document.php b/www/plugins-dist/medias/action/editer_document.php index e39986c2..fd1f7589 100644 --- a/www/plugins-dist/medias/action/editer_document.php +++ b/www/plugins-dist/medias/action/editer_document.php @@ -233,7 +233,7 @@ function document_instituer($id_document, $champs = array()) { } sql_updateq('spip_documents', $champs, 'id_document=' . intval($id_document)); - if ($statut !== $statut_ancien) { + if (!empty($champs['statut'])) { $publier_rubriques = sql_allfetsel( 'id_objet', 'spip_documents_liens', @@ -242,7 +242,7 @@ function document_instituer($id_document, $champs = array()) { 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); + calculer_rubriques_if($r['id_objet'], array('statut' => $champs['statut']), $statut_ancien, false); } } } diff --git a/www/plugins-dist/medias/lib/getid3/extension.cache.dbm.php b/www/plugins-dist/medias/lib/getid3/extension.cache.dbm.php index 2d72d955..010af103 100644 --- a/www/plugins-dist/medias/lib/getid3/extension.cache.dbm.php +++ b/www/plugins-dist/medias/lib/getid3/extension.cache.dbm.php @@ -215,13 +215,14 @@ class getID3_cached_dbm extends getID3 /** * clear cache * - * @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) { if (file_exists($filename)) { @@ -238,7 +239,7 @@ class getID3_cached_dbm extends getID3 } // Miss - $result = parent::analyze($filename); + $result = parent::analyze($filename, $filesize, $original_filename, $fp); // Save result if (isset($key) && file_exists($filename)) { diff --git a/www/plugins-dist/medias/lib/getid3/extension.cache.mysql.php b/www/plugins-dist/medias/lib/getid3/extension.cache.mysql.php index 2dd2b12a..6444bcd1 100644 --- a/www/plugins-dist/medias/lib/getid3/extension.cache.mysql.php +++ b/www/plugins-dist/medias/lib/getid3/extension.cache.mysql.php @@ -159,15 +159,16 @@ class getID3_cached_mysql extends getID3 /** * 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 @@ class getID3_cached_mysql extends getID3 } // Miss - $analysis = parent::analyze($filename, $filesize, $original_filename); + $analysis = parent::analyze($filename, $filesize, $original_filename, $fp); // Save result if (file_exists($filename)) { diff --git a/www/plugins-dist/medias/lib/getid3/extension.cache.mysqli.php b/www/plugins-dist/medias/lib/getid3/extension.cache.mysqli.php index 44ea694e..cee2c53d 100644 --- a/www/plugins-dist/medias/lib/getid3/extension.cache.mysqli.php +++ b/www/plugins-dist/medias/lib/getid3/extension.cache.mysqli.php @@ -87,6 +87,11 @@ class getID3_cached_mysqli extends getID3 */ private $table; + /** + * @var bool + */ + private $db_structure_check; + /** * constructor - see top of this file for cache type and cache_options @@ -109,8 +114,8 @@ class getID3_cached_mysqli extends getID3 // Connect to database $this->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 @@ class getID3_cached_mysqli extends getID3 // 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 @@ class getID3_cached_mysqli extends getID3 * 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 @@ class getID3_cached_mysqli extends getID3 // 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 @@ class getID3_cached_mysqli extends getID3 } // 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 @@ class getID3_cached_mysqli extends getID3 * @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 --git a/www/plugins-dist/medias/lib/getid3/extension.cache.sqlite3.php b/www/plugins-dist/medias/lib/getid3/extension.cache.sqlite3.php index 9e4a8436..dbcc72aa 100644 --- a/www/plugins-dist/medias/lib/getid3/extension.cache.sqlite3.php +++ b/www/plugins-dist/medias/lib/getid3/extension.cache.sqlite3.php @@ -172,13 +172,14 @@ class getID3_cached_sqlite3 extends getID3 /** * 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 @@ class getID3_cached_sqlite3 extends getID3 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 @@ class getID3_cached_sqlite3 extends getID3 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 --git a/www/plugins-dist/medias/lib/getid3/getid3.lib.php b/www/plugins-dist/medias/lib/getid3/getid3.lib.php index 5c5a5dfa..916c4305 100644 --- a/www/plugins-dist/medias/lib/getid3/getid3.lib.php +++ b/www/plugins-dist/medias/lib/getid3/getid3.lib.php @@ -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 @@ class getid3_lib $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 @@ class getid3_lib 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 @@ class getid3_lib $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 @@ class getid3_lib default: return false; - break; } if ($floatvalue >= 0) { $signbit = '0'; @@ -255,7 +254,7 @@ class getid3_lib if (!$bitword) { return 0; } - $signbit = $bitword{0}; + $signbit = $bitword[0]; $floatvalue = 0; $exponentbits = 0; $fractionbits = 0; @@ -275,7 +274,7 @@ class getid3_lib // 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 @@ class getid3_lib $floatvalue *= -1; } return $floatvalue; - break; default: return false; - break; } $exponentstring = substr($bitword, 1, $exponentbits); $fractionstring = substr($bitword, $exponentbits + 1, $fractionbits); @@ -343,9 +340,9 @@ class getid3_lib 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 @@ class getid3_lib $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 @@ class getid3_lib 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 @@ class getid3_lib } /** - * @param array $array1 - * @param array $array2 + * @param mixed $array1 + * @param mixed $array2 * * @return array|false */ @@ -523,8 +520,8 @@ class getid3_lib } /** - * @param array $array1 - * @param array $array2 + * @param mixed $array1 + * @param mixed $array2 * * @return array|false */ @@ -544,8 +541,8 @@ class getid3_lib } /** - * @param array $array1 - * @param array $array2 + * @param mixed $array1 + * @param mixed $array2 * * @return array|false|null */ @@ -684,10 +681,10 @@ class getid3_lib */ 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 @@ class getid3_lib */ 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 @@ class getid3_lib } /** - * @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 @@ class getid3_lib } /** - * 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 @@ class getid3_lib * @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; + $size = $end - $offset; - } - 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); + $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); - 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; - } - - // 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 @@ class getid3_lib * * @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 @@ class getid3_lib $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 @@ class getid3_lib $newcharstring .= "\xFE\xFF"; } for ($i = 0; $i < strlen($string); $i++) { - $newcharstring .= "\x00".$string{$i}; + $newcharstring .= "\x00".$string[$i]; } return $newcharstring; } @@ -974,7 +904,7 @@ class getid3_lib $newcharstring .= "\xFF\xFE"; } for ($i = 0; $i < strlen($string); $i++) { - $newcharstring .= $string{$i}."\x00"; + $newcharstring .= $string[$i]."\x00"; } return $newcharstring; } @@ -1006,27 +936,27 @@ class getid3_lib $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 @@ class getid3_lib $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 @@ class getid3_lib $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 @@ class getid3_lib // 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 @@ class getid3_lib 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 @@ class getid3_lib 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 @@ class getid3_lib * @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 @@ class getid3_lib // 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 @@ class getid3_lib /** * @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 @@ class getid3_lib 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 @@ class getid3_lib $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 @@ class getid3_lib 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 @@ class getid3_lib } } - // 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 --git a/www/plugins-dist/medias/lib/getid3/getid3.php b/www/plugins-dist/medias/lib/getid3/getid3.php index 90d7c9c2..bce97fb7 100644 --- a/www/plugins-dist/medias/lib/getid3/getid3.php +++ b/www/plugins-dist/medias/lib/getid3/getid3.php @@ -1,5 +1,4 @@ // // available at https://github.com/JamesHeinrich/getID3 // @@ -100,6 +99,13 @@ class getID3 */ 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 @@ class getID3 */ 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 @@ class getID3 } // 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 @@ class getID3 $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 @@ class getID3 // 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 @@ class getID3 } /** - * @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 @@ class getID3 // 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 @@ class getID3 /** * 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 @@ class getID3 $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 @@ class getID3 // 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 @@ class getID3 '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 @@ class getID3 '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 @@ class getID3 '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 @@ class getID3 '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 @@ class getID3 '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 @@ class getID3 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 @@ class getID3 '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 @@ class getID3 } } 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 @@ class getID3 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 @@ class getID3 } - // 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) { @@ -1495,6 +1567,17 @@ class getID3 return true; } + /** + * 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 * @@ -1508,7 +1591,6 @@ class getID3 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 @@ class getID3 * * @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 @@ abstract class getid3_handler */ $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); @@ -2025,6 +2106,61 @@ abstract class getid3_handler return fseek($this->getid3->fp, $bytes, $whence); } + /** + * @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 */ diff --git a/www/plugins-dist/medias/lib/getid3/module.archive.gzip.php b/www/plugins-dist/medias/lib/getid3/module.archive.gzip.php index 5d730be8..18d49f38 100644 --- a/www/plugins-dist/medias/lib/getid3/module.archive.gzip.php +++ b/www/plugins-dist/medias/lib/getid3/module.archive.gzip.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.archive.rar.php b/www/plugins-dist/medias/lib/getid3/module.archive.rar.php index c8f26788..4d40160d 100644 --- a/www/plugins-dist/medias/lib/getid3/module.archive.rar.php +++ b/www/plugins-dist/medias/lib/getid3/module.archive.rar.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.archive.szip.php b/www/plugins-dist/medias/lib/getid3/module.archive.szip.php index 5b0601b4..8647967c 100644 --- a/www/plugins-dist/medias/lib/getid3/module.archive.szip.php +++ b/www/plugins-dist/medias/lib/getid3/module.archive.szip.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.archive.tar.php b/www/plugins-dist/medias/lib/getid3/module.archive.tar.php index 952a626e..5b4aa566 100644 --- a/www/plugins-dist/medias/lib/getid3/module.archive.tar.php +++ b/www/plugins-dist/medias/lib/getid3/module.archive.tar.php @@ -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 @@ class getid3_tar extends getid3_handler // 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 --git a/www/plugins-dist/medias/lib/getid3/module.archive.zip.php b/www/plugins-dist/medias/lib/getid3/module.archive.zip.php index 7cb8719d..1ce3fb75 100644 --- a/www/plugins-dist/medias/lib/getid3/module.archive.zip.php +++ b/www/plugins-dist/medias/lib/getid3/module.archive.zip.php @@ -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 @@ class getid3_zip extends getid3_handler } } + // 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 --git a/www/plugins-dist/medias/lib/getid3/module.audio-video.asf.php b/www/plugins-dist/medias/lib/getid3/module.audio-video.asf.php index d42607e0..fce923c0 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio-video.asf.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio-video.asf.php @@ -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 @@ class getid3_asf extends getid3_handler $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 @@ class getid3_asf extends getid3_handler 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 @@ class getid3_asf extends getid3_handler * @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 --git a/www/plugins-dist/medias/lib/getid3/module.audio-video.bink.php b/www/plugins-dist/medias/lib/getid3/module.audio-video.bink.php index bd38e339..b59ec674 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio-video.bink.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio-video.bink.php @@ -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 @@ class getid3_bink extends getid3_handler 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 --git a/www/plugins-dist/medias/lib/getid3/module.audio-video.flv.php b/www/plugins-dist/medias/lib/getid3/module.audio-video.flv.php index eb292c61..7e684072 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio-video.flv.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio-video.flv.php @@ -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 @@ class AMFReader // null case 6: return null; - break; // Mixed array case 8: diff --git a/www/plugins-dist/medias/lib/getid3/module.audio-video.matroska.php b/www/plugins-dist/medias/lib/getid3/module.audio-video.matroska.php index b2b187b6..a2851085 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio-video.matroska.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio-video.matroska.php @@ -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 @@ class getid3_matroska extends getid3_handler break;*/ } - $info['video']['streams'][] = $track_info; + $info['video']['streams'][$trackarray['TrackUID']] = $track_info; break; case 2: // Audio @@ -342,7 +345,7 @@ class getid3_matroska extends getid3_handler 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 @@ class getid3_matroska extends getid3_handler // 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 @@ class getid3_matroska extends getid3_handler break; } - $info['audio']['streams'][] = $track_info; + $info['audio']['streams'][$trackarray['TrackUID']] = $track_info; break; } } @@ -509,6 +512,30 @@ class getid3_matroska extends getid3_handler 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 @@ class getid3_matroska extends getid3_handler 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 @@ class getid3_matroska extends getid3_handler 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 --git a/www/plugins-dist/medias/lib/getid3/module.audio-video.mpeg.php b/www/plugins-dist/medias/lib/getid3/module.audio-video.mpeg.php index f27cd4b3..5ca4120b 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio-video.mpeg.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio-video.mpeg.php @@ -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 @@ class getid3_mpeg extends getid3_handler 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 @@ $PackedElementaryStream['additional_header_bytes'] = $additional_header_bytes; $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 @@ echo 'average_File_bitrate = '.number_format(array_sum($vbr_bitrates) / count($v * @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 @@ echo 'average_File_bitrate = '.number_format(array_sum($vbr_bitrates) / count($v /** * @param int $rawaspectratio - * @param int $mpeg_version + * @param int $mpeg_version * * @return string */ diff --git a/www/plugins-dist/medias/lib/getid3/module.audio-video.nsv.php b/www/plugins-dist/medias/lib/getid3/module.audio-video.nsv.php index 68a2ca1b..043cdfc6 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio-video.nsv.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio-video.nsv.php @@ -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 @@ class getid3_nsv extends getid3_handler 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 --git a/www/plugins-dist/medias/lib/getid3/module.audio-video.quicktime.php b/www/plugins-dist/medias/lib/getid3/module.audio-video.quicktime.php index 5c791e32..c176e5a0 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio-video.quicktime.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio-video.quicktime.php @@ -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 @@ class getid3_quicktime extends getid3_handler $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 @@ class getid3_quicktime extends getid3_handler $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 @@ class getid3_quicktime extends getid3_handler 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 @@ class getid3_quicktime extends getid3_handler $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 @@ class getid3_quicktime extends getid3_handler 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 @@ class getid3_quicktime extends getid3_handler } 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 @@ class getid3_quicktime extends getid3_handler } 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 @@ class getid3_quicktime extends getid3_handler } } } - $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 @@ class getid3_quicktime extends getid3_handler $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 @@ class getid3_quicktime extends getid3_handler 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 @@ class getid3_quicktime extends getid3_handler $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 @@ class getid3_quicktime extends getid3_handler 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 @@ class getid3_quicktime extends getid3_handler $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 @@ class getid3_quicktime extends getid3_handler } $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 @@ class getid3_quicktime extends getid3_handler $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 @@ class getid3_quicktime extends getid3_handler $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 @@ class getid3_quicktime extends getid3_handler } 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 @@ class getid3_quicktime extends getid3_handler // $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 @@ class getid3_quicktime extends getid3_handler $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 @@ class getid3_quicktime extends getid3_handler 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 @@ class getid3_quicktime extends getid3_handler } 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 @@ class getid3_quicktime extends getid3_handler $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 @@ class getid3_quicktime extends getid3_handler } 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 @@ class getid3_quicktime extends getid3_handler $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 @@ class getid3_quicktime extends getid3_handler * * @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 @@ class getid3_quicktime extends getid3_handler 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 --git a/www/plugins-dist/medias/lib/getid3/module.audio-video.real.php b/www/plugins-dist/medias/lib/getid3/module.audio-video.real.php index f5d2ce7f..990379e9 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio-video.real.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio-video.real.php @@ -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 @@ class getid3_real extends getid3_handler $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 --git a/www/plugins-dist/medias/lib/getid3/module.audio-video.riff.php b/www/plugins-dist/medias/lib/getid3/module.audio-video.riff.php index 8992ad7c..cdf55338 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio-video.riff.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio-video.riff.php @@ -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 @@ class getid3_riff extends getid3_handler $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 @@ class getid3_riff extends getid3_handler 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 @@ class getid3_riff extends getid3_handler '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 @@ class getid3_riff extends getid3_handler // 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 @@ class getid3_riff extends getid3_handler $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 @@ class getid3_riff extends getid3_handler } break; - // http://en.wikipedia.org/wiki/AIFF + // http://en.wikipedia.org/wiki/AIFF case 'AIFF': case 'AIFC': $info['fileformat'] = 'aiff'; @@ -1066,7 +1069,7 @@ class getid3_riff extends getid3_handler 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 @@ class getid3_riff extends getid3_handler 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 @@ class getid3_riff extends getid3_handler 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 @@ class getid3_riff extends getid3_handler // 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 @@ class getid3_riff extends getid3_handler // 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 @@ class getid3_riff extends getid3_handler // 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 @@ class getid3_riff extends getid3_handler // 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 @@ class getid3_riff extends getid3_handler // 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 @@ class getid3_riff extends getid3_handler // $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 --git a/www/plugins-dist/medias/lib/getid3/module.audio-video.swf.php b/www/plugins-dist/medias/lib/getid3/module.audio-video.swf.php index e1151f31..fc4a5c52 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio-video.swf.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio-video.swf.php @@ -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 @@ class getid3_swf extends getid3_handler 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 --git a/www/plugins-dist/medias/lib/getid3/module.audio-video.ts.php b/www/plugins-dist/medias/lib/getid3/module.audio-video.ts.php index 24679bc7..474503a2 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio-video.ts.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio-video.ts.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.aa.php b/www/plugins-dist/medias/lib/getid3/module.audio.aa.php index 1eec54e2..171e72d1 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.aa.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.aa.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.aac.php b/www/plugins-dist/medias/lib/getid3/module.audio.aac.php index 846850cf..d4f04b85 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.aac.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.aac.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.ac3.php b/www/plugins-dist/medias/lib/getid3/module.audio.ac3.php index d4e4e4ba..636ff8f1 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.ac3.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.ac3.php @@ -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 @@ class getid3_ac3 extends getid3_handler } 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 @@ class getid3_ac3 extends getid3_handler /** * @param int $length * - * @return float|int + * @return int */ private function readHeaderBSI($length) { $data = substr($this->AC3header['bsi'], $this->BSIoffset, $length); @@ -687,7 +690,7 @@ class getid3_ac3 extends getid3_handler // -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 @@ class getid3_ac3 extends getid3_handler 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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.amr.php b/www/plugins-dist/medias/lib/getid3/module.audio.amr.php index 42ebd149..e2e45316 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.amr.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.amr.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.au.php b/www/plugins-dist/medias/lib/getid3/module.audio.au.php index a99d05d7..73df1031 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.au.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.au.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.avr.php b/www/plugins-dist/medias/lib/getid3/module.audio.avr.php index 50e29940..69a26056 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.avr.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.avr.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.bonk.php b/www/plugins-dist/medias/lib/getid3/module.audio.bonk.php index 53983914..c6cf9ac7 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.bonk.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.bonk.php @@ -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 @@ class getid3_bonk extends getid3_handler $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 @@ class getid3_bonk extends getid3_handler // 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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.dsf.php b/www/plugins-dist/medias/lib/getid3/module.audio.dsf.php index bbcee761..cd059c92 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.dsf.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.dsf.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.dss.php b/www/plugins-dist/medias/lib/getid3/module.audio.dss.php index 492393a8..dd2a56b1 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.dss.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.dss.php @@ -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 @@ class getid3_dss extends getid3_handler $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 @@ class getid3_dss extends getid3_handler // 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 @@ class getid3_dss extends getid3_handler * @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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.dts.php b/www/plugins-dist/medias/lib/getid3/module.audio.dts.php index 2dd44e9e..ff1a88fc 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.dts.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.dts.php @@ -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 @@ class getid3_dts extends getid3_handler // 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 @@ class getid3_dts extends getid3_handler * @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 @@ class getid3_dts extends getid3_handler 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 @@ class getid3_dts extends getid3_handler switch ($version) { case 7: return 0 - $index; - break; case 6: return 0 - 16 - $index; - break; } return false; } diff --git a/www/plugins-dist/medias/lib/getid3/module.audio.flac.php b/www/plugins-dist/medias/lib/getid3/module.audio.flac.php index 4edf587d..1cea4364 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.flac.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.flac.php @@ -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 @@ class getid3_flac extends getid3_handler 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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.la.php b/www/plugins-dist/medias/lib/getid3/module.audio.la.php index 3fee9d39..27a46793 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.la.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.la.php @@ -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 @@ class getid3_la extends getid3_handler $this->error('Not a LA (Lossless-Audio) file'); } return false; - break; } $info['audio']['channels'] = $info['la']['channels']; diff --git a/www/plugins-dist/medias/lib/getid3/module.audio.lpac.php b/www/plugins-dist/medias/lib/getid3/module.audio.lpac.php index 375ba206..f49e2440 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.lpac.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.lpac.php @@ -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 @@ class getid3_lpac extends getid3_handler } $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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.midi.php b/www/plugins-dist/medias/lib/getid3/module.audio.midi.php index 770481c6..eaef9cba 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.midi.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.midi.php @@ -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 @@ class getid3_midi extends getid3_handler 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 @@ class getid3_midi extends getid3_handler 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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.mod.php b/www/plugins-dist/medias/lib/getid3/module.audio.mod.php index 708d213b..bf8be33e 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.mod.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.mod.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.monkey.php b/www/plugins-dist/medias/lib/getid3/module.audio.monkey.php index 3317a93e..beaca8c1 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.monkey.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.monkey.php @@ -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 @@ class getid3_monkey extends getid3_handler $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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.mp3.php b/www/plugins-dist/medias/lib/getid3/module.audio.mp3.php index 44343804..26b28068 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.mp3.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.mp3.php @@ -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 @@ class getid3_mp3 extends getid3_handler 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 @@ class getid3_mp3 extends getid3_handler $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 @@ class getid3_mp3 extends getid3_handler $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 @@ class getid3_mp3 extends getid3_handler 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 @@ class getid3_mp3 extends getid3_handler $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 @@ class getid3_mp3 extends getid3_handler 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 @@ class getid3_mp3 extends getid3_handler 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 @@ class getid3_mp3 extends getid3_handler 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 @@ class getid3_mp3 extends getid3_handler $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 @@ class getid3_mp3 extends getid3_handler * @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 @@ class getid3_mp3 extends getid3_handler } $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 @@ class getid3_mp3 extends getid3_handler 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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.mpc.php b/www/plugins-dist/medias/lib/getid3/module.audio.mpc.php index 6d7c8512..4f6f5c89 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.mpc.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.mpc.php @@ -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 @@ class getid3_mpc extends getid3_handler 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 @@ class getid3_mpc extends getid3_handler $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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.ogg.php b/www/plugins-dist/medias/lib/getid3/module.audio.ogg.php index 51fee3e1..fe092d9d 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.ogg.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.ogg.php @@ -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 @@ class getid3_ogg extends getid3_handler default: return false; - break; } $VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4)); diff --git a/www/plugins-dist/medias/lib/getid3/module.audio.optimfrog.php b/www/plugins-dist/medias/lib/getid3/module.audio.optimfrog.php index 1c122305..7e888ccd 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.optimfrog.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.optimfrog.php @@ -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 @@ class getid3_optimfrog extends getid3_handler $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 @@ class getid3_optimfrog extends getid3_handler $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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.rkau.php b/www/plugins-dist/medias/lib/getid3/module.audio.rkau.php index 7e1c8107..8bbacd43 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.rkau.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.rkau.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.shorten.php b/www/plugins-dist/medias/lib/getid3/module.audio.shorten.php index f5e2a57d..533208fa 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.shorten.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.shorten.php @@ -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 @@ class getid3_shorten extends getid3_handler 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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.tta.php b/www/plugins-dist/medias/lib/getid3/module.audio.tta.php index 13d8fe2c..700cd05a 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.tta.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.tta.php @@ -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 @@ class getid3_tta extends getid3_handler 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 @@ class getid3_tta extends getid3_handler $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 @@ class getid3_tta extends getid3_handler 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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.voc.php b/www/plugins-dist/medias/lib/getid3/module.audio.voc.php index 44831581..f765719e 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.voc.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.voc.php @@ -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 @@ class getid3_voc extends getid3_handler $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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.vqf.php b/www/plugins-dist/medias/lib/getid3/module.audio.vqf.php index 9ab821e2..55c7881d 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.vqf.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.vqf.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.audio.wavpack.php b/www/plugins-dist/medias/lib/getid3/module.audio.wavpack.php index a6e57fd9..acb0d3ee 100644 --- a/www/plugins-dist/medias/lib/getid3/module.audio.wavpack.php +++ b/www/plugins-dist/medias/lib/getid3/module.audio.wavpack.php @@ -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 @@ class getid3_wavpack extends getid3_handler 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 @@ class getid3_wavpack extends getid3_handler 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 @@ class getid3_wavpack extends getid3_handler 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 @@ class getid3_wavpack extends getid3_handler } $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 @@ class getid3_wavpack extends getid3_handler $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 @@ class getid3_wavpack extends getid3_handler $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 --git a/www/plugins-dist/medias/lib/getid3/module.graphic.bmp.php b/www/plugins-dist/medias/lib/getid3/module.graphic.bmp.php index dc7b30d7..276688d4 100644 --- a/www/plugins-dist/medias/lib/getid3/module.graphic.bmp.php +++ b/www/plugins-dist/medias/lib/getid3/module.graphic.bmp.php @@ -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 @@ class getid3_bmp extends getid3_handler 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 @@ class getid3_bmp extends getid3_handler 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 @@ class getid3_bmp extends getid3_handler 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 @@ class getid3_bmp extends getid3_handler 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 @@ class getid3_bmp extends getid3_handler 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 --git a/www/plugins-dist/medias/lib/getid3/module.graphic.efax.php b/www/plugins-dist/medias/lib/getid3/module.graphic.efax.php index 426ef3e6..82ea3544 100644 --- a/www/plugins-dist/medias/lib/getid3/module.graphic.efax.php +++ b/www/plugins-dist/medias/lib/getid3/module.graphic.efax.php @@ -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 @@ class getid3_efax extends getid3_handler $this->error('eFax parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); return false; - - return true; } } diff --git a/www/plugins-dist/medias/lib/getid3/module.graphic.gif.php b/www/plugins-dist/medias/lib/getid3/module.graphic.gif.php index 4fb1247a..0e463c8c 100644 --- a/www/plugins-dist/medias/lib/getid3/module.graphic.gif.php +++ b/www/plugins-dist/medias/lib/getid3/module.graphic.gif.php @@ -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 @@ class getid3_gif extends getid3_handler 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 @@ class getid3_gif extends getid3_handler 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 @@ class getid3_gif extends getid3_handler } } - $info['gif']['extension_blocks'][] = $ExtensionBlock; + if ($this->getid3->option_extra_info) { + $info['gif']['extension_blocks'][] = $ExtensionBlock; + } break; case ';': diff --git a/www/plugins-dist/medias/lib/getid3/module.graphic.jpg.php b/www/plugins-dist/medias/lib/getid3/module.graphic.jpg.php index 3c874f32..5079119d 100644 --- a/www/plugins-dist/medias/lib/getid3/module.graphic.jpg.php +++ b/www/plugins-dist/medias/lib/getid3/module.graphic.jpg.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.graphic.pcd.php b/www/plugins-dist/medias/lib/getid3/module.graphic.pcd.php index 88244796..85fb4c96 100644 --- a/www/plugins-dist/medias/lib/getid3/module.graphic.pcd.php +++ b/www/plugins-dist/medias/lib/getid3/module.graphic.pcd.php @@ -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 @@ class getid3_pcd extends getid3_handler 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 @@ class getid3_pcd extends getid3_handler 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 @@ class getid3_pcd extends getid3_handler } + return false; } /** diff --git a/www/plugins-dist/medias/lib/getid3/module.graphic.png.php b/www/plugins-dist/medias/lib/getid3/module.graphic.png.php index a9827f2d..018062c3 100644 --- a/www/plugins-dist/medias/lib/getid3/module.graphic.png.php +++ b/www/plugins-dist/medias/lib/getid3/module.graphic.png.php @@ -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 @@ class getid3_png extends getid3_handler 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 --git a/www/plugins-dist/medias/lib/getid3/module.graphic.svg.php b/www/plugins-dist/medias/lib/getid3/module.graphic.svg.php index 73b9d843..8bb577b9 100644 --- a/www/plugins-dist/medias/lib/getid3/module.graphic.svg.php +++ b/www/plugins-dist/medias/lib/getid3/module.graphic.svg.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.graphic.tiff.php b/www/plugins-dist/medias/lib/getid3/module.graphic.tiff.php index 57d500f5..5d404947 100644 --- a/www/plugins-dist/medias/lib/getid3/module.graphic.tiff.php +++ b/www/plugins-dist/medias/lib/getid3/module.graphic.tiff.php @@ -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 @@ class getid3_tiff extends getid3_handler 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 @@ class getid3_tiff extends getid3_handler $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 @@ class getid3_tiff extends getid3_handler } 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 @@ class getid3_tiff extends getid3_handler * @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 --git a/www/plugins-dist/medias/lib/getid3/module.misc.cue.php b/www/plugins-dist/medias/lib/getid3/module.misc.cue.php index 4602cdec..a66e2eb2 100644 --- a/www/plugins-dist/medias/lib/getid3/module.misc.cue.php +++ b/www/plugins-dist/medias/lib/getid3/module.misc.cue.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.misc.exe.php b/www/plugins-dist/medias/lib/getid3/module.misc.exe.php index 57bea051..9064fed8 100644 --- a/www/plugins-dist/medias/lib/getid3/module.misc.exe.php +++ b/www/plugins-dist/medias/lib/getid3/module.misc.exe.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.misc.iso.php b/www/plugins-dist/medias/lib/getid3/module.misc.iso.php index 231a32a2..efca73aa 100644 --- a/www/plugins-dist/medias/lib/getid3/module.misc.iso.php +++ b/www/plugins-dist/medias/lib/getid3/module.misc.iso.php @@ -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 @@ class getid3_iso extends getid3_handler $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 @@ class getid3_iso extends getid3_handler $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 @@ class getid3_iso extends getid3_handler // 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 --git a/www/plugins-dist/medias/lib/getid3/module.misc.msoffice.php b/www/plugins-dist/medias/lib/getid3/module.misc.msoffice.php index 9a60aa08..56d07f0e 100644 --- a/www/plugins-dist/medias/lib/getid3/module.misc.msoffice.php +++ b/www/plugins-dist/medias/lib/getid3/module.misc.msoffice.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.misc.par2.php b/www/plugins-dist/medias/lib/getid3/module.misc.par2.php index f5da1937..b6c493ba 100644 --- a/www/plugins-dist/medias/lib/getid3/module.misc.par2.php +++ b/www/plugins-dist/medias/lib/getid3/module.misc.par2.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/module.misc.pdf.php b/www/plugins-dist/medias/lib/getid3/module.misc.pdf.php index c6896a69..1aca6ae3 100644 --- a/www/plugins-dist/medias/lib/getid3/module.misc.pdf.php +++ b/www/plugins-dist/medias/lib/getid3/module.misc.pdf.php @@ -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->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->error('PDF parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); + $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 --git a/www/plugins-dist/medias/lib/getid3/module.tag.apetag.php b/www/plugins-dist/medias/lib/getid3/module.tag.apetag.php index 37971a6b..26be982c 100644 --- a/www/plugins-dist/medias/lib/getid3/module.tag.apetag.php +++ b/www/plugins-dist/medias/lib/getid3/module.tag.apetag.php @@ -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 @@ class getid3_apetag extends getid3_handler 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 @@ class getid3_apetag extends getid3_handler 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 @@ class getid3_apetag extends getid3_handler 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 @@ class getid3_apetag extends getid3_handler 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 @@ class getid3_apetag extends getid3_handler 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 --git a/www/plugins-dist/medias/lib/getid3/module.tag.id3v1.php b/www/plugins-dist/medias/lib/getid3/module.tag.id3v1.php index cafc3fba..16dcf253 100644 --- a/www/plugins-dist/medias/lib/getid3/module.tag.id3v1.php +++ b/www/plugins-dist/medias/lib/getid3/module.tag.id3v1.php @@ -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 @@ class getid3_id3v1 extends getid3_handler // 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 @@ class getid3_id3v1 extends getid3_handler 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 @@ class getid3_id3v1 extends getid3_handler $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 --git a/www/plugins-dist/medias/lib/getid3/module.tag.id3v2.php b/www/plugins-dist/medias/lib/getid3/module.tag.id3v2.php index c51dedb8..85dd7a14 100644 --- a/www/plugins-dist/medias/lib/getid3/module.tag.id3v2.php +++ b/www/plugins-dist/medias/lib/getid3/module.tag.id3v2.php @@ -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 @@ class getid3_id3v2 extends getid3_handler $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 @@ class getid3_id3v2 extends getid3_handler } - $id3_flags = ord($header{5}); + $id3_flags = ord($header[5]); switch ($id3v2_majorversion) { case 2: // %ab000000 in v2.2 @@ -260,7 +263,7 @@ class getid3_id3v2 extends getid3_handler $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 @@ class getid3_id3v2 extends getid3_handler $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 @@ class getid3_id3v2 extends getid3_handler $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 @@ class getid3_id3v2 extends getid3_handler 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 @@ class getid3_id3v2 extends getid3_handler 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 @@ class getid3_id3v2 extends getid3_handler 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 @@ class getid3_id3v2 extends getid3_handler //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 @@ class getid3_id3v2 extends getid3_handler } $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 @@ class getid3_id3v2 extends getid3_handler 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 @@ class getid3_id3v2 extends getid3_handler $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 @@ class getid3_id3v2 extends getid3_handler 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 @@ class getid3_id3v2 extends getid3_handler 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 @@ class getid3_id3v2 extends getid3_handler 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 @@ class getid3_id3v2 extends getid3_handler $parsedFrame['mime'] = $frame_mimetype; $parsedFrame['filename'] = $frame_filename; - $parsedFrame['description'] = $frame_description; unset($parsedFrame['data']); @@ -1633,16 +1609,12 @@ class getid3_id3v2 extends getid3_handler $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 @@ class getid3_id3v2 extends getid3_handler $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 @@ class getid3_id3v2 extends getid3_handler $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 @@ class getid3_id3v2 extends getid3_handler 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 @@ class getid3_id3v2 extends getid3_handler $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 @@ class getid3_id3v2 extends getid3_handler // 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 @@ class getid3_id3v2 extends getid3_handler $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 @@ class getid3_id3v2 extends getid3_handler 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 @@ class getid3_id3v2 extends getid3_handler // 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); @@ -3695,6 +3694,35 @@ class getid3_id3v2 extends getid3_handler return (isset($TextEncodingNameLookup[$encoding]) ? $TextEncodingNameLookup[$encoding] : 'ISO-8859-1'); } + /** + * @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 @@ class getid3_id3v2 extends getid3_handler 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 @@ class getid3_id3v2 extends getid3_handler */ 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 --git a/www/plugins-dist/medias/lib/getid3/module.tag.lyrics3.php b/www/plugins-dist/medias/lib/getid3/module.tag.lyrics3.php index 80e81658..b2375057 100644 --- a/www/plugins-dist/medias/lib/getid3/module.tag.lyrics3.php +++ b/www/plugins-dist/medias/lib/getid3/module.tag.lyrics3.php @@ -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 @@ class getid3_lyrics3 extends getid3_handler $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 @@ class getid3_lyrics3 extends getid3_handler $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 @@ class getid3_lyrics3 extends getid3_handler default: $this->error('Cannot process Lyrics3 version '.$version.' (only v1 and v2)'); return false; - break; } diff --git a/www/plugins-dist/medias/lib/getid3/module.tag.xmp.php b/www/plugins-dist/medias/lib/getid3/module.tag.xmp.php index a976ef8e..db29601a 100644 --- a/www/plugins-dist/medias/lib/getid3/module.tag.xmp.php +++ b/www/plugins-dist/medias/lib/getid3/module.tag.xmp.php @@ -114,7 +114,7 @@ class Image_XMP $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 @@ class Image_XMP // 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 @@ class Image_XMP // 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 @@ class Image_XMP $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 @@ class Image_XMP { // 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 @@ class Image_XMP 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 @@ class Image_XMP // ignore break; } - } +// } break; } diff --git a/www/plugins-dist/medias/lib/getid3/write.apetag.php b/www/plugins-dist/medias/lib/getid3/write.apetag.php index 7fc507c2..a34beed4 100644 --- a/www/plugins-dist/medias/lib/getid3/write.apetag.php +++ b/www/plugins-dist/medias/lib/getid3/write.apetag.php @@ -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 --git a/www/plugins-dist/medias/lib/getid3/write.id3v1.php b/www/plugins-dist/medias/lib/getid3/write.id3v1.php index 6f84867d..22c46779 100644 --- a/www/plugins-dist/medias/lib/getid3/write.id3v1.php +++ b/www/plugins-dist/medias/lib/getid3/write.id3v1.php @@ -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 @@ class getid3_write_id3v1 } 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 --git a/www/plugins-dist/medias/lib/getid3/write.id3v2.php b/www/plugins-dist/medias/lib/getid3/write.id3v2.php index fae45d29..ae2313ed 100644 --- a/www/plugins-dist/medias/lib/getid3/write.id3v2.php +++ b/www/plugins-dist/medias/lib/getid3/write.id3v2.php @@ -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 @@ class getid3_write_id3v2 public $filename; /** - * @var array + * @var array|null */ public $tag_data; @@ -325,7 +328,6 @@ class getid3_write_id3v2 default: return false; - break; } return chr(bindec($flag)); } @@ -345,7 +347,7 @@ class getid3_write_id3v2 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 @@ class getid3_write_id3v2 default: return false; - break; } return chr(bindec($flag1)).chr(bindec($flag2)); @@ -852,7 +853,7 @@ class getid3_write_id3v2 $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 @@ class getid3_write_id3v2 // 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 @@ class getid3_write_id3v2 $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 @@ class getid3_write_id3v2 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 @@ class getid3_write_id3v2 $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 @@ class getid3_write_id3v2 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 @@ class getid3_write_id3v2 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 @@ class getid3_write_id3v2 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 @@ class getid3_write_id3v2 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 @@ class getid3_write_id3v2 } $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 @@ class getid3_write_id3v2 switch ($framename) { case 'RGAD': return false; - break; default: return false; - break; } } @@ -1958,10 +1960,10 @@ class getid3_write_id3v2 $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 @@ class getid3_write_id3v2 $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 --git a/www/plugins-dist/medias/lib/getid3/write.php b/www/plugins-dist/medias/lib/getid3/write.php index cc98e5d3..73eea6db 100644 --- a/www/plugins-dist/medias/lib/getid3/write.php +++ b/www/plugins-dist/medias/lib/getid3/write.php @@ -205,14 +205,12 @@ class getid3_writetags //$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 @@ class getid3_writetags default: $this->errors[] = 'unknown tag format "'.$tagformat.'" in $tagformats in WriteTags()'; return false; - break; } } @@ -311,9 +308,9 @@ class getid3_writetags } } - // 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 @@ class getid3_writetags default: $this->errors[] = 'Invalid tag format to write: "'.$tagformat.'"'; return false; - break; } if (!$success) { return false; @@ -486,7 +482,6 @@ class getid3_writetags default: $this->errors[] = 'Invalid tag format to delete: "'.$DeleteTagFormat.'"'; return false; - break; } if (!$success) { return false; @@ -508,10 +503,10 @@ class getid3_writetags // 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 @@ class getid3_writetags } } } - $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 @@ class getid3_writetags // 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 @@ class getid3_writetags 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 --git a/www/plugins-dist/medias/lib/mejs/package.js b/www/plugins-dist/medias/lib/mejs/package.js old mode 100644 new mode 100755 diff --git a/www/plugins-dist/medias/lib/mejs/package.json b/www/plugins-dist/medias/lib/mejs/package.json old mode 100644 new mode 100755 diff --git a/www/plugins-dist/medias/paquet.xml b/www/plugins-dist/medias/paquet.xml index 6b09414f..5a184a02 100644 --- a/www/plugins-dist/medias/paquet.xml +++ b/www/plugins-dist/medias/paquet.xml @@ -1,7 +1,7 @@ -

<: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 --git a/www/plugins-dist/organiseur/inc/quete_calendrier.php b/www/plugins-dist/organiseur/inc/quete_calendrier.php index c2b8cf71..1278f3e7 100644 --- a/www/plugins-dist/organiseur/inc/quete_calendrier.php +++ b/www/plugins-dist/organiseur/inc/quete_calendrier.php @@ -345,7 +345,7 @@ function quete_calendrier_interval_rv($avant, $apres) { 'DESCRIPTION' => $row['texte'], 'SUMMARY' => $row['titre'], 'CATEGORIES' => $cat, - 'ATTENDEE' => (count($auteurs) == 0) ? '' : join($auteurs, ', ') + 'ATTENDEE' => (count($auteurs) == 0) ? '' : implode(', ', $auteurs) ); } diff --git a/www/plugins-dist/revisions/inc/diff.php b/www/plugins-dist/revisions/inc/diff.php index 4fbec349..a159525b 100644 --- a/www/plugins-dist/revisions/inc/diff.php +++ b/www/plugins-dist/revisions/inc/diff.php @@ -194,7 +194,9 @@ class Diff { 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 @@ class Diff { $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 @@ class Diff { // 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 @@ class Diff { 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 --git a/www/plugins-dist/revisions/inc/revisions.php b/www/plugins-dist/revisions/inc/revisions.php index cb60ec81..cfe2a64a 100644 --- a/www/plugins-dist/revisions/inc/revisions.php +++ b/www/plugins-dist/revisions/inc/revisions.php @@ -561,8 +561,8 @@ function ajouter_version($id_objet, $objet, $champs, $titre_version = "", $id_au // 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 @@ function ajouter_version($id_objet, $objet, $champs, $titre_version = "", $id_au 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 --git a/www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3.php b/www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3.php index 81028686..2b711481 100644 --- a/www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3.php +++ b/www/plugins-dist/safehtml/lib/safehtml/classes/HTMLSax3.php @@ -68,7 +68,7 @@ class XML_HTMLSax3_StateParser { function scanCharacter() { if ($this->position < $this->length) { - return $this->rawtext{$this->position++}; + return $this->rawtext[$this->position++]; } } @@ -166,7 +166,7 @@ class XML_HTMLSax3_StateParser_Lt430 extends XML_HTMLSax3_StateParser { function scanUntilCharacters($string) { $startpos = $this->position; - while ($this->position < $this->length && strpos($string, $this->rawtext{$this->position}) === FALSE) { + while ($this->position < $this->length && strpos($string, $this->rawtext[$this->position]) === FALSE) { $this->position++; } return substr($this->rawtext, $startpos, $this->position - $startpos); @@ -174,7 +174,7 @@ class XML_HTMLSax3_StateParser_Lt430 extends XML_HTMLSax3_StateParser { function ignoreWhitespace() { while ($this->position < $this->length && - strpos(" \n\r\t", $this->rawtext{$this->position}) !== FALSE) { + strpos(" \n\r\t", $this->rawtext[$this->position]) !== FALSE) { $this->position++; } } diff --git a/www/plugins-dist/safehtml/lib/safehtml/classes/safehtml.php b/www/plugins-dist/safehtml/lib/safehtml/classes/safehtml.php index ca88e8a8..6959b1cd 100644 --- a/www/plugins-dist/safehtml/lib/safehtml/classes/safehtml.php +++ b/www/plugins-dist/safehtml/lib/safehtml/classes/safehtml.php @@ -285,7 +285,7 @@ class SafeHTML foreach ($this->blackProtocols as $proto) { $preg = "/[\s\x01-\x1F]*"; for ($i=0; $iprotoRegexps[] = $preg; diff --git a/www/plugins-dist/svp/inc/svp_outiller.php b/www/plugins-dist/svp/inc/svp_outiller.php index 9f74f5f7..e3185d93 100644 --- a/www/plugins-dist/svp/inc/svp_outiller.php +++ b/www/plugins-dist/svp/inc/svp_outiller.php @@ -196,7 +196,7 @@ function extraire_bornes($intervalle, $initialiser = false) { ) { if ($matches[1]) { $bornes['min']['valeur'] = trim($matches[1]); - $bornes['min']['incluse'] = ($intervalle{0} == "["); + $bornes['min']['incluse'] = ($intervalle[0] == "["); } if ($matches[2]) { $bornes['max']['valeur'] = trim($matches[2]); diff --git a/www/plugins-dist/svp/svp_fonctions.php b/www/plugins-dist/svp/svp_fonctions.php index 9ab89f2b..a0d9c02e 100644 --- a/www/plugins-dist/svp/svp_fonctions.php +++ b/www/plugins-dist/svp/svp_fonctions.php @@ -40,8 +40,9 @@ function svp_afficher_intervalle($intervalle, $logiciel) { } $mineure = $regs[1]; + $majeure = preg_replace(',\.99$,', '.*', $regs[2]); - $mineure_inc = $intervalle{0} == "["; + $mineure_inc = $intervalle[0] == "["; $majeure_inc = substr($intervalle, -1) == "]"; if (strlen($mineure)) { if (!strlen($majeure)) { diff --git a/www/plugins-dist/textwheel/engine/textwheel.php b/www/plugins-dist/textwheel/engine/textwheel.php index 3768e489..9cb9b64b 100644 --- a/www/plugins-dist/textwheel/engine/textwheel.php +++ b/www/plugins-dist/textwheel/engine/textwheel.php @@ -28,6 +28,8 @@ class TextWheel { protected $ruleset; protected static $subwheel = array(); + // Experimental : projet de compilation PHP d'une wheel + // pour generation d'un fichier php execute a la place de ->text() protected $compiled = array(); /** @@ -83,13 +85,14 @@ class TextWheel { foreach ($rules as $name => $rule) { $rule->name = $name; $this->initRule($rule); - if (is_string($rule->replace) - and isset($this->compiled[$rule->replace]) - and $fun = $this->compiled[$rule->replace] + if ($rule->replace + and $compiledEntry = $this->ruleCompiledEntryName($rule->replace) + and isset($this->compiled[$compiledEntry]) + and $fun = $this->compiled[$compiledEntry] ) { $pre[] = "\n###\n## $name\n###\n" . $fun; preg_match(',function (\w+), ', $fun, $r); - $rule->compilereplace = $r[1]; # ne pas modifier ->replace sinon on casse l'execution... + $rule->compilereplace = "'".$r[1]."'"; # ne pas modifier ->replace sinon on casse l'execution... } $r = "\t/* $name */\n"; @@ -109,9 +112,18 @@ class TextWheel { if ($rule->func_replace !== 'replace_identity') { $fun = 'TextWheel::' . $rule->func_replace; + $call = ''; switch ($fun) { case 'TextWheel::replace_all_cb': - $fun = $rule->replace; # trim()... + if (is_string($rule->replace)) { + $fun = $rule->replace; + } + elseif ($rule->compilereplace) { + $fun = trim($rule->compilereplace, "'"); + }; + if ($fun) { + $call = "\$t = $fun(\$t);"; + } break; case 'TextWheel::replace_preg': $fun = 'preg_replace'; @@ -125,7 +137,13 @@ class TextWheel { default: break; } - $r .= "\t" . '$t = ' . $fun . '(' . TextWheel::export($rule->match) . ', ' . TextWheel::export($rule->replace) . ', $t);' . "\n"; + if (!$call) { + if (empty($rule->compilereplace)) { + $rule->compilereplace = TextWheel::export($rule->replace); + } + $call = '$t = ' . $fun . '(' . TextWheel::export($rule->match) . ', ' . $rule->compilereplace . ', $t);'; + } + $r .= "\t$call\n"; } $comp[] = $r; @@ -161,6 +179,20 @@ class TextWheel { return $tw; } + /** + * @param $replace + * @return string + */ + protected function ruleCompiledEntryName($replace) { + if (is_array($replace)) { + return serialize($replace); + } + elseif (is_object($replace)) { + return get_class($replace) . ':' . spl_object_hash($replace); + } + return $replace; + } + /** * Initializing a rule a first call * including file, creating function or wheel @@ -183,25 +215,35 @@ class TextWheel { } if ($rule->create_replace) { + // DEPRECATED : rule->create_replace, on ne peut rien faire de mieux ici + // mais c'est voue a disparaitre $compile = $rule->replace . '($t)'; $rule->replace = create_function('$m', $rule->replace); - $this->compiled[$rule->replace] = $compile; + $this->compiled[$this->ruleCompiledEntryName($rule->replace)] = $compile; $rule->create_replace = false; $rule->is_callback = true; - } elseif ($rule->is_wheel) { - $n = count(TextWheel::$subwheel); + } + elseif ($rule->is_wheel) { + $rule_number = count(TextWheel::$subwheel); TextWheel::$subwheel[] = $this->createSubWheel($rule->replace); - $var = '$m[' . intval($rule->pick_match) . ']'; + $cname = 'compiled_' . str_replace('-', '_', $rule->name) . '_' . substr(md5(spl_object_hash($rule)),0,7); if ($rule->type == 'all' or $rule->type == 'str' or $rule->type == 'split' or !isset($rule->match)) { - $var = '$m'; + $rule->replace = function ($m) use ($rule_number) { + return TextWheel::getSubWheel($rule_number)->text($m); + }; + $rule->compilereplace = "'$cname'"; + } + else { + $pick_match = intval($rule->pick_match); + $rule->replace = function ($m) use ($rule_number, $pick_match) { + return TextWheel::getSubWheel($rule_number)->text($m[$pick_match]); + }; + $rule->compilereplace = 'function ($m) { return '.$cname.'($m['.$pick_match.']) }'; } - $code = 'return TextWheel::getSubWheel(' . $n . ')->text(' . $var . ');'; - $rule->replace = create_function('$m', $code); - $cname = 'compiled_' . str_replace('-', '_', $rule->name); - $compile = TextWheel::getSubWheel($n)->compile($cname); - $this->compiled[$rule->replace] = $compile; $rule->is_wheel = false; $rule->is_callback = true; + $compile = TextWheel::getSubWheel($rule_number)->compile($cname); + $this->compiled[$this->ruleCompiledEntryName($rule->replace)] = $compile; } # optimization diff --git a/www/plugins-dist/textwheel/engine/textwheelrule.php b/www/plugins-dist/textwheel/engine/textwheelrule.php index a3cd6fdf..2f0efc24 100644 --- a/www/plugins-dist/textwheel/engine/textwheelrule.php +++ b/www/plugins-dist/textwheel/engine/textwheelrule.php @@ -65,10 +65,12 @@ class TextWheelRule { # optional # language specific public $require; # file to require_once + # DEPRECATED : create_function deprecated a partir de PHP 7.2, ne plus utiliser public $create_replace; # do create_function('$m', %) on $this->replace, $m is the matched array # optimizations public $func_replace; + public $compilereplace; /** * Rule constructor diff --git a/www/plugins-dist/textwheel/inc/texte.php b/www/plugins-dist/textwheel/inc/texte.php index 71aa5594..325bedb7 100644 --- a/www/plugins-dist/textwheel/inc/texte.php +++ b/www/plugins-dist/textwheel/inc/texte.php @@ -377,7 +377,6 @@ function traiter_tableau($bloc) { $lignes = array(); $debut_table = $summary = ''; $l = 0; - $numeric = true; // Traiter chaque ligne $reg_line1 = ',^(\|(' . _RACCOURCI_TH_SPAN . '))+$,sS'; diff --git a/www/plugins-dist/textwheel/lib/yaml/sfYamlInline.php b/www/plugins-dist/textwheel/lib/yaml/sfYamlInline.php index 6645dd79..b72d6ee0 100644 --- a/www/plugins-dist/textwheel/lib/yaml/sfYamlInline.php +++ b/www/plugins-dist/textwheel/lib/yaml/sfYamlInline.php @@ -110,7 +110,7 @@ class sfYamlInline if ( (1 == count($keys) && '0' == $keys[0]) || - (count($keys) > 1 && array_reduce($keys, create_function('$v,$w', 'return (integer) $v + $w;'), 0) == count($keys) * (count($keys) - 1) / 2)) + (count($keys) > 1 && array_reduce($keys, function($v,$w) { return (integer) $v + $w; }, 0) == count($keys) * (count($keys) - 1) / 2)) { $output = array(); foreach ($value as $val) @@ -222,7 +222,7 @@ class sfYamlInline // evaluate the string $buffer = str_replace(array('\\n', '\\r'), array("\n", "\r"), $buffer); if (strpos($buffer,'\\x')!==false){ - $buffer = preg_replace_callback(',\\\\x([0-9a-f]+),', create_function('$m', 'return chr(hexdec($m[1]));'), $buffer); + $buffer = preg_replace_callback(',\\\\x([0-9a-f]+),', function($m) { return chr(hexdec($m[1])); }, $buffer); } } diff --git a/www/plugins-dist/textwheel/paquet.xml b/www/plugins-dist/textwheel/paquet.xml index 5a427bf2..40d79d92 100644 --- a/www/plugins-dist/textwheel/paquet.xml +++ b/www/plugins-dist/textwheel/paquet.xml @@ -1,7 +1,7 @@