Version in base suite: 4.4.13+dfsg-0+deb13u1 Base version: spip_4.4.13+dfsg-0+deb13u1 Target version: spip_4.4.15+dfsg-0+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/s/spip/spip_4.4.13+dfsg-0+deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/s/spip/spip_4.4.15+dfsg-0+deb13u1.dsc CHANGELOG.md | 8 composer.json | 5 composer.lock | 196 - debian/changelog | 19 debian/patches/0001-Fix-created-directories-and-files-default-rights.patch | 4 debian/patches/0003-Fix-displayed-version-in-the-private-interface.patch | 4 ecrire/CHANGELOG.md | 29 ecrire/action/cookie.php | 11 ecrire/composer.json | 2 ecrire/inc/auth.php | 1 ecrire/inc/filtres.php | 2 ecrire/inc/icone_renommer.php | 4 ecrire/inc/queue.php | 7 ecrire/inc/utils.php | 4 ecrire/inc_version.php | 16 ecrire/paquet.xml | 2 ecrire/public/balises.php | 7 ecrire/public/compiler.php | 33 ecrire/req/pg.exp.php | 85 ecrire/src/Afficher/Minipage/AbstractPage.php | 9 plugins-dist.json | 60 plugins-dist/aide/CHANGELOG.md | 6 plugins-dist/aide/composer.json | 2 plugins-dist/aide/paquet.xml | 2 plugins-dist/archiviste/CHANGELOG.md | 6 plugins-dist/archiviste/composer.json | 5 plugins-dist/archiviste/paquet.xml | 2 plugins-dist/archiviste/tests/SpipArchiverTest.php | 8 plugins-dist/bigup/CHANGELOG.md | 6 plugins-dist/bigup/composer.json | 2 plugins-dist/bigup/paquet.xml | 2 plugins-dist/compagnon/CHANGELOG.md | 6 plugins-dist/compagnon/action/compagnon.php | 6 plugins-dist/compagnon/composer.json | 5 plugins-dist/compagnon/paquet.xml | 2 plugins-dist/compagnon/tests/Fixtures/Afficher/Minipage/Admin.php | 26 plugins-dist/dump/CHANGELOG.md | 12 plugins-dist/dump/action/telecharger_dump.php | 6 plugins-dist/dump/base/restaurer.php | 1 plugins-dist/dump/composer.json | 5 plugins-dist/dump/inc/sauvegarder.php | 8 plugins-dist/dump/paquet.xml | 2 plugins-dist/dump/phpstan-baseline.neon | 333 +- plugins-dist/dump/tests/Fixtures/Afficher/Minipage/Admin.php | 26 plugins-dist/filtres_images/CHANGELOG.md | 7 plugins-dist/filtres_images/composer.json | 2 plugins-dist/filtres_images/filtres/images_transforme.php | 3 plugins-dist/filtres_images/paquet.xml | 2 plugins-dist/medias/CHANGELOG.md | 11 plugins-dist/medias/action/acceder_document.php | 12 plugins-dist/medias/action/copier_local.php | 2 plugins-dist/medias/action/dissocier_document.php | 2 plugins-dist/medias/action/tourner.php | 15 plugins-dist/medias/base/medias.php | 5 plugins-dist/medias/composer.json | 5 plugins-dist/medias/inc/getdocument.php | 14 plugins-dist/medias/lib/getid3/extension.cache.dbm.php | 173 - plugins-dist/medias/lib/getid3/getid3.lib.php | 101 plugins-dist/medias/lib/getid3/getid3.php | 68 plugins-dist/medias/lib/getid3/module.archive.7zip.php | 52 plugins-dist/medias/lib/getid3/module.archive.hpk.php | 2 plugins-dist/medias/lib/getid3/module.archive.tar.php | 4 plugins-dist/medias/lib/getid3/module.audio-video.asf.php | 62 plugins-dist/medias/lib/getid3/module.audio-video.ivf.php | 22 plugins-dist/medias/lib/getid3/module.audio-video.matroska.php | 188 + plugins-dist/medias/lib/getid3/module.audio-video.mpeg.php | 16 plugins-dist/medias/lib/getid3/module.audio-video.nsv.php | 2 plugins-dist/medias/lib/getid3/module.audio-video.quicktime.php | 291 +- plugins-dist/medias/lib/getid3/module.audio-video.real.php | 13 plugins-dist/medias/lib/getid3/module.audio-video.riff.php | 89 plugins-dist/medias/lib/getid3/module.audio.amr.php | 2 plugins-dist/medias/lib/getid3/module.audio.au.php | 4 plugins-dist/medias/lib/getid3/module.audio.avr.php | 6 plugins-dist/medias/lib/getid3/module.audio.bonk.php | 2 plugins-dist/medias/lib/getid3/module.audio.dsdiff.php | 10 plugins-dist/medias/lib/getid3/module.audio.dsf.php | 2 plugins-dist/medias/lib/getid3/module.audio.dss.php | 14 plugins-dist/medias/lib/getid3/module.audio.flac.php | 4 plugins-dist/medias/lib/getid3/module.audio.lpac.php | 4 plugins-dist/medias/lib/getid3/module.audio.midi.php | 24 plugins-dist/medias/lib/getid3/module.audio.mp3.php | 60 plugins-dist/medias/lib/getid3/module.audio.mpc.php | 4 plugins-dist/medias/lib/getid3/module.audio.ogg.php | 28 plugins-dist/medias/lib/getid3/module.audio.rkau.php | 2 plugins-dist/medias/lib/getid3/module.audio.shorten.php | 8 plugins-dist/medias/lib/getid3/module.audio.tta.php | 8 plugins-dist/medias/lib/getid3/module.audio.voc.php | 7 plugins-dist/medias/lib/getid3/module.audio.wavpack.php | 8 plugins-dist/medias/lib/getid3/module.graphic.bmp.php | 586 ++-- plugins-dist/medias/lib/getid3/module.graphic.jpg.php | 7 plugins-dist/medias/lib/getid3/module.graphic.png.php | 21 plugins-dist/medias/lib/getid3/module.graphic.svg.php | 2 plugins-dist/medias/lib/getid3/module.misc.cue.php | 4 plugins-dist/medias/lib/getid3/module.misc.gpx.php | 36 plugins-dist/medias/lib/getid3/module.tag.apetag.php | 8 plugins-dist/medias/lib/getid3/module.tag.id3v1.php | 5 plugins-dist/medias/lib/getid3/module.tag.id3v2.php | 89 plugins-dist/medias/lib/getid3/module.tag.lyrics3.php | 48 plugins-dist/medias/lib/getid3/module.tag.xmp.php | 183 - plugins-dist/medias/lib/getid3/write.apetag.php | 2 plugins-dist/medias/lib/getid3/write.id3v1.php | 3 plugins-dist/medias/lib/getid3/write.id3v2.php | 28 plugins-dist/medias/lib/getid3/write.metaflac.php | 21 plugins-dist/medias/lib/getid3/write.php | 10 plugins-dist/medias/lib/getid3/write.vorbiscomment.php | 4 plugins-dist/medias/medias_fonctions.php | 6 plugins-dist/medias/paquet.xml | 2 plugins-dist/medias/phpstan-baseline.neon | 102 plugins-dist/medias/tests/Fixtures/Afficher/Minipage/Admin.php | 26 plugins-dist/revisions/CHANGELOG.md | 6 plugins-dist/revisions/composer.json | 2 plugins-dist/revisions/paquet.xml | 2 plugins-dist/safehtml/CHANGELOG.md | 6 plugins-dist/safehtml/paquet.xml | 2 plugins-dist/safehtml/tests/SafeHtmlTest.php | 1403 ++++------ plugins-dist/sites/CHANGELOG.md | 7 plugins-dist/sites/paquet.xml | 2 plugins-dist/sites/prive/squelettes/contenu/site.html | 2 plugins-dist/sites/syndic/atomrss.php | 8 plugins-dist/statistiques/CHANGELOG.md | 6 plugins-dist/statistiques/action/statistiques_archiver.php | 12 plugins-dist/statistiques/composer.json | 13 plugins-dist/statistiques/exec/base_delete_referers.php | 10 plugins-dist/statistiques/exec/base_delete_stats.php | 9 plugins-dist/statistiques/paquet.xml | 2 plugins-dist/statistiques/tests/Fixtures/Afficher/Minipage/Admin.php | 26 plugins-dist/svp/CHANGELOG.md | 7 plugins-dist/svp/action/actionner.php | 13 plugins-dist/svp/action/actualiser_depot.php | 9 plugins-dist/svp/action/editer_depot.php | 12 plugins-dist/svp/action/supprimer_depot.php | 9 plugins-dist/svp/composer.json | 7 plugins-dist/svp/exec/admin_plugin.php | 7 plugins-dist/svp/inc/svp_depoter_distant.php | 1 plugins-dist/svp/paquet.xml | 2 plugins-dist/svp/phpstan-baseline.neon | 54 plugins-dist/svp/tests/Fixtures/Afficher/Minipage/Admin.php | 26 prive/CHANGELOG.md | 14 prive/formulaires/dateur/inc-dateur.html | 4 prive/formulaires/instituer_objet.php | 3 prive/ical_prive.html | 122 prive/squelettes/contenu/accueil.html | 4 prive/squelettes/contenu/synchro.html | 10 prive/transmettre/rss/signatures.html | 28 vendor/autoload.php | 2 vendor/composer/autoload_classmap.php | 11 vendor/composer/autoload_files.php | 5 vendor/composer/autoload_psr4.php | 1 vendor/composer/autoload_real.php | 10 vendor/composer/autoload_static.php | 29 vendor/composer/installed.json | 217 + vendor/composer/installed.php | 79 vendor/spip-league/kernel/CHANGELOG.md | 6 vendor/spip-league/kernel/src/Kernel.php | 18 vendor/symfony/polyfill-ctype/Ctype.php | 8 vendor/symfony/polyfill-mbstring/Mbstring.php | 82 vendor/symfony/polyfill-mbstring/bootstrap.php | 13 vendor/symfony/polyfill-php80/Php80.php | 2 vendor/symfony/polyfill-php82/Php82.php | 18 vendor/symfony/polyfill-php83/Php83.php | 29 vendor/symfony/polyfill-php83/bootstrap.php | 16 vendor/symfony/polyfill-php83/bootstrap80.php | 30 vendor/symfony/polyfill-php84/Php84.php | 271 + vendor/symfony/polyfill-php84/README.md | 1 vendor/symfony/polyfill-php84/Resources/Deprecated.php | 25 vendor/symfony/polyfill-php84/Resources/RoundingMode.php | 24 vendor/symfony/polyfill-php84/Resources/stubs/Deprecated.php | 15 vendor/symfony/polyfill-php84/Resources/stubs/Pdo/Dblib.php | 43 vendor/symfony/polyfill-php84/Resources/stubs/Pdo/Firebird.php | 39 vendor/symfony/polyfill-php84/Resources/stubs/Pdo/Mysql.php | 101 vendor/symfony/polyfill-php84/Resources/stubs/Pdo/Odbc.php | 41 vendor/symfony/polyfill-php84/Resources/stubs/Pdo/Pgsql.php | 94 vendor/symfony/polyfill-php84/Resources/stubs/Pdo/Sqlite.php | 58 vendor/symfony/polyfill-php84/Resources/stubs/ReflectionConstant.php | 4 vendor/symfony/polyfill-php84/Resources/stubs/RoundingMode.php | 44 vendor/symfony/polyfill-php84/bootstrap.php | 29 vendor/symfony/polyfill-php84/bootstrap80.php | 57 vendor/symfony/polyfill-php85/LICENSE | 19 vendor/symfony/polyfill-php85/Php85.php | 139 vendor/symfony/polyfill-php85/README.md | 20 vendor/symfony/polyfill-php85/Resources/stubs/DelayedTargetValidation.php | 18 vendor/symfony/polyfill-php85/Resources/stubs/Filter/FilterException.php | 18 vendor/symfony/polyfill-php85/Resources/stubs/Filter/FilterFailedException.php | 18 vendor/symfony/polyfill-php85/Resources/stubs/NoDiscard.php | 23 vendor/symfony/polyfill-php85/bootstrap.php | 46 vendor/symfony/polyfill-php85/bootstrap80.php | 20 vendor/symfony/polyfill-php85/composer.json | 33 187 files changed, 4721 insertions(+), 2445 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp4iedn3w3/spip_4.4.13+dfsg-0+deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp4iedn3w3/spip_4.4.15+dfsg-0+deb13u1.dsc: no acceptable signature found diff -Nru spip-4.4.13+dfsg/CHANGELOG.md spip-4.4.15+dfsg/CHANGELOG.md --- spip-4.4.13+dfsg/CHANGELOG.md 2026-03-06 10:17:16.000000000 +0000 +++ spip-4.4.15+dfsg/CHANGELOG.md 2026-05-22 07:52:14.000000000 +0000 @@ -1,5 +1,13 @@ # Changelog +## 4.4.15 - 2026-05-22 + +- Mise à jour des dépendances (ecrire, dump) + +## 4.4.14 - 2026-05-12 + +- Mise à jour des dépendances (ecrire, prive, aide, archiviste, bigup, compagnon, dump, images, medias, revisions, safehtml, sites, statistiques, svp) + ## 4.4.13 - 2026-03-06 - Mise à jour des dépendances (ecrire) -- Compatibilité PHP 7.4 diff -Nru spip-4.4.13+dfsg/composer.json spip-4.4.15+dfsg/composer.json --- spip-4.4.13+dfsg/composer.json 2026-03-06 10:17:16.000000000 +0000 +++ spip-4.4.15+dfsg/composer.json 2026-05-22 07:52:14.000000000 +0000 @@ -11,7 +11,7 @@ "php": "^7.4 || ^8.0", "spip-league/composer-installer": "^0.8", "spip-league/kernel": "^1.0", - "spip/dist": "~4.2.5", + "spip/dist": "^4.2.5", "spip/ecrire": "^4.4", "spip/prive": "^1.0", "spip/security": "^1.6", @@ -19,7 +19,8 @@ "symfony/polyfill-php81": "^1.31", "symfony/polyfill-php82": "^1.31", "symfony/polyfill-php83": "^1.31", - "symfony/polyfill-php84": "^1.31" + "symfony/polyfill-php84": "^1.31", + "symfony/polyfill-php85": "^1.31" }, "repositories": { "spip": { diff -Nru spip-4.4.13+dfsg/composer.lock spip-4.4.15+dfsg/composer.lock --- spip-4.4.13+dfsg/composer.lock 2026-03-06 10:17:16.000000000 +0000 +++ spip-4.4.15+dfsg/composer.lock 2026-05-22 07:52:14.000000000 +0000 @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3d0099e45b1637bcb5f6b7069727530e", + "content-hash": "6267f83f614ae8d466fa6c7b9ee7c7e1", "packages": [ { "name": "algo26-matthias/idna-convert", @@ -228,16 +228,16 @@ }, { "name": "spip-league/kernel", - "version": "1.0.1", + "version": "1.1.0", "source": { "type": "git", "url": "https://git.spip.net/spip-league/kernel.git", - "reference": "375feee2d7c4c0d4ac86d3c1635bf46ccae7f909" + "reference": "4f275f3504ae95892fc41412a0c62021251f2a2f" }, "dist": { "type": "zip", - "url": "https://git.spip.net/api/v4/projects/spip-league%2Fkernel/repository/archive.zip?sha=375feee2d7c4c0d4ac86d3c1635bf46ccae7f909", - "reference": "375feee2d7c4c0d4ac86d3c1635bf46ccae7f909", + "url": "https://git.spip.net/api/v4/projects/spip-league%2Fkernel/repository/archive.zip?sha=4f275f3504ae95892fc41412a0c62021251f2a2f", + "reference": "4f275f3504ae95892fc41412a0c62021251f2a2f", "shasum": "" }, "require": { @@ -278,10 +278,10 @@ "kernel" ], "support": { - "source": "https://git.spip.net/spip-league/kernel/-/tree/1.0.1", + "source": "https://git.spip.net/spip-league/kernel/-/tree/1.1.0", "issues": "https://git.spip.net/spip-league/kernel/-/issues" }, - "time": "2025-03-19T11:54:48+01:00" + "time": "2026-03-07T16:31:19+01:00" }, { "name": "spip/dist", @@ -317,16 +317,16 @@ }, { "name": "spip/ecrire", - "version": "4.4.13", + "version": "4.4.15", "source": { "type": "git", "url": "https://git.spip.net/spip/ecrire.git", - "reference": "430909d749490d9704e74a9185b0cd9849593f8f" + "reference": "82e4cf75da354af62907361b309dc0280f416d98" }, "dist": { "type": "zip", - "url": "https://git.spip.net/api/v4/projects/spip%2Fecrire/repository/archive.zip?sha=430909d749490d9704e74a9185b0cd9849593f8f", - "reference": "430909d749490d9704e74a9185b0cd9849593f8f", + "url": "https://git.spip.net/api/v4/projects/spip%2Fecrire/repository/archive.zip?sha=82e4cf75da354af62907361b309dc0280f416d98", + "reference": "82e4cf75da354af62907361b309dc0280f416d98", "shasum": "" }, "require": { @@ -336,6 +336,7 @@ "ext-xml": "*", "ext-zip": "*", "php": "^7.4 || ^8.0", + "spip-league/kernel": "^1.1", "symfony/deprecation-contracts": "^2.5", "symfony/polyfill-mbstring": "^1.31", "symfony/polyfill-php80": "^1.31", @@ -345,7 +346,6 @@ "symfony/polyfill-php84": "^1.31" }, "require-dev": { - "spip-league/kernel": "^1.x-dev", "symplify/easy-coding-standard": "^12.3" }, "type": "spip-ecrire", @@ -362,23 +362,23 @@ ], "description": "Noyau de SPIP", "support": { - "source": "https://git.spip.net/spip/ecrire/-/tree/4.4.13", + "source": "https://git.spip.net/spip/ecrire/-/tree/4.4.15", "issues": "https://git.spip.net/spip/ecrire/-/issues" }, - "time": "2026-03-06T11:13:42+01:00" + "time": "2026-05-22T09:44:50+02:00" }, { "name": "spip/prive", - "version": "1.0.10", + "version": "1.1.0", "source": { "type": "git", "url": "https://git.spip.net/spip/prive.git", - "reference": "d438e7f47f306d06f6dfd169c6c38b58b5d2226a" + "reference": "32d29f8250d47609d30c081571295bc075062a6a" }, "dist": { "type": "zip", - "url": "https://git.spip.net/api/v4/projects/spip%2Fprive/repository/archive.zip?sha=d438e7f47f306d06f6dfd169c6c38b58b5d2226a", - "reference": "d438e7f47f306d06f6dfd169c6c38b58b5d2226a", + "url": "https://git.spip.net/api/v4/projects/spip%2Fprive/repository/archive.zip?sha=32d29f8250d47609d30c081571295bc075062a6a", + "reference": "32d29f8250d47609d30c081571295bc075062a6a", "shasum": "" }, "require-dev": { @@ -390,10 +390,10 @@ ], "description": "Squelettes de l'espace privé", "support": { - "source": "https://git.spip.net/spip/prive/-/tree/1.0.10", + "source": "https://git.spip.net/spip/prive/-/tree/1.1.0", "issues": "https://git.spip.net/spip/prive/-/issues" }, - "time": "2026-03-06T10:27:32+01:00" + "time": "2026-05-12T09:51:22+02:00" }, { "name": "spip/security", @@ -662,16 +662,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + "reference": "141046a8f9477948ff284fa65be2095baafb94f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2", + "reference": "141046a8f9477948ff284fa65be2095baafb94f2", "shasum": "" }, "require": { @@ -721,7 +721,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0" }, "funding": [ { @@ -741,20 +741,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + "reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6a21eb99c6973357967f6ce3708cd55a6bec6315", + "reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315", "shasum": "" }, "require": { @@ -806,7 +806,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.37.0" }, "funding": [ { @@ -826,20 +826,20 @@ "type": "tidelift" } ], - "time": "2024-12-23T08:48:59+00:00" + "time": "2026-04-10T17:25:58+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", - "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411", + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411", "shasum": "" }, "require": { @@ -890,7 +890,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0" }, "funding": [ { @@ -910,11 +910,11 @@ "type": "tidelift" } ], - "time": "2025-01-02T08:10:11+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", @@ -970,7 +970,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.37.0" }, "funding": [ { @@ -994,16 +994,16 @@ }, { "name": "symfony/polyfill-php82", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php82.git", - "reference": "5d2ed36f7734637dacc025f179698031951b1692" + "reference": "34808efe3e68f69685796f7c253a2f1d8ea9df59" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php82/zipball/5d2ed36f7734637dacc025f179698031951b1692", - "reference": "5d2ed36f7734637dacc025f179698031951b1692", + "url": "https://api.github.com/repos/symfony/polyfill-php82/zipball/34808efe3e68f69685796f7c253a2f1d8ea9df59", + "reference": "34808efe3e68f69685796f7c253a2f1d8ea9df59", "shasum": "" }, "require": { @@ -1050,7 +1050,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php82/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php82/tree/v1.37.0" }, "funding": [ { @@ -1070,20 +1070,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { "name": "symfony/polyfill-php83", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" + "reference": "3600c2cb22399e25bb226e4a135ce91eeb2a6149" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/3600c2cb22399e25bb226e4a135ce91eeb2a6149", + "reference": "3600c2cb22399e25bb226e4a135ce91eeb2a6149", "shasum": "" }, "require": { @@ -1130,7 +1130,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.37.0" }, "funding": [ { @@ -1150,20 +1150,20 @@ "type": "tidelift" } ], - "time": "2025-07-08T02:45:35+00:00" + "time": "2026-04-10T17:25:58+00:00" }, { "name": "symfony/polyfill-php84", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" + "reference": "88486db2c389b290bf87ff1de7ebc1e13e42bb06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/88486db2c389b290bf87ff1de7ebc1e13e42bb06", + "reference": "88486db2c389b290bf87ff1de7ebc1e13e42bb06", "shasum": "" }, "require": { @@ -1210,7 +1210,87 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php84/tree/v1.37.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-04-10T18:47:49+00:00" + }, + { + "name": "symfony/polyfill-php85", + "version": "v1.37.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "fcfa4973a9917cef23f2e38774da74a2b7d115ee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/fcfa4973a9917cef23f2e38774da74a2b7d115ee", + "reference": "fcfa4973a9917cef23f2e38774da74a2b7d115ee", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php85\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php85/tree/v1.37.0" }, "funding": [ { @@ -1230,7 +1310,7 @@ "type": "tidelift" } ], - "time": "2025-06-24T13:30:11+00:00" + "time": "2026-04-26T13:10:57+00:00" }, { "name": "symfony/service-contracts", diff -Nru spip-4.4.13+dfsg/debian/changelog spip-4.4.15+dfsg/debian/changelog --- spip-4.4.13+dfsg/debian/changelog 2026-03-08 07:44:51.000000000 +0000 +++ spip-4.4.15+dfsg/debian/changelog 2026-05-23 14:49:01.000000000 +0000 @@ -1,7 +1,24 @@ +spip (4.4.15+dfsg-0+deb13u1) trixie-security; urgency=medium + + [ David Prévot ] + * Document CVE in previouss changelog entry + + [ Matthieu Marcillaud ] + * build: Ajout du polyfill PHP 8.5 + * build: update dependencies + * build: Version 4.4.15 + + Fix remote code execution vulnerability in the private space + [CVE-2026-8429] + + Fix remote code execution vulnerability in the public space that is + limited to certain nginx configurations [CVE-2026-8430] + + -- David Prévot Sat, 23 May 2026 16:49:01 +0200 + spip (4.4.13+dfsg-0+deb13u1) trixie-security; urgency=medium [ Matthieu Marcillaud ] - * build: Version 4.4.13, fixing privilege escalation introduced in 4.4.10. + * build: Version 4.4.13, fixing privilege escalation [CVE-2026-33549] + introduced in 4.4.10. [ David Prévot ] * Refresh patches header diff -Nru spip-4.4.13+dfsg/debian/patches/0001-Fix-created-directories-and-files-default-rights.patch spip-4.4.15+dfsg/debian/patches/0001-Fix-created-directories-and-files-default-rights.patch --- spip-4.4.13+dfsg/debian/patches/0001-Fix-created-directories-and-files-default-rights.patch 2026-03-08 07:41:01.000000000 +0000 +++ spip-4.4.15+dfsg/debian/patches/0001-Fix-created-directories-and-files-default-rights.patch 2026-05-23 14:47:54.000000000 +0000 @@ -13,10 +13,10 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecrire/inc_version.php b/ecrire/inc_version.php -index c70493e..b8c8efb 100644 +index 80d046f..d4b8f6d 100644 --- a/ecrire/inc_version.php +++ b/ecrire/inc_version.php -@@ -437,7 +437,7 @@ $liste_des_authentifications = [ +@@ -445,7 +445,7 @@ $liste_des_authentifications = [ # $table_des_traitements['TITRE'][]= 'typo(supprimer_numero(%s), "TYPO", $connect)'; // Droits d'acces maximum par defaut diff -Nru spip-4.4.13+dfsg/debian/patches/0003-Fix-displayed-version-in-the-private-interface.patch spip-4.4.15+dfsg/debian/patches/0003-Fix-displayed-version-in-the-private-interface.patch --- spip-4.4.13+dfsg/debian/patches/0003-Fix-displayed-version-in-the-private-interface.patch 2026-03-08 07:41:01.000000000 +0000 +++ spip-4.4.15+dfsg/debian/patches/0003-Fix-displayed-version-in-the-private-interface.patch 2026-05-23 14:47:54.000000000 +0000 @@ -14,10 +14,10 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecrire/inc_version.php b/ecrire/inc_version.php -index b8c8efb..1c6b3e6 100644 +index d4b8f6d..565e7c2 100644 --- a/ecrire/inc_version.php +++ b/ecrire/inc_version.php -@@ -462,7 +462,7 @@ $spip_sql_version = 1; +@@ -470,7 +470,7 @@ $spip_sql_version = 1; // version de spip en chaine // 1.xxyy : xx00 versions stables publiees, xxyy versions de dev // (ce qui marche pour yy ne marchera pas forcement sur une version plus ancienne) diff -Nru spip-4.4.13+dfsg/ecrire/CHANGELOG.md spip-4.4.15+dfsg/ecrire/CHANGELOG.md --- spip-4.4.13+dfsg/ecrire/CHANGELOG.md 2026-03-06 10:13:42.000000000 +0000 +++ spip-4.4.15+dfsg/ecrire/CHANGELOG.md 2026-05-22 07:44:50.000000000 +0000 @@ -2,6 +2,35 @@ Changelog de SPIP 4.4 +## 4.4.15 - 2026-05-22 + +### Security + +- spip-security/securite#4881 éviter un open-redirect + +### Fixed + +- !256 définir `_VAR_MODE` si besoin dans minipage +- #147 si la session est vide, la balise `#SESSION` doit renvoyer une chaine vide et non un tableau vide sérialisé, pour pouvoir tester |oui ou |non dessus. +- !255 Caster et définir une valeur par défaut si max_execution_time absent + + +## 4.4.14 - 2026-05-12 + +### Security + +- spip-security/securite#4879 meilleure sanitisation de HTTP_HOST + +### Fixed + +- #142 !250 Nginx peuple REMOTE_USER vide +- #141 !248 Correction PHPDoc de calculer_liste() +- #140 !245 `#CHEMIN_IMAGE` gère aussi les avif, webp et jpg + +### Deprecated + +- Annotation: _ROOT_RACINE et _ROOT_RESTREINT sont dépréciées. + ## 4.4.13 - 2026-03-06 ### Fixed diff -Nru spip-4.4.13+dfsg/ecrire/action/cookie.php spip-4.4.15+dfsg/ecrire/action/cookie.php --- spip-4.4.13+dfsg/ecrire/action/cookie.php 2026-03-06 10:13:42.000000000 +0000 +++ spip-4.4.15+dfsg/ecrire/action/cookie.php 2026-05-22 07:44:50.000000000 +0000 @@ -45,13 +45,10 @@ // La cible de notre operation de connexion $url = securiser_redirect_action(_request('url')); $redirect = $url ?: generer_url_ecrire('accueil'); - $redirect_echec = _request('url_echec'); - if (!isset($redirect_echec)) { - if (str_contains((string) $redirect, (string) param('spip.routes.back_office'))) { - $redirect_echec = generer_url_public('login', '', true); - } else { - $redirect_echec = $redirect; - } + if (str_contains((string) $redirect, (string) param('spip.routes.back_office'))) { + $redirect_echec = generer_url_public('login', '', true); + } else { + $redirect_echec = $redirect; } } diff -Nru spip-4.4.13+dfsg/ecrire/composer.json spip-4.4.15+dfsg/ecrire/composer.json --- spip-4.4.13+dfsg/ecrire/composer.json 2026-03-06 10:13:42.000000000 +0000 +++ spip-4.4.15+dfsg/ecrire/composer.json 2026-05-22 07:44:50.000000000 +0000 @@ -10,6 +10,7 @@ "ext-xml": "*", "ext-zip": "*", "algo26-matthias/idna-convert": "^3.1", + "spip-league/kernel": "^1.1", "symfony/deprecation-contracts": "^2.5", "symfony/polyfill-mbstring": "^1.31", "symfony/polyfill-php80": "^1.31", @@ -19,7 +20,6 @@ "symfony/polyfill-php84": "^1.31" }, "require-dev": { - "spip-league/kernel": "^1.x-dev", "symplify/easy-coding-standard": "^12.3" }, "repositories": { diff -Nru spip-4.4.13+dfsg/ecrire/inc/auth.php spip-4.4.15+dfsg/ecrire/inc/auth.php --- spip-4.4.13+dfsg/ecrire/inc/auth.php 2026-03-06 10:13:42.000000000 +0000 +++ spip-4.4.15+dfsg/ecrire/inc/auth.php 2026-05-22 07:44:50.000000000 +0000 @@ -190,6 +190,7 @@ // est indisponible mais tentons quand meme pour // autocreation via LDAP (isset($_SERVER['REMOTE_USER']) + and $_SERVER['REMOTE_USER'] !== '' and $r = lire_php_auth($_SERVER['PHP_AUTH_USER'] = $_SERVER['REMOTE_USER'], '')) ) { if (!$id_auteur) { diff -Nru spip-4.4.13+dfsg/ecrire/inc/filtres.php spip-4.4.15+dfsg/ecrire/inc/filtres.php --- spip-4.4.13+dfsg/ecrire/inc/filtres.php 2026-03-06 10:13:42.000000000 +0000 +++ spip-4.4.15+dfsg/ecrire/inc/filtres.php 2026-05-22 07:44:50.000000000 +0000 @@ -5427,7 +5427,7 @@ * @example * ``` * [(#AUTORISER{non}|sinon_interdire_acces)] - * [(#AUTORISER{non}|sinon_interdire_acces{#URL_PAGE{login}, 401})] + * [(#AUTORISER{non}|sinon_interdire_acces{'', 403})] * ``` * * @filtre diff -Nru spip-4.4.13+dfsg/ecrire/inc/icone_renommer.php spip-4.4.15+dfsg/ecrire/inc/icone_renommer.php --- spip-4.4.13+dfsg/ecrire/inc/icone_renommer.php 2026-03-06 10:13:42.000000000 +0000 +++ spip-4.4.15+dfsg/ecrire/inc/icone_renommer.php 2026-05-22 07:44:50.000000000 +0000 @@ -19,8 +19,8 @@ function inc_icone_renommer_dist($fond, $fonction) { $size = 24; if ( - preg_match('/(?:-([0-9]{1,3}))?([.](gif|png|svg))?$/i', $fond, $match) - and ((isset($match[0]) and $match[0]) or (isset($match[1]) and $match[1])) + preg_match('/(?:-(\d{1,3}))?([.](avif|gif|jpg|png|svg|webp))?$/i', (string) $fond, $match) + && (isset($match[0]) && $match[0] || isset($match[1]) && $match[1]) ) { if (isset($match[1]) and $match[1]) { $size = $match[1]; diff -Nru spip-4.4.13+dfsg/ecrire/inc/queue.php spip-4.4.15+dfsg/ecrire/inc/queue.php --- spip-4.4.13+dfsg/ecrire/inc/queue.php 2026-03-06 10:13:42.000000000 +0000 +++ spip-4.4.15+dfsg/ecrire/inc/queue.php 2026-05-22 07:44:50.000000000 +0000 @@ -61,11 +61,6 @@ ) { include_spip('base/abstract_sql'); - // cas pourri de ecrire/action/editer_site avec l'option reload=oui - if (defined('_GENIE_SYNDIC_NOW')) { - $arguments['id_syndic'] = _GENIE_SYNDIC_NOW; - } - // serialiser les arguments $arguments = serialize($arguments); $md5args = md5($arguments); @@ -315,7 +310,7 @@ } if (!defined('_JQ_MAX_JOBS_TIME_TO_EXECUTE')) { - $max_time = ini_get('max_execution_time') / 2; + $max_time = (intval(ini_get('max_execution_time')) ?: 30) / 2; // valeur conservatrice si on a pas reussi a lire le max_execution_time if (!$max_time) { $max_time = 5; diff -Nru spip-4.4.13+dfsg/ecrire/inc/utils.php spip-4.4.15+dfsg/ecrire/inc/utils.php --- spip-4.4.13+dfsg/ecrire/inc/utils.php 2026-03-06 10:13:42.000000000 +0000 +++ spip-4.4.15+dfsg/ecrire/inc/utils.php 2026-05-22 07:44:50.000000000 +0000 @@ -1627,7 +1627,7 @@ } // si c'est un nom d'image complet (article-24.png) essayer de le renvoyer direct - if (preg_match(',[.](png|gif|jpg|webp|svg)$,', $icone) and $f = find_in_theme("images/$icone")) { + if (preg_match(',[.](avif|gif|jpg|png|svg|webp)$,', $icone) and $f = find_in_theme("images/$icone")) { return $f; } // sinon passer par le module de renommage @@ -2194,7 +2194,7 @@ // note : HTTP_HOST contient le :port si necessaire if ($host = $_SERVER['HTTP_HOST'] ?? null) { // Filtrer $host pour proteger d'attaques d'entete HTTP - $host = (filter_var($host, FILTER_SANITIZE_URL) ?: null); + $_SERVER['HTTP_HOST'] = $host = strtr($host, "<>?\"\{\}\$'` \r\n", '____________'); } // si on n'a pas trouvé d'hôte du tout, en dernier recours on utilise adresse_site comme fallback diff -Nru spip-4.4.13+dfsg/ecrire/inc_version.php spip-4.4.15+dfsg/ecrire/inc_version.php --- spip-4.4.13+dfsg/ecrire/inc_version.php 2026-03-06 10:13:42.000000000 +0000 +++ spip-4.4.15+dfsg/ecrire/inc_version.php 2026-05-22 07:44:50.000000000 +0000 @@ -50,10 +50,18 @@ /** Chemin relatif pour aller à la racine */ define('_DIR_RACINE', _DIR_RESTREINT ? '' : '../'); -/** chemin absolu vers la racine */ +/** + * Chemin absolu vers la racine + * + * @deprecated 4.4 + */ define('_ROOT_RACINE', dirname(__DIR__) . '/'); -/** chemin absolu vers ecrire */ +/** + * Chemin absolu vers ecrire + * + * @deprecated 4.4 + */ define('_ROOT_RESTREINT', app()->getCwd() . DIRECTORY_SEPARATOR . _DIR_RESTREINT); # Le nom des 4 repertoires modifiables par les scripts lances par httpd @@ -443,8 +451,8 @@ // pour specifier les versions de SPIP necessaires // il faut s'en tenir a un nombre de decimales fixe // ex : 2.0.0, 2.0.0-dev, 2.0.0-beta, 2.0.0-beta2 -$spip_version_branche = '4.4.13'; -define('_SPIP_VERSION_ID', 40413); +$spip_version_branche = '4.4.15'; +define('_SPIP_VERSION_ID', 40415); define('_SPIP_EXTRA_VERSION', ''); // cette version dev accepte tous les plugins compatible avec la version ci-dessous diff -Nru spip-4.4.13+dfsg/ecrire/paquet.xml spip-4.4.15+dfsg/ecrire/paquet.xml --- spip-4.4.13+dfsg/ecrire/paquet.xml 2026-03-06 10:13:42.000000000 +0000 +++ spip-4.4.15+dfsg/ecrire/paquet.xml 2026-05-22 07:44:50.000000000 +0000 @@ -1,7 +1,7 @@ etoile) { + $src = "($src) ?: ''"; + } $p->code = '(is_array($a = (' . $src . ')) ? serialize($a) : "")'; } else { $p->code = 'serialize($Pile[0]??[])'; diff -Nru spip-4.4.13+dfsg/ecrire/public/compiler.php spip-4.4.15+dfsg/ecrire/public/compiler.php --- spip-4.4.13+dfsg/ecrire/public/compiler.php 2026-03-06 10:13:42.000000000 +0000 +++ spip-4.4.15+dfsg/ecrire/public/compiler.php 2026-05-22 07:44:50.000000000 +0000 @@ -10,6 +10,7 @@ \***************************************************************************/ use Spip\Compilateur\Noeud\Boucle; +use Spip\Compilateur\Noeud\Champ; use Spip\Compilateur\Noeud\Contexte; use Spip\Compilateur\Noeud\Inclure; use Spip\Compilateur\Noeud\Texte; @@ -904,11 +905,22 @@ return join(', ', $order); } -// Production du code PHP a partir de la sequence livree par le phraseur -// $boucles est passe par reference pour affectation par index_pile. -// Retourne une expression PHP, -// (qui sera argument d'un Return ou la partie droite d'une affectation). - +/** + * Production du code PHP à partir de la sequence livrée par le phraseur + * + * $boucles est passé par référence pour affectation par index_pile. + * Retourne une expression PHP, + * (qui sera argument d'un Return ou la partie droite d'une affectation). + * + * @api + * + * @param array $tableau + * @param string|array $descr + * @param-out array $boucles + * @param string $id_boucle + * + * @return false|string + */ function calculer_liste($tableau, $descr, &$boucles, $id_boucle = '') { if (!$tableau) { return "''"; @@ -974,12 +986,15 @@ define('_REGEXP_CONCAT_NON_VIDE', "/^(.*)[.]\s*'[^']+'\s*$/"); /** + * @internal + * * @uses choisir_traduction() * - * @param $tableau - * @param $descr - * @param $boucles - * @param $id_boucle + * @param array $tableau + * @param array $descr + * @param-out array $boucles + * @param string $id_boucle + * * @return array|false */ function compile_cas($tableau, $descr, &$boucles, $id_boucle) { diff -Nru spip-4.4.13+dfsg/ecrire/req/pg.exp.php spip-4.4.15+dfsg/ecrire/req/pg.exp.php --- spip-4.4.13+dfsg/ecrire/req/pg.exp.php 2026-03-06 10:13:42.000000000 +0000 +++ spip-4.4.15+dfsg/ecrire/req/pg.exp.php 2026-05-22 07:44:50.000000000 +0000 @@ -129,11 +129,14 @@ 'quote' => 'spip_pg_quote', 'replace' => 'spip_pg_replace', 'replace_multi' => 'spip_pg_replace_multi', + 'repair' => 'spip_pg_repair', 'select' => 'spip_pg_select', 'selectdb' => 'spip_pg_selectdb', - 'set_connect_charset' => 'spip_pg_set_connect_charset', + 'set_charset' => 'spip_pg_set_charset', + 'get_charset' => 'spip_pg_get_charset', 'showbase' => 'spip_pg_showbase', 'showtable' => 'spip_pg_showtable', + 'table_exists' => 'spip_pg_table_exists', 'update' => 'spip_pg_update', 'updateq' => 'spip_pg_updateq', ]; @@ -888,10 +891,11 @@ if (!$requeter) { return $r; } - if (!is_resource($r)) { + if ((!$r instanceof \PgSql\Result) && (!is_resource($r))) { return 0; } [$c] = pg_fetch_array($r, null, PGSQL_NUM); + pg_free_result($r); return $c; } @@ -1331,7 +1335,7 @@ function spip_pg_showbase($match, $serveur = '', $requeter = true) { $connexion = &$GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0]; $link = $connexion['link']; - $connexion['last'] = $q = 'SELECT tablename FROM pg_tables WHERE tablename ILIKE ' . _q($match); + $connexion['last'] = $q = 'SELECT table_name FROM information_schema.tables WHERE table_name ILIKE ' . _q($match); return spip_pg_query_simple($link, $q); } @@ -1365,6 +1369,32 @@ return count($fields) ? ['field' => $fields, 'key' => $keys] : false; } +/** + * Indiquer si une table existe dans la base de données + * + * + * @param string $table + * Table dont on cherche l’existence + * @param string $serveur + * Connecteur de la base + * @param bool $requeter + * true pour éxecuter la requête + * false pour retourner le texte de la requête. + * @return bool|string + * - true si la table existe, false sinon + * - string : requete sql, si $requeter = true + **/ +function spip_pg_table_exists(string $table, string $serveur = '', bool $requeter = true) { + $r = spip_pg_query( + 'SELECT * FROM information_schema.tables' . + ' WHERE table_name ILIKE ' . _q($table), $serveur, $requeter); + if (!$requeter) { + return $r; + } + $res = spip_pg_fetch($r); + return (bool) $res; +} + // Fonction de creation d'une table SQL nommee $nom // a partir de 2 tableaux PHP : // champs: champ => type @@ -1481,8 +1511,36 @@ } -function spip_pg_set_connect_charset($charset, $serveur = '', $requeter = true) { - spip_log('changement de charset sql a ecrire en PG', 'pg.' . _LOG_ERREUR); +/** + * Définir un charset pour la connexion avec Postgresql + * + * @param string $charset Charset à appliquer + * @param string $serveur Nom de la connexion + * @param bool $requeter inutilisé + * @return PgSql\Result|bool Jeu de résultats pour fetch() + */ +function spip_pg_set_charset(string $charset, string $serveur = '', bool $requeter = true) { + $connexion = $GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0]; + spip_log('changement de charset sql : ' . 'SET NAMES ' . _q($charset), 'pg.' . _LOG_DEBUG); + return pg_query($connexion['link'], $connexion['last'] = 'SET NAMES ' . _q($charset)); +} + + +/** + * Tester si le charset indiqué est disponible sur le serveur SQL + * + * @param array $charset Nom du charset à tester (élément de la clé 'charset') + * @param string $serveur Nom de la connexion + * @param bool $requeter inutilisé + * @return array Description du charset + */ +function spip_pg_get_charset(array $charset = [], string $serveur = '', bool $requeter = true) { + $connexion = $GLOBALS['connexions'][$serveur ? strtolower($serveur) : 0]; + $connexion['last'] = $c = 'SELECT * FROM information_schema.character_sets' + . (!$charset ? '' : (' WHERE character_set_name ILIKE' + . _q($charset['charset']))); + + return spip_pg_fetch(pg_query($connexion['link'], $c), null, $serveur); } @@ -1542,3 +1600,20 @@ function spip_versions_pg() { return function_exists('pg_connect'); } + +/** + * Réparer une table SQL + * + * Utilise `VACUUM FULL ...` de Postgresql + * + * @param string $table Nom de la table SQL + * @param string $serveur Nom de la connexion + * @param bool $requeter Exécuter la requête, sinon la retourner + * @return bool|string|array + * - string texte de la requête si demandée, + * - true si la requête a réussie, false sinon + */ +function spip_pg_repair(string $table, string $serveur = '', bool $requeter = true) { + return spip_pg_query("VACUUM FULL `$table`", $serveur, $requeter); +} + diff -Nru spip-4.4.13+dfsg/ecrire/src/Afficher/Minipage/AbstractPage.php spip-4.4.15+dfsg/ecrire/src/Afficher/Minipage/AbstractPage.php --- spip-4.4.13+dfsg/ecrire/src/Afficher/Minipage/AbstractPage.php 2026-03-06 10:13:42.000000000 +0000 +++ spip-4.4.15+dfsg/ecrire/src/Afficher/Minipage/AbstractPage.php 2026-05-22 07:44:50.000000000 +0000 @@ -241,10 +241,19 @@ public function page($corps, $options = []) { // par securite + // en cas d'erreur de connexion à la base SQL on arrive ici très tôt dans le hit if (!defined('_AJAX')) { define('_AJAX', false); } + if (!defined('_VAR_MODE')) { + /** + * Indique le mode de calcul ou d'affichage de la page. + * @see init_var_mode() + */ + define('_VAR_MODE', false); + } + $status = ((int) ($options['status'] ?? 200)) ?: 200; http_response_code($status); diff -Nru spip-4.4.13+dfsg/plugins-dist/aide/CHANGELOG.md spip-4.4.15+dfsg/plugins-dist/aide/CHANGELOG.md --- spip-4.4.13+dfsg/plugins-dist/aide/CHANGELOG.md 2026-03-06 10:17:16.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/aide/CHANGELOG.md 2026-05-22 07:52:14.000000000 +0000 @@ -1,5 +1,11 @@ # Changelog +## 3.2.7 - 2026-05-12 + +### Fixed + +- Autoriser PHP 8.5 dans le composer.json + ## 3.2.6 - 2025-09-08 ### Fixed diff -Nru spip-4.4.13+dfsg/plugins-dist/aide/composer.json spip-4.4.15+dfsg/plugins-dist/aide/composer.json --- spip-4.4.13+dfsg/plugins-dist/aide/composer.json 2026-03-06 10:17:16.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/aide/composer.json 2026-05-22 07:52:14.000000000 +0000 @@ -11,7 +11,7 @@ } ], "require": { - "php": "^7.4 || ^8.0 <=8.4" + "php": "^7.4 || ^8.0" }, "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^1.0", diff -Nru spip-4.4.13+dfsg/plugins-dist/aide/paquet.xml spip-4.4.15+dfsg/plugins-dist/aide/paquet.xml --- spip-4.4.13+dfsg/plugins-dist/aide/paquet.xml 2026-03-06 10:17:16.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/aide/paquet.xml 2026-05-22 07:52:14.000000000 +0000 @@ -1,7 +1,7 @@ [ + /*'tar' => [ true, 0, 'var/tmp/tar/test.tar', 'var/tmp/tar', [], 'var/tmp/tar/directory/test.txt', - ], + ],*/ 'tgz' => [ true, 0, @@ -297,14 +297,14 @@ [__DIR__ . '/../var/tmp/directory' => 'directory'], null, ], - 'tar' => [ + /*'tar' => [ true, 0, 'var/tmp/tar/emballer.tar', '', ['var/tmp/tar/directory/test.txt'], 'var/tmp/tar/directory', - ], + ],*/ 'tar2' => [ true, 0, diff -Nru spip-4.4.13+dfsg/plugins-dist/bigup/CHANGELOG.md spip-4.4.15+dfsg/plugins-dist/bigup/CHANGELOG.md --- spip-4.4.13+dfsg/plugins-dist/bigup/CHANGELOG.md 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/bigup/CHANGELOG.md 2026-05-22 07:52:16.000000000 +0000 @@ -1,5 +1,11 @@ # Changelog +## 3.3.10 - 2026-05-12 + +### Fixed + +- Autoriser PHP 8.5 dans le composer.json + ## 3.3.9 - 2026-02-12 ### Fixed diff -Nru spip-4.4.13+dfsg/plugins-dist/bigup/composer.json spip-4.4.15+dfsg/plugins-dist/bigup/composer.json --- spip-4.4.13+dfsg/plugins-dist/bigup/composer.json 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/bigup/composer.json 2026-05-22 07:52:16.000000000 +0000 @@ -11,7 +11,7 @@ } ], "require": { - "php": "^7.4 || ^8.0 <=8.4" + "php": "^7.4 || ^8.0" }, "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^1.0", diff -Nru spip-4.4.13+dfsg/plugins-dist/bigup/paquet.xml spip-4.4.15+dfsg/plugins-dist/bigup/paquet.xml --- spip-4.4.13+dfsg/plugins-dist/bigup/paquet.xml 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/bigup/paquet.xml 2026-05-22 07:52:16.000000000 +0000 @@ -1,7 +1,7 @@ page('Arguments de l\'action compagnon non compris'); exit; } $quoi = substr($arg, 8); diff -Nru spip-4.4.13+dfsg/plugins-dist/compagnon/composer.json spip-4.4.15+dfsg/plugins-dist/compagnon/composer.json --- spip-4.4.13+dfsg/plugins-dist/compagnon/composer.json 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/compagnon/composer.json 2026-05-22 07:52:16.000000000 +0000 @@ -17,6 +17,11 @@ "dealerdirect/phpcodesniffer-composer-installer": "^1.0", "spip/coding-standards": "^1.2" }, + "autoload-dev": { + "psr-4": { + "Spip\\": "tests/Fixtures/" + } + }, "config": { "allow-plugins": { "dealerdirect/phpcodesniffer-composer-installer": true diff -Nru spip-4.4.13+dfsg/plugins-dist/compagnon/paquet.xml spip-4.4.15+dfsg/plugins-dist/compagnon/paquet.xml --- spip-4.4.13+dfsg/plugins-dist/compagnon/paquet.xml 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/compagnon/paquet.xml 2026-05-22 07:52:16.000000000 +0000 @@ -1,7 +1,7 @@ $params + */ + public function installDebutPage(array $params = []): string { + return ''; + } + + /** + * @param array $options + */ + public function page(string $corps, array $options = []): string { + return ''; + } + + public function installFinPage(): string { + return ''; + } +} diff -Nru spip-4.4.13+dfsg/plugins-dist/dump/CHANGELOG.md spip-4.4.15+dfsg/plugins-dist/dump/CHANGELOG.md --- spip-4.4.13+dfsg/plugins-dist/dump/CHANGELOG.md 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/dump/CHANGELOG.md 2026-05-22 07:52:16.000000000 +0000 @@ -1,5 +1,17 @@ # Changelog +## 2.2.3 - 2026-05-22 + +### Fixed + +- !4736 spip/spip#6084 réparer la sauvegarde suite à !4736 + +## 2.2.2 - 2026-05-12 + +### Fixed + +- spip/spip#6084 remplacement appels minipres() en Minipage + ## 2.2.1 - 2025-02-18 ### Fixed diff -Nru spip-4.4.13+dfsg/plugins-dist/dump/action/telecharger_dump.php spip-4.4.15+dfsg/plugins-dist/dump/action/telecharger_dump.php --- spip-4.4.13+dfsg/plugins-dist/dump/action/telecharger_dump.php 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/dump/action/telecharger_dump.php 2026-05-22 07:52:16.000000000 +0000 @@ -9,6 +9,8 @@ * Ce programme est un logiciel libre distribué sous licence GNU/GPL. * \***************************************************************************/ +use Spip\Afficher\Minipage\Admin as MinipageAdmin; + if (!defined('_ECRIRE_INC_VERSION')) { return; } @@ -57,8 +59,8 @@ readfile($file); } else { http_response_code(404); - include_spip('inc/minipres'); - echo minipres(_T('erreur') . ' 404', _T('info_acces_interdit')); + $minipage = new MinipageAdmin(); + echo $minipage->page(_T('info_acces_interdit'), ['titre' => _T('erreur') . ' 404']); } // et on finit comme ca d'un coup diff -Nru spip-4.4.13+dfsg/plugins-dist/dump/base/restaurer.php spip-4.4.15+dfsg/plugins-dist/dump/base/restaurer.php --- spip-4.4.13+dfsg/plugins-dist/dump/base/restaurer.php 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/dump/base/restaurer.php 2026-05-22 07:52:16.000000000 +0000 @@ -42,7 +42,6 @@ } // parions sur une valeur tellement courante ... $max_time = time() + $timeout / 2; - include_spip('inc/minipres'); if (function_exists('ini_set')) { @ini_set('zlib.output_compression', '0'); // pour permettre l'affichage au fur et a mesure } diff -Nru spip-4.4.13+dfsg/plugins-dist/dump/composer.json spip-4.4.15+dfsg/plugins-dist/dump/composer.json --- spip-4.4.13+dfsg/plugins-dist/dump/composer.json 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/dump/composer.json 2026-05-22 07:52:16.000000000 +0000 @@ -17,6 +17,11 @@ "dealerdirect/phpcodesniffer-composer-installer": "^1.0", "spip/coding-standards": "^1.2" }, + "autoload-dev": { + "psr-4": { + "Spip\\": "tests/Fixtures" + } + }, "config": { "allow-plugins": { "dealerdirect/phpcodesniffer-composer-installer": true diff -Nru spip-4.4.13+dfsg/plugins-dist/dump/inc/sauvegarder.php spip-4.4.15+dfsg/plugins-dist/dump/inc/sauvegarder.php --- spip-4.4.13+dfsg/plugins-dist/dump/inc/sauvegarder.php 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/dump/inc/sauvegarder.php 2026-05-22 07:52:16.000000000 +0000 @@ -9,6 +9,8 @@ * Ce programme est un logiciel libre distribué sous licence GNU/GPL. * \***************************************************************************/ +use Spip\Afficher\Minipage\Admin as MinipageAdmin; + if (!defined('_ECRIRE_INC_VERSION')) { return; } @@ -38,7 +40,6 @@ } // parions sur une valeur tellement courante ... $max_time = time() + $timeout / 2; - include_spip('inc/minipres'); if (function_exists('ini_set')) { @ini_set('zlib.output_compression', '0'); // pour permettre l'affichage au fur et a mesure } @@ -46,7 +47,8 @@ $titre = _T('dump:sauvegarde_en_cours') . ' (' . (is_countable($status['tables']) ? count($status['tables']) : 0) . ') '; $balise_img = chercher_filtre('balise_img'); $titre .= $balise_img(chemin_image('loader.svg'), '', 'loader'); - echo(install_debut_html($titre)); + $minipage = new MinipageAdmin(); + echo $minipage->installDebutPage(['titre' => $titre]); // script de rechargement auto sur timeout echo http_script("window.setTimeout('location.href=\"" . $redirect . "\";'," . ($timeout * 1000) . ')'); echo "
\n"; @@ -71,7 +73,7 @@ if (!$res and $redirect) { echo dump_relance($redirect); } - echo(install_fin_html()); + echo $minipage->installFinPage(); if (@ob_get_contents()) { ob_end_flush(); } diff -Nru spip-4.4.13+dfsg/plugins-dist/dump/paquet.xml spip-4.4.15+dfsg/plugins-dist/dump/paquet.xml --- spip-4.4.13+dfsg/plugins-dist/dump/paquet.xml 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/dump/paquet.xml 2026-05-22 07:52:16.000000000 +0000 @@ -1,7 +1,7 @@ $params + */ + public function installDebutPage(array $params = []): string { + return ''; + } + + /** + * @param array $options + */ + public function page(string $corps, array $options = []): string { + return ''; + } + + public function installFinPage(): string { + return ''; + } +} diff -Nru spip-4.4.13+dfsg/plugins-dist/filtres_images/CHANGELOG.md spip-4.4.15+dfsg/plugins-dist/filtres_images/CHANGELOG.md --- spip-4.4.13+dfsg/plugins-dist/filtres_images/CHANGELOG.md 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/filtres_images/CHANGELOG.md 2026-05-22 07:52:16.000000000 +0000 @@ -1,5 +1,12 @@ # Changelog +## 4.3.7 - 2026-05-12 + +### Fixed + +- !4757 Dans certains cas avec SVG le filtre `svg_filter_sepia` est absent et nécessite d’être chargé +- Autoriser PHP 8.5 dans le composer.json + ## 4.3.6 - 2026-02-26 ### Fixed diff -Nru spip-4.4.13+dfsg/plugins-dist/filtres_images/composer.json spip-4.4.15+dfsg/plugins-dist/filtres_images/composer.json --- spip-4.4.13+dfsg/plugins-dist/filtres_images/composer.json 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/filtres_images/composer.json 2026-05-22 07:52:16.000000000 +0000 @@ -11,7 +11,7 @@ } ], "require": { - "php": "^7.4 || ^8.0 <=8.4" + "php": "^7.4 || ^8.0" }, "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^1.0", diff -Nru spip-4.4.13+dfsg/plugins-dist/filtres_images/filtres/images_transforme.php spip-4.4.15+dfsg/plugins-dist/filtres_images/filtres/images_transforme.php --- spip-4.4.13+dfsg/plugins-dist/filtres_images/filtres/images_transforme.php 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/filtres_images/filtres/images_transforme.php 2026-05-22 07:52:16.000000000 +0000 @@ -1658,7 +1658,8 @@ spip_timer('sepia'); $log = "image_sepia: caldul de $im par methode "; if ($image['format_source'] === 'svg') { - $log .= "svg"; + $log .= 'svg'; + include_spip('inc/svg'); #$svg = svg_transformer($im, ['style' => "filter:sepia(1);"]); // ne fonctionne pas dans Chrome+Safari $svg = svg_filter_sepia($im, 1); _image_gd_output($svg, $image); diff -Nru spip-4.4.13+dfsg/plugins-dist/filtres_images/paquet.xml spip-4.4.15+dfsg/plugins-dist/filtres_images/paquet.xml --- spip-4.4.13+dfsg/plugins-dist/filtres_images/paquet.xml 2026-03-06 10:17:18.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/filtres_images/paquet.xml 2026-05-22 07:52:16.000000000 +0000 @@ -1,7 +1,7 @@ page(''); + exit; break; case 404: http_response_code(404); - include_spip('inc/minipres'); - echo minipres(_T('erreur') . ' 404', _T('medias:info_document_indisponible')); + $minipage = new MinipageAdmin(); + echo $minipage->page(_T('medias:info_document_indisponible'), ['titre' => _T('erreur') . ' 404']); + exit; break; default: diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/action/copier_local.php spip-4.4.15+dfsg/plugins-dist/medias/action/copier_local.php --- spip-4.4.13+dfsg/plugins-dist/medias/action/copier_local.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/action/copier_local.php 2026-05-22 07:52:18.000000000 +0000 @@ -19,7 +19,7 @@ * Il s'agit de la partie logique, c'est a dire que cette fonction * realise la copie. * - * @param null $id_document + * @param null|int $id_document * @return bool|mixed|string */ function action_copier_local_dist($id_document = null) { diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/action/dissocier_document.php spip-4.4.15+dfsg/plugins-dist/medias/action/dissocier_document.php --- spip-4.4.13+dfsg/plugins-dist/medias/action/dissocier_document.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/action/dissocier_document.php 2026-05-22 07:52:18.000000000 +0000 @@ -23,7 +23,7 @@ /** * Dissocier un document * - * @param string $arg + * @param string|null $arg * fournit les arguments de la fonction dissocier_document * sous la forme `$id_objet-$objet-$document-suppr-safe` * diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/action/tourner.php spip-4.4.15+dfsg/plugins-dist/medias/action/tourner.php --- spip-4.4.13+dfsg/plugins-dist/medias/action/tourner.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/action/tourner.php 2026-05-22 07:52:18.000000000 +0000 @@ -50,9 +50,9 @@ * @return */ function action_tourner_post($id_document, $angle) { - $row = sql_fetsel('fichier,extension', 'spip_documents', 'id_document=' . intval($id_document)); + $row = sql_fetsel('fichier,extension,media', 'spip_documents', 'id_document=' . intval($id_document)); - if (!$row) { + if (!$row || $row['media'] !== 'image') { return; } @@ -63,7 +63,16 @@ $effacer = false; include_spip('inc/distant'); # pour copie_locale - $src = _DIR_RACINE . copie_locale(get_spip_doc($row['fichier'])); + $source = get_spip_doc($row['fichier']); + $callback_valider_url = null; + if (tester_url_absolue($source)) { + if (!valider_url_distante($source)) { + return; + } + $callback_valider_url = valider_url_distante(...); + } + $src = _DIR_RACINE . copie_locale($source, 'auto', null, null, $callback_valider_url); + if (preg_match(',^(.*)-r(90|180|270)\.([^.]+)$,', $src, $match)) { $effacer = $src; $src = $match[1] . '.' . $match[3]; diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/base/medias.php spip-4.4.15+dfsg/plugins-dist/medias/base/medias.php --- spip-4.4.13+dfsg/plugins-dist/medias/base/medias.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/base/medias.php 2026-05-22 07:52:18.000000000 +0000 @@ -195,11 +195,8 @@ 'mode', 'credits', 'alt', - 'fichier', 'distant', - 'extension', - 'id_vignette', - 'media' + 'id_vignette' ], 'champs_versionnes' => [ 'id_vignette', diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/composer.json spip-4.4.15+dfsg/plugins-dist/medias/composer.json --- spip-4.4.13+dfsg/plugins-dist/medias/composer.json 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/composer.json 2026-05-22 07:52:18.000000000 +0000 @@ -32,5 +32,10 @@ "platform": { "php": "7.4.33" } + }, + "autoload-dev": { + "psr-4": { + "Spip\\": "tests/Fixtures/" + } } } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/inc/getdocument.php spip-4.4.15+dfsg/plugins-dist/medias/inc/getdocument.php --- spip-4.4.13+dfsg/plugins-dist/medias/inc/getdocument.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/inc/getdocument.php 2026-05-22 07:52:18.000000000 +0000 @@ -9,6 +9,8 @@ * Ce programme est un logiciel libre distribué sous licence GNU/GPL. * \***************************************************************************/ +use Spip\Afficher\Minipage\Admin as MinipageAdmin; + /** * Gère un cas d'upload trop gros * @@ -29,18 +31,13 @@ // inclure les fonctions bases du core include_once _DIR_RESTREINT . 'inc/documents.php'; -include_spip('inc/minipres'); - - /** * Traite l'erreur d'un upload trop gros * * L'erreur est appelée depuis public.php et medias_detecter_fond_par_defaut * et affiche un minipres avec la taille limite de documents possibles - * - * @see minipres() - **/ -function erreur_upload_trop_gros() { + */ +function erreur_upload_trop_gros(): never { include_spip('inc/filtres'); $msg = '

' @@ -52,6 +49,7 @@ ) . '

'; - echo minipres(_T('pass_erreur'), "
" . $msg . '
'); + $minipage = new MinipageAdmin(); + echo $minipage->page('
' . $msg . '
', ['titre' => _T('pass_erreur')]); exit; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/extension.cache.dbm.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/extension.cache.dbm.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/extension.cache.dbm.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/extension.cache.dbm.php 2026-05-22 07:52:18.000000000 +0000 @@ -33,7 +33,7 @@ * getID3_cached usage: * * require_once 'getid3/getid3.php'; -* require_once 'getid3/getid3/extension.cache.dbm.php'; +* require_once 'getid3/extension.cache.dbm.php'; * $getID3 = new getID3_cached('db3', '/tmp/getid3_cache.dbm', * '/tmp/getid3_cache.lock'); * $getID3->encoding = 'UTF-8'; @@ -73,12 +73,12 @@ class getID3_cached_dbm extends getID3 { /** - * @var resource + * @var null|resource|Dba\Connection */ - private $dba; + private $dba; // @phpstan-ignore-line /** - * @var resource|bool + * @var resource|bool|null */ private $lock; @@ -93,6 +93,11 @@ private $dbm_filename; /** + * @var string + */ + private $lock_filename; + + /** * constructor - see top of this file for cache type and cache_options * * @param string $cache_type @@ -114,91 +119,102 @@ throw new Exception('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.'); } + // Store lock filename for cleanup operations + $this->lock_filename = $lock_filename; + // Create lock file if needed - if (!file_exists($lock_filename)) { - if (!touch($lock_filename)) { - throw new Exception('failed to create lock file: '.$lock_filename); + if (!file_exists($this->lock_filename)) { + if (!touch($this->lock_filename)) { + throw new Exception('failed to create lock file: '.$this->lock_filename); } } - // Open lock file for writing - if (!is_writeable($lock_filename)) { - throw new Exception('lock file: '.$lock_filename.' is not writable'); + // Open lock file for writing with read/write mode (w+) to prevent truncation on BSD systems + $this->lock = fopen($this->lock_filename, 'w+'); + if (!$this->lock) { + throw new Exception('Cannot open lock file: '.$this->lock_filename); } - $this->lock = fopen($lock_filename, 'w'); // Acquire exclusive write lock to lock file - flock($this->lock, LOCK_EX); - - // Create dbm-file if needed - if (!file_exists($dbm_filename)) { - if (!touch($dbm_filename)) { - throw new Exception('failed to create dbm file: '.$dbm_filename); - } + if (!flock($this->lock, LOCK_EX)) { + fclose($this->lock); + throw new Exception('Cannot acquire lock: '.$this->lock_filename); } - // Try to open dbm file for writing - $this->dba = dba_open($dbm_filename, 'w', $cache_type); - if (!$this->dba) { + // Store connection parameters + $this->cache_type = $cache_type; + $this->dbm_filename = $dbm_filename; - // Failed - create new dbm file - $this->dba = dba_open($dbm_filename, 'n', $cache_type); + try { + // Try to open existing DBM file + $this->dba = dba_open($this->dbm_filename, 'w', $this->cache_type); + // Create new DBM file if it didn't exist if (!$this->dba) { - throw new Exception('failed to create dbm file: '.$dbm_filename); + $this->dba = dba_open($this->dbm_filename, 'n', $this->cache_type); + if (!$this->dba) { + throw new Exception('failed to create dbm file: '.$this->dbm_filename); + } + + // Insert getID3 version number + dba_insert(getID3::VERSION, getID3::VERSION, $this->dba); } - // Insert getID3 version number - dba_insert(getID3::VERSION, getID3::VERSION, $this->dba); - } + // Check version number and clear cache if changed + if (dba_fetch(getID3::VERSION, $this->dba) != getID3::VERSION) { + $this->clear_cache(); + } - // Init misc values - $this->cache_type = $cache_type; - $this->dbm_filename = $dbm_filename; + } catch (Exception $e) { + $this->safe_close(); + throw $e; + } // Register destructor register_shutdown_function(array($this, '__destruct')); - // Check version number and clear cache if changed - if (dba_fetch(getID3::VERSION, $this->dba) != getID3::VERSION) { - $this->clear_cache(); - } - parent::__construct(); } - - /** - * destructor + * Destructor - ensure proper cleanup of resources */ public function __destruct() { - - // Close dbm file - dba_close($this->dba); - - // Release exclusive lock - flock($this->lock, LOCK_UN); - - // Close lock file - fclose($this->lock); + $this->safe_close(); } + /** + * Safely close all resources with error handling + */ + private function safe_close() { + try { + // Close DBM connection if open + if (is_resource($this->dba)) { + dba_close($this->dba); + $this->dba = null; + } + // Release lock if acquired + if (is_resource($this->lock)) { + flock($this->lock, LOCK_UN); + fclose($this->lock); + $this->lock = null; + } + } catch (Exception $e) { + error_log('getID3_cached_dbm cleanup error: ' . $e->getMessage()); + } + } /** - * clear cache + * Clear cache and recreate DBM file * * @throws Exception */ public function clear_cache() { - - // Close dbm file - dba_close($this->dba); + $this->safe_close(); // Create new dbm file $this->dba = dba_open($this->dbm_filename, 'n', $this->cache_type); - if (!$this->dba) { throw new Exception('failed to clear cache/recreate dbm file: '.$this->dbm_filename); } @@ -210,44 +226,45 @@ register_shutdown_function(array($this, '__destruct')); } - - /** - * clear cache + * Analyze file and cache results * - * @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='', $fp=null) { + try { + $key = null; + if (file_exists($filename)) { + // Calc key: filename::mod_time::size - should be unique + $key = $filename.'::'.filemtime($filename).'::'.filesize($filename); + + // Lookup key in cache + $result = dba_fetch($key, $this->dba); + + // Cache hit + if ($result !== false) { + return unserialize($result); + } + } - $key = null; - if (file_exists($filename)) { - - // Calc key filename::mod_time::size - should be unique - $key = $filename.'::'.filemtime($filename).'::'.filesize($filename); - - // Loopup key - $result = dba_fetch($key, $this->dba); + // Cache miss - perform actual analysis + $result = parent::analyze($filename, $filesize, $original_filename, $fp); - // Hit - if ($result !== false) { - return unserialize($result); + // Store result in cache if key was generated + if ($key !== null) { + dba_replace($key, serialize($result), $this->dba); } - } - // Miss - $result = parent::analyze($filename, $filesize, $original_filename, $fp); + return $result; - // Save result - if (isset($key) && file_exists($filename)) { - dba_insert($key, serialize($result), $this->dba); + } catch (Exception $e) { + $this->safe_close(); + throw $e; } - - return $result; } - } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/getid3.lib.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/getid3.lib.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/getid3.lib.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/getid3.lib.php 2026-05-22 07:52:18.000000000 +0000 @@ -11,14 +11,19 @@ // /// ///////////////////////////////////////////////////////////////// -if(!defined('GETID3_LIBXML_OPTIONS') && defined('LIBXML_VERSION')) { - if(LIBXML_VERSION >= 20621) { - define('GETID3_LIBXML_OPTIONS', LIBXML_NOENT | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_COMPACT); +if (!defined('GETID3_LIBXML_OPTIONS') && defined('LIBXML_VERSION')) { + if (LIBXML_VERSION >= 20621) { + define('GETID3_LIBXML_OPTIONS', LIBXML_NONET | LIBXML_NOWARNING | LIBXML_COMPACT); } else { - define('GETID3_LIBXML_OPTIONS', LIBXML_NOENT | LIBXML_NONET | LIBXML_NOWARNING); + define('GETID3_LIBXML_OPTIONS', LIBXML_NONET | LIBXML_NOWARNING); } } +// Available since PHP 7.0 (2015-Dec-03 https://www.php.net/ChangeLog-7.php) +if (!defined('PHP_INT_MIN')) { + define('PHP_INT_MIN', ~PHP_INT_MAX); +} + class getid3_lib { /** @@ -73,6 +78,7 @@ /** * @param int|null $variable + * @param-out int $variable * @param int $increment * * @return bool @@ -112,19 +118,20 @@ * @return bool */ public static function intValueSupported($num) { - // check if integers are 64-bit - static $hasINT64 = null; - if ($hasINT64 === null) { // 10x faster than is_null() - $hasINT64 = is_int(pow(2, 31)); // 32-bit int are limited to (2^31)-1 - if (!$hasINT64 && !defined('PHP_INT_MIN')) { - define('PHP_INT_MIN', ~PHP_INT_MAX); - } - } - // if integers are 64-bit - no other check required - if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) { - return true; - } - return false; + // really should be <= and >= but trying "(int)9.2233720368548E+18" results in PHP warning "The float 9.2233720368548E+18 is not representable as an int, cast occurred" + return (($num < PHP_INT_MAX) && ($num > PHP_INT_MIN)); + } + + /** + * Perform a division, guarding against division by zero + * + * @param float|int $numerator + * @param float|int $denominator + * @param float|int $fallback + * @return float|int + */ + public static function SafeDiv($numerator, $denominator, $fallback = 0) { + return $denominator ? $numerator / $denominator : $fallback; } /** @@ -134,7 +141,7 @@ */ public static function DecimalizeFraction($fraction) { list($numerator, $denominator) = explode('/', $fraction); - return $numerator / ($denominator ? $denominator : 1); + return (int) $numerator / ($denominator ? $denominator : 1); } /** @@ -428,7 +435,7 @@ } /** - * @param int $number + * @param int|string $number * * @return string */ @@ -732,16 +739,36 @@ * @return array|false */ public static function XML2array($XMLstring) { - if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) { - // http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html - // https://core.trac.wordpress.org/changeset/29378 - // This function has been deprecated in PHP 8.0 because in libxml 2.9.0, external entity loading is - // disabled by default, but is still needed when LIBXML_NOENT is used. - $loader = @libxml_disable_entity_loader(true); - $XMLobject = simplexml_load_string($XMLstring, 'SimpleXMLElement', GETID3_LIBXML_OPTIONS); - $return = self::SimpleXMLelement2array($XMLobject); - @libxml_disable_entity_loader($loader); - return $return; + if (function_exists('simplexml_load_string')) { + if (PHP_VERSION_ID < 80000) { + if (function_exists('libxml_disable_entity_loader')) { + // http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html + // https://core.trac.wordpress.org/changeset/29378 + // This function has been deprecated in PHP 8.0 because in libxml 2.9.0, external entity loading is + // disabled by default, but is still needed when LIBXML_NOENT is used. + $loader = @libxml_disable_entity_loader(true); + $XMLobject = simplexml_load_string($XMLstring, 'SimpleXMLElement', GETID3_LIBXML_OPTIONS); + $return = self::SimpleXMLelement2array($XMLobject); + @libxml_disable_entity_loader($loader); + return $return; + } + } else { + $allow = false; + if (defined('LIBXML_VERSION') && (LIBXML_VERSION >= 20900)) { + // https://www.php.net/manual/en/function.libxml-disable-entity-loader.php + // "as of libxml 2.9.0 entity substitution is disabled by default, so there is no need to disable the loading + // of external entities, unless there is the need to resolve internal entity references with LIBXML_NOENT." + $allow = true; + } elseif (function_exists('libxml_set_external_entity_loader')) { + libxml_set_external_entity_loader(function () { return null; }); // https://www.zend.com/blog/cve-2023-3823 + $allow = true; + } + if ($allow) { + $XMLobject = simplexml_load_string($XMLstring, 'SimpleXMLElement', GETID3_LIBXML_OPTIONS); + $return = self::SimpleXMLelement2array($XMLobject); + return $return; + } + } } return false; } @@ -871,10 +898,6 @@ * @return string */ public static function iconv_fallback_iso88591_utf8($string, $bom=false) { - if (function_exists('utf8_encode')) { - return utf8_encode($string); - } - // utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) $newcharstring = ''; if ($bom) { $newcharstring .= "\xEF\xBB\xBF"; @@ -943,10 +966,6 @@ * @return string */ public static function iconv_fallback_utf8_iso88591($string) { - if (function_exists('utf8_decode')) { - return utf8_decode($string); - } - // utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) $newcharstring = ''; $offset = 0; $stringlength = strlen($string); @@ -1493,7 +1512,7 @@ public static function GetDataImageSize($imgData, &$imageinfo=array()) { if (PHP_VERSION_ID >= 50400) { $GetDataImageSize = @getimagesizefromstring($imgData, $imageinfo); - if ($GetDataImageSize === false || !isset($GetDataImageSize[0], $GetDataImageSize[1])) { + if ($GetDataImageSize === false) { return false; } $GetDataImageSize['height'] = $GetDataImageSize[0]; @@ -1521,7 +1540,7 @@ fwrite($tmp, $imgData); fclose($tmp); $GetDataImageSize = @getimagesize($tempfilename, $imageinfo); - if (($GetDataImageSize === false) || !isset($GetDataImageSize[0]) || !isset($GetDataImageSize[1])) { + if ($GetDataImageSize === false) { return false; } $GetDataImageSize['height'] = $GetDataImageSize[0]; @@ -1715,7 +1734,7 @@ // METHOD B: cache all keys in this lookup - more memory but faster on next lookup of not-previously-looked-up key //$cache[$file][$name][substr($line, 0, $keylength)] = trim(substr($line, $keylength + 1)); $explodedLine = explode("\t", $line, 2); - $ThisKey = (isset($explodedLine[0]) ? $explodedLine[0] : ''); + $ThisKey = $explodedLine[0]; $ThisValue = (isset($explodedLine[1]) ? $explodedLine[1] : ''); $cache[$file][$name][$ThisKey] = trim($ThisValue); } @@ -1784,7 +1803,7 @@ $commandline = 'ls -l '.escapeshellarg($path).' | awk \'{print $5}\''; } if (isset($commandline)) { - $output = trim(`$commandline`); + $output = trim(shell_exec($commandline)); if (ctype_digit($output)) { $filesize = (float) $output; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/getid3.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/getid3.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/getid3.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/getid3.php 2026-05-22 07:52:18.000000000 +0000 @@ -387,7 +387,7 @@ */ protected $startup_warning = ''; - const VERSION = '1.9.22-202207161647'; + const VERSION = '1.9.25-202603080933'; const FREAD_BUFFER_SIZE = 32768; const ATTACHMENTS_NONE = false; @@ -409,10 +409,10 @@ $memoryLimit = ini_get('memory_limit'); if (preg_match('#([0-9]+) ?M#i', $memoryLimit, $matches)) { // could be stored as "16M" rather than 16777216 for example - $memoryLimit = $matches[1] * 1048576; + $memoryLimit = (int) $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 - $memoryLimit = $matches[1] * 1073741824; + $memoryLimit = (int) $matches[1] * 1073741824; } $this->memory_limit = $memoryLimit; @@ -436,11 +436,11 @@ $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 in PHP < 7.4.0 (when these functions became deprecated) - if (version_compare(PHP_VERSION, '7.4.0', '<')) { + // check for magic quotes in PHP < 5.4.0 (when these options were removed and getters always return false) + if (version_compare(PHP_VERSION, '5.4.0', '<')) { // Check for magic_quotes_runtime if (function_exists('get_magic_quotes_runtime')) { - if (get_magic_quotes_runtime()) { + if (get_magic_quotes_runtime()) { // @phpstan-ignore-line $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"; } } @@ -481,7 +481,7 @@ if (strpos($value, ' ') !== false) { if (!empty($path_so_far)) { $commandline = 'dir /x '.escapeshellarg(implode(DIRECTORY_SEPARATOR, $path_so_far)); - $dir_listing = `$commandline`; + $dir_listing = shell_exec($commandline); $lines = explode("\n", $dir_listing); foreach ($lines as $line) { $line = trim($line); @@ -529,7 +529,7 @@ * @return bool */ public function setOption($optArray) { - if (!is_array($optArray) || empty($optArray)) { + if (empty($optArray)) { return false; } foreach ($optArray as $opt => $val) { @@ -680,6 +680,8 @@ catch (getid3_exception $e) { throw $e; } + } else { + $this->warning('skipping check for '.$tag_name.' tags since option_tag_'.$tag_name.'=FALSE'); } } if (isset($this->info['id3v2']['tag_offset_start'])) { @@ -1464,9 +1466,29 @@ 'fail_ape' => 'ERROR', ), + // XZ - data - XZ compressed data + '7zip' => array( + 'pattern' => '^7z\\xBC\\xAF\\x27\\x1C', + 'group' => 'archive', + 'module' => '7zip', + 'mime_type' => 'application/x-7z-compressed', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + // Misc other formats + // GPX - data - GPS Exchange Format + 'gpx' => array ( + 'pattern' => '^<\\?xml [^>]+>[\s]* 'misc', + 'module' => 'gpx', + 'mime_type' => 'application/gpx+xml', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + // PAR2 - data - Parity Volume Set Specification 2.0 'par2' => array ( 'pattern' => '^PAR2\\x00PKT', @@ -1799,7 +1821,7 @@ if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) { $commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w -c "'.$empty.'" "'.$file.'" "'.$temp.'"'; - $VorbisCommentError = `$commandline`; + $VorbisCommentError = shell_exec($commandline); } else { @@ -1810,7 +1832,7 @@ } else { $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1'; - $VorbisCommentError = `$commandline`; + $VorbisCommentError = shell_exec($commandline); } @@ -1880,8 +1902,8 @@ // Calculate combined bitrate - audio + video $CombinedBitrate = 0; - $CombinedBitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0); - $CombinedBitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0); + $CombinedBitrate += (isset($this->info['audio']['bitrate']) && ($this->info['audio']['bitrate'] != 'free') ? $this->info['audio']['bitrate'] : 0); + $CombinedBitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0); if (($CombinedBitrate > 0) && empty($this->info['bitrate'])) { $this->info['bitrate'] = $CombinedBitrate; } @@ -1929,6 +1951,12 @@ if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) { $this->info['playtime_string'] = getid3_lib::PlaytimeString($this->info['playtime_seconds']); } + + // Look up codec name if fourcc is set but codec is not + if (!empty($this->info['video']['fourcc']) && !isset($this->info['video']['codec'])) { + $this->include_module('audio-video.riff'); + $this->info['video']['codec'] = getid3_riff::fourccLookup($this->info['video']['fourcc']); + } } /** @@ -1977,7 +2005,7 @@ } $BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate; - $this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed; + $this->info['video']['compression_ratio'] = getid3_lib::SafeDiv($BitrateCompressed, $BitrateUncompressed, 1); return true; } @@ -1988,7 +2016,9 @@ if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate']) || !is_numeric($this->info['audio']['sample_rate'])) { return false; } - $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16)); + if ($this->info['audio']['bitrate'] != 'free') { + $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16)); + } if (!empty($this->info['audio']['streams'])) { foreach ($this->info['audio']['streams'] as $streamnumber => $streamdata) { @@ -2183,6 +2213,8 @@ } /** + * @phpstan-impure + * * @return int|bool */ protected function ftell() { @@ -2195,6 +2227,8 @@ /** * @param int $bytes * + * @phpstan-impure + * * @return string|false * * @throws getid3_exception @@ -2240,6 +2274,8 @@ * @param int $bytes * @param int $whence * + * @phpstan-impure + * * @return int * * @throws getid3_exception @@ -2281,6 +2317,8 @@ } /** + * @phpstan-impure + * * @return string|false * * @throws getid3_exception @@ -2336,6 +2374,8 @@ } /** + * @phpstan-impure + * * @return bool */ protected function feof() { diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.archive.7zip.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.archive.7zip.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.archive.7zip.php 1970-01-01 00:00:00.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.archive.7zip.php 2026-05-22 07:52:18.000000000 +0000 @@ -0,0 +1,52 @@ + // +// available at https://github.com/JamesHeinrich/getID3 // +// or https://www.getid3.org // +// or http://getid3.sourceforge.net // +// see readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.archive.7zip.php // +// module for analyzing 7zip files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + +if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers + exit; +} + +class getid3_7zip extends getid3_handler +{ + /** + * @return bool + */ + public function Analyze() { + $info = &$this->getid3->info; + + $this->fseek($info['avdataoffset']); + $z7header = $this->fread(32); + + // https://py7zr.readthedocs.io/en/latest/archive_format.html + $info['7zip']['header']['magic'] = substr($z7header, 0, 6); + if ($info['7zip']['header']['magic'] != '7z'."\xBC\xAF\x27\x1C") { + $this->error('Invalid 7zip stream header magic (expecting 37 7A BC AF 27 1C, found '.getid3_lib::PrintHexBytes($info['7zip']['header']['magic']).') at offset '.$info['avdataoffset']); + return false; + } + $info['fileformat'] = '7zip'; + + $info['7zip']['header']['version_major'] = getid3_lib::LittleEndian2Int(substr($z7header, 6, 1)); // always 0x00 (?) + $info['7zip']['header']['version_minor'] = getid3_lib::LittleEndian2Int(substr($z7header, 7, 1)); // always 0x04 (?) + $info['7zip']['header']['start_header_crc'] = getid3_lib::LittleEndian2Int(substr($z7header, 8, 4)); + $info['7zip']['header']['next_header_offset'] = getid3_lib::LittleEndian2Int(substr($z7header, 12, 8)); + $info['7zip']['header']['next_header_size'] = getid3_lib::LittleEndian2Int(substr($z7header, 20, 8)); + $info['7zip']['header']['next_header_crc'] = getid3_lib::LittleEndian2Int(substr($z7header, 28, 4)); + +$this->error('7zip parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); + return false; + + } + +} diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.archive.hpk.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.archive.hpk.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.archive.hpk.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.archive.hpk.php 2026-05-22 07:52:18.000000000 +0000 @@ -43,7 +43,7 @@ $info['hpk']['header']['fragmented_filesystem_offset'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 28, 4)); $info['hpk']['header']['fragmented_filesystem_length'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 32, 4)); - $info['hpk']['header']['filesystem_entries'] = $info['hpk']['header']['fragmented_filesystem_length'] / ($info['hpk']['header']['fragments_per_file'] * 8); + $info['hpk']['header']['filesystem_entries'] = getid3_lib::SafeDiv($info['hpk']['header']['fragmented_filesystem_length'], $info['hpk']['header']['fragments_per_file'] * 8); $this->fseek($info['hpk']['header']['fragmented_filesystem_offset']); for ($i = 0; $i < $info['hpk']['header']['filesystem_entries']; $i++) { $offset = getid3_lib::LittleEndian2Int($this->fread(4)); diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.archive.tar.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.archive.tar.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.archive.tar.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.archive.tar.php 2026-05-22 07:52:18.000000000 +0000 @@ -99,7 +99,7 @@ if ($name == '') { break; } - $info['tar']['file_details'][$name] = array ( + $info['tar']['file_details'][] = array ( 'name' => $name, 'mode_raw' => $mode, 'mode' => self::display_perms($mode), @@ -117,7 +117,7 @@ 'devmajor' => $devmaj, 'devminor' => $devmin ); - $info['tar']['files'] = getid3_lib::array_merge_clobber($info['tar']['files'], getid3_lib::CreateDeepArray($info['tar']['file_details'][$name]['name'], '/', $size)); + $info['tar']['files'] = getid3_lib::array_merge_clobber($info['tar']['files'], getid3_lib::CreateDeepArray($name, '/', $size)); } return true; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.asf.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.asf.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.asf.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.asf.php 2026-05-22 07:52:18.000000000 +0000 @@ -193,7 +193,7 @@ $info['playtime_seconds'] = ($thisfile_asf_filepropertiesobject['play_duration'] / 10000000) - ($thisfile_asf_filepropertiesobject['preroll'] / 1000); //$info['bitrate'] = $thisfile_asf_filepropertiesobject['max_bitrate']; - $info['bitrate'] = ((isset($thisfile_asf_filepropertiesobject['filesize']) ? $thisfile_asf_filepropertiesobject['filesize'] : $info['filesize']) * 8) / $info['playtime_seconds']; + $info['bitrate'] = getid3_lib::SafeDiv($thisfile_asf_filepropertiesobject['filesize'] * 8, $info['playtime_seconds']); } break; @@ -336,7 +336,7 @@ // shortcut $thisfile_asf['codec_list_object'] = array(); /** @var mixed[] $thisfile_asf_codeclistobject */ - $thisfile_asf_codeclistobject = &$thisfile_asf['codec_list_object']; + $thisfile_asf_codeclistobject = &$thisfile_asf['codec_list_object']; // @phpstan-ignore-line $thisfile_asf_codeclistobject['offset'] = $NextObjectOffset + $offset; $thisfile_asf_codeclistobject['objectid'] = $NextObjectGUID; @@ -499,13 +499,17 @@ $offset += 2; $thisfile_asf_scriptcommandobject['command_types_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); $offset += 2; - for ($CommandTypesCounter = 0; $CommandTypesCounter < $thisfile_asf_scriptcommandobject['command_types_count']; $CommandTypesCounter++) { - $CommandTypeNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character - $offset += 2; - $thisfile_asf_scriptcommandobject['command_types'][$CommandTypesCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength); - $offset += $CommandTypeNameLength; + if ($thisfile_asf_scriptcommandobject['command_types_count'] > 0) { + $thisfile_asf_scriptcommandobject['command_types'] = array(); + for ($CommandTypesCounter = 0; $CommandTypesCounter < (int) $thisfile_asf_scriptcommandobject['command_types_count']; $CommandTypesCounter++) { + $CommandTypeNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character + $offset += 2; + $thisfile_asf_scriptcommandobject['command_types'][$CommandTypesCounter] = array(); + $thisfile_asf_scriptcommandobject['command_types'][$CommandTypesCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength); + $offset += $CommandTypeNameLength; + } } - for ($CommandsCounter = 0; $CommandsCounter < $thisfile_asf_scriptcommandobject['commands_count']; $CommandsCounter++) { + for ($CommandsCounter = 0; $CommandsCounter < (int) $thisfile_asf_scriptcommandobject['commands_count']; $CommandsCounter++) { $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['presentation_time'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); $offset += 4; $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['type_index'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); @@ -554,6 +558,8 @@ break; } $thisfile_asf_markerobject['markers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + /** @var int|float|false $totalMakersCount */ + $totalMakersCount = $thisfile_asf_markerobject['markers_count']; $offset += 4; $thisfile_asf_markerobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); $offset += 2; @@ -565,7 +571,8 @@ $offset += 2; $thisfile_asf_markerobject['name'] = substr($ASFHeaderData, $offset, $thisfile_asf_markerobject['name_length']); $offset += $thisfile_asf_markerobject['name_length']; - for ($MarkersCounter = 0; $MarkersCounter < $thisfile_asf_markerobject['markers_count']; $MarkersCounter++) { + for ($MarkersCounter = 0; $MarkersCounter < $totalMakersCount; $MarkersCounter++) { + $thisfile_asf_markerobject['markers'][$MarkersCounter] = array(); $thisfile_asf_markerobject['markers'][$MarkersCounter]['offset'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); $offset += 8; $thisfile_asf_markerobject['markers'][$MarkersCounter]['presentation_time'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); @@ -615,7 +622,7 @@ } $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); $offset += 2; - for ($StreamNumberCounter = 0; $StreamNumberCounter < $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count']; $StreamNumberCounter++) { + for ($StreamNumberCounter = 0; $StreamNumberCounter < (int) $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count']; $StreamNumberCounter++) { $thisfile_asf_bitratemutualexclusionobject['stream_numbers'][$StreamNumberCounter] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); $offset += 2; } @@ -759,7 +766,7 @@ $thisfile_asf_extendedcontentdescriptionobject['objectsize'] = $NextObjectSize; $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); $offset += 2; - for ($ExtendedContentDescriptorsCounter = 0; $ExtendedContentDescriptorsCounter < $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count']; $ExtendedContentDescriptorsCounter++) { + for ($ExtendedContentDescriptorsCounter = 0; $ExtendedContentDescriptorsCounter < (int) $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count']; $ExtendedContentDescriptorsCounter++) { // shortcut $thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter] = array(); $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current = &$thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter]; @@ -957,7 +964,8 @@ $thisfile_asf_streambitratepropertiesobject['objectsize'] = $NextObjectSize; $thisfile_asf_streambitratepropertiesobject['bitrate_records_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); $offset += 2; - for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) { + for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < (int) $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) { + $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter] = array(); $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); $offset += 2; $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags']['stream_number'] = $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] & 0x007F; @@ -1006,7 +1014,7 @@ if (isset($thisfile_asf_streambitratepropertiesobject['bitrate_records_count'])) { $ASFbitrateAudio = 0; $ASFbitrateVideo = 0; - for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) { + for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < (int) $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) { if (isset($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter])) { switch ($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter]['type_raw']) { case 1: @@ -1030,7 +1038,7 @@ $thisfile_video['bitrate'] = $ASFbitrateVideo; } } - if (isset($thisfile_asf['stream_properties_object']) && is_array($thisfile_asf['stream_properties_object'])) { + if (isset($thisfile_asf['stream_properties_object'])) { $thisfile_audio['bitrate'] = 0; $thisfile_video['bitrate'] = 0; @@ -1066,8 +1074,8 @@ break; } - if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { - foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { + if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { // @phpstan-ignore-line + foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { // @phpstan-ignore-line if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) { $thisfile_asf_audiomedia_currentstream['bitrate'] = $dataarray['bitrate']; $thisfile_audio['bitrate'] += $dataarray['bitrate']; @@ -1152,8 +1160,8 @@ $videomediaoffset += 4; $thisfile_asf_videomedia_currentstream['format_data']['codec_data'] = substr($streamdata['type_specific_data'], $videomediaoffset); - if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { - foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { + if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { // @phpstan-ignore-line + foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { // @phpstan-ignore-line if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) { $thisfile_asf_videomedia_currentstream['bitrate'] = $dataarray['bitrate']; $thisfile_video['streams'][$streamnumber]['bitrate'] = $dataarray['bitrate']; @@ -1266,10 +1274,13 @@ $thisfile_asf_simpleindexobject['maximum_packet_count'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4)); $offset += 4; $thisfile_asf_simpleindexobject['index_entries_count'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4)); + /** @var int|float|false $totalIndexEntriesCount */ + $totalIndexEntriesCount = $thisfile_asf_simpleindexobject['index_entries_count']; $offset += 4; - $IndexEntriesData = $SimpleIndexObjectData.$this->fread(6 * $thisfile_asf_simpleindexobject['index_entries_count']); - for ($IndexEntriesCounter = 0; $IndexEntriesCounter < $thisfile_asf_simpleindexobject['index_entries_count']; $IndexEntriesCounter++) { + $IndexEntriesData = $SimpleIndexObjectData.$this->fread(6 * $totalIndexEntriesCount); + for ($IndexEntriesCounter = 0; $IndexEntriesCounter < $totalIndexEntriesCount; $IndexEntriesCounter++) { + $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter] = array(); $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_number'] = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4)); $offset += 4; $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_count'] = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4)); @@ -1320,9 +1331,10 @@ $offset += 4; $ASFIndexObjectData .= $this->fread(4 * $thisfile_asf_asfindexobject['index_specifiers_count']); - for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { + for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < (int) $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { $IndexSpecifierStreamNumber = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); $offset += 2; + $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter] = array(); $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['stream_number'] = $IndexSpecifierStreamNumber; $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); $offset += 2; @@ -1331,17 +1343,19 @@ $ASFIndexObjectData .= $this->fread(4); $thisfile_asf_asfindexobject['index_entry_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); + /** @var int|float|false $totalIndexEntryCount */ + $totalIndexEntryCount = $thisfile_asf_asfindexobject['index_entry_count']; $offset += 4; $ASFIndexObjectData .= $this->fread(8 * $thisfile_asf_asfindexobject['index_specifiers_count']); - for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { + for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < (int) $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { $thisfile_asf_asfindexobject['block_positions'][$IndexSpecifiersCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 8)); $offset += 8; } $ASFIndexObjectData .= $this->fread(4 * $thisfile_asf_asfindexobject['index_specifiers_count'] * $thisfile_asf_asfindexobject['index_entry_count']); - for ($IndexEntryCounter = 0; $IndexEntryCounter < $thisfile_asf_asfindexobject['index_entry_count']; $IndexEntryCounter++) { - for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { + for ($IndexEntryCounter = 0; $IndexEntryCounter < $totalIndexEntryCount; $IndexEntryCounter++) { + for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < (int) $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { $thisfile_asf_asfindexobject['offsets'][$IndexSpecifiersCounter][$IndexEntryCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); $offset += 4; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.ivf.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.ivf.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.ivf.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.ivf.php 2026-05-22 07:52:18.000000000 +0000 @@ -33,7 +33,7 @@ if (substr($IVFheader, 0, 4) == 'DKIF') { - // https://wiki.multimedia.cx/index.php/IVF + // https://wiki.multimedia.cx/index.php/Duck_IVF $info['ivf']['header']['signature'] = substr($IVFheader, 0, 4); $info['ivf']['header']['version'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 4, 2)); // should be 0 $info['ivf']['header']['headersize'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 6, 2)); @@ -45,16 +45,12 @@ $info['ivf']['header']['frame_count'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 24, 4)); //$info['ivf']['header']['reserved'] = substr($IVFheader, 28, 4); - $info['ivf']['header']['frame_rate'] = (float) $info['ivf']['header']['timebase_numerator'] / $info['ivf']['header']['timebase_denominator']; + $info['ivf']['header']['frame_rate'] = (float)getid3_lib::SafeDiv($info['ivf']['header']['timebase_numerator'], $info['ivf']['header']['timebase_denominator']); if ($info['ivf']['header']['version'] > 0) { $this->warning('Expecting IVF header version 0, found version '.$info['ivf']['header']['version'].', results may not be accurate'); } - $info['video']['resolution_x'] = $info['ivf']['header']['resolution_x']; - $info['video']['resolution_y'] = $info['ivf']['header']['resolution_y']; - $info['video']['codec'] = $info['ivf']['header']['fourcc']; - $info['ivf']['frame_count'] = 0; $timestamp = 0; while (!$this->feof()) { @@ -65,9 +61,17 @@ $info['ivf']['frame_count']++; } } - if ($info['ivf']['frame_count']) { - $info['playtime_seconds'] = $timestamp / 100000; - $info['video']['frame_rate'] = (float) $info['ivf']['frame_count'] / $info['playtime_seconds']; + //if ($info['ivf']['frame_count'] && $timestamp) { + // $info['playtime_seconds'] = $timestamp / 100000; + // $info['video']['frame_rate'] = (float) $info['ivf']['frame_count'] / $info['playtime_seconds']; + //} + + $info['video']['resolution_x'] = $info['ivf']['header']['resolution_x']; + $info['video']['resolution_y'] = $info['ivf']['header']['resolution_y']; + $info['video']['fourcc'] = $info['ivf']['header']['fourcc']; + if ($info['ivf']['header']['frame_count'] && $info['ivf']['header']['frame_rate']) { + $info['video']['frame_rate'] = (float) $info['ivf']['header']['frame_rate']; + $info['playtime_seconds'] = (float) $info['ivf']['frame_count'] / $info['ivf']['header']['frame_rate']; } } else { diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.matroska.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.matroska.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.matroska.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.matroska.php 2026-05-22 07:52:18.000000000 +0000 @@ -211,6 +211,19 @@ /** + * Matroska constants + */ +define('MATROSKA_DEFAULT_TIMECODESCALE', 1000000); + +/** + * Matroska scan modes are internal state flags for how much of the file we are scanning + */ +define('MATROSKA_SCAN_HEADER', 0); +define('MATROSKA_SCAN_WHOLE_FILE', 1); +define('MATROSKA_SCAN_FIRST_CLUSTER', 2); +define('MATROSKA_SCAN_LAST_CLUSTER', 3); + +/** * @tutorial http://www.matroska.org/technical/specs/index.html * * @todo Rewrite EBML parser to reduce it's size and honor default element values @@ -241,6 +254,7 @@ private $EBMLbuffer_length = 0; private $current_offset = 0; private $unuseful_elements = array(EBML_ID_CRC32, EBML_ID_VOID); + private $scan_mode = MATROSKA_SCAN_HEADER; /** * @return bool @@ -248,6 +262,7 @@ public function Analyze() { $info = &$this->getid3->info; + $this->scan_mode = $this->parse_whole_file ? MATROSKA_SCAN_WHOLE_FILE : MATROSKA_SCAN_HEADER; // parse container try { @@ -256,14 +271,25 @@ $this->error('EBML parser: '.$e->getMessage()); } - // calculate playtime - if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) { - foreach ($info['matroska']['info'] as $key => $infoarray) { - if (isset($infoarray['Duration'])) { - // TimecodeScale is how many nanoseconds each Duration unit is - $info['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : 1000000) / 1000000000); - break; - } + $this->playtimeFromMetadata($info); + + // If there was no duration metadata, this might be an incomplete file or a streaming file + // We need Cluster information so we can use their timecodes to estimate playtime. + if (!isset($info['playtime_seconds']) && !$this->parse_whole_file) { + // Scan the start and end of file for Clusters to estimate duration + $this->scanStartEndForClusters($info); + } + + if (isset($info['matroska']['cluster']) && is_array($info['matroska']['cluster'])) { + if (!isset($info['playtime_seconds']) && !empty($info['matroska']['cluster'])) { + // estimate playtime using clusters if not yet known + $this->calculatePlaytimeFromClusters($info); + } + + // Remove cluster information from output if hide_clusters is true + // These could have been set during scanStartEndForClusters() + if ($this->hide_clusters) { + unset($info['matroska']['cluster']); } } @@ -292,12 +318,12 @@ $track_info['display_x'] = (isset($trackarray['DisplayWidth']) ? $trackarray['DisplayWidth'] : $trackarray['PixelWidth']); $track_info['display_y'] = (isset($trackarray['DisplayHeight']) ? $trackarray['DisplayHeight'] : $trackarray['PixelHeight']); - if (isset($trackarray['PixelCropBottom'])) { $track_info['crop_bottom'] = $trackarray['PixelCropBottom']; } - if (isset($trackarray['PixelCropTop'])) { $track_info['crop_top'] = $trackarray['PixelCropTop']; } - if (isset($trackarray['PixelCropLeft'])) { $track_info['crop_left'] = $trackarray['PixelCropLeft']; } - if (isset($trackarray['PixelCropRight'])) { $track_info['crop_right'] = $trackarray['PixelCropRight']; } - if (isset($trackarray['DefaultDuration'])) { $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3); } - if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; } + if (isset($trackarray['PixelCropBottom'])) { $track_info['crop_bottom'] = $trackarray['PixelCropBottom']; } + if (isset($trackarray['PixelCropTop'])) { $track_info['crop_top'] = $trackarray['PixelCropTop']; } + if (isset($trackarray['PixelCropLeft'])) { $track_info['crop_left'] = $trackarray['PixelCropLeft']; } + if (isset($trackarray['PixelCropRight'])) { $track_info['crop_right'] = $trackarray['PixelCropRight']; } + if (!empty($trackarray['DefaultDuration'])) { $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3); } + if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; } switch ($trackarray['CodecID']) { case 'V_MS/VFW/FOURCC': @@ -332,7 +358,11 @@ break;*/ } - $info['video']['streams'][$trackarray['TrackUID']] = $track_info; + if (isset($trackarray['TrackUID'])) { + $info['video']['streams'][$trackarray['TrackUID']] = $track_info; + } else { + $this->warning('Missing mandatory TrackUID for video track'); + } break; case 2: // Audio @@ -480,8 +510,11 @@ $this->warning('Unhandled audio type "'.(isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '').'"'); break; } - - $info['audio']['streams'][$trackarray['TrackUID']] = $track_info; + if (isset($trackarray['TrackUID'])) { + $info['audio']['streams'][$trackarray['TrackUID']] = $track_info; + } else { + $this->warning('Missing mandatory TrackUID for audio track'); + } break; } } @@ -1246,12 +1279,17 @@ } $this->current_offset = $subelement['end']; } - if (!$this->hide_clusters) { + + if (!$this->hide_clusters || $this->playtimeFromMetadata($info) === false) { $info['matroska']['cluster'][] = $cluster_entry; } + if ($this->scan_mode === MATROSKA_SCAN_FIRST_CLUSTER) { + // Stop parsing after finding first cluster + return; + } // check to see if all the data we need exists already, if so, break out of the loop - if (!$this->parse_whole_file) { + if ($this->scan_mode === MATROSKA_SCAN_HEADER) { if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) { if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) { if (count($info['matroska']['track_data_offsets']) == count($info['matroska']['tracks']['tracks'])) { @@ -1919,4 +1957,116 @@ return $info; } + /** + * @param array $info + * + * @return float|bool Duration when present in metadata or false + */ + private function playtimeFromMetadata(&$info) { + if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) { + foreach ($info['matroska']['info'] as $infoarray) { + if (isset($infoarray['Duration'])) { + // TimecodeScale is how many nanoseconds each Duration unit is + $info['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : MATROSKA_DEFAULT_TIMECODESCALE) / 1000000000); + return $info['playtime_seconds']; + } + } + } + return false; + } + + /** + * @param int $offset New starting offset for the buffer + * + * @return void + */ + private function resetParserBuffer($offset) { + $this->current_offset = $offset; + $this->EBMLbuffer = ''; + $this->EBMLbuffer_offset = 0; + $this->EBMLbuffer_length = 0; + } + + /** + * Scan start and end of file for cluster information when Duration is missing + * Only use this if no Duration was found in the Info element and we are not in parse_whole_file mode + * + * @param array $info + * + * @return void + */ + private function scanStartEndForClusters(&$info) { + // Scan beginning of file for first cluster + $this->resetParserBuffer($info['avdataoffset']); + $this->scan_mode = MATROSKA_SCAN_FIRST_CLUSTER; + + try { + $this->parseEBML($info); + } catch (Exception $e) { + $this->error('EBML parser (start of file): '.$e->getMessage()); + } + + // Scan end of file for last cluster + if (is_array($info['matroska']['cluster']) && !empty($info['matroska']['cluster'])) { + // Scan maximum 1MB window before EOF + $this->resetParserBuffer(max(0, $info['avdataend'] - (1024 * 1024))); + $this->scan_mode = MATROSKA_SCAN_LAST_CLUSTER; + + try { + $this->parseEBML($info); + } catch (Exception $e) { + $this->error('EBML parser (end of file): '.$e->getMessage()); + } + } + + // Reset to header parsing mode (this method is only called during header-only parsing) + $this->scan_mode = MATROSKA_SCAN_HEADER; + } + + /** + * Fetch TimecodeScale from Info element + * + * @param array $info + * + * @return int TimecodeScale value + */ + private function getTimecodeScale(&$info) { + $timecodeScale = MATROSKA_DEFAULT_TIMECODESCALE; + if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) { + foreach ($info['matroska']['info'] as $infoarray) { + if (isset($infoarray['TimecodeScale'])) { + $timecodeScale = $infoarray['TimecodeScale']; + break; + } + } + } + return $timecodeScale; + } + + /** + * Calculate duration from scanned cluster timecodes + * + * @param array $info + * + * @return void + */ + private function calculatePlaytimeFromClusters(&$info) { + $minTimecode = null; + $maxTimecode = null; + if (isset($info['matroska']['cluster']) && is_array($info['matroska']['cluster'])) { + foreach ($info['matroska']['cluster'] as $cluster) { + if (isset($cluster['ClusterTimecode'])) { + if ($minTimecode === null || $cluster['ClusterTimecode'] < $minTimecode) { + $minTimecode = $cluster['ClusterTimecode']; + } + if ($maxTimecode === null || $cluster['ClusterTimecode'] > $maxTimecode) { + $maxTimecode = $cluster['ClusterTimecode']; + } + } + } + } + if ($maxTimecode !== null && $minTimecode !== null && $maxTimecode > $minTimecode) { + $info['playtime_seconds'] = ($maxTimecode - $minTimecode) * ($this->getTimecodeScale($info) / 1000000000); + } + } } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.mpeg.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.mpeg.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.mpeg.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.mpeg.php 2026-05-22 07:52:18.000000000 +0000 @@ -292,6 +292,10 @@ $GOPheader['time_code'] = sprintf('%02d'.$time_code_separator.'%02d'.$time_code_separator.'%02d'.$time_code_separator.'%02d', $GOPheader['time_code_hours'], $GOPheader['time_code_minutes'], $GOPheader['time_code_seconds'], $GOPheader['time_code_pictures']); $info['mpeg']['group_of_pictures'][] = $GOPheader; + } else { + // https://github.com/JamesHeinrich/getID3/issues/440 + $this->warning('group_of_pictures['.$GOPcounter.'] no valid bitratemode'); + $info['mpeg']['group_of_pictures'][] = array(); } break; @@ -505,9 +509,9 @@ $last_GOP_id = max(array_keys($FramesByGOP)); $frames_in_last_GOP = count($FramesByGOP[$last_GOP_id]); $gopdata = &$info['mpeg']['group_of_pictures'][$last_GOP_id]; - $info['playtime_seconds'] = ($gopdata['time_code_hours'] * 3600) + ($gopdata['time_code_minutes'] * 60) + $gopdata['time_code_seconds'] + (($gopdata['time_code_pictures'] + $frames_in_last_GOP + 1) / $info['mpeg']['video']['frame_rate']); + $info['playtime_seconds'] = ($gopdata['time_code_hours'] * 3600) + ($gopdata['time_code_minutes'] * 60) + $gopdata['time_code_seconds'] + getid3_lib::SafeDiv($gopdata['time_code_pictures'] + $frames_in_last_GOP + 1, $info['mpeg']['video']['frame_rate']); if (!isset($info['video']['bitrate'])) { - $overall_bitrate = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds']; + $overall_bitrate = getid3_lib::SafeDiv($info['avdataend'] - $info['avdataoffset'] * 8, $info['playtime_seconds']); $info['video']['bitrate'] = $overall_bitrate - (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0); } unset($info['mpeg']['group_of_pictures']); @@ -610,14 +614,20 @@ * @return float */ public static function videoAspectRatioLookup($rawaspectratio, $mpeg_version=1, $width=0, $height=0) { + // Per http://forum.doom9.org/archive/index.php/t-84400.html + // 0.9157 is commonly accepted to mean 11/12 or .9166, the reciprocal of 12/11 (1.091) and, + // 1.0950 is commonly accepted to mean 11/10 or 1.1, the reciprocal of 10/11 (0.909) $lookup = array( - 1 => array(0, 1, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 0), + 1 => array(0, 1, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 11/12, 0.9815, 1.0255, 1.0695, 11/10, 1.1575, 1.2015, 0), 2 => array(0, 1, 1.3333, 1.7778, 2.2100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), ); $ratio = (float) (isset($lookup[$mpeg_version][$rawaspectratio]) ? $lookup[$mpeg_version][$rawaspectratio] : 0); if ($mpeg_version == 2 && $ratio != 1 && $width != 0) { // Calculate pixel aspect ratio from MPEG-2 display aspect ratio $ratio = $ratio * $height / $width; + } else if ($mpeg_version == 1 && $ratio !== 0.0) { + // The MPEG-1 tables store the reciprocal of the pixel aspect ratio. + $ratio = 1.0 / $ratio; } return $ratio; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.nsv.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.nsv.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.nsv.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.nsv.php 2026-05-22 07:52:18.000000000 +0000 @@ -215,7 +215,7 @@ } $info['playtime_seconds'] = $info['nsv']['NSVf']['playtime_ms'] / 1000; - $info['bitrate'] = ($info['nsv']['NSVf']['file_size'] * 8) / $info['playtime_seconds']; + $info['bitrate'] = getid3_lib::SafeDiv($info['nsv']['NSVf']['file_size'] * 8, $info['playtime_seconds']); return true; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.quicktime.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.quicktime.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.quicktime.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.quicktime.php 2026-05-22 07:52:18.000000000 +0000 @@ -39,11 +39,20 @@ public $ParseAllPossibleAtoms = false; /** + * real ugly, but so is the QuickTime structure that stores keys and values in different multi-nested locations that are hard to relate to each other + * https://github.com/JamesHeinrich/getID3/issues/214 + * + * @var int + */ + private $metaDATAkey = 1; + + /** * @return bool */ public function Analyze() { $info = &$this->getid3->info; + $this->metaDATAkey = 1; $info['fileformat'] = 'quicktime'; $info['quicktime']['hinting'] = false; $info['quicktime']['controller'] = 'standard'; // may be overridden if 'ctyp' atom is present @@ -147,27 +156,27 @@ @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 - $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim($lat_deg, '0').$lat_deg_dec); + $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * (float) (ltrim($lat_deg, '0').$lat_deg_dec); } elseif (strlen($lat_deg) == 4) { // [+-]DDMM.M - $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); + $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * (int) ltrim(substr($lat_deg, 0, 2), '0') + ((float) (ltrim(substr($lat_deg, 2, 2), '0').$lat_deg_dec) / 60); } elseif (strlen($lat_deg) == 6) { // [+-]DDMMSS.S - $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); + $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * (int) ltrim(substr($lat_deg, 0, 2), '0') + ((int) ltrim(substr($lat_deg, 2, 2), '0') / 60) + ((float) (ltrim(substr($lat_deg, 4, 2), '0').$lat_deg_dec) / 3600); } if (strlen($lon_deg) == 3) { // [+-]DDD.D - $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim($lon_deg, '0').$lon_deg_dec); + $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * (float) (ltrim($lon_deg, '0').$lon_deg_dec); } elseif (strlen($lon_deg) == 5) { // [+-]DDDMM.M - $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); + $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * (int) ltrim(substr($lon_deg, 0, 2), '0') + ((float) (ltrim(substr($lon_deg, 2, 2), '0').$lon_deg_dec) / 60); } elseif (strlen($lon_deg) == 7) { // [+-]DDDMMSS.S - $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); + $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * (int) ltrim(substr($lon_deg, 0, 2), '0') + ((int) ltrim(substr($lon_deg, 2, 2), '0') / 60) + ((float) (ltrim(substr($lon_deg, 4, 2), '0').$lon_deg_dec) / 3600); } if (strlen($alt_deg) == 3) { // [+-]DDD.D - $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim($alt_deg, '0').$alt_deg_dec); + $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * (float) (ltrim($alt_deg, '0').$alt_deg_dec); } elseif (strlen($alt_deg) == 5) { // [+-]DDDMM.M - $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); + $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * (int) ltrim(substr($alt_deg, 0, 2), '0') + ((float) (ltrim(substr($alt_deg, 2, 2), '0').$alt_deg_dec) / 60); } elseif (strlen($alt_deg) == 7) { // [+-]DDDMMSS.S - $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); + $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * (int) ltrim(substr($alt_deg, 0, 2), '0') + ((int) ltrim(substr($alt_deg, 2, 2), '0') / 60) + ((float) (ltrim(substr($alt_deg, 4, 2), '0').$alt_deg_dec) / 3600); } foreach (array('latitude', 'longitude', 'altitude') as $key) { @@ -181,6 +190,7 @@ } if ($ISO6709parsed['latitude'] === false) { $this->warning('location.ISO6709 string not parsed correctly: "'.$ISO6709string.'", please submit as a bug'); + unset($info['quicktime']['comments']['location.ISO6709']); } break; } @@ -215,6 +225,26 @@ $info['mime_type'] = 'video/mp4'; } } + if (!empty($info['quicktime']['ftyp']['signature']) && in_array($info['quicktime']['ftyp']['signature'], array('heic','heix','hevc','hevx','heim','heis','hevm','hevs'))) { + if ($info['mime_type'] == 'video/quicktime') { // default value, as we + // https://en.wikipedia.org/wiki/High_Efficiency_Image_File_Format +$this->error('HEIF files not currently supported'); + switch ($info['quicktime']['ftyp']['signature']) { + // https://github.com/strukturag/libheif/issues/83 (comment by Dirk Farin 2018-09-14) + case 'heic': // the usual HEIF images + case 'heix': // 10bit images, or anything that uses h265 with range extension + case 'hevc': // brands for image sequences + case 'hevx': // brands for image sequences + case 'heim': // multiview + case 'heis': // scalable + case 'hevm': // multiview sequence + case 'hevs': // scalable sequence + $info['fileformat'] = 'heif'; + $info['mime_type'] = 'image/heif'; + break; + } + } + } if (!$this->ReturnAtomData) { unset($info['quicktime']['moov']); @@ -331,7 +361,7 @@ } } elseif (isset($value_array['time_to_sample_table'])) { foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) { - if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) { + if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0) && !empty($info['quicktime']['time_scale'])) { $framerate = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3); $framecount = $value_array2['sample_count']; } @@ -443,6 +473,9 @@ } else { // Apple item list box atom handler $atomoffset = 0; +// todo (2025-10-16): 0x10B5 is probably Packed ISO639-2/T language code so this code block is likely incorrect +// need to locate sample file to figure out what is going on here and why this code was written as such +// https://developer.apple.com/documentation/quicktime-file-format/language_code_values if (substr($atom_data, 2, 2) == "\x10\xB5") { // not sure what it means, but observed on iPhone4 data. // Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data @@ -614,7 +647,9 @@ } } } - $this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']); + if (!empty($atom_structure['data'])) { // https://github.com/JamesHeinrich/getID3/issues/477#issuecomment-3723356688 + $this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']); + } break; @@ -775,8 +810,8 @@ case 'stsd': // Sample Table Sample Description atom - $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 + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); // hardcoded: 0x00 + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x000000 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); // see: https://github.com/JamesHeinrich/getID3/issues/111 @@ -793,7 +828,7 @@ } $stsdEntriesDataOffset = 8; - for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + for ($i = 0; $i < (int) $atom_structure['number_entries']; $i++) { $atom_structure['sample_description_table'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4)); $stsdEntriesDataOffset += 4; $atom_structure['sample_description_table'][$i]['data_format'] = substr($atom_data, $stsdEntriesDataOffset, 4); @@ -804,7 +839,6 @@ $stsdEntriesDataOffset += 2; $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); @@ -830,17 +864,20 @@ // video tracks // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap3/qtff3.html - $atom_structure['sample_description_table'][$i]['temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4)); - $atom_structure['sample_description_table'][$i]['spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4)); - $atom_structure['sample_description_table'][$i]['width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2)); - $atom_structure['sample_description_table'][$i]['height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2)); - $atom_structure['sample_description_table'][$i]['resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4)); - $atom_structure['sample_description_table'][$i]['resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4)); - $atom_structure['sample_description_table'][$i]['data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 4)); - $atom_structure['sample_description_table'][$i]['frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 36, 2)); - $atom_structure['sample_description_table'][$i]['compressor_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 38, 4); - $atom_structure['sample_description_table'][$i]['pixel_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 42, 2)); - $atom_structure['sample_description_table'][$i]['color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 44, 2)); + // https://developer.apple.com/documentation/quicktime-file-format + $STSDvOffset = 8; + $atom_structure['sample_description_table'][$i]['temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], $STSDvOffset, 4)); $STSDvOffset += 4; + $atom_structure['sample_description_table'][$i]['spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], $STSDvOffset, 4)); $STSDvOffset += 4; + $atom_structure['sample_description_table'][$i]['width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], $STSDvOffset, 2)); $STSDvOffset += 2; + $atom_structure['sample_description_table'][$i]['height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], $STSDvOffset, 2)); $STSDvOffset += 2; + $atom_structure['sample_description_table'][$i]['resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], $STSDvOffset, 4)); $STSDvOffset += 4; + $atom_structure['sample_description_table'][$i]['resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], $STSDvOffset, 4)); $STSDvOffset += 4; + $atom_structure['sample_description_table'][$i]['data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], $STSDvOffset, 4)); $STSDvOffset += 4; + $atom_structure['sample_description_table'][$i]['frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], $STSDvOffset, 2)); $STSDvOffset += 2; + $atom_structure['sample_description_table'][$i]['compressor_name'] = substr($atom_structure['sample_description_table'][$i]['data'], $STSDvOffset, 32) ; $STSDvOffset += 32; + $atom_structure['sample_description_table'][$i]['compressor_name'] = $this->MaybePascal2String(rtrim($atom_structure['sample_description_table'][$i]['compressor_name'], "\x00")); // https://github.com/JamesHeinrich/getID3/issues/452 + $atom_structure['sample_description_table'][$i]['pixel_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], $STSDvOffset, 2)); $STSDvOffset += 2; + $atom_structure['sample_description_table'][$i]['color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], $STSDvOffset, 2)); $STSDvOffset += 2; switch ($atom_structure['sample_description_table'][$i]['data_format']) { case '2vuY': @@ -873,7 +910,7 @@ $info['fileformat'] = 'mp4'; $info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; if ($this->QuicktimeVideoCodecLookup($info['video']['fourcc'])) { - $info['video']['fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($info['video']['fourcc']); + $info['video']['codec'] = $this->QuicktimeVideoCodecLookup($info['video']['fourcc']); } // https://www.getid3.org/phpBB3/viewtopic.php?t=1550 @@ -892,7 +929,8 @@ break; case 'mp4a': - default: + $atom_structure['sample_description_table'][$i]['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_structure['sample_description_table'][$i]['data'], 20), $baseoffset + $stsdEntriesDataOffset - 20 - 16, $atomHierarchy, $ParseAllPossibleAtoms); + $info['quicktime']['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); $info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate']; $info['quicktime']['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels']; @@ -918,9 +956,17 @@ break; } break; + + default: + break; } break; + case 'keys': + // 2025-Oct-17 probably something to do with this but I haven't found clear documentation explaining what I'm seeing, ignoring for now + // https://developer.apple.com/documentation/quicktime-file-format/metadata_key_declaration_atom/ + break; + default: switch ($atom_structure['sample_description_table'][$i]['data_format']) { case 'mp4s': @@ -1638,7 +1684,7 @@ @list($all, $latitude, $longitude, $altitude) = $matches; $info['quicktime']['comments']['gps_latitude'][] = floatval($latitude); $info['quicktime']['comments']['gps_longitude'][] = floatval($longitude); - if (!empty($altitude)) { + if (!empty($altitude)) { // @phpstan-ignore-line $info['quicktime']['comments']['gps_altitude'][] = floatval($altitude); } } else { @@ -1665,7 +1711,7 @@ ); $atom_structure['data'] = $atom_data; $atom_structure['image_mime'] = 'image/jpeg'; - $atom_structure['description'] = isset($descriptions[$atomname]) ? $descriptions[$atomname] : 'Nikon preview image'; + $atom_structure['description'] = $descriptions[$atomname]; $info['quicktime']['comments']['picture'][] = array( 'image_mime' => $atom_structure['image_mime'], 'data' => $atom_data, @@ -1682,7 +1728,7 @@ case 'NCHD': // Nikon:MakerNoteVersion - https://exiftool.org/TagNames/Nikon.html $makerNoteVersion = ''; for ($i = 0, $iMax = strlen($atom_data); $i < $iMax; ++$i) { - if (ord($atom_data[$i]) >= 0x00 && ord($atom_data[$i]) <= 0x1F) { + if (ord($atom_data[$i]) <= 0x1F) { $makerNoteVersion .= ' '.ord($atom_data[$i]); } else { $makerNoteVersion .= $atom_data[$i]; @@ -1718,16 +1764,32 @@ break; case 'data': // metaDATA atom - static $metaDATAkey = 1; // real ugly, but so is the QuickTime structure that stores keys and values in different multinested locations that are hard to relate to each other - // seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data - $atom_structure['language'] = substr($atom_data, 4 + 0, 2); - $atom_structure['unknown'] = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2)); - $atom_structure['data'] = substr($atom_data, 4 + 4); - $atom_structure['key_name'] = (isset($info['quicktime']['temp_meta_key_names'][$metaDATAkey]) ? $info['quicktime']['temp_meta_key_names'][$metaDATAkey] : ''); - $metaDATAkey++; + // seems to be 2 bytes language code (ASCII), 2 bytes language code (probably packed ISO639-2/T), remainder is useful data + $atom_structure['lang2'] = substr($atom_data, 4 + 0, 2); + $atom_structure['lang3'] = $this->QuicktimeLanguageLookup(getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2))); + $atom_structure['data'] = substr($atom_data, 4 + 4); + $atom_structure['key_name'] = (isset($info['quicktime']['temp_meta_key_names'][$this->metaDATAkey]) ? $info['quicktime']['temp_meta_key_names'][$this->metaDATAkey] : ''); + $this->metaDATAkey++; + + switch ($atom_structure['key_name']) { + case 'com.android.capture.fps': + case 'com.apple.quicktime.live-photo.vitality-score': + $atom_structure['data'] = getid3_lib::BigEndian2Float($atom_structure['data']); + break; + case 'com.apple.quicktime.camera.focal_length.35mm_equivalent': + case 'com.apple.quicktime.live-photo.auto': + case 'com.apple.quicktime.live-photo.vitality-scoring-version': + case 'com.apple.quicktime.full-frame-rate-playback-intent': + $atom_structure['data'] = getid3_lib::BigEndian2Int($atom_structure['data']); + break; + + case 'com.apple.quicktime.location.accuracy.horizontal': + $atom_structure['data'] = (float) $atom_structure['data']; // string representing float value e.g. "14.989691" + break; + } if ($atom_structure['key_name'] && $atom_structure['data']) { - @$info['quicktime']['comments'][str_replace('com.apple.quicktime.', '', $atom_structure['key_name'])][] = $atom_structure['data']; + @$info['quicktime']['comments'][str_replace('com.android.', '', str_replace('com.apple.quicktime.', '', $atom_structure['key_name']))][] = $atom_structure['data']; } break; @@ -1739,13 +1801,15 @@ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); $atom_structure['entry_count'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); $keys_atom_offset = 8; + + $keys_index_base = (!empty($info['quicktime']['temp_meta_key_names']) ? count($info['quicktime']['temp_meta_key_names']) : 0); // file may contain multiple "keys" entries, starting index should be culmulative not reset to 1 on each set; https://github.com/JamesHeinrich/getID3/issues/452 for ($i = 1; $i <= $atom_structure['entry_count']; $i++) { - $atom_structure['keys'][$i]['key_size'] = getid3_lib::BigEndian2Int(substr($atom_data, $keys_atom_offset + 0, 4)); - $atom_structure['keys'][$i]['key_namespace'] = substr($atom_data, $keys_atom_offset + 4, 4); - $atom_structure['keys'][$i]['key_value'] = substr($atom_data, $keys_atom_offset + 8, $atom_structure['keys'][$i]['key_size'] - 8); - $keys_atom_offset += $atom_structure['keys'][$i]['key_size']; // key_size includes the 4+4 bytes for key_size and key_namespace + $atom_structure['keys'][($keys_index_base + $i)]['key_size'] = getid3_lib::BigEndian2Int(substr($atom_data, $keys_atom_offset + 0, 4)); + $atom_structure['keys'][($keys_index_base + $i)]['key_namespace'] = substr($atom_data, $keys_atom_offset + 4, 4); + $atom_structure['keys'][($keys_index_base + $i)]['key_value'] = substr($atom_data, $keys_atom_offset + 8, $atom_structure['keys'][($keys_index_base + $i)]['key_size'] - 8); + $keys_atom_offset += $atom_structure['keys'][($keys_index_base + $i)]['key_size']; // key_size includes the 4+4 bytes for key_size and key_namespace - $info['quicktime']['temp_meta_key_names'][$i] = $atom_structure['keys'][$i]['key_value']; + $info['quicktime']['temp_meta_key_names'][($keys_index_base + $i)] = $atom_structure['keys'][($keys_index_base + $i)]['key_value']; } break; @@ -1968,16 +2032,16 @@ foreach (array('latitude','longitude') as $latlon) { preg_match('#^([0-9]{1,3})([0-9]{2}\\.[0-9]+)$#', $GPS_this_GPRMC['raw'][$latlon], $matches); list($dummy, $deg, $min) = $matches; - $GPS_this_GPRMC[$latlon] = $deg + ($min / 60); + $GPS_this_GPRMC[$latlon] = (int) $deg + ((float) $min / 60); } $GPS_this_GPRMC['latitude'] *= (($GPS_this_GPRMC['raw']['latitude_direction'] == 'S') ? -1 : 1); $GPS_this_GPRMC['longitude'] *= (($GPS_this_GPRMC['raw']['longitude_direction'] == 'W') ? -1 : 1); $GPS_this_GPRMC['heading'] = $GPS_this_GPRMC['raw']['angle']; $GPS_this_GPRMC['speed_knot'] = $GPS_this_GPRMC['raw']['knots']; - $GPS_this_GPRMC['speed_kmh'] = $GPS_this_GPRMC['raw']['knots'] * 1.852; + $GPS_this_GPRMC['speed_kmh'] = (float) $GPS_this_GPRMC['raw']['knots'] * 1.852; if ($GPS_this_GPRMC['raw']['variation']) { - $GPS_this_GPRMC['variation'] = $GPS_this_GPRMC['raw']['variation']; + $GPS_this_GPRMC['variation'] = (float) $GPS_this_GPRMC['raw']['variation']; $GPS_this_GPRMC['variation'] *= (($GPS_this_GPRMC['raw']['variation_direction'] == 'W') ? -1 : 1); } @@ -2100,6 +2164,125 @@ break; + case 'esds': // Elementary Stream DeScriptor + // https://github.com/JamesHeinrich/getID3/issues/414 + // https://chromium.googlesource.com/chromium/src/media/+/refs/heads/main/formats/mp4/es_descriptor.cc + // https://chromium.googlesource.com/chromium/src/media/+/refs/heads/main/formats/mp4/es_descriptor.h + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); // hardcoded: 0x00 + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x000000 + $esds_offset = 4; + + $atom_structure['ES_DescrTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + if ($atom_structure['ES_DescrTag'] != 0x03) { + $this->warning('expecting esds.ES_DescrTag = 0x03, found 0x'.sprintf('%02X', $atom_structure['ES_DescrTag']).', at offset '.$atom_structure['offset']); + break; + } + $atom_structure['ES_DescrSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); + + $atom_structure['ES_ID'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 2)); + $esds_offset += 2; + $atom_structure['ES_flagsraw'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + $atom_structure['ES_flags']['stream_dependency'] = (bool) ($atom_structure['ES_flagsraw'] & 0x80); + $atom_structure['ES_flags']['url_flag'] = (bool) ($atom_structure['ES_flagsraw'] & 0x40); + $atom_structure['ES_flags']['ocr_stream'] = (bool) ($atom_structure['ES_flagsraw'] & 0x20); + $atom_structure['ES_stream_priority'] = ($atom_structure['ES_flagsraw'] & 0x1F); + if ($atom_structure['ES_flags']['url_flag']) { + $this->warning('Unsupported esds.url_flag enabled at offset '.$atom_structure['offset']); + break; + } + if ($atom_structure['ES_flags']['stream_dependency']) { + $atom_structure['ES_dependsOn_ES_ID'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 2)); + $esds_offset += 2; + } + if ($atom_structure['ES_flags']['ocr_stream']) { + $atom_structure['ES_OCR_ES_Id'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 2)); + $esds_offset += 2; + } + + $atom_structure['ES_DecoderConfigDescrTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + if ($atom_structure['ES_DecoderConfigDescrTag'] != 0x04) { + $this->warning('expecting esds.ES_DecoderConfigDescrTag = 0x04, found 0x'.sprintf('%02X', $atom_structure['ES_DecoderConfigDescrTag']).', at offset '.$atom_structure['offset']); + break; + } + $atom_structure['ES_DecoderConfigDescrTagSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); + + $atom_structure['ES_objectTypeIndication'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + // https://stackoverflow.com/questions/3987850 + // 0x40 = "Audio ISO/IEC 14496-3" = MPEG-4 Audio + // 0x67 = "Audio ISO/IEC 13818-7 LowComplexity Profile" = MPEG-2 AAC LC + // 0x69 = "Audio ISO/IEC 13818-3" = MPEG-2 Backward Compatible Audio (MPEG-2 Layers 1, 2, and 3) + // 0x6B = "Audio ISO/IEC 11172-3" = MPEG-1 Audio (MPEG-1 Layers 1, 2, and 3) + + $streamTypePlusFlags = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + $atom_structure['ES_streamType'] = ($streamTypePlusFlags & 0xFC) >> 2; + $atom_structure['ES_upStream'] = (bool) ($streamTypePlusFlags & 0x02) >> 1; + $atom_structure['ES_bufferSizeDB'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 3)); + $esds_offset += 3; + $atom_structure['ES_maxBitrate'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 4)); + $esds_offset += 4; + $atom_structure['ES_avgBitrate'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 4)); + $esds_offset += 4; + if ($atom_structure['ES_avgBitrate']) { + $info['quicktime']['audio']['bitrate'] = $atom_structure['ES_avgBitrate']; + $info['audio']['bitrate'] = $atom_structure['ES_avgBitrate']; + } + + $atom_structure['ES_DecSpecificInfoTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + if ($atom_structure['ES_DecSpecificInfoTag'] != 0x05) { + $this->warning('expecting esds.ES_DecSpecificInfoTag = 0x05, found 0x'.sprintf('%02X', $atom_structure['ES_DecSpecificInfoTag']).', at offset '.$atom_structure['offset']); + break; + } + $atom_structure['ES_DecSpecificInfoTagSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); + + $atom_structure['ES_DecSpecificInfo'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, $atom_structure['ES_DecSpecificInfoTagSize'])); + $esds_offset += $atom_structure['ES_DecSpecificInfoTagSize']; + + $atom_structure['ES_SLConfigDescrTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + if ($atom_structure['ES_SLConfigDescrTag'] != 0x06) { + $this->warning('expecting esds.ES_SLConfigDescrTag = 0x05, found 0x'.sprintf('%02X', $atom_structure['ES_SLConfigDescrTag']).', at offset '.$atom_structure['offset']); + break; + } + $atom_structure['ES_SLConfigDescrTagSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); + + $atom_structure['ES_SLConfigDescr'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, $atom_structure['ES_SLConfigDescrTagSize'])); + $esds_offset += $atom_structure['ES_SLConfigDescrTagSize']; + break; + + case 'sgpd': // https://developer.apple.com/documentation/quicktime-file-format/sample_group_description_atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); // hardcoded: 0x00 + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x000000 + $sgpd_offset = 4; + + $atom_structure['grouping_type'] = getid3_lib::BigEndian2Int(substr($atom_data, $sgpd_offset, 4)); + $sgpd_offset += 4; + $atom_structure['default_length'] = getid3_lib::BigEndian2Int(substr($atom_data, $sgpd_offset, 4)); + $sgpd_offset += 4; + $atom_structure['entry_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sgpd_offset, 4)); + $sgpd_offset += 4; + $atom_structure['payload_data_raw'] = substr($atom_data, $sgpd_offset); + break; + + case 'sbgp': // https://developer.apple.com/documentation/quicktime-file-format/sample-to-group_atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); // hardcoded: 0x00 + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x000000 + $sbgp_offset = 4; + + $atom_structure['grouping_type'] = getid3_lib::BigEndian2Int(substr($atom_data, $sbgp_offset, 4)); + $sbgp_offset += 4; + $atom_structure['default_length'] = getid3_lib::BigEndian2Int(substr($atom_data, $sbgp_offset, 4)); + $sbgp_offset += 4; + $atom_structure['entry_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sbgp_offset, 4)); + $sbgp_offset += 4; + $atom_structure['table_data_raw'] = substr($atom_data, $sbgp_offset); + break; + // AVIF-related - https://docs.rs/avif-parse/0.13.2/src/avif_parse/boxes.rs.html case 'pitm': // Primary ITeM case 'iloc': // Item LOCation @@ -2201,6 +2384,7 @@ */ public function QuicktimeLanguageLookup($languageid) { // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-34353 + // https://developer.apple.com/documentation/quicktime-file-format/language_code_values static $QuicktimeLanguageLookup = array(); if (empty($QuicktimeLanguageLookup)) { $QuicktimeLanguageLookup[0] = 'English'; @@ -2916,11 +3100,13 @@ 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); + if (strlen($pascalstring) > 0) { + 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; } @@ -2990,6 +3176,7 @@ return array(); } + /** * @param array $info * diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.real.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.real.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.real.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.real.php 2026-05-22 07:52:18.000000000 +0000 @@ -47,8 +47,13 @@ $info['audio']['bits_per_sample'] = $info['real']['old_ra_header']['bits_per_sample']; $info['audio']['channels'] = $info['real']['old_ra_header']['channels']; - $info['playtime_seconds'] = 60 * ($info['real']['old_ra_header']['audio_bytes'] / $info['real']['old_ra_header']['bytes_per_minute']); - $info['audio']['bitrate'] = 8 * ($info['real']['old_ra_header']['audio_bytes'] / $info['playtime_seconds']); + if ($info['real']['old_ra_header']['bytes_per_minute']) { + $info['playtime_seconds'] = 60 * ($info['real']['old_ra_header']['audio_bytes'] / $info['real']['old_ra_header']['bytes_per_minute']); + $info['audio']['bitrate'] = 8 * ($info['real']['old_ra_header']['audio_bytes'] / $info['playtime_seconds']); + } else { + $info['playtime_seconds'] = 0; + $info['audio']['bitrate'] = 0; + } $info['audio']['codec'] = $this->RealAudioCodecFourCClookup($info['real']['old_ra_header']['fourcc'], $info['audio']['bitrate']); foreach ($info['real']['old_ra_header']['comments'] as $key => $valuearray) { @@ -487,8 +492,8 @@ $ParsedArray['fourcc'] = $ParsedArray['fourcc3']; } - /** @var string[]|false[] $value */ - foreach ($ParsedArray['comments'] as $key => $value) { + /** @var array $value */ + foreach ($ParsedArray['comments'] as $key => $value) { // @phpstan-ignore-line if ($value[0] === false) { $ParsedArray['comments'][$key][0] = ''; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.riff.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.riff.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.riff.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio-video.riff.php 2026-05-22 07:52:18.000000000 +0000 @@ -67,12 +67,19 @@ $RIFFsize = substr($RIFFheader, 4, 4); $RIFFsubtype = substr($RIFFheader, 8, 4); - switch ($RIFFtype) { + if ($RIFFsize == "\x00\x00\x00\x00") { + // https://github.com/JamesHeinrich/getID3/issues/468 + // may occur in streaming files where the data size is unknown + $thisfile_riff['header_size'] = $info['avdataend'] - 8; + $this->warning('RIFF size field is empty, assuming the correct value is filesize-8 ('.$thisfile_riff['header_size'].')'); + } else { + $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize); + } + switch ($RIFFtype) { case 'FORM': // AIFF, AIFC //$info['fileformat'] = 'aiff'; $this->container = 'aiff'; - $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize); $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4)); break; @@ -81,7 +88,6 @@ case 'RMP3': // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s //$info['fileformat'] = 'riff'; $this->container = 'riff'; - $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize); if ($RIFFsubtype == 'RMP3') { // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s $RIFFsubtype = 'WAVE'; @@ -98,7 +104,7 @@ $info['avdataend'] = $info['filesize']; } - $nextRIFFoffset = $Original['avdataoffset'] + 8 + $thisfile_riff['header_size']; // 8 = "RIFF" + 32-bit offset + $nextRIFFoffset = (int) $Original['avdataoffset'] + 8 + (int) $thisfile_riff['header_size']; // 8 = "RIFF" + 32-bit offset while ($nextRIFFoffset < min($info['filesize'], $info['avdataend'])) { try { $this->fseek($nextRIFFoffset); @@ -214,7 +220,7 @@ $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV) - $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']); + $info['playtime_seconds'] = (float)getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $thisfile_audio['bitrate']); } $thisfile_audio['lossless'] = false; @@ -305,8 +311,9 @@ // assigned for text fields, resulting in a null-terminated string (or possibly just a single null) followed by garbage // Keep only string as far as first null byte, discard rest of fixed-width data // https://github.com/JamesHeinrich/getID3/issues/263 - $null_terminator_offset = strpos($thisfile_riff_WAVE_bext_0[$bext_key], "\x00"); - $thisfile_riff_WAVE_bext_0[$bext_key] = substr($thisfile_riff_WAVE_bext_0[$bext_key], 0, $null_terminator_offset); + // https://github.com/JamesHeinrich/getID3/issues/430 + $null_terminator_rows = explode("\x00", $thisfile_riff_WAVE_bext_0[$bext_key]); + $thisfile_riff_WAVE_bext_0[$bext_key] = $null_terminator_rows[0]; } $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10); @@ -440,11 +447,11 @@ $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML; if (isset($parsedXML['SPEED']['MASTER_SPEED'])) { @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']); - $thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ? $denominator : 1000); + $thisfile_riff_WAVE['iXML'][0]['master_speed'] = (int) $numerator / ($denominator ? $denominator : 1000); } if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) { @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']); - $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000); + $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = (int) $numerator / ($denominator ? $denominator : 1000); } if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) { $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0')); @@ -472,7 +479,7 @@ @list($key, $value) = explode(':', $line, 2); if (substr($value, 0, 3) == '[{"') { if ($decoded = @json_decode($value, true)) { - if (!empty($decoded) && (count($decoded) == 1)) { + if (count($decoded) === 1) { $value = $decoded[0]; } else { $value = $decoded; @@ -521,7 +528,7 @@ if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) { $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; - $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']); + $info['playtime_seconds'] = (float)getid3_lib::SafeDiv((($info['avdataend'] - $info['avdataoffset']) * 8), $thisfile_audio['bitrate']); } if (!empty($info['wavpack'])) { @@ -531,7 +538,7 @@ // Reset to the way it was - RIFF parsing will have messed this up $info['avdataend'] = $Original['avdataend']; - $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + $thisfile_audio['bitrate'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']); $this->fseek($info['avdataoffset'] - 44); $RIFFdata = $this->fread(44); @@ -632,7 +639,7 @@ } } if ($info['avdataend'] > $info['filesize']) { - switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat : '') { + switch ($thisfile_audio_dataformat) { case 'wavpack': // WavPack case 'lpac': // LPAC case 'ofr': // OptimFROG @@ -672,7 +679,7 @@ $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'); } } - if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) { + if ($thisfile_audio_dataformat == 'ac3') { unset($thisfile_audio['bits_per_sample']); if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) { $thisfile_audio['bitrate'] = $info['ac3']['bitrate']; @@ -781,15 +788,15 @@ /** @var array $thisfile_riff_video_current */ $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex]; - if ($thisfile_riff_raw_avih['dwWidth'] > 0) { + if ($thisfile_riff_raw_avih['dwWidth'] > 0) { // @phpstan-ignore-line $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth']; $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width']; } - if ($thisfile_riff_raw_avih['dwHeight'] > 0) { + if ($thisfile_riff_raw_avih['dwHeight'] > 0) { // @phpstan-ignore-line $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight']; $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height']; } - if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) { + if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) { // @phpstan-ignore-line $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames']; $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames']; } @@ -1132,7 +1139,9 @@ $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment'); foreach ($CommentsChunkNames as $key => $value) { if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) { - $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data']; + // https://github.com/JamesHeinrich/getID3/issues/430 + $null_terminator_rows = explode("\x00", $thisfile_riff[$RIFFsubtype][$key][0]['data']); + $thisfile_riff['comments'][$value][] = $null_terminator_rows[0]; } } /* @@ -1224,7 +1233,9 @@ $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment'); foreach ($CommentsChunkNames as $key => $value) { if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) { - $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data']; + // https://github.com/JamesHeinrich/getID3/issues/430 + $null_terminator_rows = explode("\x00", $thisfile_riff[$RIFFsubtype][$key][0]['data']); + $thisfile_riff['comments'][$value][] = $null_terminator_rows[0]; } } @@ -1364,19 +1375,19 @@ } if ($info['playtime_seconds'] > 0) { - if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) { + if ($thisfile_riff_audio !== null && $thisfile_riff_video !== null) { if (!isset($info['bitrate'])) { $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); } - } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) { + } elseif ($thisfile_riff_audio !== null && $thisfile_riff_video === null) { // @phpstan-ignore-line if (!isset($thisfile_audio['bitrate'])) { $thisfile_audio['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); } - } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) { + } elseif ($thisfile_riff_audio === null && $thisfile_riff_video !== null) { if (!isset($thisfile_video['bitrate'])) { $thisfile_video['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); @@ -1387,7 +1398,6 @@ if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && ($thisfile_audio['bitrate'] > 0) && ($info['playtime_seconds'] > 0)) { - $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); $thisfile_audio['bitrate'] = 0; $thisfile_video['bitrate'] = $info['bitrate']; @@ -1601,9 +1611,18 @@ $this->error('Expecting chunk name at offset '.($this->ftell() - 8).' but found nothing. Aborting RIFF parsing.'); break; } - if (($chunksize == 0) && ($chunkname != 'JUNK')) { - $this->warning('Chunk ('.$chunkname.') size at offset '.($this->ftell() - 4).' is zero. Aborting RIFF parsing.'); - break; + if ($chunksize == 0) { + if ($chunkname == 'JUNK') { + // this is allowed + } elseif ($chunkname == 'data') { + // https://github.com/JamesHeinrich/getID3/issues/468 + // may occur in streaming files where the data size is unknown + $chunksize = $info['avdataend'] - $this->ftell(); + $this->warning('RIFF.data size field is empty, assuming the correct value is filesize-offset ('.$chunksize.')'); + } else { + $this->warning('Chunk ('.$chunkname.') size at offset '.($this->ftell() - 4).' is zero. Aborting RIFF parsing.'); + break; + } } if (($chunksize % 2) != 0) { // all structures are packed on word boundaries @@ -1693,7 +1712,7 @@ break; } $thisindex = 0; - if (isset($RIFFchunk[$chunkname]) && is_array($RIFFchunk[$chunkname])) { + if (isset($RIFFchunk[$chunkname])) { $thisindex = count($RIFFchunk[$chunkname]); } $RIFFchunk[$chunkname][$thisindex]['offset'] = $this->ftell() - 8; @@ -1717,9 +1736,11 @@ $getid3_temp->info['avdataend'] = $info['avdataend']; $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__); $getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false); - if (empty($getid3_temp->info['error'])) { - $info['audio'] = $getid3_temp->info['audio']; - $info['mpeg'] = $getid3_temp->info['mpeg']; + if (!empty($getid3_temp->info['mpeg']['audio']['bitrate']) && ($getid3_temp->info['mpeg']['audio']['bitrate'] != 'free')) { // if it detects as "free" bitrate then it's almost certainly a false-match MP3 sync, ignore + if (empty($getid3_temp->info['error'])) { + $info['audio'] = $getid3_temp->info['audio']; + $info['mpeg'] = $getid3_temp->info['mpeg']; + } } unset($getid3_temp, $getid3_mp3); } @@ -1913,7 +1934,7 @@ if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) { unset($RIFFchunk[$chunkname][$thisindex]); } - if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) { + if (count($RIFFchunk[$chunkname]) === 0) { unset($RIFFchunk[$chunkname]); } $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize); @@ -2034,7 +2055,7 @@ foreach ($RIFFinfoKeyLookup as $key => $value) { if (isset($RIFFinfoArray[$key])) { foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) { - if (trim($commentdata['data']) != '') { + if (!empty($commentdata['data']) && trim($commentdata['data']) != '') { if (isset($CommentsTargetArray[$value])) { $CommentsTargetArray[$value][] = trim($commentdata['data']); } else { @@ -2805,6 +2826,10 @@ VLV1 VideoLogic/PURE Digital Videologic Capture VP30 On2 VP3.0 VP31 On2 VP3.1 + VP50 On2 VP5 + VP60 On2 VP6 + VP70 On2 VP7 + VP80 On2 VP8 VP6F On2 TrueMotion VP6 VX1K Lucent VX1000S Video Codec VX2K Lucent VX2000S Video Codec diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.amr.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.amr.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.amr.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.amr.php 2026-05-22 07:52:18.000000000 +0000 @@ -62,7 +62,7 @@ } while (strlen($buffer) > 0); $info['playtime_seconds'] = array_sum($thisfile_amr['frame_mode_count']) * 0.020; // each frame contain 160 samples and is 20 milliseconds long - $info['audio']['bitrate'] = (8 * ($info['avdataend'] - $info['avdataoffset'])) / $info['playtime_seconds']; // bitrate could be calculated from average bitrate by distributation of frame types. That would give effective audio bitrate, this gives overall file bitrate which will be a little bit higher since every frame will waste 8 bits for header, plus a few bits for octet padding + $info['audio']['bitrate'] = getid3_lib::SafeDiv(8 * ($info['avdataend'] - $info['avdataoffset']), $info['playtime_seconds']); // bitrate could be calculated from average bitrate by distributation of frame types. That would give effective audio bitrate, this gives overall file bitrate which will be a little bit higher since every frame will waste 8 bits for header, plus a few bits for octet padding $info['bitrate'] = $info['audio']['bitrate']; return true; diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.au.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.au.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.au.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.au.php 2026-05-22 07:52:18.000000000 +0000 @@ -69,8 +69,8 @@ $this->warning('Possible truncated file - expecting "'.$thisfile_au['data_size'].'" bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"'); } - $info['playtime_seconds'] = $thisfile_au['data_size'] / ($thisfile_au['sample_rate'] * $thisfile_au['channels'] * ($thisfile_au['used_bits_per_sample'] / 8)); - $info['audio']['bitrate'] = ($thisfile_au['data_size'] * 8) / $info['playtime_seconds']; + $info['audio']['bitrate'] = $thisfile_au['sample_rate'] * $thisfile_au['channels'] * $thisfile_au['used_bits_per_sample']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($thisfile_au['data_size'], $info['audio']['bitrate'] / 8); return true; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.avr.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.avr.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.avr.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.avr.php 2026-05-22 07:52:18.000000000 +0000 @@ -120,9 +120,9 @@ $info['audio']['bits_per_sample'] = $info['avr']['bits_per_sample']; $info['audio']['sample_rate'] = $info['avr']['sample_rate']; $info['audio']['channels'] = ($info['avr']['flags']['stereo'] ? 2 : 1); - $info['playtime_seconds'] = ($info['avr']['sample_length'] / $info['audio']['channels']) / $info['avr']['sample_rate']; - $info['audio']['bitrate'] = ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 8 : 16)) / $info['playtime_seconds']; - + $bits_per_sample = ($info['avr']['bits_per_sample'] == 8) ? 8 : 16; + $info['audio']['bitrate'] = $bits_per_sample * $info['audio']['channels'] * $info['avr']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['avr']['sample_length'] * $bits_per_sample, $info['audio']['bitrate']); return true; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.bonk.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.bonk.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.bonk.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.bonk.php 2026-05-22 07:52:18.000000000 +0000 @@ -154,7 +154,7 @@ $info['audio']['lossless'] = $thisfile_bonk_BONK['lossless']; $info['audio']['codec'] = 'bonk'; - $info['playtime_seconds'] = $thisfile_bonk_BONK['number_samples'] / ($thisfile_bonk_BONK['sample_rate'] * $thisfile_bonk_BONK['channels']); + $info['playtime_seconds'] = getid3_lib::SafeDiv($thisfile_bonk_BONK['number_samples'], $thisfile_bonk_BONK['sample_rate'] * $thisfile_bonk_BONK['channels']); if ($info['playtime_seconds'] > 0) { $info['audio']['bitrate'] = (($info['bonk']['dataend'] - $info['bonk']['dataoffset']) * 8) / $info['playtime_seconds']; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.dsdiff.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.dsdiff.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.dsdiff.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.dsdiff.php 2026-05-22 07:52:18.000000000 +0000 @@ -195,9 +195,13 @@ $this->fseek(1, SEEK_CUR); } - if ($commentkey = (($thisChunk['name'] == 'DIAR') ? 'artist' : (($thisChunk['name'] == 'DITI') ? 'title' : ''))) { - @$info['dsdiff']['comments'][$commentkey][] = $thisChunk['description']; - } + $commentKeys = array( + 'DIAR' => 'artist', + 'DITI' => 'title' + ); + $commentkey = $commentKeys[$thisChunk['name']]; + + $info['dsdiff']['comments'][$commentkey][] = $thisChunk['description']; break; case 'EMID': // Edited Master ID chunk if ($thisChunk['size']) { diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.dsf.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.dsf.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.dsf.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.dsf.php 2026-05-22 07:52:18.000000000 +0000 @@ -115,7 +115,7 @@ $info['audio']['sample_rate'] = $info['dsf']['fmt']['sample_rate']; $info['audio']['channels'] = $info['dsf']['fmt']['channels']; $info['audio']['bitrate'] = $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'] * $info['audio']['channels']; - $info['playtime_seconds'] = ($info['dsf']['data']['data_chunk_size'] * 8) / $info['audio']['bitrate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['dsf']['data']['data_chunk_size'] * 8, $info['audio']['bitrate']); return true; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.dss.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.dss.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.dss.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.dss.php 2026-05-22 07:52:18.000000000 +0000 @@ -71,7 +71,9 @@ $this->getid3->warning('playtime_ms ('.number_format($info['dss']['playtime_ms'] / 1000, 3).') does not match playtime_sec ('.number_format($info['dss']['playtime_sec']).') - using playtime_sec value'); } } - $info['audio']['bitrate'] = ($info['filesize'] * 8) / $info['playtime_seconds']; + if ($info['playtime_seconds'] > 0) { + $info['audio']['bitrate'] = ($info['filesize'] * 8) / $info['playtime_seconds']; + } return true; } @@ -83,11 +85,11 @@ */ public function DSSdateStringToUnixDate($datestring) { $y = (int) substr($datestring, 0, 2); - $m = substr($datestring, 2, 2); - $d = substr($datestring, 4, 2); - $h = substr($datestring, 6, 2); - $i = substr($datestring, 8, 2); - $s = substr($datestring, 10, 2); + $m = (int) substr($datestring, 2, 2); + $d = (int) substr($datestring, 4, 2); + $h = (int) substr($datestring, 6, 2); + $i = (int) substr($datestring, 8, 2); + $s = (int) substr($datestring, 10, 2); $y += (($y < 95) ? 2000 : 1900); return mktime($h, $i, $s, $m, $d, $y); } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.flac.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.flac.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.flac.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.flac.php 2026-05-22 07:52:18.000000000 +0000 @@ -168,10 +168,10 @@ $info['flac']['compressed_audio_bytes'] = $info['avdataend'] - $info['avdataoffset']; } $info['flac']['uncompressed_audio_bytes'] = $info['flac']['STREAMINFO']['samples_stream'] * $info['flac']['STREAMINFO']['channels'] * ($info['flac']['STREAMINFO']['bits_per_sample'] / 8); - if ($info['flac']['uncompressed_audio_bytes'] == 0) { + if ($info['flac']['uncompressed_audio_bytes'] == 0 && $info['flac']['STREAMINFO']['samples_stream'] > 0) { return $this->error('Corrupt FLAC file: uncompressed_audio_bytes == zero'); } - if (!empty($info['flac']['compressed_audio_bytes'])) { + if (!empty($info['flac']['compressed_audio_bytes']) && $info['flac']['STREAMINFO']['samples_stream'] > 0) { $info['flac']['compression_ratio'] = $info['flac']['compressed_audio_bytes'] / $info['flac']['uncompressed_audio_bytes']; } } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.lpac.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.lpac.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.lpac.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.lpac.php 2026-05-22 07:52:18.000000000 +0000 @@ -126,8 +126,8 @@ } } - $info['playtime_seconds'] = $info['lpac']['total_samples'] / $info['audio']['sample_rate']; - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['lpac']['total_samples'], $info['audio']['sample_rate']); + $info['audio']['bitrate'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']); return true; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.midi.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.midi.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.midi.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.midi.php 2026-05-22 07:52:18.000000000 +0000 @@ -46,6 +46,15 @@ $this->fseek($info['avdataoffset']); $MIDIdata = $this->fread($this->getid3->fread_buffer_size()); + + $minHeaderSize = 14; // MIDI header (4+4+2+2+2) + $minTrackHeaderSize = 8; // Track header (4+4) + $minTotalSize = $minHeaderSize + $minTrackHeaderSize; + if ($info['filesize'] < $minTotalSize || strlen($MIDIdata) < $minTotalSize) { + $this->error('File too small to be a valid MIDI file.'); + return false; + } + $offset = 0; $MIDIheaderID = substr($MIDIdata, $offset, 4); // 'MThd' if ($MIDIheaderID != GETID3_MIDI_MAGIC_MTHD) { @@ -88,7 +97,7 @@ } } - if (!is_array($trackdataarray) || count($trackdataarray) === 0) { + if (count($trackdataarray) === 0) { $this->error('Cannot find MIDI track information'); unset($thisfile_midi); unset($info['fileformat']); @@ -99,7 +108,6 @@ $thisfile_midi['totalticks'] = 0; $info['playtime_seconds'] = 0; $CurrentMicroSecondsPerBeat = 500000; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat - $CurrentBeatsPerMinute = 120; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat $MicroSecondsPerQuarterNoteAfter = array (); $MIDIevents = array(); @@ -112,7 +120,7 @@ $TicksAtCurrentBPM = 0; while ($eventsoffset < strlen($trackdata)) { $eventid = 0; - if (isset($MIDIevents[$tracknumber]) && is_array($MIDIevents[$tracknumber])) { + if (isset($MIDIevents[$tracknumber])) { $eventid = count($MIDIevents[$tracknumber]); } $deltatime = 0; @@ -244,7 +252,6 @@ return false; } $thisfile_midi_raw['events'][$tracknumber][$CumulativeDeltaTime]['us_qnote'] = $CurrentMicroSecondsPerBeat; - $CurrentBeatsPerMinute = (1000000 / $CurrentMicroSecondsPerBeat) * 60; $MicroSecondsPerQuarterNoteAfter[$CumulativeDeltaTime] = $CurrentMicroSecondsPerBeat; $TicksAtCurrentBPM = 0; break; @@ -332,6 +339,15 @@ } } + // Fallback: If playtime_seconds is still empty/zero, estimate using default tempo + // 120 BPM = 0.5 per quarter note = 480 quarternote ticks + if (empty($info['playtime_seconds']) && !empty($thisfile_midi['totalticks'])) { + $ticksPerQuarterNote = isset($thisfile_midi_raw['ticksperqnote']) ? $thisfile_midi_raw['ticksperqnote'] : 480; + if ($ticksPerQuarterNote > 0) { + $totalQuarterNotes = $thisfile_midi['totalticks'] / $ticksPerQuarterNote; + $info['playtime_seconds'] = $totalQuarterNotes * 0.5; + } + } if (!empty($info['playtime_seconds'])) { $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.mp3.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.mp3.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.mp3.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.mp3.php 2026-05-22 07:52:18.000000000 +0000 @@ -305,7 +305,11 @@ } elseif (!empty($info['audio']['bitrate'])) { if ($info['audio']['bitrate_mode'] == 'cbr') { - $encoder_options = strtoupper($info['audio']['bitrate_mode']).round($info['audio']['bitrate'] / 1000); + if ($info['audio']['bitrate'] == 'free') { + $encoder_options = strtoupper($info['audio']['bitrate_mode']); + } else { + $encoder_options = strtoupper($info['audio']['bitrate_mode']).round($info['audio']['bitrate'] / 1000); + } } else { $encoder_options = strtoupper($info['audio']['bitrate_mode']); } @@ -315,7 +319,7 @@ $encoder_options .= ' -b'.$thisfile_mpeg_audio_lame['bitrate_min']; } - if (isset($thisfile_mpeg_audio['bitrate']) && $thisfile_mpeg_audio['bitrate'] === 'free') { + if (isset($thisfile_mpeg_audio['bitrate']) && ($thisfile_mpeg_audio['bitrate'] === 'free')) { $encoder_options .= ' --freeformat'; } @@ -712,7 +716,7 @@ //$info['audio']['bitrate'] = (($framelengthfloat - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144; $info['audio']['bitrate'] = $framelengthfloat * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 144; } - $thisfile_mpeg_audio['framelength'] = floor($framelengthfloat); + $thisfile_mpeg_audio['framelength'] = (int) floor($framelengthfloat); } if ($thisfile_mpeg_audio['xing_flags']['toc']) { @@ -919,7 +923,7 @@ // LAME CBR - if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1 && $thisfile_mpeg_audio['bitrate'] !== 'free') { + if (($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) && ($thisfile_mpeg_audio['bitrate'] !== 'free')) { $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']); @@ -1174,8 +1178,7 @@ $nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']); if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) { - /** @phpstan-ignore-next-line */ - getid3_lib::safe_inc($info['mp3_validity_check_bitrates'][$nextframetestarray['mpeg']['audio']['bitrate']]); + getid3_lib::safe_inc($info['mp3_validity_check_bitrates'][intval($nextframetestarray['mpeg']['audio']['bitrate'])]); if ($ScanAsCBR) { // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) { @@ -1186,7 +1189,7 @@ // next frame is OK, get ready to check the one after that if (isset($nextframetestarray['mpeg']['audio']['framelength']) && ($nextframetestarray['mpeg']['audio']['framelength'] > 0)) { - $nextframetestoffset += $nextframetestarray['mpeg']['audio']['framelength']; + $nextframetestoffset += (int) $nextframetestarray['mpeg']['audio']['framelength']; } else { $this->error('Frame at offset ('.$offset.') is has an invalid frame length.'); return false; @@ -1380,11 +1383,11 @@ $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']); + $pct_data_scanned = getid3_lib::SafeDiv($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) { foreach ($value1 as $key2 => $value2) { - $Distribution[$key1][$key2] = round($value2 / $pct_data_scanned); + $Distribution[$key1][$key2] = $pct_data_scanned ? round($value2 / $pct_data_scanned) : 1; } } break; @@ -1475,7 +1478,7 @@ $SyncSeekAttemptsMax = 1000; $FirstFrameThisfileInfo = null; while ($SynchSeekOffset < $sync_seek_buffer_size) { - if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !feof($this->getid3->fp)) { + if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !$this->feof()) { if ($SynchSeekOffset > $sync_seek_buffer_size) { // if a synch's not found within the first 128k bytes, then give up @@ -1490,20 +1493,6 @@ unset($info['mpeg']); } return false; - - } elseif (feof($this->getid3->fp)) { - - $this->error('Could not find valid MPEG audio synch before end of file'); - if (isset($info['audio']['bitrate'])) { - unset($info['audio']['bitrate']); - } - if (isset($info['mpeg']['audio'])) { - unset($info['mpeg']['audio']); - } - if (isset($info['mpeg']) && (!is_array($info['mpeg']) || (count($info['mpeg']) == 0))) { - unset($info['mpeg']); - } - return false; } } @@ -1652,7 +1641,7 @@ } $frames_scanned++; if ($frames_scan_per_segment && (++$frames_scanned_this_segment >= $frames_scan_per_segment)) { - $this_pct_scanned = ($this->ftell() - $scan_start_offset[$current_segment]) / ($info['avdataend'] - $info['avdataoffset']); + $this_pct_scanned = getid3_lib::SafeDiv($this->ftell() - $scan_start_offset[$current_segment], $info['avdataend'] - $info['avdataoffset']); if (($current_segment == 0) && (($this_pct_scanned * $max_scan_segments) >= 1)) { // file likely contains < $max_frames_scan, just scan as one segment $max_scan_segments = 1; @@ -1743,6 +1732,10 @@ } $info['audio']['channels'] = $info['mpeg']['audio']['channels']; + if ($info['audio']['channels'] < 1) { + $this->error('Corrupt MP3 file: no channels'); + return false; + } $info['audio']['channelmode'] = $info['mpeg']['audio']['channelmode']; $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; return true; @@ -1771,14 +1764,15 @@ static $MPEGaudioBitrate; if (empty($MPEGaudioBitrate)) { $MPEGaudioBitrate = array ( - '1' => array (1 => array('free', 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000), - 2 => array('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000), - 3 => array('free', 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000) - ), - - '2' => array (1 => array('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000), - 2 => array('free', 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000), - ) + '1' => array( + 1 => array('free', 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000), + 2 => array('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000), + 3 => array('free', 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000) + ), + '2' => array( + 1 => array('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000), + 2 => array('free', 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000), + ), ); $MPEGaudioBitrate['2'][3] = $MPEGaudioBitrate['2'][2]; $MPEGaudioBitrate['2.5'] = $MPEGaudioBitrate['2']; diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.mpc.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.mpc.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.mpc.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.mpc.php 2026-05-22 07:52:18.000000000 +0000 @@ -137,7 +137,7 @@ $info['audio']['channels'] = $thisPacket['channels']; $info['audio']['sample_rate'] = $thisPacket['sample_frequency']; $info['playtime_seconds'] = $thisPacket['sample_count'] / $thisPacket['sample_frequency']; - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + $info['audio']['bitrate'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']); break; case 'RG': // Replay Gain @@ -282,7 +282,7 @@ $info['audio']['sample_rate'] = $thisfile_mpc_header['sample_rate']; $thisfile_mpc_header['samples'] = ((($thisfile_mpc_header['frame_count'] - 1) * 1152) + $thisfile_mpc_header['last_frame_length']) * $info['audio']['channels']; - $info['playtime_seconds'] = ($thisfile_mpc_header['samples'] / $info['audio']['channels']) / $info['audio']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($thisfile_mpc_header['samples'], $info['audio']['channels'] * $info['audio']['sample_rate']); if ($info['playtime_seconds'] == 0) { $this->error('Corrupt MPC file: playtime_seconds == zero'); return false; diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.ogg.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.ogg.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.ogg.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.ogg.php 2026-05-22 07:52:18.000000000 +0000 @@ -210,8 +210,8 @@ $filedataoffset += 20; $info['ogg']['skeleton']['fishead']['version'] = $info['ogg']['skeleton']['fishead']['raw']['version_major'].'.'.$info['ogg']['skeleton']['fishead']['raw']['version_minor']; - $info['ogg']['skeleton']['fishead']['presentationtime'] = $info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator']; - $info['ogg']['skeleton']['fishead']['basetime'] = $info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator']; + $info['ogg']['skeleton']['fishead']['presentationtime'] = getid3_lib::SafeDiv($info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'], $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator']); + $info['ogg']['skeleton']['fishead']['basetime'] = getid3_lib::SafeDiv($info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'], $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator']); $info['ogg']['skeleton']['fishead']['utc'] = $info['ogg']['skeleton']['fishead']['raw']['utc']; @@ -288,7 +288,7 @@ $info['audio']['sample_rate'] = $info['flac']['STREAMINFO']['sample_rate']; $info['audio']['channels'] = $info['flac']['STREAMINFO']['channels']; $info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample']; - $info['playtime_seconds'] = $info['flac']['STREAMINFO']['samples_stream'] / $info['flac']['STREAMINFO']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['flac']['STREAMINFO']['samples_stream'], $info['flac']['STREAMINFO']['sample_rate']); } } else { @@ -350,6 +350,12 @@ $this->fseek(max($info['avdataend'] - $this->getid3->fread_buffer_size(), 0)); $LastChunkOfOgg = strrev($this->fread($this->getid3->fread_buffer_size())); if ($LastOggSpostion = strpos($LastChunkOfOgg, 'SggO')) { + if (substr($LastChunkOfOgg, 13, 8) === "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF") { + // https://github.com/JamesHeinrich/getID3/issues/450 + // "Sometimes, Opus encoders (WhatsApp voice registrations and others) add a special last header with a granule duration of 0xFFFFFFFFFFFFFF. + // This value indicates "this is the end," but must be ignored; otherwise, it makes calculations wrong." + $LastOggSpostion = strpos($LastChunkOfOgg, 'SggO', $LastOggSpostion + 1); + } $this->fseek($info['avdataend'] - ($LastOggSpostion + strlen('SggO'))); $info['avdataend'] = $this->ftell(); $info['ogg']['pageheader']['eos'] = $this->ParseOggPageHeader(); @@ -359,7 +365,7 @@ return false; } if (!empty($info['audio']['sample_rate'])) { - $info['ogg']['bitrate_average'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['ogg']['samples'] / $info['audio']['sample_rate']); + $info['ogg']['bitrate_average'] = (($info['avdataend'] - $info['avdataoffset']) * 8) * $info['audio']['sample_rate'] / $info['ogg']['samples']; } } @@ -534,12 +540,12 @@ $filedata = $this->fread($this->getid3->fread_buffer_size()); $filedataoffset = 0; - while ((substr($filedata, $filedataoffset++, 4) != 'OggS')) { + while (substr($filedata, $filedataoffset++, 4) != 'OggS') { if (($this->ftell() - $oggheader['page_start_offset']) >= $this->getid3->fread_buffer_size()) { // should be found before here return false; } - if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) { + if (($filedataoffset + 28) > strlen($filedata)) { if ($this->feof() || (($filedata .= $this->fread($this->getid3->fread_buffer_size())) === '')) { // get some more data, unless eof, in which case fail return false; @@ -787,29 +793,29 @@ switch ($index) { case 'rg_audiophile': case 'replaygain_album_gain': - $info['replay_gain']['album']['adjustment'] = (double) $commentvalue[0]; + $info['replay_gain']['album']['adjustment'] = (float) $commentvalue[0]; unset($info['ogg']['comments'][$index]); break; case 'rg_radio': case 'replaygain_track_gain': - $info['replay_gain']['track']['adjustment'] = (double) $commentvalue[0]; + $info['replay_gain']['track']['adjustment'] = (float) $commentvalue[0]; unset($info['ogg']['comments'][$index]); break; case 'replaygain_album_peak': - $info['replay_gain']['album']['peak'] = (double) $commentvalue[0]; + $info['replay_gain']['album']['peak'] = (float) $commentvalue[0]; unset($info['ogg']['comments'][$index]); break; case 'rg_peak': case 'replaygain_track_peak': - $info['replay_gain']['track']['peak'] = (double) $commentvalue[0]; + $info['replay_gain']['track']['peak'] = (float) $commentvalue[0]; unset($info['ogg']['comments'][$index]); break; case 'replaygain_reference_loudness': - $info['replay_gain']['reference_volume'] = (double) $commentvalue[0]; + $info['replay_gain']['reference_volume'] = (float) $commentvalue[0]; unset($info['ogg']['comments'][$index]); break; diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.rkau.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.rkau.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.rkau.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.rkau.php 2026-05-22 07:52:18.000000000 +0000 @@ -75,7 +75,7 @@ $info['audio']['sample_rate'] = $info['rkau']['sample_rate']; $info['playtime_seconds'] = $info['rkau']['source_bytes'] / ($info['rkau']['sample_rate'] * $info['rkau']['channels'] * ($info['rkau']['bits_per_sample'] / 8)); - $info['audio']['bitrate'] = ($info['rkau']['compressed_bytes'] * 8) / $info['playtime_seconds']; + $info['audio']['bitrate'] = getid3_lib::SafeDiv($info['rkau']['compressed_bytes'] * 8, $info['playtime_seconds']); return true; diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.shorten.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.shorten.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.shorten.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.shorten.php 2026-05-22 07:52:18.000000000 +0000 @@ -139,7 +139,7 @@ static $shorten_present; if (!isset($shorten_present)) { - $shorten_present = file_exists('/usr/local/bin/shorten') || `which shorten`; + $shorten_present = file_exists('/usr/local/bin/shorten') || shell_exec('which shorten'); } if (!$shorten_present) { $this->error('shorten binary was not found in path or /usr/local/bin'); @@ -149,7 +149,7 @@ } - $output = `$commandline`; + $output = shell_exec($commandline); if (!empty($output) && (substr($output, 12, 4) == 'fmt ')) { @@ -166,7 +166,7 @@ if (substr($output, 20 + $fmt_size, 4) == 'data') { - $info['playtime_seconds'] = getid3_lib::LittleEndian2Int(substr($output, 20 + 4 + $fmt_size, 4)) / $DecodedWAVFORMATEX['raw']['nAvgBytesPerSec']; + $info['playtime_seconds'] = getid3_lib::SafeDiv(getid3_lib::LittleEndian2Int(substr($output, 20 + 4 + $fmt_size, 4)), $DecodedWAVFORMATEX['raw']['nAvgBytesPerSec']); } else { @@ -175,7 +175,7 @@ } - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8; + $info['audio']['bitrate'] = getid3_lib::SafeDiv($info['avdataend'] - $info['avdataoffset'], $info['playtime_seconds']) * 8; } else { diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.tta.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.tta.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.tta.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.tta.php 2026-05-22 07:52:18.000000000 +0000 @@ -59,7 +59,7 @@ $info['tta']['samples_per_channel'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4)); $info['audio']['encoder_options'] = '-e'.$info['tta']['compression_level']; - $info['playtime_seconds'] = $info['tta']['samples_per_channel'] / $info['tta']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['tta']['samples_per_channel'], $info['tta']['sample_rate']); break; case '2': // TTA v2.x @@ -75,7 +75,7 @@ $info['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 16, 4)); $info['audio']['encoder_options'] = '-e'.$info['tta']['compression_level']; - $info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['tta']['data_length'], $info['tta']['sample_rate']); break; case '1': // TTA v3.x @@ -91,7 +91,7 @@ $info['tta']['crc32_footer'] = substr($ttaheader, 18, 4); $info['tta']['seek_point'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 22, 4)); - $info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['tta']['data_length'], $info['tta']['sample_rate']); break; default: @@ -103,7 +103,7 @@ $info['audio']['bits_per_sample'] = $info['tta']['bits_per_sample']; $info['audio']['sample_rate'] = $info['tta']['sample_rate']; $info['audio']['channels'] = $info['tta']['channels']; - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + $info['audio']['bitrate'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']); return true; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.voc.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.voc.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.voc.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.voc.php 2026-05-22 07:52:18.000000000 +0000 @@ -69,7 +69,6 @@ $BlockSize = getid3_lib::LittleEndian2Int(substr($BlockData, 1, 3)); $ThisBlock = array(); - /** @phpstan-ignore-next-line */ getid3_lib::safe_inc($thisfile_voc['blocktypes'][$BlockType], 1); switch ($BlockType) { case 0: // Terminator @@ -140,7 +139,7 @@ $thisfile_audio['sample_rate'] = $ThisBlock['sample_rate']; $thisfile_audio['bits_per_sample'] = $ThisBlock['bits_per_sample']; - $thisfile_audio['channels'] = $ThisBlock['channels']; + $thisfile_audio['channels'] = $ThisBlock['channels'] ?: 1; break; default: @@ -164,8 +163,8 @@ ksort($thisfile_voc['blocktypes']); if (!empty($thisfile_voc['compressed_bits_per_sample'])) { - $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($thisfile_voc['compressed_bits_per_sample'] * $thisfile_audio['channels'] * $thisfile_audio['sample_rate']); - $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + $info['playtime_seconds'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $thisfile_voc['compressed_bits_per_sample'] * $thisfile_audio['channels'] * $thisfile_audio['sample_rate']); + $thisfile_audio['bitrate'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']); } return true; diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.wavpack.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.wavpack.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.audio.wavpack.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.audio.wavpack.php 2026-05-22 07:52:18.000000000 +0000 @@ -42,7 +42,7 @@ if ($this->ftell() >= $info['avdataend']) { break; - } elseif (feof($this->getid3->fp)) { + } elseif ($this->feof()) { break; } elseif ( isset($info['wavpack']['blockheader']['total_samples']) && @@ -157,11 +157,11 @@ $info['audio']['lossless'] = !$info['wavpack']['blockheader']['flags']['hybrid']; } - while (!feof($this->getid3->fp) && ($this->ftell() < ($blockheader_offset + $blockheader_size + 8))) { + while (!$this->feof() && ($this->ftell() < ($blockheader_offset + $blockheader_size + 8))) { $metablock = array('offset'=>$this->ftell()); $metablockheader = $this->fread(2); - if (feof($this->getid3->fp)) { + if ($this->feof()) { break; } $metablock['id'] = ord($metablockheader[0]); @@ -243,7 +243,7 @@ $metablock['riff']['original_filesize'] = $original_wav_filesize; $info['wavpack']['riff_trailer_size'] = $original_wav_filesize - $metablock['riff']['WAVE']['data'][0]['size'] - $metablock['riff']['header_size']; - $info['playtime_seconds'] = $info['wavpack']['blockheader']['total_samples'] / $info['audio']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['wavpack']['blockheader']['total_samples'], $info['audio']['sample_rate']); // Safe RIFF header in case there's a RIFF footer later $metablockRIFFheader = $metablock['data']; diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.graphic.bmp.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.graphic.bmp.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.graphic.bmp.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.graphic.bmp.php 2026-05-22 07:52:18.000000000 +0000 @@ -336,307 +336,311 @@ } if ($this->ExtractData) { - $this->fseek($thisfile_bmp_header_raw['data_offset']); - $RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundry - $BMPpixelData = $this->fread($thisfile_bmp_header_raw['height'] * $RowByteLength); - $pixeldataoffset = 0; - $thisfile_bmp_header_raw['compression'] = (isset($thisfile_bmp_header_raw['compression']) ? $thisfile_bmp_header_raw['compression'] : ''); - switch ($thisfile_bmp_header_raw['compression']) { - - case 0: // BI_RGB - switch ($thisfile_bmp_header_raw['bits_per_pixel']) { - 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++]); - for ($i = 7; $i >= 0; $i--) { - $paletteindex = ($paletteindexbyte & (0x01 << $i)) >> $i; - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - $col++; + if (!$thisfile_bmp_header_raw['width'] || !$thisfile_bmp_header_raw['height']) { + $thisfile_bmp['data'] = array(); + } else { + $this->fseek($thisfile_bmp_header_raw['data_offset']); + $RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundry + $BMPpixelData = $this->fread($thisfile_bmp_header_raw['height'] * $RowByteLength); + $pixeldataoffset = 0; + $thisfile_bmp_header_raw['compression'] = (isset($thisfile_bmp_header_raw['compression']) ? $thisfile_bmp_header_raw['compression'] : ''); + switch ($thisfile_bmp_header_raw['compression']) { + + case 0: // BI_RGB + switch ($thisfile_bmp_header_raw['bits_per_pixel']) { + 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++]); + for ($i = 7; $i >= 0; $i--) { + $paletteindex = ($paletteindexbyte & (0x01 << $i)) >> $i; + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; + $col++; + } + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; + + 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++]); + for ($i = 1; $i >= 0; $i--) { + $paletteindex = ($paletteindexbyte & (0x0F << (4 * $i))) >> (4 * $i); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; + $col++; + } + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; } } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - 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++]); - for ($i = 1; $i >= 0; $i--) { - $paletteindex = ($paletteindexbyte & (0x0F << (4 * $i))) >> (4 * $i); + break; + + 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++]); $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - $col++; + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; } } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - 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++]); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - 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]); - $pixeldataoffset += 3; - } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - 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]); - $pixeldataoffset += 4; - } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - case 16: - // ? - break; - - default: - $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); - break; - } - break; + break; + 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]); + $pixeldataoffset += 3; + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; - case 1: // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp - switch ($thisfile_bmp_header_raw['bits_per_pixel']) { - case 8: - $pixelcounter = 0; - while ($pixeldataoffset < strlen($BMPpixelData)) { - $firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - if ($firstbyte == 0) { - - // escaped/absolute mode - the first byte of the pair can be set to zero to - // indicate an escape character that denotes the end of a line, the end of - // a bitmap, or a delta, depending on the value of the second byte. - switch ($secondbyte) { - case 0: - // end of line - // no need for special processing, just ignore - break; - - case 1: - // end of bitmap - $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case - break; - - case 2: - // delta - The 2 bytes following the escape contain unsigned values - // indicating the horizontal and vertical offsets of the next pixel - // from the current position. - $colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement; - $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement; - $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col; - break; - - default: - // In absolute mode, the first byte is zero and the second byte is a - // value in the range 03H through FFH. The second byte represents the - // number of bytes that follow, each of which contains the color index - // of a single pixel. Each run must be aligned on a word boundary. - for ($i = 0; $i < $secondbyte; $i++) { - $paletteindex = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $col = $pixelcounter % $thisfile_bmp_header_raw['width']; - $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - $pixelcounter++; - } - while (($pixeldataoffset % 2) != 0) { - // Each run must be aligned on a word boundary. - $pixeldataoffset++; - } - break; - } - - } else { - - // encoded mode - the first byte specifies the number of consecutive pixels - // to be drawn using the color index contained in the second byte. - for ($i = 0; $i < $firstbyte; $i++) { - $col = $pixelcounter % $thisfile_bmp_header_raw['width']; - $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$secondbyte]; - $pixelcounter++; - } - - } - } - break; - - default: - $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); - break; - } - break; + 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]); + $pixeldataoffset += 4; + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; + case 16: + // ? + break; + + default: + $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); + break; + } + break; + + + case 1: // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp + switch ($thisfile_bmp_header_raw['bits_per_pixel']) { + case 8: + $pixelcounter = 0; + while ($pixeldataoffset < strlen($BMPpixelData)) { + $firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + if ($firstbyte == 0) { + + // escaped/absolute mode - the first byte of the pair can be set to zero to + // indicate an escape character that denotes the end of a line, the end of + // a bitmap, or a delta, depending on the value of the second byte. + switch ($secondbyte) { + case 0: + // end of line + // no need for special processing, just ignore + break; + + case 1: + // end of bitmap + $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case + break; + + case 2: + // delta - The 2 bytes following the escape contain unsigned values + // indicating the horizontal and vertical offsets of the next pixel + // from the current position. + $colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement; + $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement; + $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col; + break; + + default: + // In absolute mode, the first byte is zero and the second byte is a + // value in the range 03H through FFH. The second byte represents the + // number of bytes that follow, each of which contains the color index + // of a single pixel. Each run must be aligned on a word boundary. + for ($i = 0; $i < $secondbyte; $i++) { + $paletteindex = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $col = $pixelcounter % $thisfile_bmp_header_raw['width']; + $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; + $pixelcounter++; + } + while (($pixeldataoffset % 2) != 0) { + // Each run must be aligned on a word boundary. + $pixeldataoffset++; + } + break; + } + + } else { + + // encoded mode - the first byte specifies the number of consecutive pixels + // to be drawn using the color index contained in the second byte. + for ($i = 0; $i < $firstbyte; $i++) { + $col = $pixelcounter % $thisfile_bmp_header_raw['width']; + $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$secondbyte]; + $pixelcounter++; + } + } + } + break; - case 2: // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp - switch ($thisfile_bmp_header_raw['bits_per_pixel']) { - case 4: - $pixelcounter = 0; - $paletteindexes = array(); - while ($pixeldataoffset < strlen($BMPpixelData)) { - $firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - if ($firstbyte == 0) { - - // escaped/absolute mode - the first byte of the pair can be set to zero to - // indicate an escape character that denotes the end of a line, the end of - // a bitmap, or a delta, depending on the value of the second byte. - switch ($secondbyte) { - case 0: - // end of line - // no need for special processing, just ignore - break; - - case 1: - // end of bitmap - $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case - break; - - case 2: - // delta - The 2 bytes following the escape contain unsigned values - // indicating the horizontal and vertical offsets of the next pixel - // from the current position. - $colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement; - $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement; - $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col; - break; - - default: - // In absolute mode, the first byte is zero. The second byte contains the number - // of color indexes that follow. Subsequent bytes contain color indexes in their - // high- and low-order 4 bits, one color index for each pixel. In absolute mode, - // each run must be aligned on a word boundary. - $paletteindexes = array(); - for ($i = 0; $i < ceil($secondbyte / 2); $i++) { - $paletteindexbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4; - $paletteindexes[] = ($paletteindexbyte & 0x0F); - } - while (($pixeldataoffset % 2) != 0) { - // Each run must be aligned on a word boundary. - $pixeldataoffset++; - } - - foreach ($paletteindexes as $paletteindex) { - $col = $pixelcounter % $thisfile_bmp_header_raw['width']; - $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - $pixelcounter++; - } - break; - } - - } else { - - // encoded mode - the first byte of the pair contains the number of pixels to be - // drawn using the color indexes in the second byte. The second byte contains two - // color indexes, one in its high-order 4 bits and one in its low-order 4 bits. - // The first of the pixels is drawn using the color specified by the high-order - // 4 bits, the second is drawn using the color in the low-order 4 bits, the third - // is drawn using the color in the high-order 4 bits, and so on, until all the - // pixels specified by the first byte have been drawn. - $paletteindexes[0] = ($secondbyte & 0xF0) >> 4; - $paletteindexes[1] = ($secondbyte & 0x0F); - for ($i = 0; $i < $firstbyte; $i++) { - $col = $pixelcounter % $thisfile_bmp_header_raw['width']; - $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindexes[($i % 2)]]; - $pixelcounter++; - } - - } - } - break; - - default: - $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); - break; - } - break; + default: + $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); + break; + } + break; + + + + case 2: // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp + switch ($thisfile_bmp_header_raw['bits_per_pixel']) { + case 4: + $pixelcounter = 0; + $paletteindexes = array(); + while ($pixeldataoffset < strlen($BMPpixelData)) { + $firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + if ($firstbyte == 0) { + + // escaped/absolute mode - the first byte of the pair can be set to zero to + // indicate an escape character that denotes the end of a line, the end of + // a bitmap, or a delta, depending on the value of the second byte. + switch ($secondbyte) { + case 0: + // end of line + // no need for special processing, just ignore + break; + + case 1: + // end of bitmap + $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case + break; + + case 2: + // delta - The 2 bytes following the escape contain unsigned values + // indicating the horizontal and vertical offsets of the next pixel + // from the current position. + $colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement; + $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement; + $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col; + break; + + default: + // In absolute mode, the first byte is zero. The second byte contains the number + // of color indexes that follow. Subsequent bytes contain color indexes in their + // high- and low-order 4 bits, one color index for each pixel. In absolute mode, + // each run must be aligned on a word boundary. + $paletteindexes = array(); + for ($i = 0; $i < ceil($secondbyte / 2); $i++) { + $paletteindexbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4; + $paletteindexes[] = ($paletteindexbyte & 0x0F); + } + while (($pixeldataoffset % 2) != 0) { + // Each run must be aligned on a word boundary. + $pixeldataoffset++; + } + + foreach ($paletteindexes as $paletteindex) { + $col = $pixelcounter % $thisfile_bmp_header_raw['width']; + $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; + $pixelcounter++; + } + break; + } + + } else { + + // encoded mode - the first byte of the pair contains the number of pixels to be + // drawn using the color indexes in the second byte. The second byte contains two + // color indexes, one in its high-order 4 bits and one in its low-order 4 bits. + // The first of the pixels is drawn using the color specified by the high-order + // 4 bits, the second is drawn using the color in the low-order 4 bits, the third + // is drawn using the color in the high-order 4 bits, and so on, until all the + // pixels specified by the first byte have been drawn. + $paletteindexes[0] = ($secondbyte & 0xF0) >> 4; + $paletteindexes[1] = ($secondbyte & 0x0F); + for ($i = 0; $i < $firstbyte; $i++) { + $col = $pixelcounter % $thisfile_bmp_header_raw['width']; + $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindexes[($i % 2)]]; + $pixelcounter++; + } + } + } + break; - case 3: // BI_BITFIELDS - switch ($thisfile_bmp_header_raw['bits_per_pixel']) { - case 16: - case 32: - $redshift = 0; - $greenshift = 0; - $blueshift = 0; - while ((($thisfile_bmp_header_raw['red_mask'] >> $redshift) & 0x01) == 0) { - $redshift++; - } - while ((($thisfile_bmp_header_raw['green_mask'] >> $greenshift) & 0x01) == 0) { - $greenshift++; - } - while ((($thisfile_bmp_header_raw['blue_mask'] >> $blueshift) & 0x01) == 0) { - $blueshift++; - } - for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { - for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { - $pixelvalue = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $thisfile_bmp_header_raw['bits_per_pixel'] / 8)); - $pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8; - - $red = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['red_mask']) >> $redshift) / ($thisfile_bmp_header_raw['red_mask'] >> $redshift)) * 255)); - $green = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw['green_mask'] >> $greenshift)) * 255)); - $blue = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw['blue_mask'] >> $blueshift)) * 255)); - $thisfile_bmp['data'][$row][$col] = (($red << 16) | ($green << 8) | ($blue)); - } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - default: - $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); - break; - } - break; + default: + $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); + break; + } + break; + + + case 3: // BI_BITFIELDS + switch ($thisfile_bmp_header_raw['bits_per_pixel']) { + case 16: + case 32: + $redshift = 0; + $greenshift = 0; + $blueshift = 0; + while ((($thisfile_bmp_header_raw['red_mask'] >> $redshift) & 0x01) == 0) { + $redshift++; + } + while ((($thisfile_bmp_header_raw['green_mask'] >> $greenshift) & 0x01) == 0) { + $greenshift++; + } + while ((($thisfile_bmp_header_raw['blue_mask'] >> $blueshift) & 0x01) == 0) { + $blueshift++; + } + for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { + $pixelvalue = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $thisfile_bmp_header_raw['bits_per_pixel'] / 8)); + $pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8; + + $red = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['red_mask']) >> $redshift) / ($thisfile_bmp_header_raw['red_mask'] >> $redshift)) * 255)); + $green = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw['green_mask'] >> $greenshift)) * 255)); + $blue = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw['blue_mask'] >> $blueshift)) * 255)); + $thisfile_bmp['data'][$row][$col] = (($red << 16) | ($green << 8) | ($blue)); + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; + + default: + $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); + break; + } + break; - default: // unhandled compression type - $this->error('Unknown/unhandled compression type value ('.$thisfile_bmp_header_raw['compression'].') - cannot decompress pixel data'); - break; + default: // unhandled compression type + $this->error('Unknown/unhandled compression type value ('.$thisfile_bmp_header_raw['compression'].') - cannot decompress pixel data'); + break; + } } } @@ -672,12 +676,16 @@ } if (headers_sent()) { echo 'plotted '.($BMPinfo['resolution_x'] * $BMPinfo['resolution_y']).' pixels in '.(time() - $starttime).' seconds
'; - imagedestroy($im); + if (PHP_VERSION_ID < 80000) { // imagedestroy does nothing after PHP8 and give deprecation warnings in PHP8.5 + imagedestroy($im); + } exit; } else { header('Content-type: image/png'); imagepng($im); - imagedestroy($im); + if (PHP_VERSION_ID < 80000) { + imagedestroy($im); + } return true; } } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.graphic.jpg.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.graphic.jpg.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.graphic.jpg.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.graphic.jpg.php 2026-05-22 07:52:18.000000000 +0000 @@ -116,12 +116,13 @@ } if (isset($info['jpg']['exif']['GPS']['GPSDateStamp'])) { + $computed_time = array(0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0); + $explodedGPSDateStamp = explode(':', $info['jpg']['exif']['GPS']['GPSDateStamp']); - $computed_time[5] = (isset($explodedGPSDateStamp[0]) ? $explodedGPSDateStamp[0] : ''); + $computed_time[5] = $explodedGPSDateStamp[0]; $computed_time[3] = (isset($explodedGPSDateStamp[1]) ? $explodedGPSDateStamp[1] : ''); $computed_time[4] = (isset($explodedGPSDateStamp[2]) ? $explodedGPSDateStamp[2] : ''); - $computed_time = array(0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0); if (isset($info['jpg']['exif']['GPS']['GPSTimeStamp']) && is_array($info['jpg']['exif']['GPS']['GPSTimeStamp'])) { foreach ($info['jpg']['exif']['GPS']['GPSTimeStamp'] as $key => $value) { $computed_time[$key] = getid3_lib::DecimalizeFraction($value); @@ -185,7 +186,7 @@ * @return mixed */ public function CastAsAppropriate($value) { - if (is_array($value)) { + if (is_array($value) || is_null($value)) { return $value; } elseif (preg_match('#^[0-9]+/[0-9]+$#', $value)) { return getid3_lib::DecimalizeFraction($value); diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.graphic.png.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.graphic.png.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.graphic.png.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.graphic.png.php 2026-05-22 07:52:18.000000000 +0000 @@ -137,7 +137,7 @@ case 'tRNS': // Transparency $thisfile_png_chunk_type_text['header'] = $chunk; - switch ($thisfile_png['IHDR']['raw']['color_type']) { + switch ($thisfile_png['IHDR']['raw']['color_type']) { // @phpstan-ignore-line case 0: $thisfile_png_chunk_type_text['transparent_color_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2)); break; @@ -273,7 +273,7 @@ case 'bKGD': // Background Color $thisfile_png_chunk_type_text['header'] = $chunk; - switch ($thisfile_png['IHDR']['raw']['color_type']) { + switch ($thisfile_png['IHDR']['raw']['color_type']) { // @phpstan-ignore-line case 0: case 4: $thisfile_png_chunk_type_text['background_gray'] = getid3_lib::BigEndian2Int($chunk['data']); @@ -307,7 +307,7 @@ case 'sBIT': // Significant Bits $thisfile_png_chunk_type_text['header'] = $chunk; - switch ($thisfile_png['IHDR']['raw']['color_type']) { + switch ($thisfile_png['IHDR']['raw']['color_type']) { // @phpstan-ignore-line case 0: $thisfile_png_chunk_type_text['significant_bits_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1)); break; @@ -422,10 +422,7 @@ case 'gIFg': // GIF Graphic Control Extension - $gIFgCounter = 0; - if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) { - $gIFgCounter = count($thisfile_png_chunk_type_text); - } + $gIFgCounter = count($thisfile_png_chunk_type_text); $thisfile_png_chunk_type_text[$gIFgCounter]['header'] = $chunk; $thisfile_png_chunk_type_text[$gIFgCounter]['disposal_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1)); $thisfile_png_chunk_type_text[$gIFgCounter]['user_input_flag'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1)); @@ -434,10 +431,7 @@ case 'gIFx': // GIF Application Extension - $gIFxCounter = 0; - if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) { - $gIFxCounter = count($thisfile_png_chunk_type_text); - } + $gIFxCounter = count($thisfile_png_chunk_type_text); $thisfile_png_chunk_type_text[$gIFxCounter]['header'] = $chunk; $thisfile_png_chunk_type_text[$gIFxCounter]['application_identifier'] = substr($chunk['data'], 0, 8); $thisfile_png_chunk_type_text[$gIFxCounter]['authentication_code'] = substr($chunk['data'], 8, 3); @@ -446,10 +440,7 @@ case 'IDAT': // Image Data - $idatinformationfieldindex = 0; - if (isset($thisfile_png['IDAT']) && is_array($thisfile_png['IDAT'])) { - $idatinformationfieldindex = count($thisfile_png['IDAT']); - } + $idatinformationfieldindex = count($thisfile_png['IDAT']); unset($chunk['data']); $thisfile_png_chunk_type_text[$idatinformationfieldindex]['header'] = $chunk; break; diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.graphic.svg.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.graphic.svg.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.graphic.svg.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.graphic.svg.php 2026-05-22 07:52:18.000000000 +0000 @@ -59,7 +59,7 @@ $keyvaluepair = trim($keyvaluepair); if ($keyvaluepair) { $keyvalueexploded = explode('=', $keyvaluepair); - $key = (isset($keyvalueexploded[0]) ? $keyvalueexploded[0] : ''); + $key = $keyvalueexploded[0]; $value = (isset($keyvalueexploded[1]) ? $keyvalueexploded[1] : ''); $info['svg'][$section_to_fix]['sections'][$key] = trim($value, '"'); } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.misc.cue.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.misc.cue.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.misc.cue.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.misc.cue.php 2026-05-22 07:52:18.000000000 +0000 @@ -147,7 +147,7 @@ public function parseComment($line, $track_on) { $explodedline = explode(' ', $line, 3); - $comment_REM = (isset($explodedline[0]) ? $explodedline[0] : ''); + $comment_REM = $explodedline[0]; $comment_type = (isset($explodedline[1]) ? $explodedline[1] : ''); $comment_data = (isset($explodedline[2]) ? $explodedline[2] : ''); if (($comment_REM == 'REM') && $comment_type) { @@ -262,7 +262,7 @@ //extract the minutes, seconds, and frames $explodedline = explode(':', $line); - $minutes = (isset($explodedline[0]) ? $explodedline[0] : ''); + $minutes = $explodedline[0]; $seconds = (isset($explodedline[1]) ? $explodedline[1] : ''); $frames = (isset($explodedline[2]) ? $explodedline[2] : ''); diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.misc.gpx.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.misc.gpx.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.misc.gpx.php 1970-01-01 00:00:00.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.misc.gpx.php 2026-05-22 07:52:18.000000000 +0000 @@ -0,0 +1,36 @@ + // +// available at https://github.com/JamesHeinrich/getID3 // +// or https://www.getid3.org // +// or http://getid3.sourceforge.net // +// see readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.misc.gpx.php // +// module for analyzing gpx files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + +if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers + exit; +} + +class getid3_gpx extends getid3_handler +{ + /** + * @return bool + */ + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'gpx'; + + $this->error('gpx parsing not enabled in this version of getID3()'); + return false; + + } + +} diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.tag.apetag.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.tag.apetag.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.tag.apetag.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.tag.apetag.php 2026-05-22 07:52:18.000000000 +0000 @@ -42,6 +42,10 @@ $this->warning('Unable to check for APEtags because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'); return false; } + if (PHP_INT_MAX == 2147483647) { + // https://github.com/JamesHeinrich/getID3/issues/439 + $this->warning('APEtag flags may not be parsed correctly on 32-bit PHP'); + } $id3v1tagsize = 128; $apetagheadersize = 32; @@ -267,7 +271,7 @@ case 'cover art (publisher logo)': case 'cover art (recording)': case 'cover art (studio)': - // list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html + // list of possible cover arts from https://github.com/mono/taglib-sharp/blob/taglib-sharp-2.0.3.2/src/TagLib/Ape/Tag.cs if (is_array($thisfile_ape_items_current['data'])) { $this->warning('APEtag "'.$item_key.'" should be flagged as Binary data, but was incorrectly flagged as UTF-8'); $thisfile_ape_items_current['data'] = implode("\x00", $thisfile_ape_items_current['data']); @@ -332,7 +336,7 @@ $info['ape']['comments']['picture'][] = $comments_picture_data; unset($comments_picture_data); } - } while (false); + } while (false); // @phpstan-ignore-line break; default: diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.tag.id3v1.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.tag.id3v1.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.tag.id3v1.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.tag.id3v1.php 2026-05-22 07:52:18.000000000 +0000 @@ -29,6 +29,9 @@ if (!getid3_lib::intValueSupported($info['filesize'])) { $this->warning('Unable to check for ID3v1 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'); return false; + } elseif ($info['filesize'] < 128) { + $this->warning('Unable to check for ID3v1 because file is too small'); + return false; } if($info['filesize'] < 256) { @@ -66,7 +69,7 @@ if (!empty($ParsedID3v1['genre'])) { unset($ParsedID3v1['genreid']); } - if (isset($ParsedID3v1['genre']) && (empty($ParsedID3v1['genre']) || ($ParsedID3v1['genre'] == 'Unknown'))) { + if (empty($ParsedID3v1['genre']) || ($ParsedID3v1['genre'] == 'Unknown')) { unset($ParsedID3v1['genre']); } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.tag.id3v2.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.tag.id3v2.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.tag.id3v2.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.tag.id3v2.php 2026-05-22 07:52:18.000000000 +0000 @@ -659,7 +659,7 @@ // Owner identifier $00 // Identifier $exploded = explode("\x00", $parsedFrame['data'], 2); - $parsedFrame['ownerid'] = (isset($exploded[0]) ? $exploded[0] : ''); + $parsedFrame['ownerid'] = $exploded[0]; $parsedFrame['data'] = (isset($exploded[1]) ? $exploded[1] : ''); } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'TXXX')) || // 4.2.2 TXXX User defined text information frame @@ -679,7 +679,7 @@ $frame_textencoding_terminator = "\x00"; } $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { + if (substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1) === "\x00") { $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 } $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); @@ -771,7 +771,7 @@ $frame_textencoding_terminator = "\x00"; } $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { + if (substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1) === "\x00") { $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 } $parsedFrame['encodingid'] = $frame_textencoding; @@ -998,7 +998,7 @@ $frame_language = substr($parsedFrame['data'], $frame_offset, 3); $frame_offset += 3; $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { + if (substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1) === "\x00") { $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 } $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); @@ -1062,19 +1062,21 @@ if ($frame_terminatorpos === false) { $frame_remainingdata = ''; } else { - if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { + if (substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator), 1) === "\x00") { $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 } $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)) { - // timestamp probably omitted for first data item - } else { - $parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 4)); - $frame_remainingdata = substr($frame_remainingdata, 4); + if (strlen($frame_remainingdata)) { // https://github.com/JamesHeinrich/getID3/issues/444 + 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)); + $frame_remainingdata = substr($frame_remainingdata, 4); + } + $timestampindex++; } - $timestampindex++; } } unset($parsedFrame['data']); @@ -1106,7 +1108,7 @@ $frame_language = substr($parsedFrame['data'], $frame_offset, 3); $frame_offset += 3; $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { + if (substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1) === "\x00") { $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 } $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); @@ -1146,7 +1148,7 @@ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00"); $frame_idstring = substr($parsedFrame['data'], 0, $frame_terminatorpos); - if (ord($frame_idstring) === 0) { + if ($frame_idstring === "\x00") { $frame_idstring = ''; } $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00")); @@ -1277,7 +1279,7 @@ $frame_interpolationmethod = ord(substr($parsedFrame['data'], $frame_offset++, 1)); $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_idstring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_idstring) === 0) { + if ($frame_idstring === "\x00") { $frame_idstring = ''; } $parsedFrame['description'] = $frame_idstring; @@ -1304,7 +1306,7 @@ // Adjustment $xx (xx ...) $frame_offset = 0; - $parsedFrame['adjustmentbits'] = substr($parsedFrame['data'], $frame_offset++, 1); + $parsedFrame['adjustmentbits'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); $frame_adjustmentbytes = ceil($parsedFrame['adjustmentbits'] / 8); $frame_remainingdata = (string) substr($parsedFrame['data'], $frame_offset); @@ -1383,7 +1385,7 @@ // MIME type instead of 3-char ID3v2.2-format image type (thanks xbhoffØpacbell*net) $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_mimetype) === 0) { + if ($frame_mimetype === "\x00") { $frame_mimetype = ''; } $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype))); @@ -1398,7 +1400,7 @@ if ($id3v2_majorversion > 2 && strlen($parsedFrame['data']) > $frame_offset) { $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_mimetype) === 0) { + if ($frame_mimetype === "\x00") { $frame_mimetype = ''; } $frame_offset = $frame_terminatorpos + strlen("\x00"); @@ -1410,7 +1412,7 @@ $this->warning('data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset)); } else { $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { + if (substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1) === "\x00") { $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 } $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); @@ -1494,7 +1496,7 @@ unset($comments_picture_data); } } - } while (false); + } while (false); // @phpstan-ignore-line } } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GEOB')) || // 4.15 GEOB General encapsulated object @@ -1517,23 +1519,23 @@ } $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_mimetype) === 0) { + if ($frame_mimetype === "\x00") { $frame_mimetype = ''; } $frame_offset = $frame_terminatorpos + strlen("\x00"); $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { + if (substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1) === "\x00") { $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 } $frame_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_filename) === 0) { + if ($frame_filename === "\x00") { $frame_filename = ''; } $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator); $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { + if (substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1) === "\x00") { $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 } $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); @@ -1572,7 +1574,7 @@ $frame_offset = 0; $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_emailaddress = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_emailaddress) === 0) { + if ($frame_emailaddress === "\x00") { $frame_emailaddress = ''; } $frame_offset = $frame_terminatorpos + strlen("\x00"); @@ -1637,7 +1639,7 @@ $frame_offset = 0; $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_ownerid) === 0) { + if ($frame_ownerid === "\x00") { $frame_ownerid = ''; } $frame_offset = $frame_terminatorpos + strlen("\x00"); @@ -1671,7 +1673,7 @@ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_url = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_url) === 0) { + if ($frame_url === "\x00") { $frame_url = ''; } $frame_offset = $frame_terminatorpos + strlen("\x00"); @@ -1801,17 +1803,17 @@ $frame_receivedasid = ord(substr($parsedFrame['data'], $frame_offset++, 1)); $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { + if (substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1) === "\x00") { $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 } $frame_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_sellername) === 0) { + if ($frame_sellername === "\x00") { $frame_sellername = ''; } $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator); $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { + if (substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1) === "\x00") { $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 } $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); @@ -1849,7 +1851,7 @@ $frame_offset = 0; $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_ownerid) === 0) { + if ($frame_ownerid === "\x00") { $frame_ownerid = ''; } $frame_offset = $frame_terminatorpos + strlen("\x00"); @@ -1872,7 +1874,7 @@ $frame_offset = 0; $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_ownerid) === 0) { + if ($frame_ownerid === "\x00") { $frame_ownerid = ''; } $frame_offset = $frame_terminatorpos + strlen("\x00"); @@ -1892,7 +1894,7 @@ $frame_offset = 0; $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_ownerid) === 0) { + if ($frame_ownerid === "\x00") { $frame_ownerid = ''; } $frame_offset = $frame_terminatorpos + strlen("\x00"); @@ -3753,18 +3755,12 @@ * @return bool */ 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) { - // allowed - } elseif (($numberstring[$i] == '-') && $allownegative && ($i == 0)) { - // allowed - } else { - return false; - } - } - } - return true; + $pattern = '#^'; + $pattern .= ($allownegative ? '\\-?' : ''); + $pattern .= '[0-9]+'; + $pattern .= ($allowdecimal ? '(\\.[0-9]+)?' : ''); + $pattern .= '$#'; + return preg_match($pattern, $numberstring); } /** @@ -3773,10 +3769,7 @@ * @return bool */ public static function IsValidDateStampString($datestamp) { - if (strlen($datestamp) != 8) { - return false; - } - if (!self::IsANumber($datestamp, false)) { + if (!preg_match('#^[12][0-9]{3}[01][0-9][0123][0-9]$#', $datestamp)) { return false; } $year = substr($datestamp, 0, 4); diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.tag.lyrics3.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.tag.lyrics3.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.tag.lyrics3.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.tag.lyrics3.php 2026-05-22 07:52:18.000000000 +0000 @@ -110,19 +110,23 @@ if (!isset($info['ape'])) { if (isset($info['lyrics3']['tag_offset_start'])) { $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, $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(); - if (!empty($getid3_temp->info['ape'])) { - $info['ape'] = $getid3_temp->info['ape']; - } - if (!empty($getid3_temp->info['replay_gain'])) { - $info['replay_gain'] = $getid3_temp->info['replay_gain']; + if ($this->getid3->option_tag_apetag) { + getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true); + $getid3_temp = new getID3(); + $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(); + if (!empty($getid3_temp->info['ape'])) { + $info['ape'] = $getid3_temp->info['ape']; + } + if (!empty($getid3_temp->info['replay_gain'])) { + $info['replay_gain'] = $getid3_temp->info['replay_gain']; + } + unset($getid3_temp, $getid3_apetag); + } else { + $this->warning('Unable to check for Lyrics3 and APE tags interaction since option_tag_apetag=FALSE'); } - unset($getid3_temp, $getid3_apetag); } else { $this->warning('Lyrics3 and APE tags appear to have become entangled (most likely due to updating the APE tags with a non-Lyrics3-aware tagger)'); } @@ -227,7 +231,7 @@ foreach ($imagestrings as $key => $imagestring) { if (strpos($imagestring, '||') !== false) { $imagearray = explode('||', $imagestring); - $ParsedLyrics3['images'][$key]['filename'] = (isset($imagearray[0]) ? $imagearray[0] : ''); + $ParsedLyrics3['images'][$key]['filename'] = $imagearray[0]; $ParsedLyrics3['images'][$key]['description'] = (isset($imagearray[1]) ? $imagearray[1] : ''); $ParsedLyrics3['images'][$key]['timestamp'] = $this->Lyrics3Timestamp2Seconds(isset($imagearray[2]) ? $imagearray[2] : ''); } @@ -272,7 +276,7 @@ */ public function Lyrics3Timestamp2Seconds($rawtimestamp) { if (preg_match('#^\\[([0-9]{2}):([0-9]{2})\\]$#', $rawtimestamp, $regs)) { - return (int) (($regs[1] * 60) + $regs[2]); + return (int) (((int) $regs[1] * 60) + (int) $regs[2]); } return false; } @@ -287,28 +291,28 @@ $notimestamplyricsarray = array(); foreach ($lyricsarray as $key => $lyricline) { $regs = array(); - unset($thislinetimestamps); + $thislinetimestamps = array(); while (preg_match('#^(\\[[0-9]{2}:[0-9]{2}\\])#', $lyricline, $regs)) { $thislinetimestamps[] = $this->Lyrics3Timestamp2Seconds($regs[0]); $lyricline = str_replace($regs[0], '', $lyricline); } $notimestamplyricsarray[$key] = $lyricline; - if (isset($thislinetimestamps) && is_array($thislinetimestamps)) { + if (count($thislinetimestamps) > 0) { sort($thislinetimestamps); foreach ($thislinetimestamps as $timestampkey => $timestamp) { - if (isset($Lyrics3data['synchedlyrics'][$timestamp])) { + if (isset($Lyrics3data['comments']['synchedlyrics'][$timestamp])) { // timestamps only have a 1-second resolution, it's possible that multiple lines // could have the same timestamp, if so, append - $Lyrics3data['synchedlyrics'][$timestamp] .= "\r\n".$lyricline; + $Lyrics3data['comments']['synchedlyrics'][$timestamp] .= "\r\n".$lyricline; } else { - $Lyrics3data['synchedlyrics'][$timestamp] = $lyricline; + $Lyrics3data['comments']['synchedlyrics'][$timestamp] = $lyricline; } } } } - $Lyrics3data['unsynchedlyrics'] = implode("\r\n", $notimestamplyricsarray); - if (isset($Lyrics3data['synchedlyrics']) && is_array($Lyrics3data['synchedlyrics'])) { - ksort($Lyrics3data['synchedlyrics']); + $Lyrics3data['comments']['unsynchedlyrics'][0] = implode("\r\n", $notimestamplyricsarray); + if (isset($Lyrics3data['comments']['synchedlyrics']) && is_array($Lyrics3data['comments']['synchedlyrics'])) { + ksort($Lyrics3data['comments']['synchedlyrics']); } return true; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.tag.xmp.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.tag.xmp.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/module.tag.xmp.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/module.tag.xmp.php 2026-05-22 07:52:18.000000000 +0000 @@ -34,6 +34,77 @@ class Image_XMP { /** + * The names of the JPEG segment markers, indexed by their marker number + */ + private static $jpeg_segments_name = array( + 0x01 => 'TEM', + 0x02 => 'RES', + 0xC0 => 'SOF0', + 0xC1 => 'SOF1', + 0xC2 => 'SOF2', + 0xC3 => 'SOF4', + 0xC4 => 'DHT', + 0xC5 => 'SOF5', + 0xC6 => 'SOF6', + 0xC7 => 'SOF7', + 0xC8 => 'JPG', + 0xC9 => 'SOF9', + 0xCA => 'SOF10', + 0xCB => 'SOF11', + 0xCC => 'DAC', + 0xCD => 'SOF13', + 0xCE => 'SOF14', + 0xCF => 'SOF15', + 0xD0 => 'RST0', + 0xD1 => 'RST1', + 0xD2 => 'RST2', + 0xD3 => 'RST3', + 0xD4 => 'RST4', + 0xD5 => 'RST5', + 0xD6 => 'RST6', + 0xD7 => 'RST7', + 0xD8 => 'SOI', + 0xD9 => 'EOI', + 0xDA => 'SOS', + 0xDB => 'DQT', + 0xDC => 'DNL', + 0xDD => 'DRI', + 0xDE => 'DHP', + 0xDF => 'EXP', + 0xE0 => 'APP0', + 0xE1 => 'APP1', + 0xE2 => 'APP2', + 0xE3 => 'APP3', + 0xE4 => 'APP4', + 0xE5 => 'APP5', + 0xE6 => 'APP6', + 0xE7 => 'APP7', + 0xE8 => 'APP8', + 0xE9 => 'APP9', + 0xEA => 'APP10', + 0xEB => 'APP11', + 0xEC => 'APP12', + 0xED => 'APP13', + 0xEE => 'APP14', + 0xEF => 'APP15', + 0xF0 => 'JPG0', + 0xF1 => 'JPG1', + 0xF2 => 'JPG2', + 0xF3 => 'JPG3', + 0xF4 => 'JPG4', + 0xF5 => 'JPG5', + 0xF6 => 'JPG6', + 0xF7 => 'JPG7', + 0xF8 => 'JPG8', + 0xF9 => 'JPG9', + 0xFA => 'JPG10', + 0xFB => 'JPG11', + 0xFC => 'JPG12', + 0xFD => 'JPG13', + 0xFE => 'COM', + ); + + /** * @var string * The name of the image file that contains the XMP fields to extract and modify. * @see Image_XMP() @@ -146,12 +217,21 @@ $segdatastart = ftell($filehnd); // Read the segment data with length indicated by the previously read size - $segdata = fread($filehnd, $decodedsize['size'] - 2); + // fread will complain about trying to read zero bytes: "fread(): Argument #2 ($length) must be greater than 0" -- https://github.com/JamesHeinrich/getID3/issues/418 + if ($decodedsize['size'] > 2) { + $segdata = fread($filehnd, $decodedsize['size'] - 2); + } elseif ($decodedsize['size'] == 2) { + $segdata = ''; + } else { + // invalid length + fclose($filehnd); + return false; + } // Store the segment information in the output array $headerdata[] = array( 'SegType' => ord($data[1]), - 'SegName' => $GLOBALS['JPEG_Segment_Names'][ord($data[1])], + 'SegName' => self::$jpeg_segments_name[ord($data[1])], 'SegDataStart' => $segdatastart, 'SegData' => $segdata, ); @@ -250,7 +330,11 @@ if (xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 0) == false) { // Error setting case folding - destroy the parser and return - xml_parser_free($xml_parser); + if (PHP_VERSION_ID < 80000) { // xml_parser_free does nothing after PHP8 and give deprecation warnings in PHP8.5 + xml_parser_free($xml_parser); + } else { + unset($xml_parser); + } return false; } @@ -260,7 +344,11 @@ if (xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0) == false) { // Error setting case folding - destroy the parser and return - xml_parser_free($xml_parser); + if (PHP_VERSION_ID < 80000) { // xml_parser_free does nothing after PHP8 and give deprecation warnings in PHP8.5 + xml_parser_free($xml_parser); + } else { + unset($xml_parser); + } return false; } @@ -268,12 +356,20 @@ if (xml_parse_into_struct($xml_parser, $xmltext, $values, $tags) == 0) { // Error Parsing XML - destroy the parser and return - xml_parser_free($xml_parser); + if (PHP_VERSION_ID < 80000) { // xml_parser_free does nothing after PHP8 and give deprecation warnings in PHP8.5 + xml_parser_free($xml_parser); + } else { + unset($xml_parser); + } return false; } // Destroy the xml parser - xml_parser_free($xml_parser); + if (PHP_VERSION_ID < 80000) { // xml_parser_free does nothing after PHP8 and give deprecation warnings in PHP8.5 + xml_parser_free($xml_parser); + } else { + unset($xml_parser); + } // Clear the output array $xmp_array = array(); @@ -701,77 +797,4 @@ 'exif:Rows', 'exif:Settings', ); -*/ - -/** -* Global Variable: JPEG_Segment_Names -* -* The names of the JPEG segment markers, indexed by their marker number -*/ -$GLOBALS['JPEG_Segment_Names'] = array( - 0x01 => 'TEM', - 0x02 => 'RES', - 0xC0 => 'SOF0', - 0xC1 => 'SOF1', - 0xC2 => 'SOF2', - 0xC3 => 'SOF4', - 0xC4 => 'DHT', - 0xC5 => 'SOF5', - 0xC6 => 'SOF6', - 0xC7 => 'SOF7', - 0xC8 => 'JPG', - 0xC9 => 'SOF9', - 0xCA => 'SOF10', - 0xCB => 'SOF11', - 0xCC => 'DAC', - 0xCD => 'SOF13', - 0xCE => 'SOF14', - 0xCF => 'SOF15', - 0xD0 => 'RST0', - 0xD1 => 'RST1', - 0xD2 => 'RST2', - 0xD3 => 'RST3', - 0xD4 => 'RST4', - 0xD5 => 'RST5', - 0xD6 => 'RST6', - 0xD7 => 'RST7', - 0xD8 => 'SOI', - 0xD9 => 'EOI', - 0xDA => 'SOS', - 0xDB => 'DQT', - 0xDC => 'DNL', - 0xDD => 'DRI', - 0xDE => 'DHP', - 0xDF => 'EXP', - 0xE0 => 'APP0', - 0xE1 => 'APP1', - 0xE2 => 'APP2', - 0xE3 => 'APP3', - 0xE4 => 'APP4', - 0xE5 => 'APP5', - 0xE6 => 'APP6', - 0xE7 => 'APP7', - 0xE8 => 'APP8', - 0xE9 => 'APP9', - 0xEA => 'APP10', - 0xEB => 'APP11', - 0xEC => 'APP12', - 0xED => 'APP13', - 0xEE => 'APP14', - 0xEF => 'APP15', - 0xF0 => 'JPG0', - 0xF1 => 'JPG1', - 0xF2 => 'JPG2', - 0xF3 => 'JPG3', - 0xF4 => 'JPG4', - 0xF5 => 'JPG5', - 0xF6 => 'JPG6', - 0xF7 => 'JPG7', - 0xF8 => 'JPG8', - 0xF9 => 'JPG9', - 0xFA => 'JPG10', - 0xFB => 'JPG11', - 0xFC => 'JPG12', - 0xFD => 'JPG13', - 0xFE => 'COM', -); +*/ \ No newline at end of file diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/write.apetag.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/write.apetag.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/write.apetag.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/write.apetag.php 2026-05-22 07:52:18.000000000 +0000 @@ -27,7 +27,7 @@ public $filename; /** - * @var array + * @var array|null */ public $tag_data; diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/write.id3v1.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/write.id3v1.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/write.id3v1.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/write.id3v1.php 2026-05-22 07:52:18.000000000 +0000 @@ -80,7 +80,8 @@ (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'] : '')); + $this->tag_data['track_number'] + ); fwrite($fp_source, $new_id3v1_tag_data, 128); fclose($fp_source); return true; diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/write.id3v2.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/write.id3v2.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/write.id3v2.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/write.id3v2.php 2026-05-22 07:52:18.000000000 +0000 @@ -126,26 +126,12 @@ if (file_exists($this->filename) && getID3::is_writable($this->filename) && isset($OldThisFileInfo['id3v2']['headerlength']) && ($OldThisFileInfo['id3v2']['headerlength'] == strlen($NewID3v2Tag))) { // best and fastest method - insert-overwrite existing tag (padded to length of old tag if neccesary) - if (file_exists($this->filename)) { - - if (is_readable($this->filename) && getID3::is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'r+b'))) { - rewind($fp); - fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag)); - fclose($fp); - } else { - $this->errors[] = 'Could not fopen("'.$this->filename.'", "r+b")'; - } - + if (is_readable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'r+b'))) { + rewind($fp); + fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag)); + fclose($fp); } else { - - if (getID3::is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'wb'))) { - rewind($fp); - fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag)); - fclose($fp); - } else { - $this->errors[] = 'Could not fopen("'.$this->filename.'", "wb")'; - } - + $this->errors[] = 'Could not fopen("'.$this->filename.'", "r+b")'; } } else { @@ -224,7 +210,7 @@ if ($OldThisFileInfo['avdataoffset'] !== false) { fseek($fp_source, $OldThisFileInfo['avdataoffset']); } - if (getID3::is_writable($this->filename) && is_file($this->filename) && ($fp_temp = fopen($this->filename.'getid3tmp', 'w+b'))) { + if (getID3::is_writable($this->filename) && ($fp_temp = fopen($this->filename.'getid3tmp', 'w+b'))) { while ($buffer = fread($fp_source, $this->fread_buffer_size)) { fwrite($fp_temp, $buffer, strlen($buffer)); } @@ -264,7 +250,7 @@ fwrite($fp_temp, $buffer, strlen($buffer)); } fclose($fp_source); - if (getID3::is_writable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'wb'))) { + if ($fp_source = fopen($this->filename, 'wb')) { rewind($fp_temp); while ($buffer = fread($fp_temp, $this->fread_buffer_size)) { fwrite($fp_source, $buffer, strlen($buffer)); diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/write.metaflac.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/write.metaflac.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/write.metaflac.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/write.metaflac.php 2026-05-22 07:52:18.000000000 +0000 @@ -71,7 +71,7 @@ $picture_typeid = (!empty($picturedetails['picturetypeid']) ? $this->ID3v2toFLACpictureTypes($picturedetails['picturetypeid']) : 3); // default to "3:Cover (front)" $picture_mimetype = (!empty($picturedetails['mime']) ? $picturedetails['mime'] : ''); // should be auto-detected $picture_width_height_depth = ''; - $this->pictures[] = $picture_typeid.'|'.$picture_mimetype.'|'.preg_replace('#[^\x20-\x7B\x7D-\x7F]#', '', $picturedetails['description']).'|'.$picture_width_height_depth.'|'.$temppicturefilename; + $this->pictures[] = $picture_typeid.'|'.$picture_mimetype.'|'.preg_replace('#[^\x20-\x7B\x7D-\x7F]#', '', (string) $picturedetails['description']).'|'.$picture_width_height_depth.'|'.$temppicturefilename; } else { $this->errors[] = 'failed to open temporary tags file, tags not written - fopen("'.$temppicturefilename.'", "wb")'; return false; @@ -118,12 +118,17 @@ $commandline .= ' --import-picture-from='.escapeshellarg($picturecommand); } $commandline .= ' '.escapeshellarg($this->filename).' 2>&1'; - $metaflacError = `$commandline`; + $metaflacError = shell_exec($commandline); if (empty($metaflacError)) { - clearstatcache(true, $this->filename); - if ($timestampbeforewriting == filemtime($this->filename)) { - $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not written'; + if (abs(time() - $timestampbeforewriting) < 5) { + // https://github.com/JamesHeinrich/getID3/issues/474 + // probably working on a temporary (or otherwise newly-created) file so hack-check file-modification-date will always fail + } else { + clearstatcache(true, $this->filename); + if ($timestampbeforewriting == filemtime($this->filename)) { + $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not written'; + } } } } else { @@ -138,7 +143,7 @@ $commandline .= ' --import-picture-from='.escapeshellarg($picturecommand); } $commandline .= ' '.escapeshellarg($this->filename).' 2>&1'; - $metaflacError = `$commandline`; + $metaflacError = shell_exec($commandline); } @@ -177,7 +182,7 @@ $timestampbeforewriting = filemtime($this->filename); $commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --remove-all-tags "'.$this->filename.'" 2>&1'; - $metaflacError = `$commandline`; + $metaflacError = shell_exec($commandline); if (empty($metaflacError)) { clearstatcache(true, $this->filename); @@ -193,7 +198,7 @@ // It's simpler on *nix $commandline = 'metaflac --remove-all-tags "'.$this->filename.'" 2>&1'; - $metaflacError = `$commandline`; + $metaflacError = shell_exec($commandline); } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/write.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/write.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/write.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/write.php 2026-05-22 07:52:18.000000000 +0000 @@ -144,8 +144,8 @@ return false; } - if (!is_array($this->tagformats)) { - $this->errors[] = 'tagformats must be an array in getid3_writetags'; + if (count($this->tagformats) === 0) { + $this->errors[] = 'tagformats is empty in getid3_writetags'; return false; } // prevent duplicate tag formats @@ -285,8 +285,8 @@ } // Validation of supplied data - if (!is_array($this->tag_data)) { - $this->errors[] = '$this->tag_data is not an array in WriteTags()'; + if (count($this->tag_data) === 0) { + $this->errors[] = '$this->tag_data is empty in WriteTags()'; return false; } // convert supplied data array keys to upper case, if they're not already @@ -679,7 +679,7 @@ $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 0; $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value; $ID3v2_tag_data_converted = true; - } while (false); + } while (false); // @phpstan-ignore-line } if (!$ID3v2_tag_data_converted) { $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 1; diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/write.vorbiscomment.php spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/write.vorbiscomment.php --- spip-4.4.13+dfsg/plugins-dist/medias/lib/getid3/write.vorbiscomment.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/lib/getid3/write.vorbiscomment.php 2026-05-22 07:52:18.000000000 +0000 @@ -88,7 +88,7 @@ $timestampbeforewriting = filemtime($this->filename); $commandline = GETID3_HELPERAPPSDIR.'vorbiscomment.exe -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1'; - $VorbiscommentError = `$commandline`; + $VorbiscommentError = shell_exec($commandline); if (empty($VorbiscommentError)) { clearstatcache(true, $this->filename); @@ -103,7 +103,7 @@ } else { $commandline = 'vorbiscomment -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1'; - $VorbiscommentError = `$commandline`; + $VorbiscommentError = shell_exec($commandline); } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/medias_fonctions.php spip-4.4.15+dfsg/plugins-dist/medias/medias_fonctions.php --- spip-4.4.13+dfsg/plugins-dist/medias/medias_fonctions.php 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/medias_fonctions.php 2026-05-22 07:52:18.000000000 +0000 @@ -9,6 +9,8 @@ * Ce programme est un logiciel libre distribué sous licence GNU/GPL. * \***************************************************************************/ +use Spip\Afficher\Minipage\Admin as MinipageAdmin; + /** * Fonctions utiles pour les squelettes et déclarations de boucle * pour le compilateur @@ -50,8 +52,8 @@ and strncmp($_SERVER['CONTENT_TYPE'], 'multipart/form-data', 19) == 0 and $_SERVER['CONTENT_LENGTH'] > medias_inigetoctets('post_max_size') ) { - include_spip('inc/minipres'); - echo minipres(_T('medias:upload_limit', ['max' => ini_get('post_max_size')])); + $minipage = new MinipageAdmin(); + echo $minipage->page('', ['titre' => _T('medias:upload_limit', ['max' => ini_get('post_max_size')])]); exit; } diff -Nru spip-4.4.13+dfsg/plugins-dist/medias/paquet.xml spip-4.4.15+dfsg/plugins-dist/medias/paquet.xml --- spip-4.4.13+dfsg/plugins-dist/medias/paquet.xml 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/medias/paquet.xml 2026-05-22 07:52:18.000000000 +0000 @@ -1,7 +1,7 @@ $params + */ + public function installDebutPage(array $params = []): string { + return ''; + } + + /** + * @param array $options + */ + public function page(string $corps, array $options = []): string { + return ''; + } + + public function installFinPage(): string { + return ''; + } +} diff -Nru spip-4.4.13+dfsg/plugins-dist/revisions/CHANGELOG.md spip-4.4.15+dfsg/plugins-dist/revisions/CHANGELOG.md --- spip-4.4.13+dfsg/plugins-dist/revisions/CHANGELOG.md 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/revisions/CHANGELOG.md 2026-05-22 07:52:18.000000000 +0000 @@ -1,5 +1,11 @@ # Changelog +## 3.1.12 - 2026-05-12 + +### Fixed + +- Autoriser PHP 8.5 dans le composer.json + ## 3.1.11 - 2026-03-06 ### Fixed diff -Nru spip-4.4.13+dfsg/plugins-dist/revisions/composer.json spip-4.4.15+dfsg/plugins-dist/revisions/composer.json --- spip-4.4.13+dfsg/plugins-dist/revisions/composer.json 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/revisions/composer.json 2026-05-22 07:52:18.000000000 +0000 @@ -11,7 +11,7 @@ } ], "require": { - "php": "^7.4 || ^8.0 <=8.4" + "php": "^7.4 || ^8.0" }, "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^1.0", diff -Nru spip-4.4.13+dfsg/plugins-dist/revisions/paquet.xml spip-4.4.15+dfsg/plugins-dist/revisions/paquet.xml --- spip-4.4.13+dfsg/plugins-dist/revisions/paquet.xml 2026-03-06 10:17:20.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/revisions/paquet.xml 2026-05-22 07:52:18.000000000 +0000 @@ -1,7 +1,7 @@ - array ( - 0 => '', - 1 => '', - ), - 1 => - array ( - 0 => '0', - 1 => '0', - ), - 2 => - array ( - 0 => [ - 'Un texte avec des liens [Article 1->art1] [spip->https://www.spip.net] https://www.spip.net', - 'Un texte avec des liens [Article 1->art1] [spip->https://www.spip.net] https://www.spip.net', - ], - 1 => 'Un texte avec des liens [Article 1->art1] [spip->https://www.spip.net] https://www.spip.net', - ), - 3 => - array ( - 0 => 'Un texte avec des entités &<>"', - 1 => 'Un texte avec des entités &<>"', - ), - 4 => - array ( - 0 => 'Un texte avec des entit&eacute;s echap&eacute; &amp;&lt;&gt;&quot;', - 1 => 'Un texte avec des entit&eacute;s echap&eacute; &amp;&lt;&gt;&quot;', - ), - 5 => - array ( - 0 => 'Un texte avec des entités numériques &<>"', - 1 => 'Un texte avec des entités numériques &<>"', - ), - 6 => - array ( - 0 => 'Un texte avec des entit&#233;s num&#233;riques echap&#233;es &#38;&#60;&#62;&quot;', - 1 => 'Un texte avec des entit&#233;s num&#233;riques echap&#233;es &#38;&#60;&#62;&quot;', - ), - 7 => - array ( - 0 => [ - 'Un texte sans entites &<>"\'', - 'Un texte sans entites &<>"\'', - ], - 1 => 'Un texte sans entites &<>"\'', - ), - 8 => - array ( - 0 => '{{{Des raccourcis}}} {italique} {{gras}} du code', - 1 => '{{{Des raccourcis}}} {italique} {{gras}} du code', - ), - 9 => - array ( - 0 => [ - 'Un modele https://www.spip.net]>', - 'Un modele https://www.spip.net]>', - ], - 1 => 'Un modele https://www.spip.net]>', - ), - 10 => - array ( - 0 => 'Un texte avec des retour + public static function providerXSS() + { + $essais = [ + 0 => [ + 0 => '', + 1 => '' + ], + 1 => [ + 0 => '0', + 1 => '0' + ], + 2 => [ + 0 => [ + 'Un texte avec des liens [Article 1->art1] [spip->https://www.spip.net] https://www.spip.net', + 'Un texte avec des liens [Article 1->art1] [spip->https://www.spip.net] https://www.spip.net', + ], + 1 => 'Un texte avec des liens [Article 1->art1] [spip->https://www.spip.net] https://www.spip.net' + ], + 3 => [ + 0 => 'Un texte avec des entités &<>"', + 1 => 'Un texte avec des entités &<>"' + ], + 4 => [ + 0 => 'Un texte avec des entit&eacute;s echap&eacute; &amp;&lt;&gt;&quot;', + 1 => 'Un texte avec des entit&eacute;s echap&eacute; &amp;&lt;&gt;&quot;' + ], + 5 => [ + 0 => 'Un texte avec des entités numériques &<>"', + 1 => 'Un texte avec des entités numériques &<>"' + ], + 6 => [ + 0 => 'Un texte avec des entit&#233;s num&#233;riques echap&#233;es &#38;&#60;&#62;&quot;', + 1 => 'Un texte avec des entit&#233;s num&#233;riques echap&#233;es &#38;&#60;&#62;&quot;' + ], + 7 => [ + 0 => [ + 'Un texte sans entites &<>"\'', + 'Un texte sans entites &<>"\'', + ], + 1 => 'Un texte sans entites &<>"\'' + ], + 8 => [ + 0 => '{{{Des raccourcis}}} {italique} {{gras}} du code', + 1 => '{{{Des raccourcis}}} {italique} {{gras}} du code' + ], + 9 => [ + 0 => [ + 'Un modele https://www.spip.net]>', + 'Un modele https://www.spip.net]>', + ], + 1 => 'Un modele https://www.spip.net]>' + ], + 10 => [ + 0 => 'Un texte avec des retour a la ligne et meme des paragraphes', - 1 => 'Un texte avec des retour + 1 => 'Un texte avec des retour a la ligne et meme des -paragraphes', - ), - 11 => - array ( - 0 => [ - '\';alert(String.fromCharCode(88,83,83))//\\\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\\";alert(String.fromCharCode(88,83,83))//-->">\'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>=&{}', - '\';alert(String.fromCharCode(88,83,83))//\\\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\\";alert(String.fromCharCode(88,83,83))//-->">\'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>=&{}', - ], - 1 => '\';alert(String.fromCharCode(88,83,83))//\\\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\\";alert(String.fromCharCode(88,83,83))//-->">\'>=&{}', - ), - 12 => - array ( - 0 => [ - '\'\';!--"=&{()}', - '\'\';!--"=&{()}', - ], - 1 => '\'\';!--"=&{()}', - ), - 13 => - array ( - 0 => '<SCRIPT>alert(\'XSS\')</SCRIPT>', - 1 => '', - ), - 14 => - array ( - 0 => '<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>', - 1 => '', - ), - 15 => - array ( - 0 => '<SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>', - 1 => '', - ), - 16 => - array ( - 0 => [ - '<base HREF="javascript:alert(\'XSS\');//">', - '<base HREF="javascript:alert(\'XSS\');//">', - ], - 1 => '', - ), - 17 => - array ( - 0 => '<BGSOUND SRC="javascript:alert(\'XSS\');">', - 1 => '', - ), - 18 => - array ( - 0 => '<BODY BACKGROUND="javascript:alert(\'XSS\');">', - 1 => '', - ), - 19 => - array ( - 0 => '<BODY ONLOAD=alert(\'XSS\')>', - 1 => '', - ), - 20 => - array ( - 0 => '
', - 1 => '
', - ), - 21 => - array ( - 0 => '
', - 1 => '
', - ), - 22 => - array ( - 0 => '
', - 1 => '
', - ), - 23 => - array ( - 0 => '', - 1 => '', - ), - 24 => - array ( - 0 => '<IFRAME SRC="javascript:alert(\'XSS\');"></IFRAME>', - 1 => '', - ), - 25 => - array ( - 0 => [ - '', - '', - '', - ], - 1 => '', - ), - 26 => - array ( - 0 => '<IMG SRC="javascript:alert(\'XSS\');">', - 1 => '', - ), - 27 => - array ( - 0 => '<IMG SRC=javascript:alert(\'XSS\')>', - 1 => '', - ), - 28 => - array ( - 0 => '<IMG DYNSRC="javascript:alert(\'XSS\');">', - 1 => '', - ), - 29 => - array ( - 0 => '<IMG LOWSRC="javascript:alert(\'XSS\');">', - 1 => '', - ), - 30 => - array ( - 0 => [ - '', - 'somecommand.php?somevariables=maliciouscode', - 'somecommand.php?somevariables=maliciouscode', - ], - 1 => '', - ), - 31 => - array ( - 0 => [ - 'exp/*', - 'exp/*', - ], - 1 => 'exp/*', - ), - 32 => - array ( - 0 => '
  • XSS
', - 1 => '
  • XSS', - ), - 33 => - array ( - 0 => '<IMG SRC=\'vbscript:msgbox("XSS")\'>', - 1 => '', - ), - 34 => - array ( - 0 => '', - 1 => '', - ), - 35 => - array ( - 0 => '<IMG SRC="livescript:[code]">', - 1 => '', - ), - 36 => - array ( - 0 => '�script�alert(�XSS�)�/script�', - 1 => '�script�alert(�XSS�)�/script�', - ), - 37 => - array ( - 0 => '<META HTTP-EQUIV="refresh" CONTENT="0;url=javascript:alert(\'XSS\');">', - 1 => '', - ), - 38 => - array ( - 0 => '<META HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">', - 1 => '', - ), - 39 => - array ( - 0 => '<META HTTP-EQUIV="refresh" CONTENT="0; URL=http://;URL=javascript:alert(\'XSS\');">', - 1 => '', - ), - 40 => - array ( - 0 => [ - '', - '', - ], - 1 => '', - ), - 41 => - array ( - 0 => '', - 1 => '', - ), - 42 => - array ( - 0 => '<OBJECT classid=clsid:ae24fdae-03c6-11d1-8b76-0080c744f389><param name=url value=javascript:alert(\'XSS\')></OBJECT>', - 1 => '', - ), - 43 => - array ( - 0 => '', - 1 => '', - ), - 44 => - array ( - 0 => '', - 1 => '', - ), - 45 => - array ( - 0 => [ - '', - '', - ], - 1 => '', - ), - 46 => - array ( - 0 => [ - '', - '', - ], - 1 => '', - ), - 47 => - array ( - 0 => '', - 1 => '', - ), - 48 => - array ( - 0 => '', - 1 => '', - ), - 49 => - array ( - 0 => '', - 1 => '', - ), - 50 => - array ( - 0 => '', - 1 => '', - ), - 51 => - array ( - 0 => '', - 1 => '', - ), - 52 => - array ( - 0 => '', - 1 => '', - ), - 53 => - array ( - 0 => '', - 1 => '', - ), - 54 => - array ( - 0 => [ - '
    ', - '', - ], - 1 => '
    ', - ), - 55 => - array ( - 0 => [ - '
    ', - '
    ', - '', - ], - 1 => '
    ', - ), - 56 => - array ( - 0 => [ - ' -<?import namespace="xss" implementation="http://ha.ckers.org/xss.htc"> +paragraphes' + ], + 11 => [ + 0 => [ + '\';alert(String.fromCharCode(88,83,83))//\\\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\\";alert(String.fromCharCode(88,83,83))//-->">\'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>=&{}', + '\';alert(String.fromCharCode(88,83,83))//\\\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\\";alert(String.fromCharCode(88,83,83))//-->">\'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>=&{}', + ], + 1 => '\';alert(String.fromCharCode(88,83,83))//\\\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\\";alert(String.fromCharCode(88,83,83))//-->">\'>=&{}' + ], + 12 => [ + 0 => ['\'\';!--"=&{()}', '\'\';!--"=&{()}'], + 1 => '\'\';!--"=&{()}' + ], + 13 => [ + 0 => '<SCRIPT>alert(\'XSS\')</SCRIPT>', + 1 => '' + ], + 14 => [ + 0 => '<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>', + 1 => '' + ], + 15 => [ + 0 => '<SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>', + 1 => '' + ], + 16 => [ + 0 => [ + '<base HREF="javascript:alert(\'XSS\');//">', + '<base HREF="javascript:alert(\'XSS\');//">', + ], + 1 => '' + ], + 17 => [ + 0 => '⚠️ <BGSOUND SRC="javascript:alert(\'XSS\');">', + 1 => '' + ], + 18 => [ + 0 => '⚠️ <BODY BACKGROUND="javascript:alert(\'XSS\');">', + 1 => '' + ], + 19 => [ + 0 => '⚠️ <BODY ONLOAD=alert(\'XSS\')>', + 1 => '' + ], + 20 => [ + 0 => '
    ', + 1 => '
    ' + ], + 21 => [ + 0 => '
    ', + 1 => '
    ' + ], + 22 => [ + 0 => '
    ', + 1 => '
    ' + ], + 23 => [ + 0 => '', + 1 => '' + ], + 24 => [ + 0 => '⚠️ <IFRAME SRC="javascript:alert(\'XSS\');"></IFRAME>', + 1 => '' + ], + 25 => [ + 0 => '⚠️ <INPUT TYPE="IMAGE" SRC="javascript:alert(\'XSS\');">', + 1 => '' + ], + 26 => [ + 0 => '⚠️ <IMG SRC="javascript:alert(\'XSS\');">', + 1 => '' + ], + 27 => [ + 0 => '⚠️ <IMG SRC=javascript:alert(\'XSS\')>', + 1 => '' + ], + 28 => [ + 0 => '⚠️ <IMG DYNSRC="javascript:alert(\'XSS\');">', + 1 => '' + ], + 29 => [ + 0 => '⚠️ <IMG LOWSRC="javascript:alert(\'XSS\');">', + 1 => '' + ], + 30 => [ + 0 => [ + '', + 'somecommand.php?somevariables=maliciouscode', + 'somecommand.php?somevariables=maliciouscode', + ], + 1 => '' + ], + 31 => [ + 0 => [ + 'exp/*', + 'exp/*', + ], + 1 => 'exp/*' + ], + 32 => [ + 0 => '
    • XSS
    ', + 1 => '
    • XSS' + ], + 33 => [ + 0 => '⚠️ <IMG SRC=\'vbscript:msgbox("XSS")\'>', + 1 => '' + ], + 34 => [ + 0 => '', + 1 => '' + ], + 35 => [ + 0 => '⚠️ <IMG SRC="livescript:[code]">', + 1 => '' + ], + 36 => [ + 0 => '�script�alert(�XSS�)�/script�', + 1 => '�script�alert(�XSS�)�/script�' + ], + 37 => [ + 0 => '⚠️ <META HTTP-EQUIV="refresh" CONTENT="0;url=javascript:alert(\'XSS\');">', + 1 => '' + ], + 38 => [ + 0 => '⚠️ <META HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">', + 1 => '' + ], + 39 => [ + 0 => '⚠️ <META HTTP-EQUIV="refresh" CONTENT="0; URL=http://;URL=javascript:alert(\'XSS\');">', + 1 => '' + ], + 40 => [ + 0 => ['', ''], + 1 => '' + ], + 41 => [ + 0 => '', + 1 => '' + ], + 42 => [ + 0 => '⚠️ <OBJECT classid=clsid:ae24fdae-03c6-11d1-8b76-0080c744f389><param name=url value=javascript:alert(\'XSS\')></OBJECT>', + 1 => '' + ], + 43 => [ + 0 => '', + 1 => '' + ], + 44 => [ + 0 => '', + 1 => '' + ], + 45 => [ + 0 => ['', ''], + 1 => '' + ], + 46 => [ + 0 => ['', ''], + 1 => '' + ], + 47 => [ + 0 => '', + 1 => '' + ], + 48 => [ + 0 => '', + 1 => '' + ], + 49 => [ + 0 => '', + 1 => '' + ], + 50 => [ + 0 => '', + 1 => '' + ], + 51 => [ + 0 => '', + 1 => '' + ], + 52 => [ + 0 => '', + 1 => '' + ], + 53 => [ + 0 => '', + 1 => '' + ], + 54 => [ + 0 => ['
      ', ''], + 1 => '
      ' + ], + 55 => [ + 0 => [ + '
      ', + '
      ', + '', + ], + 1 => '
      ' + ], + 56 => [ + 0 => [ + ' +<?import namespace="xss" implementation="http://ha.ckers.org/xss.htc"> XSS ', - ' + ' <?import namespace="xss" implementation="http://ha.ckers.org/xss.htc"> XSS', - ], - 1 => ' + ], + 1 => ' XSS -', - ), - 57 => - array ( - 0 => [ - '', - '<IMG SRC="javascript:alert(\'XSS\');"> +' + ], + 57 => [ + 0 => [ + '', + '<IMG SRC="javascript:alert(\'XSS\');"> ', - ], - 1 => ']]> + ], + 1 => ']]> -', - ), - 58 => - array ( - 0 => [' +' + ], + 58 => [ + 0 => ['javas<!-- -->cript:alert(\'XSS\') ', - 'javas<!-- -->cript:alert(\'XSS\')', - 'javas<!-- -->cript:alert(\'XSS\')', - ], - 1 => ' - -', - ), - 59 => - array ( - 0 => [ - ' + ], + 1 => ' + +' + ], + 59 => [ + 0 => [ + ' ', - '', - ], - 1 => ' -', - ), - 60 => - array ( - 0 => [ - ' + '', + ], + 1 => ' +' + ], + 60 => [ + 0 => [ + ' <?xml:namespace prefix="t" ns="urn:schemas-microsoft-com:time"> <?import namespace="t" implementation="#default#time2"> <SCRIPT DEFER>alert(\'XSS\')</SCRIPT>"> ', - ' + ' <?xml:namespace prefix="t" ns="urn:schemas-microsoft-com:time"> <?import namespace="t" implementation="#default#time2"> <SCRIPT DEFER>alert(\'XSS\')</SCRIPT>"> ', - ], - 1 => ' + ], + 1 => ' - ', - ), - 61 => - array ( - 0 => '', - 1 => '', - ), - 62 => - array ( - 0 => [ - '<SCRIPT>alert(\'XSS\')</SCRIPT>">', - '<SCRIPT>alert(\'XSS\')</SCRIPT>">', - ], - 1 => '', - ), - 63 => - array ( - 0 => [ - '', - '', - ], - 1 => '', - ), - 64 => - array ( - 0 => '<SCRIPT SRC="http://ha.ckers.org/xss.jpg"></SCRIPT>', - 1 => '', - ), - 65 => - array ( - 0 => '', - 1 => '', - ), - 66 => - array ( - 0 => [ - '<? echo(\'alert("XSS")\'); ?>', - '<? echo(\'alert("XSS")\'); ?>', - ], - 1 => 'alert("XSS")\'); ?>', - ), - 67 => - array ( - 0 => [ - '
      ', - '
      ', - '
      ', - ], - 1 => '
      ', - ), - 68 => - array ( - 0 => [ - '< +' + ], + 62 => [ + 0 => [ + '<SCRIPT>alert(\'XSS\')</SCRIPT>">', + '<SCRIPT>alert(\'XSS\')</SCRIPT>">', + ], + 1 => '' + ], + 63 => [ + 0 => ['', ''], + 1 => '' + ], + 64 => [ + 0 => '<SCRIPT SRC="http://ha.ckers.org/xss.jpg"></SCRIPT>', + 1 => '' + ], + 65 => [ + 0 => '', + 1 => '' + ], + 66 => [ + 0 => [ + '<? echo(\'alert("XSS")\'); ?>', + '<? echo(\'alert("XSS")\'); ?>', + ], + 1 => 'alert("XSS")\'); ?>' + ], + 67 => [ + 0 => ['
      ', '
      ', '
      '], + 1 => '
      ' + ], + 68 => [ + 0 => [ + '< %3C < < @@ -571,7 +474,7 @@ \\x3C \\u003c \\u003C', - '< + '< %3C &lt < @@ -645,8 +548,8 @@ \\x3C \\u003c \\u003C', -], - 1 => '< + ], + 1 => '< %3C < < @@ -719,112 +622,97 @@ \\x3c \\x3C \\u003c -\\u003C', - ), - 69 => - array ( - 0 => '<IMG SRC=JaVaScRiPt:alert(\'XSS\')>', - 1 => '', - ), - 70 => - array ( - 0 => '<IMG SRC=javascript:alert(&quot;XSS&quot;)>', - 1 => '', - ), - 71 => - array ( - 0 => '<IMG SRC=`javascript:alert("RSnake says, \'XSS\'")`>', - 1 => '', - ), - 72 => - array ( - 0 => '<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>', - 1 => '', - ), - 73 => - array ( - 0 => [ - '', - '' - ], - 1 => '', - ), - 74 => - array ( - 0 => [ - '', - '', - ], - 1 => '', - ), - 75 => - array ( - 0 => [ - '
      ', - '
      ' - ], - 1 => '
      ', - ), - 76 => - array ( - 0 => [ - '', - '', - ], - 1 => '', - ), - 77 => - array ( - 0 => [ - ' ', - '+ADw-SCRIPT+AD4-alert(\'XSS\');+ADw-/SCRIPT+AD4-', - ], - 1 => ' +ADw-SCRIPT+AD4-alert(\'XSS\');+ADw-/SCRIPT+AD4-', - ), - 78 => - array ( - 0 => '\\";alert(\'XSS\');//', - 1 => '\\";alert(\'XSS\');//', - ), - 79 => - array ( - 0 => '<SCRIPT>alert("XSS");</SCRIPT>', - 1 => '', - ), - 80 => - array ( - 0 => '', - 1 => '', - ), - 81 => - array ( - 0 => '<IMG SRC="jav ascript:alert(\'XSS\');">', - 1 => '', - ), - 82 => - array ( - 0 => '<IMG SRC="jav&#x09;ascript:alert(\'XSS\');">', - 1 => '', - ), - 83 => - array ( - 0 => '<IMG SRC="jav&#x0A;ascript:alert(\'XSS\');">', - 1 => '', - ), - 84 => - array ( - 0 => '<IMG SRC="jav&#x0D;ascript:alert(\'XSS\');">', - 1 => '', - ), - 85 => - array ( - 0 => [ - ' +\\u003C' + ], + 69 => [ + 0 => '⚠️ <IMG SRC=JaVaScRiPt:alert(\'XSS\')>', + 1 => '' + ], + 70 => [ + 0 => '⚠️ <IMG SRC=javascript:alert("XSS")>', + 1 => '' + ], + 71 => [ + 0 => '⚠️ <IMG SRC=`javascript:alert("RSnake says, \'XSS\'")`>', + 1 => '' + ], + 72 => [ + 0 => '⚠️ <IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>', + 1 => '' + ], + 73 => [ + 0 => [ + '⚠️ <IMG SRC=javascript:alert(\'XSS\')>', + ], + 1 => '' + ], + 74 => [ + 0 => [ + '', + '', + ], + 1 => '' + ], + 75 => [ + 0 => [ + '
      ', + '
      ', + ], + 1 => '
      ' + ], + 76 => [ + 0 => [ + '', + '', + ], + 1 => '' + ], + 77 => [ + 0 => [ + ' +ADw-SCRIPT+AD4-alert(\'XSS\');+ADw-/SCRIPT+AD4-', + '+ADw-SCRIPT+AD4-alert(\'XSS\');+ADw-/SCRIPT+AD4-', + ], + 1 => ' +ADw-SCRIPT+AD4-alert(\'XSS\');+ADw-/SCRIPT+AD4-' + ], + 78 => [ + 0 => '\\";alert(\'XSS\');//', + 1 => '\\";alert(\'XSS\');//' + ], + 79 => [ + 0 => '<SCRIPT>alert("XSS");</SCRIPT>', + 1 => '' + ], + 80 => [ + 0 => '', + 1 => '' + ], + 81 => [ + 0 => '⚠️ <IMG SRC="jav ascript:alert(\'XSS\');">', + 1 => '' + ], + 82 => [ + // tabulation + 0 => '⚠️ <IMG SRC="jav ascript:alert(\'XSS\');">', + 1 => '' + ], + 83 => [ + 0 => '⚠️ <IMG SRC="jav +ascript:alert(\'XSS\');">', + 1 => '' + ], + 84 => [ + 0 => '⚠️ <IMG SRC="jav +ascript:alert(\'XSS\');">', + 1 => '' + ], + 85 => [ + 0 => [ + ' +', + 'j a v a s c r i p t : a l e r t ( \' X S S \' ) ', - 'j a v a s c r i p t : a l e r t ( \' X S S \' )', - 'j a v a s c r i p t : a l e r t ( \' X S S \' )', - ], - 1 => ' ' -', - ), - 86 => - array ( - 0 => [ - '<IMG SRC=java' . "\0" . 'script:alert("XSS")>', - '<IMG SRC=javascript:alert("XSS")>', - ], - 1 => '', - ), - 87 => - array ( - 0 => [ - '&alert("XSS")', - '&', - ], - 1 => '&alert("XSS")', - ), - 88 => - array ( - 0 => '<IMG SRC=" &#14; javascript:alert(\'XSS\');">', - 1 => '', - ), - 89 => - array ( - 0 => '<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>', - 1 => '', - ), - 90 => - array ( - 0 => [ - '|\\]^`=alert("XSS")>', - '', - ], - 1 => '', - ), - 91 => - array ( - 0 => '<SCRIPT SRC=http://ha.ckers.org/xss.js', - 1 => '', - ), - 96 => - array ( - 0 => [ - '<SCRIPT>alert("XSS")</SCRIPT>">', - '<SCRIPT>alert("XSS")</SCRIPT>">', - ], - 1 => '">', - ), - 97 => - array ( - 0 => [ - '<SCRIPT>a=/XSS/
      +' + ], + 86 => [ + 0 => [ + '⚠️ <IMG SRC=javascript:alert("XSS")>', + ], + 1 => '' + ], + 87 => [ + 0 => ['&alert("XSS")', '&'], + 1 => '&alert("XSS")' + ], + 88 => [ + 0 => '⚠️ <IMG SRC=" &#14; javascript:alert(\'XSS\');">', + 1 => '' + ], + 89 => [ + 0 => '<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>', + 1 => '' + ], + 90 => [ + 0 => ['|\\]^`=alert("XSS")>', ''], + 1 => '' + ], + 91 => [ + 0 => '<SCRIPT SRC=http://ha.ckers.org/xss.js', + 1 => '' + ], + 96 => [ + 0 => [ + '<SCRIPT>alert("XSS")</SCRIPT>">', + '<SCRIPT>alert("XSS")</SCRIPT>">', + ], + 1 => '">' + ], + 97 => [ + 0 => [ + '<SCRIPT>a=/XSS/
      alert(a.source)</SCRIPT>
      ', - '<SCRIPT>a=/XSS/
      + '<SCRIPT>a=/XSS/
      alert(a.source)</SCRIPT>
      ', - ], - 1 => '', - ), - 98 => - array ( - 0 => '<SCRIPT a=">" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', - 1 => '', - ), - 99 => - array ( - 0 => '<SCRIPT ="blah" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', - 1 => '', - ), - 100 => - array ( - 0 => '<SCRIPT a="blah" \'\' SRC="http://ha.ckers.org/xss.js"></SCRIPT>', - 1 => '', - ), - 101 => - array ( - 0 => '<SCRIPT "a=\'>\'" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', - 1 => '', - ), - 102 => - array ( - 0 => '<SCRIPT a=`>` SRC="http://ha.ckers.org/xss.js"></SCRIPT>', - 1 => '', - ), - 103 => - array ( - 0 => [ - '<SCRIPT>document.write("<SCRI");</SCRIPT>PT SRC="http://ha.ckers.org/xss.js">', - '<SCRIPT>document.write("<SCRI");</SCRIPT>PT SRC="http://ha.ckers.org/xss.js">', - ], - 1 => 'PT SRC="http://ha.ckers.org/xss.js">', - ), - 104 => - array ( - 0 => '<SCRIPT a=">\'>" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', - 1 => '', - ), - 105 => - array ( - 0 => 'XSS', - 1 => 'XSS', - ), - 106 => - array ( - 0 => [ - 'XSS', - 'XSS', - ], - 1 => 'XSS', - ), - 107 => - array ( - 0 => 'XSS', - 1 => 'XSS', - ), - 108 => - array ( - 0 => 'XSS', - 1 => 'XSS', - ), - 109 => - array ( - 0 => 'XSS', - 1 => 'XSS', - ), - 110 => - array ( - 0 => [ - 'XSS', - 'XSS', - ], - 1 => 'XSS', - ), - 111 => - array ( - 0 => 'XSS', - 1 => 'XSS', - ), - 112 => - array ( - 0 => 'XSS', - 1 => 'XSS', - ), - 113 => - array ( - 0 => [ - 'XSS', - 'XSS', - ], - 1 => 'XSS', - ), - 114 => - array ( - 0 => [ - 'XSS', - 'XSS', - ], - 1 => 'XSS', - ), - 115 => - array ( - 0 => 'XSS', - 1 => 'XSS', - ), - 116 => - array ( - 0 => 'XSS', - 1 => 'XSS', - ), - 117 => - array ( - 0 => 'XSS', - 1 => 'XSS', - ), - 118 => - array ( - 0 => [ - 'XSS', // safehtml - 'XSS', // htmlpurifier - ], - 1 => 'XSS', - ), - 119 => - array ( - 0 => '', - 1 => '', - ), - - 120 => - array ( - 0 => '30,00 EUR', - 1 => '30,00 EUR', - ), - - - 121 => - array ( - 0 => '30,00 EUR', - 1 => '30,00 EUR', - ), - - 122 => - array ( - 0 => '30,00 EUR', - 1 => '30,00 EUR', - ), - - 123 => - array ( - 0 => '30,00 EUR', - 1 => '30,00 EUR', - ), - -); + ], + 1 => '' + ], + 98 => [ + 0 => '<SCRIPT a=">" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', + 1 => '' + ], + 99 => [ + 0 => '<SCRIPT ="blah" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', + 1 => '' + ], + 100 => [ + 0 => '<SCRIPT a="blah" \'\' SRC="http://ha.ckers.org/xss.js"></SCRIPT>', + 1 => '' + ], + 101 => [ + 0 => '<SCRIPT "a=\'>\'" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', + 1 => '' + ], + 102 => [ + 0 => '<SCRIPT a=`>` SRC="http://ha.ckers.org/xss.js"></SCRIPT>', + 1 => '' + ], + 103 => [ + 0 => [ + '<SCRIPT>document.write("<SCRI");</SCRIPT>PT SRC="http://ha.ckers.org/xss.js">', + '<SCRIPT>document.write("<SCRI");</SCRIPT>PT SRC="http://ha.ckers.org/xss.js">', + ], + 1 => 'PT SRC="http://ha.ckers.org/xss.js">' + ], + 104 => [ + 0 => '<SCRIPT a=">\'>" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', + 1 => '' + ], + 105 => [ + 0 => 'XSS', + 1 => 'XSS' + ], + 106 => [ + 0 => [ + 'XSS', + 'XSS', + ], + 1 => 'XSS' + ], + 107 => [ + 0 => 'XSS', + 1 => 'XSS' + ], + 108 => [ + 0 => 'XSS', + 1 => 'XSS' + ], + 109 => [ + 0 => 'XSS', + 1 => 'XSS' + ], + 110 => [ + 0 => [ + 'XSS', + 'XSS', + ], + 1 => 'XSS' + ], + 111 => [ + 0 => 'XSS', + 1 => 'XSS' + ], + 112 => [ + 0 => 'XSS', + 1 => 'XSS' + ], + 113 => [ + 0 => [ + 'XSS', + 'XSS', + ], + 1 => 'XSS' + ], + 114 => [ + 0 => [ + 'XSS', + 'XSS', + ], + 1 => 'XSS' + ], + 115 => [ + 0 => 'XSS', + 1 => 'XSS' + ], + 116 => [ + 0 => 'XSS', + 1 => 'XSS' + ], + 117 => [ + 0 => '⚠️ <A HREF="javascript:document.location=\'http://www.google.com/\'">XSS', + 1 => 'XSS' + ], + 118 => [ + 0 => [ + 'XSS', // safehtml + 'XSS', // htmlpurifier + ], + 1 => 'XSS' + ], + 119 => [ + 0 => '', + 1 => '' + ], + 120 => [ + 0 => '30,00 EUR', + 1 => '30,00 EUR' + ], + 121 => [ + 0 => '30,00 EUR', + 1 => '30,00 EUR' + ], + 122 => [ + 0 => '30,00 EUR', + 1 => '30,00 EUR' + ], + 123 => [ + 0 => '30,00 EUR', + 1 => '30,00 EUR' + ] + ]; return $essais; } diff -Nru spip-4.4.13+dfsg/plugins-dist/sites/CHANGELOG.md spip-4.4.15+dfsg/plugins-dist/sites/CHANGELOG.md --- spip-4.4.13+dfsg/plugins-dist/sites/CHANGELOG.md 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/sites/CHANGELOG.md 2026-05-22 07:52:20.000000000 +0000 @@ -1,5 +1,12 @@ # Changelog +## 4.4.4 - 2026-05-12 + +### Fixed + +- #4869 warning -- quand un item RSS comporte une balise `source` autofermante +- #4866 réparer le bouton "Tenter une nouvelle récupération" quand un site est en erreur de syndication + ## 4.4.3 - 2026-02-18 ### Security diff -Nru spip-4.4.13+dfsg/plugins-dist/sites/paquet.xml spip-4.4.15+dfsg/plugins-dist/sites/paquet.xml --- spip-4.4.13+dfsg/plugins-dist/sites/paquet.xml 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/sites/paquet.xml 2026-05-22 07:52:20.000000000 +0000 @@ -1,7 +1,7 @@ <:sites:avis_site_syndique_probleme{url_syndic=#GET{url_aff}}:> - [(#BOUTON_ACTION{<:sites:lien_nouvelle_recuperation:>,#URL_ACTION_AUTEUR{editer_site,#ID_SYNDIC,#SELF}|parametre_url{reload,oui},ajax})] + [(#BOUTON_ACTION{<:sites:lien_nouvelle_recuperation:>,#URL_ACTION_AUTEUR{syndiquer_site,#ID_SYNDIC,#SELF},ajax})]
      ] , par=date, env, ajax, recherche_integree=1} /> diff -Nru spip-4.4.13+dfsg/plugins-dist/sites/syndic/atomrss.php spip-4.4.15+dfsg/plugins-dist/sites/syndic/atomrss.php --- spip-4.4.13+dfsg/plugins-dist/sites/syndic/atomrss.php 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/sites/syndic/atomrss.php 2026-05-22 07:52:20.000000000 +0000 @@ -373,12 +373,8 @@ $match ) ) { - $data['source'] = trim($match[3]); - $data['url_source'] = str_replace( - '&', - '&', - trim(extraire_attribut($match[1], 'url')) - ); + $data['source'] = trim($match[3] ?? ''); + $data['url_source'] = str_replace('&', '&', trim(extraire_attribut($match[1], 'url'))); } // Récupération de l'id quelqu'il soit diff -Nru spip-4.4.13+dfsg/plugins-dist/statistiques/CHANGELOG.md spip-4.4.15+dfsg/plugins-dist/statistiques/CHANGELOG.md --- spip-4.4.13+dfsg/plugins-dist/statistiques/CHANGELOG.md 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/statistiques/CHANGELOG.md 2026-05-22 07:52:20.000000000 +0000 @@ -1,4 +1,10 @@ # Changelog + +## 3.1.12 - 2026-05-12 + +### Fixed + +- spip/spip#6084 remplacement appels minipres() en Minipage ## 3.1.11 - 2026-02-12 diff -Nru spip-4.4.13+dfsg/plugins-dist/statistiques/action/statistiques_archiver.php spip-4.4.15+dfsg/plugins-dist/statistiques/action/statistiques_archiver.php --- spip-4.4.13+dfsg/plugins-dist/statistiques/action/statistiques_archiver.php 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/statistiques/action/statistiques_archiver.php 2026-05-22 07:52:20.000000000 +0000 @@ -9,6 +9,8 @@ * Ce programme est un logiciel libre distribué sous licence GNU/GPL. * \***************************************************************************/ +use Spip\Afficher\Minipage\Admin as MinipageAdmin; + /** * Action d'archivage des statistiques * @@ -59,8 +61,9 @@ } if (!autoriser('webmestre')) { - include_spip('inc/minipres'); - minipres(); + $minipage = new MinipageAdmin(); + echo $minipage->page(''); + exit; } if ( @@ -70,8 +73,9 @@ 'nettoyer_referers_articles' ]) ) { - include_spip('inc/minipres'); - minipres('Argument non compris'); + $minipage = new MinipageAdmin(); + echo $minipage->page('Argument non compris'); + exit; } $func = 'statistiques_' . $arg; diff -Nru spip-4.4.13+dfsg/plugins-dist/statistiques/composer.json spip-4.4.15+dfsg/plugins-dist/statistiques/composer.json --- spip-4.4.13+dfsg/plugins-dist/statistiques/composer.json 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/statistiques/composer.json 2026-05-22 07:52:20.000000000 +0000 @@ -17,6 +17,11 @@ "dealerdirect/phpcodesniffer-composer-installer": "^1.0", "spip/coding-standards": "^1.2" }, + "autoload-dev": { + "psr-4": { + "Spip\\": "tests/Fixtures/" + } + }, "config": { "allow-plugins": { "dealerdirect/phpcodesniffer-composer-installer": true @@ -24,5 +29,13 @@ "platform": { "php": "7.4.33" } + }, + "scripts": { + "analyse": "phpstan --memory-limit=-1", + "baseline": "phpstan --memory-limit=-1 --generate-baseline --allow-empty-baseline", + "check-cs": "ecs check --ansi", + "fix-cs": "ecs check --fix --ansi", + "rector": "rector process --ansi", + "rector-dry-run": "rector process --dry-run --ansi" } } diff -Nru spip-4.4.13+dfsg/plugins-dist/statistiques/exec/base_delete_referers.php spip-4.4.15+dfsg/plugins-dist/statistiques/exec/base_delete_referers.php --- spip-4.4.13+dfsg/plugins-dist/statistiques/exec/base_delete_referers.php 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/statistiques/exec/base_delete_referers.php 2026-05-22 07:52:20.000000000 +0000 @@ -9,16 +9,14 @@ * Ce programme est un logiciel libre distribué sous licence GNU/GPL. * \***************************************************************************/ -if (!defined('_ECRIRE_INC_VERSION')) { - return; -} - +use Spip\Afficher\Minipage\Admin as MinipageAdmin; function exec_base_delete_referers_dist() { include_spip('inc/autoriser'); if (!autoriser('detruire', '_statistiques')) { - include_spip('inc/minipres'); - echo minipres(); + $minipage = new MinipageAdmin(); + echo $minipage->page(''); + exit; } else { include_spip('inc/headers'); $admin = charger_fonction('admin', 'inc'); diff -Nru spip-4.4.13+dfsg/plugins-dist/statistiques/exec/base_delete_stats.php spip-4.4.15+dfsg/plugins-dist/statistiques/exec/base_delete_stats.php --- spip-4.4.13+dfsg/plugins-dist/statistiques/exec/base_delete_stats.php 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/statistiques/exec/base_delete_stats.php 2026-05-22 07:52:20.000000000 +0000 @@ -9,16 +9,15 @@ * Ce programme est un logiciel libre distribué sous licence GNU/GPL. * \***************************************************************************/ -if (!defined('_ECRIRE_INC_VERSION')) { - return; -} +use Spip\Afficher\Minipage\Admin as MinipageAdmin; function exec_base_delete_stats_dist() { include_spip('inc/autoriser'); if (!autoriser('detruire', '_statistiques')) { - include_spip('inc/minipres'); - echo minipres(); + $minipage = new MinipageAdmin(); + echo $minipage->page(''); + exit; } else { include_spip('inc/headers'); $admin = charger_fonction('admin', 'inc'); diff -Nru spip-4.4.13+dfsg/plugins-dist/statistiques/paquet.xml spip-4.4.15+dfsg/plugins-dist/statistiques/paquet.xml --- spip-4.4.13+dfsg/plugins-dist/statistiques/paquet.xml 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/statistiques/paquet.xml 2026-05-22 07:52:20.000000000 +0000 @@ -1,7 +1,7 @@ $params + */ + public function installDebutPage(array $params = []): string { + return ''; + } + + /** + * @param array $options + */ + public function page(string $corps, array $options = []): string { + return ''; + } + + public function installFinPage(): string { + return ''; + } +} diff -Nru spip-4.4.13+dfsg/plugins-dist/svp/CHANGELOG.md spip-4.4.15+dfsg/plugins-dist/svp/CHANGELOG.md --- spip-4.4.13+dfsg/plugins-dist/svp/CHANGELOG.md 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/svp/CHANGELOG.md 2026-05-22 07:52:20.000000000 +0000 @@ -1,5 +1,12 @@ # Changelog +## 3.2.5 - 2026-05-12 + +### Fixed + +- Type incorrect dans svp_redirige_boucle créant une erreur fatale en PHP 8.5 +- spip/spip#6084 remplacement appels minipres() en Minipage + ## 3.2.4 - 2026-02-12 ### Added diff -Nru spip-4.4.13+dfsg/plugins-dist/svp/action/actionner.php spip-4.4.15+dfsg/plugins-dist/svp/action/actionner.php --- spip-4.4.13+dfsg/plugins-dist/svp/action/actionner.php 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/svp/action/actionner.php 2026-05-22 07:52:20.000000000 +0000 @@ -5,12 +5,9 @@ * * @plugin SVP pour SPIP * @license GPL - * @package SPIP\SVP\Actions */ -if (!defined('_ECRIRE_INC_VERSION')) { - return; -} +use Spip\Afficher\Minipage\Admin as MinipageAdmin; /** * Action effectuant 1 action dans la liste des actions à réaliser @@ -22,8 +19,8 @@ // droits include_spip('inc/autoriser'); if (!autoriser('configurer', '_plugins')) { - include_spip('inc/minipres'); - echo minipres(); + $minipage = new MinipageAdmin(); + echo $minipage->page(''); exit; } @@ -113,7 +110,7 @@ @ini_set('output_buffering', 'off'); @ini_set('implicit_flush', 1); } - @ob_implicit_flush(1); + @ob_implicit_flush(true); $progress = round($progres * 100); $pres = ''; @@ -132,7 +129,7 @@ 'css_files' => [find_in_theme('minipage-svp.css')], 'footer' => '' ]; - $minipage = new Spip\Afficher\Minipage\Admin(); + $minipage = new MinipageAdmin(); echo $minipage->page($pres, $options); exit; } diff -Nru spip-4.4.13+dfsg/plugins-dist/svp/action/actualiser_depot.php spip-4.4.15+dfsg/plugins-dist/svp/action/actualiser_depot.php --- spip-4.4.13+dfsg/plugins-dist/svp/action/actualiser_depot.php 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/svp/action/actualiser_depot.php 2026-05-22 07:52:20.000000000 +0000 @@ -5,9 +5,10 @@ * * @plugin SVP pour SPIP * @license GPL - * @package SPIP\SVP\Actions */ +use Spip\Afficher\Minipage\Admin as MinipageAdmin; + /** * Action de mise à jour en base de données de la liste des plugins * d'un ou de tous les dépots @@ -20,9 +21,9 @@ // Verification des autorisations if (!autoriser('webmestre')) { - include_spip('inc/minipres'); - echo minipres(); - exit(); + $minipage = new MinipageAdmin(); + echo $minipage->page(''); + exit; } // Actualisation des plugins du depot ou de tous les plugins suivant l'argument de l'action diff -Nru spip-4.4.13+dfsg/plugins-dist/svp/action/editer_depot.php spip-4.4.15+dfsg/plugins-dist/svp/action/editer_depot.php --- spip-4.4.13+dfsg/plugins-dist/svp/action/editer_depot.php 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/svp/action/editer_depot.php 2026-05-22 07:52:20.000000000 +0000 @@ -9,16 +9,14 @@ * Ce programme est un logiciel libre distribué sous licence GNU/GPL. * \***************************************************************************/ +use Spip\Afficher\Minipage\Admin as MinipageAdmin; + /** * Gestion de l'action editer_depot * * @plugin SVP pour SPIP * @license GPL - * @package SPIP\SVP\Actions */ -if (!defined('_ECRIRE_INC_VERSION')) { - return; -} /** * Action de mise à jour des descriptions d'un dépot @@ -33,9 +31,9 @@ // Verification des autorisations if (!autoriser('webmestre')) { - include_spip('inc/minipres'); - echo minipres(); - exit(); + $minipage = new MinipageAdmin(); + echo $minipage->page(''); + exit; } // Le depot n'est jamais cree par une edition mais via le formulaire ajouter_depot diff -Nru spip-4.4.13+dfsg/plugins-dist/svp/action/supprimer_depot.php spip-4.4.15+dfsg/plugins-dist/svp/action/supprimer_depot.php --- spip-4.4.13+dfsg/plugins-dist/svp/action/supprimer_depot.php 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/svp/action/supprimer_depot.php 2026-05-22 07:52:20.000000000 +0000 @@ -5,9 +5,10 @@ * * @plugin SVP pour SPIP * @license GPL - * @package SPIP\SVP\Actions */ +use Spip\Afficher\Minipage\Admin as MinipageAdmin; + /** * Action de suppression en base de données d'un dépot et de ses plugins * @@ -22,9 +23,9 @@ // Verification des autorisations if (!autoriser('webmestre')) { - include_spip('inc/minipres'); - echo minipres(); - exit(); + $minipage = new MinipageAdmin(); + echo $minipage->page(''); + exit; } // Suppression du depot et de ses plugins diff -Nru spip-4.4.13+dfsg/plugins-dist/svp/composer.json spip-4.4.15+dfsg/plugins-dist/svp/composer.json --- spip-4.4.13+dfsg/plugins-dist/svp/composer.json 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/svp/composer.json 2026-05-22 07:52:20.000000000 +0000 @@ -40,9 +40,16 @@ } }, "scripts": { + "analyse": "phpstan --memory-limit=-1", + "baseline": "phpstan --memory-limit=-1 --generate-baseline --allow-empty-baseline", "check-cs": "ecs check --ansi", "fix-cs": "ecs check --fix --ansi", "rector": "rector process --ansi", "rector-dry-run": "rector process --dry-run --ansi" + }, + "autoload-dev": { + "psr-4": { + "Spip\\": "tests/Fixtures/" + } } } diff -Nru spip-4.4.13+dfsg/plugins-dist/svp/exec/admin_plugin.php spip-4.4.15+dfsg/plugins-dist/svp/exec/admin_plugin.php --- spip-4.4.13+dfsg/plugins-dist/svp/exec/admin_plugin.php 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/svp/exec/admin_plugin.php 2026-05-22 07:52:20.000000000 +0000 @@ -9,6 +9,8 @@ * Ce programme est un logiciel libre distribué sous licence GNU/GPL. * \***************************************************************************/ +use Spip\Afficher\Minipage\Admin as MinipageAdmin; + /** * Surcharge de la page admin_plugin de SPIP * @@ -41,8 +43,9 @@ function exec_admin_plugin_dist() { if (!autoriser('configurer', '_plugins')) { - include_spip('inc/minipres'); - echo minipres(); + $minipage = new MinipageAdmin(); + echo $minipage->page(''); + exit; } // on fait la verif du path avant tout, diff -Nru spip-4.4.13+dfsg/plugins-dist/svp/inc/svp_depoter_distant.php spip-4.4.15+dfsg/plugins-dist/svp/inc/svp_depoter_distant.php --- spip-4.4.13+dfsg/plugins-dist/svp/inc/svp_depoter_distant.php 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/svp/inc/svp_depoter_distant.php 2026-05-22 07:52:20.000000000 +0000 @@ -1031,4 +1031,5 @@ } } + return ''; } diff -Nru spip-4.4.13+dfsg/plugins-dist/svp/paquet.xml spip-4.4.15+dfsg/plugins-dist/svp/paquet.xml --- spip-4.4.13+dfsg/plugins-dist/svp/paquet.xml 2026-03-06 10:17:22.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist/svp/paquet.xml 2026-05-22 07:52:20.000000000 +0000 @@ -1,7 +1,7 @@ $params + */ + public function installDebutPage(array $params = []): string { + return ''; + } + + /** + * @param array $options + */ + public function page(string $corps, array $options = []): string { + return ''; + } + + public function installFinPage(): string { + return ''; + } +} diff -Nru spip-4.4.13+dfsg/plugins-dist.json spip-4.4.15+dfsg/plugins-dist.json --- spip-4.4.13+dfsg/plugins-dist.json 2026-03-06 10:17:16.000000000 +0000 +++ spip-4.4.15+dfsg/plugins-dist.json 2026-05-22 07:52:14.000000000 +0000 @@ -2,49 +2,49 @@ "aide": { "path": "plugins-dist/aide", "source": "https://git.spip.net/spip/aide.git", - "branch": "3.2", - "tag": "3.2.6" + "branch": "3.x", + "tag": "3.2.7" }, "archiviste": { "path": "plugins-dist/archiviste", "source": "https://git.spip.net/spip/archiviste.git", - "branch": "2.2", - "tag": "2.2.4" + "branch": "2.x", + "tag": "2.2.5" }, "bigup": { "path": "plugins-dist/bigup", "source": "https://git.spip.net/spip/bigup.git", - "branch": "3.3", - "tag": "3.3.9" + "branch": "3.x", + "tag": "3.3.10" }, "compagnon": { "path": "plugins-dist/compagnon", "source": "https://git.spip.net/spip/compagnon.git", - "branch": "3.2", - "tag": "3.2.1" + "branch": "3.x", + "tag": "3.3.0" }, "compresseur": { "path": "plugins-dist/compresseur", "source": "https://git.spip.net/spip/compresseur.git", - "branch": "2.2", + "branch": "2.x", "tag": "2.2.3" }, "dump": { "path": "plugins-dist/dump", "source": "https://git.spip.net/spip/dump.git", - "branch": "2.2", - "tag": "2.2.1" + "branch": "2.x", + "tag": "2.2.3" }, "filtres_images": { "path": "plugins-dist/filtres_images", "source": "https://git.spip.net/spip/images.git", - "branch": "4.3", - "tag": "4.3.6" + "branch": "4.x", + "tag": "4.3.7" }, "forum": { "path": "plugins-dist/forum", "source": "https://git.spip.net/spip/forum.git", - "branch": "3.1", + "branch": "3.x", "tag": "3.1.14" }, "mediabox": { @@ -56,67 +56,67 @@ "medias": { "path": "plugins-dist/medias", "source": "https://git.spip.net/spip/medias.git", - "branch": "4.4", - "tag": "4.4.9" + "branch": "4.x", + "tag": "4.4.10" }, "mots": { "path": "plugins-dist/mots", "source": "https://git.spip.net/spip/mots.git", - "branch": "4.3", + "branch": "4.x", "tag": "4.3.0" }, "plan": { "path": "plugins-dist/plan", "source": "https://git.spip.net/spip/plan.git", - "branch": "4.1", + "branch": "4.x", "tag": "4.1.6" }, "porte_plume": { "path": "plugins-dist/porte_plume", "source": "https://git.spip.net/spip/porte-plume.git", - "branch": "3.1", + "branch": "3.x", "tag": "3.1.10" }, "revisions": { "path": "plugins-dist/revisions", "source": "https://git.spip.net/spip/revisions.git", - "branch": "3.1", - "tag": "3.1.11" + "branch": "3.x", + "tag": "3.1.12" }, "safehtml": { "path": "plugins-dist/safehtml", "source": "https://git.spip.net/spip/safehtml.git", - "branch": "3.1", - "tag": "3.1.5" + "branch": "3.x", + "tag": "3.1.6" }, "sites": { "path": "plugins-dist/sites", "source": "https://git.spip.net/spip/sites.git", "branch": "4.x", - "tag": "4.4.3" + "tag": "4.4.4" }, "statistiques": { "path": "plugins-dist/statistiques", "source": "https://git.spip.net/spip/stats.git", - "branch": "3.1", - "tag": "3.1.11" + "branch": "3.x", + "tag": "3.1.12" }, "svp": { "path": "plugins-dist/svp", "source": "https://git.spip.net/spip/svp.git", - "branch": "3.2", - "tag": "3.2.4" + "branch": "3.x", + "tag": "3.2.5" }, "textwheel": { "path": "plugins-dist/textwheel", "source": "https://git.spip.net/spip/tw.git", - "branch": "3.3", + "branch": "3.x", "tag": "3.3.8" }, "urls_etendues": { "path": "plugins-dist/urls_etendues", "source": "https://git.spip.net/spip/urls.git", - "branch": "4.2", + "branch": "4.x", "tag": "4.2.2" } } \ No newline at end of file diff -Nru spip-4.4.13+dfsg/prive/CHANGELOG.md spip-4.4.15+dfsg/prive/CHANGELOG.md --- spip-4.4.13+dfsg/prive/CHANGELOG.md 2026-03-06 09:27:32.000000000 +0000 +++ spip-4.4.15+dfsg/prive/CHANGELOG.md 2026-05-12 07:51:22.000000000 +0000 @@ -5,6 +5,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 1.1.0 - 2026-05-12 + +### Fixed + +- spip/compresseur!4890 Utiliser `minifier` à la place de `compacte` +- !126 !136 Vérification du formulaire d'institution générique des pour les personnes non webmestres avec un objet sans parent +- #107 Chaîne de langue pour les articles à paraître +- !141 Conditionner l'affichage des liens ical dans Suivre la vie du site + +### Removed + +- spip-contrib-extensions/organiseur#4698 spip/spip#6084 ical_prive.html déplacé dans le plugin Organiseur. +- !139 spip-contrib-extensions/petitions#3949 Suppression du suivi RSS des signatures de pétitions, déplacé dans le plugin Pétitions. + ## 1.0.10 - 2026-03-06 ### Fixed diff -Nru spip-4.4.13+dfsg/prive/formulaires/dateur/inc-dateur.html spip-4.4.15+dfsg/prive/formulaires/dateur/inc-dateur.html --- spip-4.4.13+dfsg/prive/formulaires/dateur/inc-dateur.html 2026-03-06 09:27:32.000000000 +0000 +++ spip-4.4.15+dfsg/prive/formulaires/dateur/inc-dateur.html 2026-05-12 07:51:22.000000000 +0000 @@ -180,8 +180,8 @@ }