diff --git a/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/files/7ee02eb092b334c4-23450.svg b/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/files/7ee02eb092b334c4-23450.svg new file mode 100644 index 0000000..b7e8dc0 --- /dev/null +++ b/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/files/7ee02eb092b334c4-23450.svg @@ -0,0 +1,97 @@ + +ImageMagick sur Debian : convert-im6, magick, et leur lien avec les binaires sous-jacents +Schéma illustrant comment les commandes convert et magick sont des symlinks vers les binaires versionnés convert-im6.q16 et magick-im7.q16 sur Debian. + + + + +ImageMagick sur Debian +Ce que tu tapes, ce que le système exécute + + +Debian 11 / 12 (bookworm) + + + +convert +tu tapes + + + + + + +indispo +par défaut + + + + +convert-im6 +tu tapes + + + + + + +IM 6 +.q16 + + + +Debian 13 (trixie) + + + +convert +symlink + + + + + + +IM 7 +.q16 + + + + +magick +recommandé + + + + + + +IM 7 +.q16 + + +Pourquoi ce renommage ? + + + +ImageMagick 6 +convert, identify, +mogrify, composite + + + + +ImageMagick 7 +magick +(commande unique) + + ++ +noms en +conflit + + +Solution Debian : suffixer chaque binaire +convert-im6.q16 / magick-im7.q16 → cohabitation possible + + \ No newline at end of file diff --git a/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/files/cover.svg b/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/files/cover.svg new file mode 100644 index 0000000..14a049e --- /dev/null +++ b/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/files/cover.svg @@ -0,0 +1,115 @@ + +magick : la commande unifiée d'ImageMagick 7 +Illustration représentant la commande magick comme une baguette magique transformant une image source en plusieurs formats. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +photo.jpg + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +PNG +photo.png + + + + +WEBP +photo.webp + + + + +AVIF +photo.avif + + + + + + + + +magick +one command, every format + +$ magick photo.jpg -resize 1600 photo.webp +ImageMagick 7 + \ No newline at end of file diff --git a/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/index.md b/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/index.md index 99efbec..6ad1a99 100644 --- a/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/index.md +++ b/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/index.md @@ -1,183 +1,78 @@ -ImageMagick est depuis de nombreuses années un outil incontournable pour la manipulation d’images en ligne de commande. Il est utilisé aussi bien dans des scripts simples que dans des chaînes de traitement industrielles, des environnements serveurs ou des pipelines CI/CD. +Si tu as déjà installé ImageMagick sur un serveur Debian, tu es probablement tombé sur cette étrangeté : la commande `convert` historique est là, mais elle s'appelle `convert-im6`. Et la commande moderne `magick`, présente partout ailleurs, semble manquer à l'appel — sauf si tu es sur Debian 13, où elle est revenue. -Cependant, sous Debian (et ses dérivés comme Ubuntu), l’utilisation d’ImageMagick peut prêter à confusion : la commande historique `convert` n’est pas disponible telle quelle, remplacée par `convert-im6`, et la commande moderne `magick` semble absente. +Le sujet est un peu plus subtil qu'il n'y paraît, et beaucoup d'explications qui circulent sur le web sont fausses (notamment celle qui prétend que `convert` entrerait en conflit avec un binaire de `util-linux` — c'est un mythe). Voilà ce qui se passe réellement. -Cet article clarifie les raisons de ce choix, les implications techniques, et les bonnes pratiques à adopter. +## Un peu de contexte sur ImageMagick ---- +ImageMagick, c'est une suite d'outils en ligne de commande pour manipuler des images : conversion de formats, redimensionnement, compression, génération de vignettes, watermarks, lecture de métadonnées… Le genre d'outil qu'on retrouve aussi bien dans un script bash de cinq lignes que dans une chaîne de traitement industrielle ou un pipeline CI. -## 1. ImageMagick : rappel sur l’architecture +Historiquement, la suite est composée de plusieurs binaires distincts, chacun avec son rôle : `convert` pour la conversion, `identify` pour lire les métadonnées, `mogrify` pour le traitement par lot, `composite` pour combiner des images, `montage` pour les planches. C'est l'architecture d'**ImageMagick 6**, la version qui a régné en maître pendant une bonne quinzaine d'années. -ImageMagick est une suite d’outils permettant : +Depuis 2016, **ImageMagick 7** est disponible. Le grand changement, c'est qu'il unifie tout derrière une seule commande : `magick`. Les anciennes commandes deviennent des sous-commandes (`magick convert`, `magick identify`, etc.), même si pour la rétrocompatibilité un binaire `magick` peut continuer à se comporter comme `convert` quand on l'appelle avec une syntaxe d'IM6. -* la conversion de formats d’images, -* le redimensionnement, -* la compression, -* l’analyse des métadonnées, -* le traitement par lot, -* la génération d’images (watermarks, miniatures, montages, etc.). +## Pourquoi le suffixe `-im6` sur Debian -Historiquement, chaque fonction correspondait à un binaire distinct : +C'est ici que beaucoup d'articles racontent n'importe quoi. La vraie raison n'a rien à voir avec un conflit avec `util-linux` — je l'ai vérifié, aucun paquet système ne fournit de commande `convert`. Tu peux le vérifier toi-même : `dpkg -S /usr/bin/convert` ne renvoie rien qui vienne de util-linux. -* `convert` -* `identify` -* `mogrify` -* `montage` -* `composite` +La vraie raison est plus prosaïque. Pendant des années, Debian a voulu pouvoir **packager IM6 et IM7 en parallèle** dans la même distribution, pour permettre une transition en douceur. Le souci, c'est que les deux versions fournissent des binaires aux mêmes noms (`convert`, `identify`, `mogrify`…) avec des comportements légèrement différents. Impossible de les installer côte à côte sans renommer. -Cette architecture correspond à **ImageMagick 6**. +La solution adoptée par les mainteneurs Debian a été d'ajouter un suffixe explicite au nom de chaque binaire : ---- +- les outils d'IM6 deviennent `convert-im6.q16`, `identify-im6.q16`, etc. +- les outils d'IM7 deviennent `magick-im7.q16` et compagnie -## 2. Pourquoi Debian n’utilise pas `convert` +Le `.q16` indique la profondeur quantique du binaire (16 bits par canal, la valeur par défaut), et le `-im6` / `-im7` indique la version d'ImageMagick. Les noms classiques (`convert`, `magick`) ne sont alors que des symlinks gérés par `update-alternatives`, qui pointent vers la version active. C'est le même mécanisme que pour `java`, `editor`, ou `python` à une époque. -Sous Debian, la commande `convert` appartient déjà au paquet **util-linux**. -Elle sert à convertir des systèmes de fichiers (par exemple FAT vers ext4). +## Ce qui change entre Debian 11, 12 et 13 -Pour éviter toute ambiguïté et collision binaire, Debian a fait le choix de : +C'est l'autre point que la plupart des articles ratent : la situation n'est pas la même selon la version de Debian. -* **ne pas fournir `convert` pour ImageMagick** -* renommer les binaires ImageMagick avec le suffixe `-im6` +Sur **Debian 11 (bullseye) et 12 (bookworm)**, le paquet `imagemagick` installe IM6 (version 6.9.11.60). Tu n'as que `convert-im6` et ses copains, et `magick` n'existe pas dans les dépôts officiels (le paquet `imagemagick-7.q16` existe mais n'est pas le défaut). C'est cette situation que décrivent la plupart des tutoriels qui traînent sur le web. -Ainsi, sous Debian : +Sur **Debian 13 (trixie)**, sorti en août 2025, le défaut a basculé sur IM7 (version 7.1.1.43). La commande `magick` est disponible, et `convert` est désormais un symlink vers `magick-im7.q16`. Tu peux le vérifier : -| Fonction | Binaire | -| ------------------ | --------------- | -| Conversion d’image | `convert-im6` | -| Identification | `identify-im6` | -| Traitement par lot | `mogrify-im6` | -| Composition | `composite-im6` | - -Ce choix garantit la stabilité du système et évite toute confusion avec des outils bas niveau. - ---- - -## 3. ImageMagick 6 vs ImageMagick 7 - -### ImageMagick 6 (Debian) - -* Architecture historique -* Commandes séparées -* Très stable -* Largement utilisée en production -* Maintenance conservatrice - -Exemple : - -``` -convert-im6 image.jpg image.png +```bash +$ readlink -f /usr/bin/convert +/usr/bin/magick-im7.q16 ``` ---- +Autrement dit, sur Trixie, si tu écris `convert image.jpg image.png`, tu appelles en réalité IM7 sous un nom d'IM6. Ça fonctionne pour la plupart des usages, mais attention : IM7 est plus strict sur l'ordre des arguments en ligne de commande (`magick [INPUT-OPTIONS] INPUT [OUTPUT-OPTIONS] OUTPUT`), donc certains scripts anciens peuvent grogner. -### ImageMagick 7 +## Correspondance entre les deux versions -ImageMagick 7 introduit une évolution majeure : -👉 **une commande unique : `magick`** +| ImageMagick 6 (Debian 11/12) | ImageMagick 7 (Debian 13) | +| ---------------------------- | ------------------------- | +| `convert-im6` | `magick` | +| `identify-im6` | `magick identify` | +| `mogrify-im6` | `magick mogrify` | +| `composite-im6` | `magick composite` | -Toutes les fonctionnalités sont regroupées derrière ce binaire. +Pour les cas simples, le comportement est identique. Une commande de redimensionnement classique passe sans modification : -Exemple : - -``` -magick image.jpg image.png -``` - -Avantages : - -* syntaxe unifiée -* meilleure gestion mémoire -* prise en charge améliorée des formats modernes (WebP, AVIF, HEIF) -* comportement plus cohérent dans les scripts - ---- - -## 4. Pourquoi `magick` n’est pas disponible par défaut sous Debian - -Debian privilégie : - -* la stabilité à long terme, -* la compatibilité ascendante, -* les mises à jour maîtrisées. - -ImageMagick 7, bien que mature, est considéré comme une rupture de comportement par rapport à la version 6. -Pour cette raison, Debian stable fournit uniquement **ImageMagick 6**, et donc **pas la commande `magick`**. - ---- - -## 5. Correspondance entre IM6 et IM7 - -| ImageMagick 6 (Debian) | ImageMagick 7 | -| ---------------------- | ------------------ | -| `convert-im6` | `magick` | -| `identify-im6` | `magick identify` | -| `mogrify-im6` | `magick mogrify` | -| `composite-im6` | `magick composite` | - ---- - -## 6. Exemple concret de conversion - -### Sous Debian (IM6) - -``` +```bash +# Debian 11/12 convert-im6 photo.jpg -resize 1600x1600 photo_reduite.jpg -``` -### Sous IM7 - -``` +# Debian 13 magick photo.jpg -resize 1600x1600 photo_reduite.jpg ``` -Le comportement est identique. +## Faut-il s'inquiéter sur un serveur en production ? ---- +Si tu administres une machine Debian 12 ou plus ancienne, non. IM6 est toujours activement maintenu pour les CVE (les correctifs sont régulièrement backportés dans les paquets stable), et la plupart des scripts existants continueront de fonctionner. Le `-im6` dans le nom du binaire est juste du marquage, pas une dépréciation. -## 7. Faut-il installer ImageMagick 7 sur Debian ? +Si tu migres vers Debian 13, prévois un peu de temps pour relire tes scripts. Les pièges classiques : -### Cas où cela peut être justifié +- l'ordre des options qui devient plus strict ; +- quelques comportements de couleur et d'alpha qui ont changé entre les deux versions, notamment sur les opérations chaînées ; +- le fichier `policy.xml` qui a déménagé : `/etc/ImageMagick-6/` devient `/etc/ImageMagick-7/`. Si tu avais assoupli les restrictions sur les PDF ou PostScript (un grand classique), il faut reporter la modification. -* Besoin explicite de `magick` -* Utilisation intensive de formats modernes (AVIF, HEIF) -* Développement d’outils multi-plateformes -* Environnement isolé (conteneur, VM, CI) +Pour un projet PHP comme les tiens, l'extension Imagick côté PHP est sensible à cette transition : la version compilée doit correspondre à la version d'IM installée, sinon `pecl install imagick` échoue. Sur Trixie, c'est IM7 qu'il faut lier. -### Cas où il vaut mieux rester en IM6 +## En pratique -* Serveur de production -* Scripts existants -* Environnement stable long terme -* Administration système classique +Sur Debian 11/12, utilise `convert-im6`, `identify-im6`, etc. C'est la convention locale, pas une version dégradée. Si tu veux `magick` malgré tout, tu peux installer le paquet `imagemagick-7.q16` (présent dans les dépôts depuis bookworm) et basculer les alternatives manuellement, mais ce n'est presque jamais nécessaire. ---- +Sur Debian 13, utilise `magick` directement. La commande `convert` reste disponible par compatibilité, mais elle pointe en réalité vers IM7 — autant utiliser le nom officiel. -## 8. Recommandation opérationnelle - -Sur Debian : - -* ✔ Utiliser `convert-im6` et les outils associés -* ✔ S’appuyer sur la stabilité d’ImageMagick 6 -* ✔ Éviter les alias globaux modifiant `convert` -* ❌ Ne pas forcer l’installation d’IM7 sans besoin réel - -Pour un environnement de développement ou de test, IM7 peut être installé séparément sans conflit, à condition de ne pas écraser les binaires système. - ---- - -## 9. Conclusion - -La présence de `convert-im6` au lieu de `magick` n’est ni une anomalie ni une régression : -c’est un **choix volontaire de Debian**, dicté par la stabilité et la cohérence du système. - -ImageMagick 6 reste parfaitement adapté à la majorité des usages professionnels. -ImageMagick 7 apporte une ergonomie moderne, mais n’est pas indispensable dans la majorité des cas. - ---- - -### En résumé - -* `convert-im6` → normal sous Debian -* `magick` → ImageMagick 7 uniquement -* Les deux sont fonctionnellement équivalents -* Le choix dépend du contexte, pas d’une supériorité technique absolue +Et dans tous les cas, évite les alias globaux qui réécrivent `convert` : ça finit toujours par mordre quelqu'un, soit toi dans six mois, soit le prochain qui reprendra le serveur. \ No newline at end of file diff --git a/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/meta.json b/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/meta.json index 5ddf16c..95b6261 100644 --- a/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/meta.json +++ b/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/meta.json @@ -1,13 +1,34 @@ { "uuid": "0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485", - "slug": "imagemagick-sous-debian-comprendre-convert-im6-magick-et-les-choix-de-conception", - "title": "ImageMagick sous Debian : comprendre `convert-im6`, `magick` et les choix de conception", + "slug": "imagemagick-sur-debian-pourquoi-convert-im6-et-ou-trouver-magick", + "title": "ImageMagick sur Debian : pourquoi `convert-im6` et où trouver `magick`", "author": "cedric@abonnel.fr", "published": true, - "published_at": "2025-12-28 15:32:01", + "published_at": "2025-12-28 15:32", "created_at": "2025-12-28 15:32:01", - "updated_at": "2025-12-28 15:32:01", - "revisions": [], - "cover": "cover.jpg", + "updated_at": "2026-05-12 00:29:00", + "revisions": [ + { + "n": 1, + "date": "2026-05-12 00:29:00", + "comment": "", + "title": "ImageMagick sur Debian : pourquoi `convert-im6` et où trouver `magick`" + } + ], + "cover": "cover.svg", + "files_meta": { + "45de275c5f174797-24653.svg": { + "author": "", + "source_url": "" + }, + "7ee02eb092b334c4-23450.svg": { + "author": "", + "source_url": "" + } + }, + "external_links": [], + "seo_title": "", + "seo_description": "", + "og_image": "", "category": "linux" } diff --git a/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/revisions/0001.md b/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/revisions/0001.md new file mode 100644 index 0000000..1065904 --- /dev/null +++ b/data/0e0b8d1d-3352-4ab7-bc70-7bc1f02ee485/revisions/0001.md @@ -0,0 +1,78 @@ +Si tu as déjà installé ImageMagick sur un serveur Debian, tu es probablement tombé sur cette étrangeté : la commande `convert` historique est là, mais elle s'appelle `convert-im6`. Et la commande moderne `magick`, présente partout ailleurs, semble manquer à l'appel — sauf si tu es sur Debian 13, où elle est revenue. + +Le sujet est un peu plus subtil qu'il n'y paraît, et beaucoup d'explications qui circulent sur le web sont fausses (notamment celle qui prétend que `convert` entrerait en conflit avec un binaire de `util-linux` — c'est un mythe). Voilà ce qui se passe réellement. + +## Un peu de contexte sur ImageMagick + +ImageMagick, c'est une suite d'outils en ligne de commande pour manipuler des images : conversion de formats, redimensionnement, compression, génération de vignettes, watermarks, lecture de métadonnées… Le genre d'outil qu'on retrouve aussi bien dans un script bash de cinq lignes que dans une chaîne de traitement industrielle ou un pipeline CI. + +Historiquement, la suite est composée de plusieurs binaires distincts, chacun avec son rôle : `convert` pour la conversion, `identify` pour lire les métadonnées, `mogrify` pour le traitement par lot, `composite` pour combiner des images, `montage` pour les planches. C'est l'architecture d'**ImageMagick 6**, la version qui a régné en maître pendant une bonne quinzaine d'années. + +Depuis 2016, **ImageMagick 7** est disponible. Le grand changement, c'est qu'il unifie tout derrière une seule commande : `magick`. Les anciennes commandes deviennent des sous-commandes (`magick convert`, `magick identify`, etc.), même si pour la rétrocompatibilité un binaire `magick` peut continuer à se comporter comme `convert` quand on l'appelle avec une syntaxe d'IM6. + +## Pourquoi le suffixe `-im6` sur Debian + +C'est ici que beaucoup d'articles racontent n'importe quoi. La vraie raison n'a rien à voir avec un conflit avec `util-linux` — je l'ai vérifié, aucun paquet système ne fournit de commande `convert`. Tu peux le vérifier toi-même : `dpkg -S /usr/bin/convert` ne renvoie rien qui vienne de util-linux. + +La vraie raison est plus prosaïque. Pendant des années, Debian a voulu pouvoir **packager IM6 et IM7 en parallèle** dans la même distribution, pour permettre une transition en douceur. Le souci, c'est que les deux versions fournissent des binaires aux mêmes noms (`convert`, `identify`, `mogrify`…) avec des comportements légèrement différents. Impossible de les installer côte à côte sans renommer. + +La solution adoptée par les mainteneurs Debian a été d'ajouter un suffixe explicite au nom de chaque binaire : + +- les outils d'IM6 deviennent `convert-im6.q16`, `identify-im6.q16`, etc. +- les outils d'IM7 deviennent `magick-im7.q16` et compagnie + +Le `.q16` indique la profondeur quantique du binaire (16 bits par canal, la valeur par défaut), et le `-im6` / `-im7` indique la version d'ImageMagick. Les noms classiques (`convert`, `magick`) ne sont alors que des symlinks gérés par `update-alternatives`, qui pointent vers la version active. C'est le même mécanisme que pour `java`, `editor`, ou `python` à une époque. + +## Ce qui change entre Debian 11, 12 et 13 + +C'est l'autre point que la plupart des articles ratent : la situation n'est pas la même selon la version de Debian. + +Sur **Debian 11 (bullseye) et 12 (bookworm)**, le paquet `imagemagick` installe IM6 (version 6.9.11.60). Tu n'as que `convert-im6` et ses copains, et `magick` n'existe pas dans les dépôts officiels (le paquet `imagemagick-7.q16` existe mais n'est pas le défaut). C'est cette situation que décrivent la plupart des tutoriels qui traînent sur le web. + +Sur **Debian 13 (trixie)**, sorti en août 2025, le défaut a basculé sur IM7 (version 7.1.1.43). La commande `magick` est disponible, et `convert` est désormais un symlink vers `magick-im7.q16`. Tu peux le vérifier : + +```bash +$ readlink -f /usr/bin/convert +/usr/bin/magick-im7.q16 +``` + +Autrement dit, sur Trixie, si tu écris `convert image.jpg image.png`, tu appelles en réalité IM7 sous un nom d'IM6. Ça fonctionne pour la plupart des usages, mais attention : IM7 est plus strict sur l'ordre des arguments en ligne de commande (`magick [INPUT-OPTIONS] INPUT [OUTPUT-OPTIONS] OUTPUT`), donc certains scripts anciens peuvent grogner. + +## Correspondance entre les deux versions + +| ImageMagick 6 (Debian 11/12) | ImageMagick 7 (Debian 13) | +| ---------------------------- | ------------------------- | +| `convert-im6` | `magick` | +| `identify-im6` | `magick identify` | +| `mogrify-im6` | `magick mogrify` | +| `composite-im6` | `magick composite` | + +Pour les cas simples, le comportement est identique. Une commande de redimensionnement classique passe sans modification : + +```bash +# Debian 11/12 +convert-im6 photo.jpg -resize 1600x1600 photo_reduite.jpg + +# Debian 13 +magick photo.jpg -resize 1600x1600 photo_reduite.jpg +``` + +## Faut-il s'inquiéter sur un serveur en production ? + +Si tu administres une machine Debian 12 ou plus ancienne, non. IM6 est toujours activement maintenu pour les CVE (les correctifs sont régulièrement backportés dans les paquets stable), et la plupart des scripts existants continueront de fonctionner. Le `-im6` dans le nom du binaire est juste du marquage, pas une dépréciation. + +Si tu migres vers Debian 13, prévois un peu de temps pour relire tes scripts. Les pièges classiques : + +- l'ordre des options qui devient plus strict ; +- quelques comportements de couleur et d'alpha qui ont changé entre les deux versions, notamment sur les opérations chaînées ; +- le fichier `policy.xml` qui a déménagé : `/etc/ImageMagick-6/` devient `/etc/ImageMagick-7/`. Si tu avais assoupli les restrictions sur les PDF ou PostScript (un grand classique), il faut reporter la modification. + +Pour un projet PHP comme les tiens, l'extension Imagick côté PHP est sensible à cette transition : la version compilée doit correspondre à la version d'IM installée, sinon `pecl install imagick` échoue. Sur Trixie, c'est IM7 qu'il faut lier. + +## En pratique + +Sur Debian 11/12, utilise `convert-im6`, `identify-im6`, etc. C'est la convention locale, pas une version dégradée. Si tu veux `magick` malgré tout, tu peux installer le paquet `imagemagick-7.q16` (présent dans les dépôts depuis bookworm) et basculer les alternatives manuellement, mais ce n'est presque jamais nécessaire. + +Sur Debian 13, utilise `magick` directement. La commande `convert` reste disponible par compatibilité, mais elle pointe en réalité vers IM7 — autant utiliser le nom officiel. + +Et dans tous les cas, évite les alias globaux qui réécrivent `convert` : ça finit toujours par mordre quelqu'un, soit toi dans six mois, soit le prochain qui reprendra le serveur. \ No newline at end of file diff --git a/data/11186836-bbac-4054-82db-a3bfed14a274/files/cover.png b/data/11186836-bbac-4054-82db-a3bfed14a274/files/cover.png new file mode 100644 index 0000000..37eeb1d Binary files /dev/null and b/data/11186836-bbac-4054-82db-a3bfed14a274/files/cover.png differ diff --git a/data/11186836-bbac-4054-82db-a3bfed14a274/index.md b/data/11186836-bbac-4054-82db-a3bfed14a274/index.md index ccb70b5..c48d273 100644 --- a/data/11186836-bbac-4054-82db-a3bfed14a274/index.md +++ b/data/11186836-bbac-4054-82db-a3bfed14a274/index.md @@ -1,43 +1,43 @@ -## 1. Présentation générale +## 1. À quoi ça sert -ImageMagick est une suite d’outils en ligne de commande permettant de **créer, convertir, modifier et analyser des images**. -Il supporte plus de 200 formats (JPEG, PNG, WebP, TIFF, PDF, SVG, HEIC, etc.) et fonctionne sans interface graphique, ce qui le rend idéal pour : +ImageMagick, c'est l'outil qu'on sort quand on veut manipuler des images sans ouvrir un logiciel graphique. Pas de Photoshop, pas de GIMP, pas de clic-droit "Redimensionner" sur cent fichiers à la suite : juste une commande dans un terminal, et le travail est fait. -* les serveurs, -* les scripts automatisés, -* les pipelines CI/CD, -* les traitements en masse, -* les environnements sans interface graphique (SSH, Docker, etc.). +C'est une suite d'outils qui sait lire, écrire et transformer plus de 200 formats — du JPEG classique au PDF en passant par le HEIC des iPhones, le WebP de Google ou le bon vieux TIFF des scanners. L'absence d'interface graphique est ici une fonctionnalité, pas un défaut : elle permet de l'utiliser partout où il n'y a pas d'écran, et surtout dans tout ce qui doit tourner tout seul. -Depuis la version 7, la commande principale est `magick`, qui remplace progressivement les anciennes commandes (`convert`, `identify`, `mogrify`, etc.). +On le retrouve donc naturellement : ---- +- sur des serveurs web qui génèrent des miniatures à la volée, +- dans des scripts qui traitent des dossiers entiers d'un coup, +- dans des pipelines CI/CD pour préparer des assets, +- dans des conteneurs Docker, accessibles uniquement en SSH. + +Depuis la version 7, tout passe par une commande unique : `magick`. Les anciennes commandes (`convert`, `identify`, `mogrify`...) existent toujours pour la compatibilité, mais elles ne sont plus la norme. ## 2. Installation -Sous Debian / Ubuntu : +Sur Debian ou Ubuntu : ```bash sudo apt install imagemagick ``` -Vérification : +On vérifie ensuite que tout est en place : ```bash magick -version ``` ---- +La sortie indique aussi les délégués compilés (libwebp, libheif, libraw, etc.). Si un format précis vous intéresse, c'est ici qu'il faut regarder : ImageMagick ne sait lire un format que si la bibliothèque correspondante est présente au moment de la compilation. -## 3. Principe fondamental de fonctionnement +## 3. Comment ImageMagick raisonne -ImageMagick fonctionne selon une logique simple : +Toutes les commandes suivent la même logique : ``` magick [entrée] [options] [sortie] ``` -Chaque option modifie l’image en mémoire, dans l’ordre où elle est écrite. +L'image est chargée en mémoire, puis chaque option s'applique **dans l'ordre où elle est écrite**, comme une chaîne de traitement. Ce point est important : déplacer une option dans la ligne peut changer le résultat final. Exemple : @@ -45,144 +45,134 @@ Exemple : magick input.jpg -resize 800x600 -quality 85 output.jpg ``` -➡️ L’image est chargée → redimensionnée → compressée → enregistrée. +Ici, l'image est lue, redimensionnée à 800×600, puis compressée à 85% de qualité, puis écrite sur le disque. Si on inversait `-quality` et `-resize`, le résultat serait identique dans ce cas précis, mais avec des opérations qui modifient les pixels (flou, conversion d'espace colorimétrique, recadrage), l'ordre devient critique. ---- +## 4. Convertir d'un format à un autre -## 4. Conversion de format - -### Conversion simple +Le cas le plus simple : changer l'extension du fichier de sortie suffit. ```bash magick image.png image.jpg ``` -Cela convertit automatiquement le format selon l’extension du fichier de sortie. +ImageMagick détecte le format cible à partir de l'extension et fait la conversion. C'est aussi simple que ça pour 90% des cas. -### Conversion avec changement de profondeur de couleur +Quand on veut être plus précis — par exemple forcer une profondeur de couleur particulière — on l'indique explicitement : ```bash magick image.png -depth 8 image.jpg ``` -Utile pour réduire la taille ou assurer une compatibilité. +Utile quand on récupère des images en 16 bits par canal qu'on veut ramener à du 8 bits standard, soit pour gagner de la place, soit pour garantir la compatibilité avec un logiciel récalcitrant. ---- +## 5. Redimensionner -## 5. Redimensionnement des images - -### Redimensionnement simple +### La méthode brutale ```bash magick image.jpg -resize 800x600 image_resized.jpg ``` -⚠️ Cela force exactement ces dimensions, quitte à déformer l’image. +Cette commande redimensionne à 800×600 **en respectant les proportions** par défaut, contrairement à ce qu'on pourrait croire. Si l'image source est en 4:3, elle rentrera pile dedans ; si elle est en 16:9, ImageMagick choisira la dimension la plus contraignante et l'autre sera plus petite que demandé. ---- - -### Conserver les proportions (recommandé) +Pour forcer exactement ces dimensions quitte à déformer l'image, il faut ajouter un point d'exclamation : ```bash -magick image.jpg -resize 800x600\> image_resized.jpg +magick image.jpg -resize 800x600! image_resized.jpg ``` -Le `>` signifie : +### Ne rétrécir que les grandes images -> Ne redimensionner que si l’image dépasse ces dimensions. +C'est probablement le cas le plus utile au quotidien : on a un dossier d'images, on veut s'assurer qu'aucune ne dépasse 1600 pixels, mais on ne veut pas agrandir les petites (ce qui dégraderait leur qualité). ---- +```bash +magick image.jpg -resize "1600x1600>" image_resized.jpg +``` -### Redimensionnement par pourcentage +Le `>` signifie « uniquement si l'image est plus grande ». Les guillemets sont nécessaires car `>` est interprété par le shell comme une redirection. On peut aussi échapper le caractère avec `\>`. + +### En pourcentage ```bash magick image.jpg -resize 50% image_small.jpg ``` ---- +Pratique quand on veut diviser la taille par deux sans calculer les dimensions exactes. -## 6. Qualité et compression +## 6. Qualité et poids du fichier -### Réduire la taille du fichier JPEG +Pour les JPEG, le paramètre `-quality` règle le compromis entre fidélité visuelle et poids du fichier : ```bash magick image.jpg -quality 85 image.jpg ``` -* 100 : qualité maximale -* 80–85 : bon compromis web -* <70 : perte visible +Quelques repères en pratique : ---- +- **100** : qualité maximale, fichier énorme, différence imperceptible avec 95. +- **85** : la valeur par défaut de la plupart des appareils photo, et un excellent compromis pour le web. +- **75** : encore très acceptable, gain de place notable. +- **En dessous de 70** : les artefacts deviennent visibles, surtout sur les aplats de couleur. -### Suppression des métadonnées (EXIF, GPS, etc.) +### Supprimer les métadonnées + +Les fichiers issus d'appareils photo ou de smartphones embarquent beaucoup d'informations : modèle de l'appareil, date, parfois coordonnées GPS, miniature intégrée, profil colorimétrique... Tout ça peut peser plusieurs dizaines de kilo-octets, et surtout poser des problèmes de confidentialité. ```bash magick image.jpg -strip image.jpg ``` -Très utile pour : +L'option `-strip` fait le ménage. À utiliser systématiquement avant de publier des photos sur le web, et indispensable dès qu'on parle de RGPD ou d'anonymisation. Attention en revanche pour la photographie professionnelle où certaines métadonnées (droits d'auteur, profil ICC) peuvent être nécessaires. -* anonymisation -* gain de place -* conformité RGPD +## 7. Recadrer et adapter à un cadre ---- - -## 7. Redimensionnement intelligent (crop & resize) - -### Recadrer une image +### Recadrage classique ```bash magick image.jpg -crop 800x600+100+50 output.jpg ``` -Format : +La syntaxe se lit comme une fenêtre qu'on découpe dans l'image : largeur × hauteur, décalée de 100 pixels depuis la gauche et 50 pixels depuis le haut. -``` -largeur x hauteur + décalage_x + décalage_y -``` +### Remplir un cadre exact, sans déformation ---- - -### Remplir un cadre sans déformation +C'est le besoin typique des miniatures de site : on veut toutes les vignettes en 800×600 pile, peu importe le format des photos d'origine. ```bash magick image.jpg -resize 800x600^ -gravity center -extent 800x600 output.jpg ``` -Cela : +Trois étapes enchaînées : -* redimensionne en conservant les proportions -* coupe l’excédent centré +1. `-resize 800x600^` redimensionne pour que l'image **remplisse** le cadre (le `^` inverse la logique habituelle : on prend la plus grande dimension comme contrainte, pas la plus petite). +2. `-gravity center` indique qu'on veut centrer le découpage. +3. `-extent 800x600` coupe ce qui dépasse pour obtenir exactement la taille voulue. -Très utilisé pour les miniatures. +Le résultat : aucune déformation, aucune bande noire, juste un éventuel rognage sur les bords les plus longs. ---- +## 8. Traiter un dossier entier -## 8. Traitement par lot - -### Conversion de tous les fichiers d’un dossier +Une boucle Bash suffit pour convertir tous les PNG d'un dossier en JPEG : ```bash -for f in *.jpg; do - magick "$f" "${f%.jpg}.png" +for f in *.png; do + magick "$f" "${f%.png}.jpg" done ``` -### Redimensionnement massif (avec écrasement) +La syntaxe `${f%.png}` retire l'extension `.png` du nom, on y ajoute `.jpg`. Simple et fiable. + +Pour modifier les fichiers **sur place**, ImageMagick fournit `mogrify` : ```bash -mogrify -resize 1600x1600\> *.jpg +mogrify -resize "1600x1600>" *.jpg ``` -⚠️ `mogrify` modifie les fichiers originaux. +Cette commande écrase chaque fichier par sa version redimensionnée. C'est rapide et pratique, mais ça veut aussi dire qu'**il n'y a pas de retour en arrière** : si la commande est mal écrite, le dossier original est perdu. Règle absolue : travailler sur une copie, ou s'assurer d'avoir une sauvegarde. ---- +## 9. Texte et filigranes -## 9. Ajout de texte et filigranes - -### Ajouter un texte +### Apposer une mention textuelle ```bash magick image.jpg \ @@ -193,83 +183,82 @@ magick image.jpg \ image_marked.jpg ``` -### Ajouter un watermark (image) +`-gravity` ancre le texte dans un coin de l'image (les neuf positions classiques : `northwest`, `north`, `northeast`, `west`, `center`...), et `-annotate` ajoute un décalage par rapport à ce point d'ancrage. Ici, `+10+10` éloigne le texte de 10 pixels du coin inférieur droit. + +### Superposer un logo ou un watermark image ```bash magick image.jpg watermark.png -gravity center -composite output.jpg ``` ---- +L'image principale est lue en premier, le filigrane en second, puis `-composite` les fusionne. Si le watermark a un canal alpha (transparence), il est respecté. -## 10. Gestion des couleurs +## 10. Couleurs et tons -### Convertir en niveaux de gris +Passage en noir et blanc : ```bash magick image.jpg -colorspace Gray output.jpg ``` -### Ajuster luminosité / contraste +Réglage de la luminosité et du contraste (valeurs en pourcentage, positives ou négatives) : ```bash magick image.jpg -brightness-contrast 10x5 output.jpg ``` ---- +Ici, +10% de luminosité et +5% de contraste. Pour assombrir, on utilise des valeurs négatives : `-brightness-contrast -10x0`. -## 11. Informations sur une image +## 11. Inspecter une image -### Détails complets +Pour obtenir les informations essentielles — format, dimensions, profondeur : ```bash magick identify image.jpg ``` -### Informations étendues +Pour tout savoir, y compris les métadonnées EXIF, le profil colorimétrique, l'histogramme : ```bash magick identify -verbose image.jpg ``` ---- +La sortie verbeuse peut faire plusieurs pages, mais c'est inestimable pour diagnostiquer un problème ou comprendre d'où vient un fichier. ## 12. Formats modernes -### Conversion vers WebP +Le WebP de Google offre une compression nettement meilleure que le JPEG à qualité équivalente, et il est aujourd'hui supporté par tous les navigateurs courants : ```bash magick image.jpg -quality 80 image.webp ``` -### Conversion vers AVIF +L'AVIF va encore plus loin en termes de compression, au prix d'un encodage plus lent : ```bash magick image.jpg image.avif ``` ---- +Si la commande échoue avec une erreur de délégué, c'est que votre installation d'ImageMagick a été compilée sans le support AVIF — il faudra installer `libheif` ou recompiler. -## 13. Bonnes pratiques +## 13. Quelques règles à se fixer -* Toujours tester sur une copie -* Éviter `mogrify` sans sauvegarde -* Utiliser `-strip` pour le web -* Privilégier `libvips` pour très gros volumes -* Automatiser via scripts Bash +- **Toujours travailler sur une copie** quand on découvre une nouvelle commande. `mogrify` en particulier ne pardonne pas. +- **Stripper les métadonnées** avant toute publication web. +- **Pour de très gros volumes** (plusieurs milliers d'images, ou des images très lourdes), regarder du côté de `libvips` : c'est plus rapide et beaucoup moins gourmand en mémoire qu'ImageMagick. Pour tout le reste, ImageMagick est largement suffisant. +- **Automatiser dès qu'on répète** : si la même commande revient deux fois, elle mérite un script. +- **Lire les messages d'erreur** : ImageMagick est verbeux, et la plupart des problèmes (délégué manquant, permissions, format non reconnu) sont explicitement nommés dans la sortie. + +## 14. Là où on le croise vraiment + +En pratique, ImageMagick finit presque toujours dans les mêmes situations : + +- préparation d'images pour un site web (redimensionnement + compression + strip), +- génération de miniatures à la volée côté serveur, +- normalisation d'un catalogue photo hétérogène (formats, tailles, profils), +- conversion massive d'archives anciennes vers des formats modernes, +- nettoyage des métadonnées avant diffusion publique. --- -## 14. Cas d’usage typiques - -* Préparation d’images pour un site web -* Génération de miniatures -* Normalisation d’un catalogue photo -* Conversion massive pour archivage -* Nettoyage de métadonnées avant publication - ---- - -ImageMagick est un outil extrêmement puissant, capable de remplacer de nombreux logiciels graphiques lorsqu’on maîtrise sa syntaxe. -Il s’intègre parfaitement dans des scripts, des serveurs et des chaînes de traitement automatisées. - -Pour un usage professionnel ou intensif, c’est un outil incontournable sous Linux. \ No newline at end of file +ImageMagick fait partie de ces outils qu'on apprivoise lentement mais qu'on garde longtemps. Au début, on copie des commandes trouvées en ligne sans tout comprendre. Puis on commence à reconnaître les options, à les combiner, à écrire ses propres scripts. Et un jour, on se rend compte qu'on a remplacé un logiciel entier par trois lignes de Bash — et qu'on n'a jamais été aussi efficace pour traiter des images. \ No newline at end of file diff --git a/data/11186836-bbac-4054-82db-a3bfed14a274/meta.json b/data/11186836-bbac-4054-82db-a3bfed14a274/meta.json index 0ef7cc1..db7f03d 100644 --- a/data/11186836-bbac-4054-82db-a3bfed14a274/meta.json +++ b/data/11186836-bbac-4054-82db-a3bfed14a274/meta.json @@ -1,13 +1,36 @@ { "uuid": "11186836-bbac-4054-82db-a3bfed14a274", - "slug": "imagemagick-le-couteau-suisse-de-la-manipulation-d-images-sous-linux", - "title": "ImageMagick : le couteau suisse de la manipulation d’images sous Linux", + "slug": "imagemagick-traiter-des-images-en-ligne-de-commande", + "title": "ImageMagick : traiter des images en ligne de commande", "author": "cedric@abonnel.fr", "published": true, - "published_at": "2025-12-28 14:56:14", + "published_at": "2025-12-28 14:56", "created_at": "2025-12-28 14:56:14", - "updated_at": "2025-12-28 14:56:14", - "revisions": [], - "cover": "cover.jpg", + "updated_at": "2026-05-12 00:36:01", + "revisions": [ + { + "n": 1, + "date": "2026-05-12 00:33:58", + "comment": "", + "title": "ImageMagick : traiter des images en ligne de commande" + }, + { + "n": 2, + "date": "2026-05-12 00:36:01", + "comment": "", + "title": "ImageMagick : traiter des images en ligne de commande" + } + ], + "cover": "cover.png", + "files_meta": { + "cover.png": { + "author": "", + "source_url": "https://imagemagick.org/image/logo.png" + } + }, + "external_links": [], + "seo_title": "", + "seo_description": "", + "og_image": "", "category": "linux" } diff --git a/data/11186836-bbac-4054-82db-a3bfed14a274/revisions/0001.md b/data/11186836-bbac-4054-82db-a3bfed14a274/revisions/0001.md new file mode 100644 index 0000000..50d4808 --- /dev/null +++ b/data/11186836-bbac-4054-82db-a3bfed14a274/revisions/0001.md @@ -0,0 +1,264 @@ +## 1. À quoi ça sert + +ImageMagick, c'est l'outil qu'on sort quand on veut manipuler des images sans ouvrir un logiciel graphique. Pas de Photoshop, pas de GIMP, pas de clic-droit "Redimensionner" sur cent fichiers à la suite : juste une commande dans un terminal, et le travail est fait. + +C'est une suite d'outils qui sait lire, écrire et transformer plus de 200 formats — du JPEG classique au PDF en passant par le HEIC des iPhones, le WebP de Google ou le bon vieux TIFF des scanners. L'absence d'interface graphique est ici une fonctionnalité, pas un défaut : elle permet de l'utiliser partout où il n'y a pas d'écran, et surtout dans tout ce qui doit tourner tout seul. + +On le retrouve donc naturellement : + +- sur des serveurs web qui génèrent des miniatures à la volée, +- dans des scripts qui traitent des dossiers entiers d'un coup, +- dans des pipelines CI/CD pour préparer des assets, +- dans des conteneurs Docker, accessibles uniquement en SSH. + +Depuis la version 7, tout passe par une commande unique : `magick`. Les anciennes commandes (`convert`, `identify`, `mogrify`...) existent toujours pour la compatibilité, mais elles ne sont plus la norme. + +## 2. Installation + +Sur Debian ou Ubuntu : + +```bash +sudo apt install imagemagick +``` + +On vérifie ensuite que tout est en place : + +```bash +magick -version +``` + +La sortie indique aussi les délégués compilés (libwebp, libheif, libraw, etc.). Si un format précis vous intéresse, c'est ici qu'il faut regarder : ImageMagick ne sait lire un format que si la bibliothèque correspondante est présente au moment de la compilation. + +## 3. Comment ImageMagick raisonne + +Toutes les commandes suivent la même logique : + +``` +magick [entrée] [options] [sortie] +``` + +L'image est chargée en mémoire, puis chaque option s'applique **dans l'ordre où elle est écrite**, comme une chaîne de traitement. Ce point est important : déplacer une option dans la ligne peut changer le résultat final. + +Exemple : + +```bash +magick input.jpg -resize 800x600 -quality 85 output.jpg +``` + +Ici, l'image est lue, redimensionnée à 800×600, puis compressée à 85% de qualité, puis écrite sur le disque. Si on inversait `-quality` et `-resize`, le résultat serait identique dans ce cas précis, mais avec des opérations qui modifient les pixels (flou, conversion d'espace colorimétrique, recadrage), l'ordre devient critique. + +## 4. Convertir d'un format à un autre + +Le cas le plus simple : changer l'extension du fichier de sortie suffit. + +```bash +magick image.png image.jpg +``` + +ImageMagick détecte le format cible à partir de l'extension et fait la conversion. C'est aussi simple que ça pour 90% des cas. + +Quand on veut être plus précis — par exemple forcer une profondeur de couleur particulière — on l'indique explicitement : + +```bash +magick image.png -depth 8 image.jpg +``` + +Utile quand on récupère des images en 16 bits par canal qu'on veut ramener à du 8 bits standard, soit pour gagner de la place, soit pour garantir la compatibilité avec un logiciel récalcitrant. + +## 5. Redimensionner + +### La méthode brutale + +```bash +magick image.jpg -resize 800x600 image_resized.jpg +``` + +Cette commande redimensionne à 800×600 **en respectant les proportions** par défaut, contrairement à ce qu'on pourrait croire. Si l'image source est en 4:3, elle rentrera pile dedans ; si elle est en 16:9, ImageMagick choisira la dimension la plus contraignante et l'autre sera plus petite que demandé. + +Pour forcer exactement ces dimensions quitte à déformer l'image, il faut ajouter un point d'exclamation : + +```bash +magick image.jpg -resize 800x600! image_resized.jpg +``` + +### Ne rétrécir que les grandes images + +C'est probablement le cas le plus utile au quotidien : on a un dossier d'images, on veut s'assurer qu'aucune ne dépasse 1600 pixels, mais on ne veut pas agrandir les petites (ce qui dégraderait leur qualité). + +```bash +magick image.jpg -resize "1600x1600>" image_resized.jpg +``` + +Le `>` signifie « uniquement si l'image est plus grande ». Les guillemets sont nécessaires car `>` est interprété par le shell comme une redirection. On peut aussi échapper le caractère avec `\>`. + +### En pourcentage + +```bash +magick image.jpg -resize 50% image_small.jpg +``` + +Pratique quand on veut diviser la taille par deux sans calculer les dimensions exactes. + +## 6. Qualité et poids du fichier + +Pour les JPEG, le paramètre `-quality` règle le compromis entre fidélité visuelle et poids du fichier : + +```bash +magick image.jpg -quality 85 image.jpg +``` + +Quelques repères en pratique : + +- **100** : qualité maximale, fichier énorme, différence imperceptible avec 95. +- **85** : la valeur par défaut de la plupart des appareils photo, et un excellent compromis pour le web. +- **75** : encore très acceptable, gain de place notable. +- **En dessous de 70** : les artefacts deviennent visibles, surtout sur les aplats de couleur. + +### Supprimer les métadonnées + +Les fichiers issus d'appareils photo ou de smartphones embarquent beaucoup d'informations : modèle de l'appareil, date, parfois coordonnées GPS, miniature intégrée, profil colorimétrique... Tout ça peut peser plusieurs dizaines de kilo-octets, et surtout poser des problèmes de confidentialité. + +```bash +magick image.jpg -strip image.jpg +``` + +L'option `-strip` fait le ménage. À utiliser systématiquement avant de publier des photos sur le web, et indispensable dès qu'on parle de RGPD ou d'anonymisation. Attention en revanche pour la photographie professionnelle où certaines métadonnées (droits d'auteur, profil ICC) peuvent être nécessaires. + +## 7. Recadrer et adapter à un cadre + +### Recadrage classique + +```bash +magick image.jpg -crop 800x600+100+50 output.jpg +``` + +La syntaxe se lit comme une fenêtre qu'on découpe dans l'image : largeur × hauteur, décalée de 100 pixels depuis la gauche et 50 pixels depuis le haut. + +### Remplir un cadre exact, sans déformation + +C'est le besoin typique des miniatures de site : on veut toutes les vignettes en 800×600 pile, peu importe le format des photos d'origine. + +```bash +magick image.jpg -resize 800x600^ -gravity center -extent 800x600 output.jpg +``` + +Trois étapes enchaînées : + +1. `-resize 800x600^` redimensionne pour que l'image **remplisse** le cadre (le `^` inverse la logique habituelle : on prend la plus grande dimension comme contrainte, pas la plus petite). +2. `-gravity center` indique qu'on veut centrer le découpage. +3. `-extent 800x600` coupe ce qui dépasse pour obtenir exactement la taille voulue. + +Le résultat : aucune déformation, aucune bande noire, juste un éventuel rognage sur les bords les plus longs. + +## 8. Traiter un dossier entier + +Une boucle Bash suffit pour convertir tous les PNG d'un dossier en JPEG : + +```bash +for f in *.png; do + magick "$f" "${f%.png}.jpg" +done +``` + +La syntaxe `${f%.png}` retire l'extension `.png` du nom, on y ajoute `.jpg`. Simple et fiable. + +Pour modifier les fichiers **sur place**, ImageMagick fournit `mogrify` : + +```bash +mogrify -resize "1600x1600>" *.jpg +``` + +Cette commande écrase chaque fichier par sa version redimensionnée. C'est rapide et pratique, mais ça veut aussi dire qu'**il n'y a pas de retour en arrière** : si la commande est mal écrite, le dossier original est perdu. Règle absolue : travailler sur une copie, ou s'assurer d'avoir une sauvegarde. + +## 9. Texte et filigranes + +### Apposer une mention textuelle + +```bash +magick image.jpg \ + -gravity southeast \ + -pointsize 24 \ + -fill white \ + -annotate +10+10 "© MonSite" \ + image_marked.jpg +``` + +`-gravity` ancre le texte dans un coin de l'image (les neuf positions classiques : `northwest`, `north`, `northeast`, `west`, `center`...), et `-annotate` ajoute un décalage par rapport à ce point d'ancrage. Ici, `+10+10` éloigne le texte de 10 pixels du coin inférieur droit. + +### Superposer un logo ou un watermark image + +```bash +magick image.jpg watermark.png -gravity center -composite output.jpg +``` + +L'image principale est lue en premier, le filigrane en second, puis `-composite` les fusionne. Si le watermark a un canal alpha (transparence), il est respecté. + +## 10. Couleurs et tons + +Passage en noir et blanc : + +```bash +magick image.jpg -colorspace Gray output.jpg +``` + +Réglage de la luminosité et du contraste (valeurs en pourcentage, positives ou négatives) : + +```bash +magick image.jpg -brightness-contrast 10x5 output.jpg +``` + +Ici, +10% de luminosité et +5% de contraste. Pour assombrir, on utilise des valeurs négatives : `-brightness-contrast -10x0`. + +## 11. Inspecter une image + +Pour obtenir les informations essentielles — format, dimensions, profondeur : + +```bash +magick identify image.jpg +``` + +Pour tout savoir, y compris les métadonnées EXIF, le profil colorimétrique, l'histogramme : + +```bash +magick identify -verbose image.jpg +``` + +La sortie verbeuse peut faire plusieurs pages, mais c'est inestimable pour diagnostiquer un problème ou comprendre d'où vient un fichier. + +## 12. Formats modernes + +Le WebP de Google offre une compression nettement meilleure que le JPEG à qualité équivalente, et il est aujourd'hui supporté par tous les navigateurs courants : + +```bash +magick image.jpg -quality 80 image.webp +``` + +L'AVIF va encore plus loin en termes de compression, au prix d'un encodage plus lent : + +```bash +magick image.jpg image.avif +``` + +Si la commande échoue avec une erreur de délégué, c'est que votre installation d'ImageMagick a été compilée sans le support AVIF — il faudra installer `libheif` ou recompiler. + +## 13. Quelques règles à se fixer + +- **Toujours travailler sur une copie** quand on découvre une nouvelle commande. `mogrify` en particulier ne pardonne pas. +- **Stripper les métadonnées** avant toute publication web. +- **Pour de très gros volumes** (plusieurs milliers d'images, ou des images très lourdes), regarder du côté de `libvips` : c'est plus rapide et beaucoup moins gourmand en mémoire qu'ImageMagick. Pour tout le reste, ImageMagick est largement suffisant. +- **Automatiser dès qu'on répète** : si la même commande revient deux fois, elle mérite un script. +- **Lire les messages d'erreur** : ImageMagick est verbeux, et la plupart des problèmes (délégué manquant, permissions, format non reconnu) sont explicitement nommés dans la sortie. + +## 14. Là où on le croise vraiment + +En pratique, ImageMagick finit presque toujours dans les mêmes situations : + +- préparation d'images pour un site web (redimensionnement + compression + strip), +- génération de miniatures à la volée côté serveur, +- normalisation d'un catalogue photo hétérogène (formats, tailles, profils), +- conversion massive d'archives anciennes vers des formats modernes, +- nettoyage des métadonnées avant diffusion publique. + +--- + +ImageMagick fait partie de ces outils qu'on apprivoise lentement mais qu'on garde longtemps. Au début, on copie des commandes trouvées en ligne sans tout comprendre. Puis on commence à reconnaître les options, à les combiner, à écrire ses propres scripts. Et un jour, on se rend compte qu'on a remplacé un logiciel entier par trois lignes de Bash — et qu'on n'a jamais été aussi efficace pour traiter des images. \ No newline at end of file diff --git a/data/11186836-bbac-4054-82db-a3bfed14a274/revisions/0002.md b/data/11186836-bbac-4054-82db-a3bfed14a274/revisions/0002.md new file mode 100644 index 0000000..c48d273 --- /dev/null +++ b/data/11186836-bbac-4054-82db-a3bfed14a274/revisions/0002.md @@ -0,0 +1,264 @@ +## 1. À quoi ça sert + +ImageMagick, c'est l'outil qu'on sort quand on veut manipuler des images sans ouvrir un logiciel graphique. Pas de Photoshop, pas de GIMP, pas de clic-droit "Redimensionner" sur cent fichiers à la suite : juste une commande dans un terminal, et le travail est fait. + +C'est une suite d'outils qui sait lire, écrire et transformer plus de 200 formats — du JPEG classique au PDF en passant par le HEIC des iPhones, le WebP de Google ou le bon vieux TIFF des scanners. L'absence d'interface graphique est ici une fonctionnalité, pas un défaut : elle permet de l'utiliser partout où il n'y a pas d'écran, et surtout dans tout ce qui doit tourner tout seul. + +On le retrouve donc naturellement : + +- sur des serveurs web qui génèrent des miniatures à la volée, +- dans des scripts qui traitent des dossiers entiers d'un coup, +- dans des pipelines CI/CD pour préparer des assets, +- dans des conteneurs Docker, accessibles uniquement en SSH. + +Depuis la version 7, tout passe par une commande unique : `magick`. Les anciennes commandes (`convert`, `identify`, `mogrify`...) existent toujours pour la compatibilité, mais elles ne sont plus la norme. + +## 2. Installation + +Sur Debian ou Ubuntu : + +```bash +sudo apt install imagemagick +``` + +On vérifie ensuite que tout est en place : + +```bash +magick -version +``` + +La sortie indique aussi les délégués compilés (libwebp, libheif, libraw, etc.). Si un format précis vous intéresse, c'est ici qu'il faut regarder : ImageMagick ne sait lire un format que si la bibliothèque correspondante est présente au moment de la compilation. + +## 3. Comment ImageMagick raisonne + +Toutes les commandes suivent la même logique : + +``` +magick [entrée] [options] [sortie] +``` + +L'image est chargée en mémoire, puis chaque option s'applique **dans l'ordre où elle est écrite**, comme une chaîne de traitement. Ce point est important : déplacer une option dans la ligne peut changer le résultat final. + +Exemple : + +```bash +magick input.jpg -resize 800x600 -quality 85 output.jpg +``` + +Ici, l'image est lue, redimensionnée à 800×600, puis compressée à 85% de qualité, puis écrite sur le disque. Si on inversait `-quality` et `-resize`, le résultat serait identique dans ce cas précis, mais avec des opérations qui modifient les pixels (flou, conversion d'espace colorimétrique, recadrage), l'ordre devient critique. + +## 4. Convertir d'un format à un autre + +Le cas le plus simple : changer l'extension du fichier de sortie suffit. + +```bash +magick image.png image.jpg +``` + +ImageMagick détecte le format cible à partir de l'extension et fait la conversion. C'est aussi simple que ça pour 90% des cas. + +Quand on veut être plus précis — par exemple forcer une profondeur de couleur particulière — on l'indique explicitement : + +```bash +magick image.png -depth 8 image.jpg +``` + +Utile quand on récupère des images en 16 bits par canal qu'on veut ramener à du 8 bits standard, soit pour gagner de la place, soit pour garantir la compatibilité avec un logiciel récalcitrant. + +## 5. Redimensionner + +### La méthode brutale + +```bash +magick image.jpg -resize 800x600 image_resized.jpg +``` + +Cette commande redimensionne à 800×600 **en respectant les proportions** par défaut, contrairement à ce qu'on pourrait croire. Si l'image source est en 4:3, elle rentrera pile dedans ; si elle est en 16:9, ImageMagick choisira la dimension la plus contraignante et l'autre sera plus petite que demandé. + +Pour forcer exactement ces dimensions quitte à déformer l'image, il faut ajouter un point d'exclamation : + +```bash +magick image.jpg -resize 800x600! image_resized.jpg +``` + +### Ne rétrécir que les grandes images + +C'est probablement le cas le plus utile au quotidien : on a un dossier d'images, on veut s'assurer qu'aucune ne dépasse 1600 pixels, mais on ne veut pas agrandir les petites (ce qui dégraderait leur qualité). + +```bash +magick image.jpg -resize "1600x1600>" image_resized.jpg +``` + +Le `>` signifie « uniquement si l'image est plus grande ». Les guillemets sont nécessaires car `>` est interprété par le shell comme une redirection. On peut aussi échapper le caractère avec `\>`. + +### En pourcentage + +```bash +magick image.jpg -resize 50% image_small.jpg +``` + +Pratique quand on veut diviser la taille par deux sans calculer les dimensions exactes. + +## 6. Qualité et poids du fichier + +Pour les JPEG, le paramètre `-quality` règle le compromis entre fidélité visuelle et poids du fichier : + +```bash +magick image.jpg -quality 85 image.jpg +``` + +Quelques repères en pratique : + +- **100** : qualité maximale, fichier énorme, différence imperceptible avec 95. +- **85** : la valeur par défaut de la plupart des appareils photo, et un excellent compromis pour le web. +- **75** : encore très acceptable, gain de place notable. +- **En dessous de 70** : les artefacts deviennent visibles, surtout sur les aplats de couleur. + +### Supprimer les métadonnées + +Les fichiers issus d'appareils photo ou de smartphones embarquent beaucoup d'informations : modèle de l'appareil, date, parfois coordonnées GPS, miniature intégrée, profil colorimétrique... Tout ça peut peser plusieurs dizaines de kilo-octets, et surtout poser des problèmes de confidentialité. + +```bash +magick image.jpg -strip image.jpg +``` + +L'option `-strip` fait le ménage. À utiliser systématiquement avant de publier des photos sur le web, et indispensable dès qu'on parle de RGPD ou d'anonymisation. Attention en revanche pour la photographie professionnelle où certaines métadonnées (droits d'auteur, profil ICC) peuvent être nécessaires. + +## 7. Recadrer et adapter à un cadre + +### Recadrage classique + +```bash +magick image.jpg -crop 800x600+100+50 output.jpg +``` + +La syntaxe se lit comme une fenêtre qu'on découpe dans l'image : largeur × hauteur, décalée de 100 pixels depuis la gauche et 50 pixels depuis le haut. + +### Remplir un cadre exact, sans déformation + +C'est le besoin typique des miniatures de site : on veut toutes les vignettes en 800×600 pile, peu importe le format des photos d'origine. + +```bash +magick image.jpg -resize 800x600^ -gravity center -extent 800x600 output.jpg +``` + +Trois étapes enchaînées : + +1. `-resize 800x600^` redimensionne pour que l'image **remplisse** le cadre (le `^` inverse la logique habituelle : on prend la plus grande dimension comme contrainte, pas la plus petite). +2. `-gravity center` indique qu'on veut centrer le découpage. +3. `-extent 800x600` coupe ce qui dépasse pour obtenir exactement la taille voulue. + +Le résultat : aucune déformation, aucune bande noire, juste un éventuel rognage sur les bords les plus longs. + +## 8. Traiter un dossier entier + +Une boucle Bash suffit pour convertir tous les PNG d'un dossier en JPEG : + +```bash +for f in *.png; do + magick "$f" "${f%.png}.jpg" +done +``` + +La syntaxe `${f%.png}` retire l'extension `.png` du nom, on y ajoute `.jpg`. Simple et fiable. + +Pour modifier les fichiers **sur place**, ImageMagick fournit `mogrify` : + +```bash +mogrify -resize "1600x1600>" *.jpg +``` + +Cette commande écrase chaque fichier par sa version redimensionnée. C'est rapide et pratique, mais ça veut aussi dire qu'**il n'y a pas de retour en arrière** : si la commande est mal écrite, le dossier original est perdu. Règle absolue : travailler sur une copie, ou s'assurer d'avoir une sauvegarde. + +## 9. Texte et filigranes + +### Apposer une mention textuelle + +```bash +magick image.jpg \ + -gravity southeast \ + -pointsize 24 \ + -fill white \ + -annotate +10+10 "© MonSite" \ + image_marked.jpg +``` + +`-gravity` ancre le texte dans un coin de l'image (les neuf positions classiques : `northwest`, `north`, `northeast`, `west`, `center`...), et `-annotate` ajoute un décalage par rapport à ce point d'ancrage. Ici, `+10+10` éloigne le texte de 10 pixels du coin inférieur droit. + +### Superposer un logo ou un watermark image + +```bash +magick image.jpg watermark.png -gravity center -composite output.jpg +``` + +L'image principale est lue en premier, le filigrane en second, puis `-composite` les fusionne. Si le watermark a un canal alpha (transparence), il est respecté. + +## 10. Couleurs et tons + +Passage en noir et blanc : + +```bash +magick image.jpg -colorspace Gray output.jpg +``` + +Réglage de la luminosité et du contraste (valeurs en pourcentage, positives ou négatives) : + +```bash +magick image.jpg -brightness-contrast 10x5 output.jpg +``` + +Ici, +10% de luminosité et +5% de contraste. Pour assombrir, on utilise des valeurs négatives : `-brightness-contrast -10x0`. + +## 11. Inspecter une image + +Pour obtenir les informations essentielles — format, dimensions, profondeur : + +```bash +magick identify image.jpg +``` + +Pour tout savoir, y compris les métadonnées EXIF, le profil colorimétrique, l'histogramme : + +```bash +magick identify -verbose image.jpg +``` + +La sortie verbeuse peut faire plusieurs pages, mais c'est inestimable pour diagnostiquer un problème ou comprendre d'où vient un fichier. + +## 12. Formats modernes + +Le WebP de Google offre une compression nettement meilleure que le JPEG à qualité équivalente, et il est aujourd'hui supporté par tous les navigateurs courants : + +```bash +magick image.jpg -quality 80 image.webp +``` + +L'AVIF va encore plus loin en termes de compression, au prix d'un encodage plus lent : + +```bash +magick image.jpg image.avif +``` + +Si la commande échoue avec une erreur de délégué, c'est que votre installation d'ImageMagick a été compilée sans le support AVIF — il faudra installer `libheif` ou recompiler. + +## 13. Quelques règles à se fixer + +- **Toujours travailler sur une copie** quand on découvre une nouvelle commande. `mogrify` en particulier ne pardonne pas. +- **Stripper les métadonnées** avant toute publication web. +- **Pour de très gros volumes** (plusieurs milliers d'images, ou des images très lourdes), regarder du côté de `libvips` : c'est plus rapide et beaucoup moins gourmand en mémoire qu'ImageMagick. Pour tout le reste, ImageMagick est largement suffisant. +- **Automatiser dès qu'on répète** : si la même commande revient deux fois, elle mérite un script. +- **Lire les messages d'erreur** : ImageMagick est verbeux, et la plupart des problèmes (délégué manquant, permissions, format non reconnu) sont explicitement nommés dans la sortie. + +## 14. Là où on le croise vraiment + +En pratique, ImageMagick finit presque toujours dans les mêmes situations : + +- préparation d'images pour un site web (redimensionnement + compression + strip), +- génération de miniatures à la volée côté serveur, +- normalisation d'un catalogue photo hétérogène (formats, tailles, profils), +- conversion massive d'archives anciennes vers des formats modernes, +- nettoyage des métadonnées avant diffusion publique. + +--- + +ImageMagick fait partie de ces outils qu'on apprivoise lentement mais qu'on garde longtemps. Au début, on copie des commandes trouvées en ligne sans tout comprendre. Puis on commence à reconnaître les options, à les combiner, à écrire ses propres scripts. Et un jour, on se rend compte qu'on a remplacé un logiciel entier par trois lignes de Bash — et qu'on n'a jamais été aussi efficace pour traiter des images. \ No newline at end of file diff --git a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/_thumb_945482b26e8a76ab-49498.png b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/_thumb_945482b26e8a76ab-49498.png new file mode 100644 index 0000000..dcdffa3 Binary files /dev/null and b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/_thumb_945482b26e8a76ab-49498.png differ diff --git a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/_thumb_a1080cd703289e6b-144512.png b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/_thumb_a1080cd703289e6b-144512.png new file mode 100644 index 0000000..b4d0890 Binary files /dev/null and b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/_thumb_a1080cd703289e6b-144512.png differ diff --git a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/_thumb_cae639a42d79414f-68314.jpg b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/_thumb_cae639a42d79414f-68314.jpg new file mode 100644 index 0000000..72ed808 Binary files /dev/null and b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/_thumb_cae639a42d79414f-68314.jpg differ diff --git a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/_thumb_dc5413a86e9c042a-22419.jpg b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/_thumb_dc5413a86e9c042a-22419.jpg new file mode 100644 index 0000000..38ed16a Binary files /dev/null and b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/_thumb_dc5413a86e9c042a-22419.jpg differ diff --git a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/cover.jpg b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/cover.jpg new file mode 100644 index 0000000..3c9539c Binary files /dev/null and b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/files/cover.jpg differ diff --git a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/index.md b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/index.md index b2c84ad..fa2609e 100644 --- a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/index.md +++ b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/index.md @@ -1,204 +1,87 @@ -## Comment les réseaux mobiles évitent la saturation +Un attentat, un séisme, un match du Stade de France, une grande panne d'électricité. Dans ces moments-là, des centaines de milliers de gens dégainent leur téléphone au même instant. Le réseau mobile est dimensionné pour un usage moyen, pas pour un pic massif simultané, et il devrait théoriquement s'effondrer. La plupart du temps, il tient. Pas parfaitement, pas pour tout le monde, mais il tient — et surtout, les appels d'urgence continuent de passer. C'est le résultat d'une série de mécanismes empilés depuis les années 1990, que la 4G a affinés et que la 5G a élargis. Cet article les passe en revue, et termine sur une question qu'on me pose souvent : est-ce que mon forfait à 50 € me donne une place prioritaire dans cette file d'attente ? -Quand beaucoup de personnes utilisent leur téléphone en même temps (catastrophe, événement sportif, panne électrique, etc.), le réseau mobile peut rapidement être saturé. -Depuis la 2G, les opérateurs ont mis en place des mécanismes pour : +## Trois questions, pas une -* éviter l’effondrement total du réseau, -* garantir l’accès aux **services essentiels**, -* maintenir les **communications d’urgence**. +Quand une cellule commence à chauffer, l'opérateur doit répondre à trois questions distinctes. Qui a le droit de se connecter ? Une fois connecté, qui passe en premier ? Et quels services doivent absolument continuer à fonctionner, quoi qu'il arrive ? -En 4G et en 5G, ces mécanismes existent toujours, mais sous des formes **beaucoup plus sophistiquées**. +La 2G ne savait répondre qu'à la première. Elle filtrait à l'entrée et basta. La 4G a ajouté la deuxième : une fois admis sur le réseau, votre trafic est traité différemment selon son importance. La 5G ajoute la troisième : elle peut créer des réseaux virtuels parallèles dont certains sont réservés à des usages critiques, totalement isolés des autres. + +## Le filtrage à l'entrée + +Chaque carte SIM porte un numéro de classe d'accès, hérité du GSM, entre 0 et 15. Les classes 0 à 9 couvrent le grand public — autrement dit nous tous. Les classes 11 à 15 sont réservées : services de secours, autorités publiques, personnel opérateur, usages militaires selon les pays. + +Quand une cellule est surchargée, l'eNodeB (la station de base 4G) diffuse une consigne aux téléphones du secteur : « les classes 0 à 9, vous attendez ». C'est l'**Access Class Barring**. Concrètement, votre téléphone reçoit ce message et bloque lui-même votre tentative d'appel ou de connexion data, sans même envoyer la demande à la station. C'est élégant parce que ça soulage la station avant même qu'elle ne soit sollicitée. Les classes prioritaires, elles, passent sans encombre. + +Une variante plus dure, l'**Extended Access Barring**, vise les objets connectés et les usages non urgents. Quand une vraie crise se déclare, l'opérateur peut couper les compteurs intelligents, les alarmes domestiques et autres équipements bavards pour préserver la bande passante humaine. + +En 5G, ce mécanisme a été refondu sous le nom d'**UAC** — *Unified Access Control*, introduit dans la Release 15 du 3GPP. UAC unifie dans un seul cadre ce qui était auparavant éparpillé entre ACB, EAB et d'autres dispositifs spécifiques. Il repose sur deux notions complémentaires. Les *Access Identities* identifient qui vous êtes : utilisateur lambda, abonné à un service prioritaire type MPS ou MCS, personnel d'urgence, agent opérateur. Les *Access Categories* identifient ce que vous essayez de faire : appel d'urgence, connexion data normale, SMS, mise à jour de localisation. La combinaison des deux détermine si votre demande passe ou pas. La granularité gagnée par rapport à la 4G est réelle : on peut bloquer un type d'action précis pour un type d'utilisateur précis, par exemple « les abonnés grand public ne peuvent plus initier de nouveaux appels data, mais les SMS et les appels voix continuent ». + +## La priorité une fois connecté + +Là où la 4G a vraiment innové, c'est en introduisant le **QCI** — *QoS Class Identifier*. Chaque flux de données qui transite sur le réseau se voit attribuer un numéro entre 1 et 9 (avec quelques valeurs supplémentaires pour des cas spéciaux) qui dit à l'infrastructure comment le traiter. + +| Usage | QCI | Traitement | +|---|---|---| +| Appel VoLTE (voix sur LTE) | 1 | Latence minimale, débit garanti | +| Visioconférence | 2 | Débit garanti | +| Signalisation réseau | 5 | Très haute priorité | +| Streaming vidéo | 6 ou 8 | Best effort prioritaire | +| Web et internet général | 9 | Best effort standard | + +Quand la cellule est encombrée, le routeur sait quoi sacrifier en premier. YouTube va ralentir, les pages web vont mettre du temps à charger, mais l'appel téléphonique de votre voisin reste audible. C'est un compromis assumé : on dégrade volontairement les usages secondaires pour préserver les usages critiques. + +La 5G a transposé ce mécanisme sous le nom de **5QI** (*5G QoS Identifier*) avec davantage de niveaux et une meilleure prise en compte des cas que la 4G gérait mal — notamment les services à très basse latence pour les usines connectées ou la voiture autonome. La voix d'urgence garde son sommet, les données critiques industrielles s'intercalent juste après, le streaming et le web restent en bas de la pile. + +## L'isolation par tranches : le network slicing + +C'est l'apport majeur de la 5G en matière de gestion de crise. Au lieu de partager une seule infrastructure entre tous les usages, on peut maintenant la découper logiciellement en tranches — des *slices* — qui se comportent comme autant de réseaux indépendants, alors qu'ils tournent sur les mêmes antennes et les mêmes câbles. + +Un opérateur peut par exemple maintenir une tranche pour le grand public avec ses millions d'abonnés et son trafic massif, une autre pour les services d'urgence dimensionnée pour rester fluide même quand le reste sature, une troisième pour les objets connectés industriels avec des garanties de latence, et une quatrième pour des opérateurs critiques type SNCF, EDF ou hôpitaux. Chaque tranche a ses propres règles d'admission, ses propres priorités, ses propres garanties de performance. Si la tranche grand public est totalement saturée, celle des secours ne le sait même pas. + +Cette isolation est ce qui distingue le plus fondamentalement la 5G des générations précédentes. Avant, tout le monde se battait pour les mêmes ressources, avec juste des priorités différentes pour départager. Maintenant, certaines ressources sont retirées du combat dès le départ. + +## Récapitulatif + +| Génération | Ce qui est contrôlé | Comment | +|---|---|---| +| 2G | L'accès au réseau | Classes d'accès 0-15 | +| 4G | L'accès + la priorité du trafic | ACB / EAB + QCI | +| 5G | L'accès + la priorité + l'isolation des services | UAC + 5QI + network slicing | + +Tous ces mécanismes restent invisibles tant que tout va bien. Vous ne savez pas qu'ils existent. Vous découvrez leur existence le jour où votre voisin n'arrive plus à charger ses mails alors que les pompiers, eux, continuent de communiquer normalement. Ce jour-là, ce n'est pas de la magie. C'est trente ans d'ingénierie radio qui ont anticipé que ça arriverait. --- -# 1. Le principe général +## Et mon forfait premium, alors ? -Dans un réseau moderne, il y a **trois niveaux de contrôle** : +Question logique à ce stade. Si le réseau sait techniquement prioriser certains flux par rapport à d'autres, qu'est-ce qui empêche un opérateur de faire passer ses abonnés à 50 € devant ceux à 10 € quand les antennes saturent ? La réponse honnête commence par un aveu : techniquement, rien. L'outil existe, il s'appelle **Quality of Service** (QoS), c'est exactement le mécanisme qu'on vient de décrire. Si demain Orange ou SFR voulaient créer une voie rapide pour leurs abonnés haut de gamme, ils auraient les outils dans la boîte. Pourtant, ils ne le font pas. Pour quatre raisons. -1. **Qui a le droit d’entrer sur le réseau ?** -2. **Qui est prioritaire une fois connecté ?** -3. **Quels services doivent absolument continuer à fonctionner ?** +### La loi européenne l'interdit -La 2G répondait surtout à la première question. -La 4G et la 5G répondent **aux trois**. +Le règlement **(UE) 2015/2120**, dit « règlement internet ouvert », oblige les opérateurs à traiter tout le trafic de la même façon, sans discrimination liée à l'expéditeur, au destinataire, au contenu ou à l'application. Il a fêté ses dix ans en novembre 2025, et l'ARCEP a profité de l'anniversaire pour rappeler que c'est l'un des piliers du modèle numérique européen. Les sanctions sont sérieuses : jusqu'à **3 % du chiffre d'affaires** de l'opérateur fautif. Un opérateur français qui annoncerait demain « avec notre forfait Premium, vous passez devant les autres » se retrouverait devant l'ARCEP dans la semaine. ---- +Le règlement laisse quelques portes ouvertes pour les services dits « spécialisés » qui ont besoin d'une qualité garantie — téléchirurgie, voiture connectée. Mais ces exceptions sont étroitement encadrées et ne couvrent absolument pas le confort d'un client haut de gamme qui voudrait charger son Instagram plus vite à 19h. -# 2. En 4G (LTE) +Aux États-Unis, l'histoire est différente. La FCC a tenté de restaurer la neutralité du net en 2024, mais en janvier 2025 la cour d'appel du sixième circuit a invalidé la décision, jugeant que la FCC n'avait pas l'autorité légale pour reclasser le haut débit comme service public. Avec l'arrivée de Brendan Carr à la tête de la FCC, ouvertement opposé à la neutralité du net, il n'y a aujourd'hui plus de règle fédérale outre-Atlantique. Quelques États (Californie, Washington, New York, Oregon) ont leurs propres lois qui maintiennent le principe, mais à l'échelle du pays, les opérateurs américains pourraient légalement faire ce que leurs homologues européens n'ont pas le droit de faire. Pourtant, ils ne le font pas ouvertement non plus, et la raison renvoie aux trois points suivants. -## 2.1 Contrôle d’accès : Access Class Barring +### C'est commercialement intenable -Chaque carte SIM contient toujours une **classe d’accès** (0 à 15). +Imagine la publicité : « Forfait Premium à 50 € — passez devant les pauvres pendant les heures de pointe ». Le slogan ne se vend pas. Les directions marketing savent que dire à la moitié de leurs clients qu'ils sont des citoyens de seconde zone du réseau est le plus court chemin vers une crise de réputation. C'est pour ça qu'on vous vend « plus de Go », « 5G ultra rapide », « roaming inclus dans 110 pays » — des promesses qui sonnent positivement sans jamais dire à personne qu'il est désavantagé. -* Classes **0 à 9** : grand public -* Classes **11 à 15** : sécurité, urgence, opérateur, etc. +### L'effet boule de neige serait toxique -En cas de surcharge, le réseau peut activer l’**Access Class Barring** : +Imagine que ça se mette quand même en place. Les riches passent devant. Les antennes restent saturées pour les autres, qui se mettent à payer plus pour échapper à la saturation, ce qui sature encore plus les bas forfaits, ce qui pousse encore plus de gens à monter en gamme. Au bout de cinq ans, on a un réseau à deux vitesses où les forfaits modestes deviennent quasi inutilisables aux heures critiques, et où la connexion mobile correcte devient un service de luxe. Ce n'est plus un service de télécommunications, c'est un système de classes. -* certaines classes sont **bloquées temporairement**, -* les classes prioritaires restent **autorisées**. +C'est exactement ce que la neutralité du net cherche à empêcher. Pas par idéologie, mais parce qu'on a déjà vu où mène ce genre de spirale dans les pays où elle n'est pas protégée. Certains opérateurs proposent par exemple des forfaits où Facebook et WhatsApp sont gratuits mais où le reste est payant, ce qui revient à dire que le bon internet est celui que l'opérateur a choisi pour vous. Ce n'est plus tout à fait le même service. -👉 C’est l’héritier direct des classes GSM. +### Ça ne résoudrait rien ---- +Quand un réseau sature, ce n'est pas un problème de répartition entre utilisateurs, c'est un problème de **capacité totale**. Faire passer Pierre avant Paul ne crée pas un seul bit de bande passante supplémentaire. Ça déplace juste le problème de l'un vers l'autre. La vraie solution, quand une cellule sature trop souvent, c'est d'installer plus d'antennes, de densifier le réseau, de basculer sur une fréquence plus performante ou de passer à la génération suivante. C'est cher, c'est long, ça implique des autorisations administratives et des négociations foncières, mais c'est la seule réponse qui tient la route. Prioriser, c'est rapide, mais ça repousse le mur, ça ne le déplace pas. -## 2.2 Priorité une fois connecté : la QoS +C'est comme si on proposait une voie réservée aux Mercedes sur l'A7 un samedi de chassé-croisé. Techniquement, on peut peindre la ligne au sol et installer les panneaux dans la matinée. Mais cette voie ne réduit pas le bouchon, elle le concentre sur les voies restantes ; elle écorne le principe d'égalité d'accès à l'infrastructure publique ; et elle ne change rien au problème de fond, qui est qu'il y a trop de voitures pour la route disponible. La vraie solution reste la même qu'avant : élargir l'autoroute, ou convaincre une partie des gens de prendre le train. -En 4G, être connecté ne suffit pas. -Chaque communication reçoit un **niveau de qualité de service** appelé **QCI** (*QoS Class Identifier*). +### Le caveat 5G -On peut comparer cela à des **voies de circulation** : +Une nuance honnête pour finir. Le *network slicing* complique le débat juridique. Un opérateur peut créer des tranches de réseau avec des qualités différenciées en toute légalité quand il s'agit d'usages spécialisés — santé, industrie, transports. La question qui agite régulateurs et juristes depuis plusieurs années est de savoir où finit le service spécialisé légitime et où commence le contournement déguisé de la neutralité du net. L'ARCEP a ouvert ce chantier, et c'est probablement là, plus que dans une revanche commerciale brutale sur les forfaits premium, que se jouera la prochaine bataille. -* autoroute prioritaire pour les urgences, -* route normale pour le trafic courant. - -### Exemples simples - -| Usage | QCI | Priorité | -| ------------------------- | --- | ---------- | -| Appels VoLTE | 1 | Très haute | -| Signalisation réseau | 5 | Haute | -| Internet mobile classique | 9 | Normale | - -Résultat : - -* même si la data ralentit, -* les **appels d’urgence** et la **signalisation** passent toujours en premier. - ---- - -## 2.3 Ce que la 4G a changé - -Par rapport au GSM : - -* on ne gère plus seulement **l’accès**, -* on gère aussi **la qualité et la priorité du trafic**. - -Le réseau peut : - -* ralentir YouTube, -* mais maintenir la voix et les appels critiques. - ---- - -# 3. En 5G - -La 5G reprend tout ce qui existe en 4G **et ajoute une couche stratégique**. - ---- - -## 3.1 Contrôle d’accès : toujours présent - -On retrouve : - -* Access Class Barring, -* Extended Access Barring pour les situations de crise. - -Les classes prioritaires (secours, autorités, opérateurs) conservent leur accès même quand le réseau est saturé. - ---- - -## 3.2 Priorité du trafic : 5QI - -Le QCI devient **5QI** (*5G QoS Identifier*). - -Même principe, mais plus précis : - -* plus de niveaux, -* meilleure adaptation au service. - -### Exemples - -| Service | 5QI | Objectif | -| ----------------- | --- | ---------------- | -| Voix d’urgence | 1 | Latence minimale | -| Données critiques | 7 | Fiabilité élevée | -| Internet standard | 9 | Best effort | - ---- - -## 3.3 La grande nouveauté : le Network Slicing - -La 5G introduit un concept clé : **le découpage du réseau en tranches logiques**. - -On peut comparer cela à plusieurs **réseaux virtuels** sur une même infrastructure physique. - -### Exemples de slices - -* Slice **grand public** -* Slice **services d’urgence** -* Slice **transports / énergie** -* Slice **objets connectés** - -Chaque slice a : - -* ses propres règles de priorité, -* ses propres garanties de performance, -* son propre contrôle d’accès. - -👉 Si le slice grand public est saturé, -le slice des secours **continue de fonctionner normalement**. - ---- - -# 4. Ce que cela change concrètement - -## En situation normale - -Tout le monde accède au réseau sans différence visible. - -## En situation de crise - -Le réseau applique automatiquement : - -1. **Filtrage à l’entrée** - - * certaines cartes SIM peuvent être temporairement bloquées. -2. **Priorité du trafic** - - * appels et services critiques passent avant le reste. -3. **Isolation par slices (5G)** - - * les services vitaux sont protégés de la saturation générale. - ---- - -# 5. Et les forfaits dans tout ça ? - -Une question fréquente : - -> Les forfaits “premium”, “illimités” donnent-ils une priorité réseau ? - -**Réponse : non.** - -Les priorités techniques ne dépendent **pas** : - -* du prix du forfait, -* des options commerciales. - -Elles dépendent uniquement : - -* du **profil réseau** associé à la SIM, -* du **statut de l’utilisateur** (grand public, sécurité, opérateur, urgence), -* des **politiques de gestion de crise** de l’opérateur. - -Un abonné classique, même avec un forfait haut de gamme, reste dans une **classe standard**. - ---- - -# 6. Comparaison simple - -| Génération | Ce qui est contrôlé | Comment | -| ---------- | ---------------------------- | ------------------- | -| **2G** | Accès au réseau | Classes d’accès | -| **4G** | Accès + priorité trafic | ACB + QCI | -| **5G** | Accès + priorité + isolation | ACB + 5QI + slicing | - ---- - -# 7. En résumé - -* Les **classes d’accès** du GSM existent toujours en 4G et 5G sous forme modernisée. -* La **4G** ajoute la gestion fine de la priorité du trafic. -* La **5G** va plus loin avec le **network slicing**, qui permet de garantir des réseaux quasi indépendants pour les services essentiels. -* Les **forfaits commerciaux** n’influencent pas ces mécanismes : seule la **politique réseau** de l’opérateur compte. +Mais pour répondre simplement à la question : non, votre forfait à 50 € ne vous donne pas la priorité réseau sur celui de votre voisin à 10 €. Il vous donne plus de data, parfois un meilleur débit théorique, des options en plus. Pas une place dans la file. \ No newline at end of file diff --git a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/meta.json b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/meta.json index 003f7a7..c3e9f8f 100644 --- a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/meta.json +++ b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/meta.json @@ -1,13 +1,162 @@ { "uuid": "4f443bcb-b0d4-47f8-837d-61627e6c94f2", "slug": "priorites-et-acces-au-reseau-en-4g-et-5g", - "title": "Priorités et accès au réseau en 4G et 5G", + "title": "Pourquoi le réseau mobile ne s'effondre pas le jour où tout le monde téléphone en même temps", "author": "cedric@abonnel.fr", "published": true, - "published_at": "2026-01-06 22:21:04", + "published_at": "2026-01-06 22:21", "created_at": "2026-01-06 22:21:04", - "updated_at": "2026-01-06 22:21:04", - "revisions": [], + "updated_at": "2026-05-11 23:40:18", + "revisions": [ + { + "n": 1, + "date": "2026-05-11 23:06:50", + "comment": "", + "title": "Comment les réseaux mobiles tiennent debout quand tout le monde téléphone en même temps" + }, + { + "n": 2, + "date": "2026-05-11 23:09:07", + "comment": "", + "title": "Comment les réseaux mobiles tiennent debout quand tout le monde téléphone en même temps" + }, + { + "n": 3, + "date": "2026-05-11 23:11:33", + "comment": "", + "title": "Comment les réseaux mobiles tiennent debout quand tout le monde téléphone en même temps" + }, + { + "n": 4, + "date": "2026-05-11 23:14:26", + "comment": "", + "title": "Comment les réseaux mobiles tiennent debout quand tout le monde téléphone en même temps" + }, + { + "n": 5, + "date": "2026-05-11 23:16:33", + "comment": "", + "title": "Comment les réseaux mobiles tiennent debout quand tout le monde téléphone en même temps" + }, + { + "n": 6, + "date": "2026-05-11 23:16:56", + "comment": "", + "title": "Comment les réseaux mobiles tiennent debout quand tout le monde téléphone en même temps" + }, + { + "n": 7, + "date": "2026-05-11 23:40:18", + "comment": "", + "title": "Pourquoi le réseau mobile ne s'effondre pas le jour où tout le monde téléphone en même temps" + } + ], "cover": "cover.jpg", + "files_meta": { + "_preview.png": { + "author": "", + "source_url": "" + }, + "_thumb_dc5413a86e9c042a-22419.jpg": { + "author": "", + "source_url": "" + }, + "_thumb_945482b26e8a76ab-49498.png": { + "author": "", + "source_url": "" + }, + "_thumb_a1080cd703289e6b-144512.png": { + "author": "", + "source_url": "" + }, + "_thumb_cae639a42d79414f-68314.jpg": { + "author": "", + "source_url": "" + }, + "03bcf841dafcc9f4-87771.jpg": { + "author": "", + "source_url": "https://www.ariase.com/uploads/media/124b4e1790cf20b8fed653884ef1eb46d235922f.jpeg" + }, + "cover.jpg": { + "author": "", + "source_url": "" + } + }, + "external_links": [ + { + "url": "https://arxiv.org/pdf/2012.05520", + "name": "An Overview of 5G System Accessibility Differentiation and Control", + "added_at": "2026-05-11 23:04:53", + "author": "-", + "meta": { + "mime": "application/pdf", + "size": 717772, + "description": "IEEE Transactions on Magnetics", + "date": "2021-09-28 10:31:29+02:00", + "subject": "IEEE Transactions on Magnetics", + "creator": "-", + "producer": "Microsoft® Word for Microsoft 365", + "pages": 9, + "pdf_version": "PDF 1.7", + "page_size": "Letter (216×279 mm)" + } + }, + { + "url": "https://www.techplayon.com/5g-nr-cell-access-control/", + "name": "5G NR Cell Access Control - Techplayon - RRC Signalling", + "added_at": "2026-05-11 23:05:34", + "author": "Author", + "meta": { + "mime": "text/html", + "size": 79963, + "description": "Access Control barring refers to a traffic congestion control mechanism to secure and ensure the success of critical communications", + "og_image": "/file?uuid=4f443bcb-b0d4-47f8-837d-61627e6c94f2&name=_thumb_dc5413a86e9c042a-22419.jpg", + "site_name": "Techplayon", + "og_type": "article", + "language": "en_US", + "date": "2019-12-21T17:44:54+00:00", + "canonical": "https://www.techplayon.com/5g-nr-cell-access-control/" + } + }, + { + "url": "https://simnovus.com/unified-access-control-uac-the-gatekeeper-of-5g-networks/", + "name": "Unified Access Control (UAC): The Gatekeeper of 5G Networks - Simnovus", + "added_at": "2026-05-11 23:11:58", + "meta": { + "mime": "text/html", + "size": 124603, + "description": "Unified Access Control (UAC) is a fundamental component of 5G networks that governs access to network resources. It replaces the traditional access control", + "og_image": "/file?uuid=4f443bcb-b0d4-47f8-837d-61627e6c94f2&name=_thumb_cae639a42d79414f-68314.jpg", + "site_name": "Simnovus", + "og_type": "article", + "language": "en_US", + "date": "2024-08-14T10:58:09+05:30", + "canonical": "https://simnovus.com/unified-access-control-uac-the-gatekeeper-of-5g-networks/" + } + }, + { + "url": "https://www.sharetechnote.com/html/5G/5G_UAC.html", + "name": "5G | ShareTechnote", + "added_at": "2026-05-11 23:12:20", + "meta": { + "mime": "text/html", + "size": 28707, + "og_image": "/file?uuid=4f443bcb-b0d4-47f8-837d-61627e6c94f2&name=_thumb_a1080cd703289e6b-144512.png" + } + }, + { + "url": "https://www.telecomgurukul.com/post/advanced-access-control-mechanisms-in-lte-and-5g-nr-networks", + "name": "Advanced Access Control Mechanisms in LTE and 5G NR Networks", + "added_at": "2026-05-11 23:14:17", + "meta": { + "mime": "text/html", + "size": 1344890, + "og_image": "/file?uuid=4f443bcb-b0d4-47f8-837d-61627e6c94f2&name=_thumb_945482b26e8a76ab-49498.png" + } + } + ], + "seo_title": "", + "seo_description": "", + "og_image": "", "category": "télécom" } diff --git a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0001.md b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0001.md new file mode 100644 index 0000000..3c19ca1 --- /dev/null +++ b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0001.md @@ -0,0 +1,80 @@ +Un attentat, un séisme, un match du Stade de France, une grande panne d'électricité. Dans ces moments-là, des centaines de milliers de gens dégainent leur téléphone en même temps. Le réseau mobile, qui est dimensionné pour un usage moyen et pas pour un pic massif simultané, devrait théoriquement s'effondrer. La plupart du temps, il tient. Pas parfaitement, pas pour tout le monde, mais il tient — et surtout, les appels d'urgence continuent de passer. C'est le résultat d'une série de mécanismes empilés depuis les années 1990, et que la 4G et la 5G ont raffinés. Voici comment ça marche, sans le jargon mais sans non plus mentir sur ce qui se passe vraiment. + +## Trois questions, pas une + +Dans un réseau cellulaire moderne, l'opérateur doit répondre à trois questions distinctes quand la cellule commence à chauffer. Qui a le droit de se connecter ? Une fois connecté, qui passe en premier ? Et quels services doivent absolument continuer à fonctionner, quoi qu'il arrive ? + +La 2G ne savait répondre qu'à la première. Elle filtrait à l'entrée et basta. La 4G a ajouté la deuxième : une fois admis sur le réseau, votre trafic n'est plus traité de la même manière selon son importance. La 5G ajoute la troisième : elle peut littéralement créer des réseaux virtuels parallèles, dont certains sont réservés à des usages critiques et isolés des autres. + +## En 4G : filtrer puis prioriser + +### Filtrer à l'entrée + +Chaque carte SIM porte un numéro de classe d'accès, hérité du GSM, entre 0 et 15. Les classes 0 à 9 couvrent le grand public — autrement dit nous tous. Les classes 11 à 15 sont réservées : services de secours, autorités publiques, personnel opérateur, usages militaires selon les pays. + +Quand une cellule est surchargée, l'eNodeB (la station de base 4G) diffuse une consigne aux téléphones du secteur : « les classes 0 à 9, vous attendez ». C'est l'**Access Class Barring**. Concrètement, votre téléphone reçoit ce message et bloque lui-même votre tentative d'appel ou de connexion data, sans même envoyer la demande à la station. C'est élégant parce que ça soulage la station avant même qu'elle ne soit sollicitée. Les classes prioritaires, elles, passent sans encombre. + +Il existe une variante plus dure appelée **Extended Access Barring**, conçue pour les objets connectés et les usages non urgents. Quand une vraie crise se déclare, l'opérateur peut couper les compteurs intelligents, les alarmes domestiques et autres équipements bavards pour préserver la bande passante humaine. + +### Prioriser une fois connecté + +Là où la 4G a vraiment innové, c'est en introduisant le **QCI** — *QoS Class Identifier*. Chaque flux de données qui transite sur le réseau se voit attribuer un numéro entre 1 et 9 (et quelques valeurs au-dessus pour des cas spéciaux) qui dit à l'infrastructure comment le traiter. + +Quelques exemples concrets : + +| Usage | QCI | Traitement | +|---|---|---| +| Appel VoLTE (voix sur LTE) | 1 | Latence minimale, débit garanti | +| Signalisation réseau | 5 | Très haute priorité | +| Visioconférence | 2 | Débit garanti | +| Streaming vidéo | 6 ou 8 | Best effort prioritaire | +| Web et internet général | 9 | Best effort standard | + +Quand la cellule est encombrée, le routeur sait quoi sacrifier en premier. YouTube va ralentir, les pages web vont mettre du temps à charger, mais l'appel téléphonique de votre voisin reste audible. C'est un compromis assumé : on dégrade volontairement les usages secondaires pour préserver les usages critiques. + +## En 5G : ajouter le découpage + +### Un mécanisme d'accès refondu + +La 5G garde l'esprit du barring mais change son nom et sa mécanique. L'ancien Access Class Barring est remplacé par l'**UAC** — *Unified Access Control*, introduit dans la Release 15 du 3GPP. L'idée est d'unifier dans un seul cadre ce qui était auparavant éparpillé entre ACB, EAB et d'autres mécanismes spécifiques. + +UAC repose sur deux notions. Les **Access Identities** identifient qui vous êtes (utilisateur lambda, abonné à un service prioritaire type MPS ou MCS, personnel d'urgence, agent opérateur). Les **Access Categories** identifient ce que vous essayez de faire (appel d'urgence, connexion data normale, SMS, mise à jour de localisation). La combinaison des deux détermine si votre demande passe ou pas. + +Ce qui change vraiment, c'est la granularité. En 4G, on bloquait une classe entière. En 5G, on peut bloquer un type d'action précis pour un type d'utilisateur précis — par exemple « les abonnés grand public ne peuvent plus initier de nouveaux appels data, mais les SMS et les appels voix continuent ». L'opérateur peut aussi définir ses propres catégories d'accès, calées sur sa politique commerciale et technique. + +### Le QCI devient le 5QI + +Même logique qu'en 4G mais avec plus de finesse. Le **5QI** (*5G QoS Identifier*) propose davantage de niveaux et tient compte de cas que la 4G gérait mal, notamment les services à très basse latence pour les usines connectées ou la voiture autonome. La voix d'urgence garde son sommet, les données critiques industrielles s'intercalent juste après, le streaming et le web restent en bas de la pile. + +### La vraie nouveauté : le network slicing + +C'est l'apport majeur de la 5G en termes de gestion de crise. Au lieu de partager une seule infrastructure entre tous les usages, on peut maintenant la **découper logiciellement en tranches** — des *slices* — qui se comportent comme autant de réseaux indépendants, alors qu'ils tournent sur les mêmes antennes et les mêmes câbles. + +Un opérateur peut par exemple maintenir : + +- une tranche pour le grand public, avec ses millions d'abonnés et son trafic massif, +- une tranche pour les services d'urgence et de sécurité, dimensionnée pour rester fluide même quand le reste sature, +- une tranche pour les objets connectés industriels, avec des garanties de latence, +- une tranche pour les opérateurs critiques type SNCF, EDF, hôpitaux. + +Chaque tranche a ses propres règles d'admission, ses propres priorités, ses propres garanties de performance. Si la tranche grand public est totalement saturée, celle des secours ne le sait même pas. Cette isolation est ce qui distingue le plus fondamentalement la 5G des générations précédentes, où tout le monde se battait pour les mêmes ressources, avec juste des priorités différentes. + +## Et le forfait premium dans tout ça ? + +Question qu'on entend souvent : si je paie un forfait à 50 € au lieu d'un forfait à 10 €, est-ce que je passe avant les autres en cas de saturation ? + +Non. + +Les priorités techniques décrites au-dessus ne dépendent ni du prix du forfait, ni des options commerciales souscrites. Elles dépendent du profil réseau associé à votre SIM (lui-même fonction de votre statut : grand public, secours, opérateur, services prioritaires officiels), et des politiques de gestion de crise programmées par l'opérateur. Un cadre dirigeant avec un forfait illimité reste, du point de vue du réseau, un abonné de classe d'accès 0-9 comme tout le monde. + +Le forfait premium vous donne plus de data, parfois un meilleur débit théorique en conditions normales, des options de roaming, du cloud gratuit. Il ne vous donne pas la priorité face à un pompier ou à un préfet. + +## Pour résumer + +| Génération | Ce qui est contrôlé | Comment | +|---|---|---| +| 2G | L'accès au réseau | Classes d'accès 0-15 | +| 4G | L'accès + la priorité du trafic | ACB / EAB + QCI | +| 5G | L'accès + la priorité + l'isolation des services | UAC + 5QI + network slicing | + +Ce qui est intéressant, c'est que ces mécanismes restent invisibles tant que tout va bien. Vous ne savez pas qu'ils existent. Vous découvrez leur existence le jour où votre voisin n'arrive plus à charger ses mails alors que les pompiers, eux, continuent de communiquer normalement. Ce jour-là, ce n'est pas de la magie. C'est trente ans d'ingénierie radio qui ont anticipé que ça arriverait. \ No newline at end of file diff --git a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0002.md b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0002.md new file mode 100644 index 0000000..66bf0c2 --- /dev/null +++ b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0002.md @@ -0,0 +1,80 @@ +Un attentat, un séisme, un match du Stade de France, une grande panne d'électricité. Dans ces moments-là, des centaines de milliers de gens dégainent leur téléphone en même temps. Le réseau mobile, qui est dimensionné pour un usage moyen et pas pour un pic massif simultané, devrait théoriquement s'effondrer. La plupart du temps, il tient. Pas parfaitement, pas pour tout le monde, mais il tient — et surtout, les appels d'urgence continuent de passer. C'est le résultat d'une série de mécanismes empilés depuis les années 1990, et que la 4G et la 5G ont raffinés. Voici comment ça marche, sans le jargon mais sans non plus mentir sur ce qui se passe vraiment. + +## Trois questions, pas une + +Dans un réseau cellulaire moderne, l'opérateur doit répondre à trois questions distinctes quand la cellule commence à chauffer. Qui a le droit de se connecter ? Une fois connecté, qui passe en premier ? Et quels services doivent absolument continuer à fonctionner, quoi qu'il arrive ? + +La 2G ne savait répondre qu'à la première. Elle filtrait à l'entrée et basta. La 4G a ajouté la deuxième : une fois admis sur le réseau, votre trafic n'est plus traité de la même manière selon son importance. La 5G ajoute la troisième : elle peut littéralement créer des réseaux virtuels parallèles, dont certains sont réservés à des usages critiques et isolés des autres. + +## En 4G : filtrer puis prioriser + +### Filtrer à l'entrée + +Chaque carte SIM porte un numéro de classe d'accès, hérité du GSM, entre 0 et 15. Les classes 0 à 9 couvrent le grand public — autrement dit nous tous. Les classes 11 à 15 sont réservées : services de secours, autorités publiques, personnel opérateur, usages militaires selon les pays. + +Quand une cellule est surchargée, l'eNodeB (la station de base 4G) diffuse une consigne aux téléphones du secteur : « les classes 0 à 9, vous attendez ». C'est l'**Access Class Barring**. Concrètement, votre téléphone reçoit ce message et bloque lui-même votre tentative d'appel ou de connexion data, sans même envoyer la demande à la station. C'est élégant parce que ça soulage la station avant même qu'elle ne soit sollicitée. Les classes prioritaires, elles, passent sans encombre. + +Il existe une variante plus dure appelée **Extended Access Barring**, conçue pour les objets connectés et les usages non urgents. Quand une vraie crise se déclare, l'opérateur peut couper les compteurs intelligents, les alarmes domestiques et autres équipements bavards pour préserver la bande passante humaine. + +### Prioriser une fois connecté + +Là où la 4G a vraiment innové, c'est en introduisant le **QCI** — *QoS Class Identifier*. Chaque flux de données qui transite sur le réseau se voit attribuer un numéro entre 1 et 9 (et quelques valeurs au-dessus pour des cas spéciaux) qui dit à l'infrastructure comment le traiter. + +Quelques exemples concrets : + +| Usage | QCI | Traitement | +|---|---|---| +| Appel VoLTE (voix sur LTE) | 1 | Latence minimale, débit garanti | +| Signalisation réseau | 5 | Très haute priorité | +| Visioconférence | 2 | Débit garanti | +| Streaming vidéo | 6 ou 8 | Best effort prioritaire | +| Web et internet général | 9 | Best effort standard | + +Quand la cellule est encombrée, le routeur sait quoi sacrifier en premier. YouTube va ralentir, les pages web vont mettre du temps à charger, mais l'appel téléphonique de votre voisin reste audible. C'est un compromis assumé : on dégrade volontairement les usages secondaires pour préserver les usages critiques. + +## En 5G : ajouter le découpage + +### Un mécanisme d'accès refondu + +La 5G garde l'esprit du barring mais change son nom et sa mécanique. L'ancien Access Class Barring est remplacé par l'**UAC** — *Unified Access Control*, introduit dans la Release 15 du 3GPP. L'idée est d'unifier dans un seul cadre ce qui était auparavant éparpillé entre ACB, EAB et d'autres mécanismes spécifiques. + +UAC repose sur deux notions. Les **Access Identities** identifient qui vous êtes (utilisateur lambda, abonné à un service prioritaire type MPS ou MCS, personnel d'urgence, agent opérateur). Les **Access Categories** identifient ce que vous essayez de faire (appel d'urgence, connexion data normale, SMS, mise à jour de localisation). La combinaison des deux détermine si votre demande passe ou pas. + +Ce qui change vraiment, c'est la granularité. En 4G, on bloquait une classe entière. En 5G, on peut bloquer un type d'action précis pour un type d'utilisateur précis — par exemple « les abonnés grand public ne peuvent plus initier de nouveaux appels data, mais les SMS et les appels voix continuent ». L'opérateur peut aussi définir ses propres catégories d'accès, calées sur sa politique commerciale et technique. + +### Le QCI devient le 5QI + +Même logique qu'en 4G mais avec plus de finesse. Le **5QI** (*5G QoS Identifier*) propose davantage de niveaux et tient compte de cas que la 4G gérait mal, notamment les services à très basse latence pour les usines connectées ou la voiture autonome. La voix d'urgence garde son sommet, les données critiques industrielles s'intercalent juste après, le streaming et le web restent en bas de la pile. + +### La vraie nouveauté : le network slicing + +C'est l'apport majeur de la 5G en termes de gestion de crise. Au lieu de partager une seule infrastructure entre tous les usages, on peut maintenant la **découper logiciellement en tranches** — des *slices* — qui se comportent comme autant de réseaux indépendants, alors qu'ils tournent sur les mêmes antennes et les mêmes câbles. + +Un opérateur peut par exemple maintenir : + +- une tranche pour le grand public, avec ses millions d'abonnés et son trafic massif, +- une tranche pour les services d'urgence et de sécurité, dimensionnée pour rester fluide même quand le reste sature, +- une tranche pour les objets connectés industriels, avec des garanties de latence, +- une tranche pour les opérateurs critiques type SNCF, EDF, hôpitaux. + +Chaque tranche a ses propres règles d'admission, ses propres priorités, ses propres garanties de performance. Si la tranche grand public est totalement saturée, celle des secours ne le sait même pas. Cette isolation est ce qui distingue le plus fondamentalement la 5G des générations précédentes, où tout le monde se battait pour les mêmes ressources, avec juste des priorités différentes. + +## Et le forfait premium dans tout ça ? + +Question qu'on entend souvent : si je paie un forfait à 50 € au lieu d'un forfait à 10 €, est-ce que je passe avant les autres en cas de saturation ? + +Non. + +Les priorités techniques décrites au-dessus ne dépendent ni du prix du forfait, ni des options commerciales souscrites. Elles dépendent du profil réseau associé à votre SIM (lui-même fonction de votre statut : grand public, secours, opérateur, services prioritaires officiels), et des politiques de gestion de crise programmées par l'opérateur. Un cadre dirigeant avec un forfait illimité reste, du point de vue du réseau, un abonné de classe d'accès 0-9 comme tout le monde. + +Le forfait premium vous donne plus de data, parfois un meilleur débit théorique en conditions normales, des options de roaming, du cloud gratuit. Il ne vous donne pas la priorité face à un pompier ou à un préfet. + +## Pour résumer + +| Génération | Ce qui est contrôlé | Comment | +|---|---|---| +| 2G | L'accès au réseau | Classes d'accès 0-15 | +| 4G | L'accès + la priorité du trafic | ACB / EAB + QCI | +| 5G | L'accès + la priorité + l'isolation des services | UAC + 5QI + network slicing | + +Ce qui est intéressant, c'est que ces mécanismes restent invisibles tant que tout va bien. Vous ne savez pas qu'ils existent. Vous découvrez leur existence le jour où votre voisin n'arrive plus à charger ses mails alors que les pompiers, eux, continuent de communiquer normalement. Ce jour-là, ce n'est pas de la magie. C'est trente ans d'ingénierie radio qui ont anticipé que ça arriverait. \ No newline at end of file diff --git a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0003.md b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0003.md new file mode 100644 index 0000000..66bf0c2 --- /dev/null +++ b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0003.md @@ -0,0 +1,80 @@ +Un attentat, un séisme, un match du Stade de France, une grande panne d'électricité. Dans ces moments-là, des centaines de milliers de gens dégainent leur téléphone en même temps. Le réseau mobile, qui est dimensionné pour un usage moyen et pas pour un pic massif simultané, devrait théoriquement s'effondrer. La plupart du temps, il tient. Pas parfaitement, pas pour tout le monde, mais il tient — et surtout, les appels d'urgence continuent de passer. C'est le résultat d'une série de mécanismes empilés depuis les années 1990, et que la 4G et la 5G ont raffinés. Voici comment ça marche, sans le jargon mais sans non plus mentir sur ce qui se passe vraiment. + +## Trois questions, pas une + +Dans un réseau cellulaire moderne, l'opérateur doit répondre à trois questions distinctes quand la cellule commence à chauffer. Qui a le droit de se connecter ? Une fois connecté, qui passe en premier ? Et quels services doivent absolument continuer à fonctionner, quoi qu'il arrive ? + +La 2G ne savait répondre qu'à la première. Elle filtrait à l'entrée et basta. La 4G a ajouté la deuxième : une fois admis sur le réseau, votre trafic n'est plus traité de la même manière selon son importance. La 5G ajoute la troisième : elle peut littéralement créer des réseaux virtuels parallèles, dont certains sont réservés à des usages critiques et isolés des autres. + +## En 4G : filtrer puis prioriser + +### Filtrer à l'entrée + +Chaque carte SIM porte un numéro de classe d'accès, hérité du GSM, entre 0 et 15. Les classes 0 à 9 couvrent le grand public — autrement dit nous tous. Les classes 11 à 15 sont réservées : services de secours, autorités publiques, personnel opérateur, usages militaires selon les pays. + +Quand une cellule est surchargée, l'eNodeB (la station de base 4G) diffuse une consigne aux téléphones du secteur : « les classes 0 à 9, vous attendez ». C'est l'**Access Class Barring**. Concrètement, votre téléphone reçoit ce message et bloque lui-même votre tentative d'appel ou de connexion data, sans même envoyer la demande à la station. C'est élégant parce que ça soulage la station avant même qu'elle ne soit sollicitée. Les classes prioritaires, elles, passent sans encombre. + +Il existe une variante plus dure appelée **Extended Access Barring**, conçue pour les objets connectés et les usages non urgents. Quand une vraie crise se déclare, l'opérateur peut couper les compteurs intelligents, les alarmes domestiques et autres équipements bavards pour préserver la bande passante humaine. + +### Prioriser une fois connecté + +Là où la 4G a vraiment innové, c'est en introduisant le **QCI** — *QoS Class Identifier*. Chaque flux de données qui transite sur le réseau se voit attribuer un numéro entre 1 et 9 (et quelques valeurs au-dessus pour des cas spéciaux) qui dit à l'infrastructure comment le traiter. + +Quelques exemples concrets : + +| Usage | QCI | Traitement | +|---|---|---| +| Appel VoLTE (voix sur LTE) | 1 | Latence minimale, débit garanti | +| Signalisation réseau | 5 | Très haute priorité | +| Visioconférence | 2 | Débit garanti | +| Streaming vidéo | 6 ou 8 | Best effort prioritaire | +| Web et internet général | 9 | Best effort standard | + +Quand la cellule est encombrée, le routeur sait quoi sacrifier en premier. YouTube va ralentir, les pages web vont mettre du temps à charger, mais l'appel téléphonique de votre voisin reste audible. C'est un compromis assumé : on dégrade volontairement les usages secondaires pour préserver les usages critiques. + +## En 5G : ajouter le découpage + +### Un mécanisme d'accès refondu + +La 5G garde l'esprit du barring mais change son nom et sa mécanique. L'ancien Access Class Barring est remplacé par l'**UAC** — *Unified Access Control*, introduit dans la Release 15 du 3GPP. L'idée est d'unifier dans un seul cadre ce qui était auparavant éparpillé entre ACB, EAB et d'autres mécanismes spécifiques. + +UAC repose sur deux notions. Les **Access Identities** identifient qui vous êtes (utilisateur lambda, abonné à un service prioritaire type MPS ou MCS, personnel d'urgence, agent opérateur). Les **Access Categories** identifient ce que vous essayez de faire (appel d'urgence, connexion data normale, SMS, mise à jour de localisation). La combinaison des deux détermine si votre demande passe ou pas. + +Ce qui change vraiment, c'est la granularité. En 4G, on bloquait une classe entière. En 5G, on peut bloquer un type d'action précis pour un type d'utilisateur précis — par exemple « les abonnés grand public ne peuvent plus initier de nouveaux appels data, mais les SMS et les appels voix continuent ». L'opérateur peut aussi définir ses propres catégories d'accès, calées sur sa politique commerciale et technique. + +### Le QCI devient le 5QI + +Même logique qu'en 4G mais avec plus de finesse. Le **5QI** (*5G QoS Identifier*) propose davantage de niveaux et tient compte de cas que la 4G gérait mal, notamment les services à très basse latence pour les usines connectées ou la voiture autonome. La voix d'urgence garde son sommet, les données critiques industrielles s'intercalent juste après, le streaming et le web restent en bas de la pile. + +### La vraie nouveauté : le network slicing + +C'est l'apport majeur de la 5G en termes de gestion de crise. Au lieu de partager une seule infrastructure entre tous les usages, on peut maintenant la **découper logiciellement en tranches** — des *slices* — qui se comportent comme autant de réseaux indépendants, alors qu'ils tournent sur les mêmes antennes et les mêmes câbles. + +Un opérateur peut par exemple maintenir : + +- une tranche pour le grand public, avec ses millions d'abonnés et son trafic massif, +- une tranche pour les services d'urgence et de sécurité, dimensionnée pour rester fluide même quand le reste sature, +- une tranche pour les objets connectés industriels, avec des garanties de latence, +- une tranche pour les opérateurs critiques type SNCF, EDF, hôpitaux. + +Chaque tranche a ses propres règles d'admission, ses propres priorités, ses propres garanties de performance. Si la tranche grand public est totalement saturée, celle des secours ne le sait même pas. Cette isolation est ce qui distingue le plus fondamentalement la 5G des générations précédentes, où tout le monde se battait pour les mêmes ressources, avec juste des priorités différentes. + +## Et le forfait premium dans tout ça ? + +Question qu'on entend souvent : si je paie un forfait à 50 € au lieu d'un forfait à 10 €, est-ce que je passe avant les autres en cas de saturation ? + +Non. + +Les priorités techniques décrites au-dessus ne dépendent ni du prix du forfait, ni des options commerciales souscrites. Elles dépendent du profil réseau associé à votre SIM (lui-même fonction de votre statut : grand public, secours, opérateur, services prioritaires officiels), et des politiques de gestion de crise programmées par l'opérateur. Un cadre dirigeant avec un forfait illimité reste, du point de vue du réseau, un abonné de classe d'accès 0-9 comme tout le monde. + +Le forfait premium vous donne plus de data, parfois un meilleur débit théorique en conditions normales, des options de roaming, du cloud gratuit. Il ne vous donne pas la priorité face à un pompier ou à un préfet. + +## Pour résumer + +| Génération | Ce qui est contrôlé | Comment | +|---|---|---| +| 2G | L'accès au réseau | Classes d'accès 0-15 | +| 4G | L'accès + la priorité du trafic | ACB / EAB + QCI | +| 5G | L'accès + la priorité + l'isolation des services | UAC + 5QI + network slicing | + +Ce qui est intéressant, c'est que ces mécanismes restent invisibles tant que tout va bien. Vous ne savez pas qu'ils existent. Vous découvrez leur existence le jour où votre voisin n'arrive plus à charger ses mails alors que les pompiers, eux, continuent de communiquer normalement. Ce jour-là, ce n'est pas de la magie. C'est trente ans d'ingénierie radio qui ont anticipé que ça arriverait. \ No newline at end of file diff --git a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0004.md b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0004.md new file mode 100644 index 0000000..3c19ca1 --- /dev/null +++ b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0004.md @@ -0,0 +1,80 @@ +Un attentat, un séisme, un match du Stade de France, une grande panne d'électricité. Dans ces moments-là, des centaines de milliers de gens dégainent leur téléphone en même temps. Le réseau mobile, qui est dimensionné pour un usage moyen et pas pour un pic massif simultané, devrait théoriquement s'effondrer. La plupart du temps, il tient. Pas parfaitement, pas pour tout le monde, mais il tient — et surtout, les appels d'urgence continuent de passer. C'est le résultat d'une série de mécanismes empilés depuis les années 1990, et que la 4G et la 5G ont raffinés. Voici comment ça marche, sans le jargon mais sans non plus mentir sur ce qui se passe vraiment. + +## Trois questions, pas une + +Dans un réseau cellulaire moderne, l'opérateur doit répondre à trois questions distinctes quand la cellule commence à chauffer. Qui a le droit de se connecter ? Une fois connecté, qui passe en premier ? Et quels services doivent absolument continuer à fonctionner, quoi qu'il arrive ? + +La 2G ne savait répondre qu'à la première. Elle filtrait à l'entrée et basta. La 4G a ajouté la deuxième : une fois admis sur le réseau, votre trafic n'est plus traité de la même manière selon son importance. La 5G ajoute la troisième : elle peut littéralement créer des réseaux virtuels parallèles, dont certains sont réservés à des usages critiques et isolés des autres. + +## En 4G : filtrer puis prioriser + +### Filtrer à l'entrée + +Chaque carte SIM porte un numéro de classe d'accès, hérité du GSM, entre 0 et 15. Les classes 0 à 9 couvrent le grand public — autrement dit nous tous. Les classes 11 à 15 sont réservées : services de secours, autorités publiques, personnel opérateur, usages militaires selon les pays. + +Quand une cellule est surchargée, l'eNodeB (la station de base 4G) diffuse une consigne aux téléphones du secteur : « les classes 0 à 9, vous attendez ». C'est l'**Access Class Barring**. Concrètement, votre téléphone reçoit ce message et bloque lui-même votre tentative d'appel ou de connexion data, sans même envoyer la demande à la station. C'est élégant parce que ça soulage la station avant même qu'elle ne soit sollicitée. Les classes prioritaires, elles, passent sans encombre. + +Il existe une variante plus dure appelée **Extended Access Barring**, conçue pour les objets connectés et les usages non urgents. Quand une vraie crise se déclare, l'opérateur peut couper les compteurs intelligents, les alarmes domestiques et autres équipements bavards pour préserver la bande passante humaine. + +### Prioriser une fois connecté + +Là où la 4G a vraiment innové, c'est en introduisant le **QCI** — *QoS Class Identifier*. Chaque flux de données qui transite sur le réseau se voit attribuer un numéro entre 1 et 9 (et quelques valeurs au-dessus pour des cas spéciaux) qui dit à l'infrastructure comment le traiter. + +Quelques exemples concrets : + +| Usage | QCI | Traitement | +|---|---|---| +| Appel VoLTE (voix sur LTE) | 1 | Latence minimale, débit garanti | +| Signalisation réseau | 5 | Très haute priorité | +| Visioconférence | 2 | Débit garanti | +| Streaming vidéo | 6 ou 8 | Best effort prioritaire | +| Web et internet général | 9 | Best effort standard | + +Quand la cellule est encombrée, le routeur sait quoi sacrifier en premier. YouTube va ralentir, les pages web vont mettre du temps à charger, mais l'appel téléphonique de votre voisin reste audible. C'est un compromis assumé : on dégrade volontairement les usages secondaires pour préserver les usages critiques. + +## En 5G : ajouter le découpage + +### Un mécanisme d'accès refondu + +La 5G garde l'esprit du barring mais change son nom et sa mécanique. L'ancien Access Class Barring est remplacé par l'**UAC** — *Unified Access Control*, introduit dans la Release 15 du 3GPP. L'idée est d'unifier dans un seul cadre ce qui était auparavant éparpillé entre ACB, EAB et d'autres mécanismes spécifiques. + +UAC repose sur deux notions. Les **Access Identities** identifient qui vous êtes (utilisateur lambda, abonné à un service prioritaire type MPS ou MCS, personnel d'urgence, agent opérateur). Les **Access Categories** identifient ce que vous essayez de faire (appel d'urgence, connexion data normale, SMS, mise à jour de localisation). La combinaison des deux détermine si votre demande passe ou pas. + +Ce qui change vraiment, c'est la granularité. En 4G, on bloquait une classe entière. En 5G, on peut bloquer un type d'action précis pour un type d'utilisateur précis — par exemple « les abonnés grand public ne peuvent plus initier de nouveaux appels data, mais les SMS et les appels voix continuent ». L'opérateur peut aussi définir ses propres catégories d'accès, calées sur sa politique commerciale et technique. + +### Le QCI devient le 5QI + +Même logique qu'en 4G mais avec plus de finesse. Le **5QI** (*5G QoS Identifier*) propose davantage de niveaux et tient compte de cas que la 4G gérait mal, notamment les services à très basse latence pour les usines connectées ou la voiture autonome. La voix d'urgence garde son sommet, les données critiques industrielles s'intercalent juste après, le streaming et le web restent en bas de la pile. + +### La vraie nouveauté : le network slicing + +C'est l'apport majeur de la 5G en termes de gestion de crise. Au lieu de partager une seule infrastructure entre tous les usages, on peut maintenant la **découper logiciellement en tranches** — des *slices* — qui se comportent comme autant de réseaux indépendants, alors qu'ils tournent sur les mêmes antennes et les mêmes câbles. + +Un opérateur peut par exemple maintenir : + +- une tranche pour le grand public, avec ses millions d'abonnés et son trafic massif, +- une tranche pour les services d'urgence et de sécurité, dimensionnée pour rester fluide même quand le reste sature, +- une tranche pour les objets connectés industriels, avec des garanties de latence, +- une tranche pour les opérateurs critiques type SNCF, EDF, hôpitaux. + +Chaque tranche a ses propres règles d'admission, ses propres priorités, ses propres garanties de performance. Si la tranche grand public est totalement saturée, celle des secours ne le sait même pas. Cette isolation est ce qui distingue le plus fondamentalement la 5G des générations précédentes, où tout le monde se battait pour les mêmes ressources, avec juste des priorités différentes. + +## Et le forfait premium dans tout ça ? + +Question qu'on entend souvent : si je paie un forfait à 50 € au lieu d'un forfait à 10 €, est-ce que je passe avant les autres en cas de saturation ? + +Non. + +Les priorités techniques décrites au-dessus ne dépendent ni du prix du forfait, ni des options commerciales souscrites. Elles dépendent du profil réseau associé à votre SIM (lui-même fonction de votre statut : grand public, secours, opérateur, services prioritaires officiels), et des politiques de gestion de crise programmées par l'opérateur. Un cadre dirigeant avec un forfait illimité reste, du point de vue du réseau, un abonné de classe d'accès 0-9 comme tout le monde. + +Le forfait premium vous donne plus de data, parfois un meilleur débit théorique en conditions normales, des options de roaming, du cloud gratuit. Il ne vous donne pas la priorité face à un pompier ou à un préfet. + +## Pour résumer + +| Génération | Ce qui est contrôlé | Comment | +|---|---|---| +| 2G | L'accès au réseau | Classes d'accès 0-15 | +| 4G | L'accès + la priorité du trafic | ACB / EAB + QCI | +| 5G | L'accès + la priorité + l'isolation des services | UAC + 5QI + network slicing | + +Ce qui est intéressant, c'est que ces mécanismes restent invisibles tant que tout va bien. Vous ne savez pas qu'ils existent. Vous découvrez leur existence le jour où votre voisin n'arrive plus à charger ses mails alors que les pompiers, eux, continuent de communiquer normalement. Ce jour-là, ce n'est pas de la magie. C'est trente ans d'ingénierie radio qui ont anticipé que ça arriverait. \ No newline at end of file diff --git a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0005.md b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0005.md new file mode 100644 index 0000000..66bf0c2 --- /dev/null +++ b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0005.md @@ -0,0 +1,80 @@ +Un attentat, un séisme, un match du Stade de France, une grande panne d'électricité. Dans ces moments-là, des centaines de milliers de gens dégainent leur téléphone en même temps. Le réseau mobile, qui est dimensionné pour un usage moyen et pas pour un pic massif simultané, devrait théoriquement s'effondrer. La plupart du temps, il tient. Pas parfaitement, pas pour tout le monde, mais il tient — et surtout, les appels d'urgence continuent de passer. C'est le résultat d'une série de mécanismes empilés depuis les années 1990, et que la 4G et la 5G ont raffinés. Voici comment ça marche, sans le jargon mais sans non plus mentir sur ce qui se passe vraiment. + +## Trois questions, pas une + +Dans un réseau cellulaire moderne, l'opérateur doit répondre à trois questions distinctes quand la cellule commence à chauffer. Qui a le droit de se connecter ? Une fois connecté, qui passe en premier ? Et quels services doivent absolument continuer à fonctionner, quoi qu'il arrive ? + +La 2G ne savait répondre qu'à la première. Elle filtrait à l'entrée et basta. La 4G a ajouté la deuxième : une fois admis sur le réseau, votre trafic n'est plus traité de la même manière selon son importance. La 5G ajoute la troisième : elle peut littéralement créer des réseaux virtuels parallèles, dont certains sont réservés à des usages critiques et isolés des autres. + +## En 4G : filtrer puis prioriser + +### Filtrer à l'entrée + +Chaque carte SIM porte un numéro de classe d'accès, hérité du GSM, entre 0 et 15. Les classes 0 à 9 couvrent le grand public — autrement dit nous tous. Les classes 11 à 15 sont réservées : services de secours, autorités publiques, personnel opérateur, usages militaires selon les pays. + +Quand une cellule est surchargée, l'eNodeB (la station de base 4G) diffuse une consigne aux téléphones du secteur : « les classes 0 à 9, vous attendez ». C'est l'**Access Class Barring**. Concrètement, votre téléphone reçoit ce message et bloque lui-même votre tentative d'appel ou de connexion data, sans même envoyer la demande à la station. C'est élégant parce que ça soulage la station avant même qu'elle ne soit sollicitée. Les classes prioritaires, elles, passent sans encombre. + +Il existe une variante plus dure appelée **Extended Access Barring**, conçue pour les objets connectés et les usages non urgents. Quand une vraie crise se déclare, l'opérateur peut couper les compteurs intelligents, les alarmes domestiques et autres équipements bavards pour préserver la bande passante humaine. + +### Prioriser une fois connecté + +Là où la 4G a vraiment innové, c'est en introduisant le **QCI** — *QoS Class Identifier*. Chaque flux de données qui transite sur le réseau se voit attribuer un numéro entre 1 et 9 (et quelques valeurs au-dessus pour des cas spéciaux) qui dit à l'infrastructure comment le traiter. + +Quelques exemples concrets : + +| Usage | QCI | Traitement | +|---|---|---| +| Appel VoLTE (voix sur LTE) | 1 | Latence minimale, débit garanti | +| Signalisation réseau | 5 | Très haute priorité | +| Visioconférence | 2 | Débit garanti | +| Streaming vidéo | 6 ou 8 | Best effort prioritaire | +| Web et internet général | 9 | Best effort standard | + +Quand la cellule est encombrée, le routeur sait quoi sacrifier en premier. YouTube va ralentir, les pages web vont mettre du temps à charger, mais l'appel téléphonique de votre voisin reste audible. C'est un compromis assumé : on dégrade volontairement les usages secondaires pour préserver les usages critiques. + +## En 5G : ajouter le découpage + +### Un mécanisme d'accès refondu + +La 5G garde l'esprit du barring mais change son nom et sa mécanique. L'ancien Access Class Barring est remplacé par l'**UAC** — *Unified Access Control*, introduit dans la Release 15 du 3GPP. L'idée est d'unifier dans un seul cadre ce qui était auparavant éparpillé entre ACB, EAB et d'autres mécanismes spécifiques. + +UAC repose sur deux notions. Les **Access Identities** identifient qui vous êtes (utilisateur lambda, abonné à un service prioritaire type MPS ou MCS, personnel d'urgence, agent opérateur). Les **Access Categories** identifient ce que vous essayez de faire (appel d'urgence, connexion data normale, SMS, mise à jour de localisation). La combinaison des deux détermine si votre demande passe ou pas. + +Ce qui change vraiment, c'est la granularité. En 4G, on bloquait une classe entière. En 5G, on peut bloquer un type d'action précis pour un type d'utilisateur précis — par exemple « les abonnés grand public ne peuvent plus initier de nouveaux appels data, mais les SMS et les appels voix continuent ». L'opérateur peut aussi définir ses propres catégories d'accès, calées sur sa politique commerciale et technique. + +### Le QCI devient le 5QI + +Même logique qu'en 4G mais avec plus de finesse. Le **5QI** (*5G QoS Identifier*) propose davantage de niveaux et tient compte de cas que la 4G gérait mal, notamment les services à très basse latence pour les usines connectées ou la voiture autonome. La voix d'urgence garde son sommet, les données critiques industrielles s'intercalent juste après, le streaming et le web restent en bas de la pile. + +### La vraie nouveauté : le network slicing + +C'est l'apport majeur de la 5G en termes de gestion de crise. Au lieu de partager une seule infrastructure entre tous les usages, on peut maintenant la **découper logiciellement en tranches** — des *slices* — qui se comportent comme autant de réseaux indépendants, alors qu'ils tournent sur les mêmes antennes et les mêmes câbles. + +Un opérateur peut par exemple maintenir : + +- une tranche pour le grand public, avec ses millions d'abonnés et son trafic massif, +- une tranche pour les services d'urgence et de sécurité, dimensionnée pour rester fluide même quand le reste sature, +- une tranche pour les objets connectés industriels, avec des garanties de latence, +- une tranche pour les opérateurs critiques type SNCF, EDF, hôpitaux. + +Chaque tranche a ses propres règles d'admission, ses propres priorités, ses propres garanties de performance. Si la tranche grand public est totalement saturée, celle des secours ne le sait même pas. Cette isolation est ce qui distingue le plus fondamentalement la 5G des générations précédentes, où tout le monde se battait pour les mêmes ressources, avec juste des priorités différentes. + +## Et le forfait premium dans tout ça ? + +Question qu'on entend souvent : si je paie un forfait à 50 € au lieu d'un forfait à 10 €, est-ce que je passe avant les autres en cas de saturation ? + +Non. + +Les priorités techniques décrites au-dessus ne dépendent ni du prix du forfait, ni des options commerciales souscrites. Elles dépendent du profil réseau associé à votre SIM (lui-même fonction de votre statut : grand public, secours, opérateur, services prioritaires officiels), et des politiques de gestion de crise programmées par l'opérateur. Un cadre dirigeant avec un forfait illimité reste, du point de vue du réseau, un abonné de classe d'accès 0-9 comme tout le monde. + +Le forfait premium vous donne plus de data, parfois un meilleur débit théorique en conditions normales, des options de roaming, du cloud gratuit. Il ne vous donne pas la priorité face à un pompier ou à un préfet. + +## Pour résumer + +| Génération | Ce qui est contrôlé | Comment | +|---|---|---| +| 2G | L'accès au réseau | Classes d'accès 0-15 | +| 4G | L'accès + la priorité du trafic | ACB / EAB + QCI | +| 5G | L'accès + la priorité + l'isolation des services | UAC + 5QI + network slicing | + +Ce qui est intéressant, c'est que ces mécanismes restent invisibles tant que tout va bien. Vous ne savez pas qu'ils existent. Vous découvrez leur existence le jour où votre voisin n'arrive plus à charger ses mails alors que les pompiers, eux, continuent de communiquer normalement. Ce jour-là, ce n'est pas de la magie. C'est trente ans d'ingénierie radio qui ont anticipé que ça arriverait. \ No newline at end of file diff --git a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0006.md b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0006.md new file mode 100644 index 0000000..66bf0c2 --- /dev/null +++ b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0006.md @@ -0,0 +1,80 @@ +Un attentat, un séisme, un match du Stade de France, une grande panne d'électricité. Dans ces moments-là, des centaines de milliers de gens dégainent leur téléphone en même temps. Le réseau mobile, qui est dimensionné pour un usage moyen et pas pour un pic massif simultané, devrait théoriquement s'effondrer. La plupart du temps, il tient. Pas parfaitement, pas pour tout le monde, mais il tient — et surtout, les appels d'urgence continuent de passer. C'est le résultat d'une série de mécanismes empilés depuis les années 1990, et que la 4G et la 5G ont raffinés. Voici comment ça marche, sans le jargon mais sans non plus mentir sur ce qui se passe vraiment. + +## Trois questions, pas une + +Dans un réseau cellulaire moderne, l'opérateur doit répondre à trois questions distinctes quand la cellule commence à chauffer. Qui a le droit de se connecter ? Une fois connecté, qui passe en premier ? Et quels services doivent absolument continuer à fonctionner, quoi qu'il arrive ? + +La 2G ne savait répondre qu'à la première. Elle filtrait à l'entrée et basta. La 4G a ajouté la deuxième : une fois admis sur le réseau, votre trafic n'est plus traité de la même manière selon son importance. La 5G ajoute la troisième : elle peut littéralement créer des réseaux virtuels parallèles, dont certains sont réservés à des usages critiques et isolés des autres. + +## En 4G : filtrer puis prioriser + +### Filtrer à l'entrée + +Chaque carte SIM porte un numéro de classe d'accès, hérité du GSM, entre 0 et 15. Les classes 0 à 9 couvrent le grand public — autrement dit nous tous. Les classes 11 à 15 sont réservées : services de secours, autorités publiques, personnel opérateur, usages militaires selon les pays. + +Quand une cellule est surchargée, l'eNodeB (la station de base 4G) diffuse une consigne aux téléphones du secteur : « les classes 0 à 9, vous attendez ». C'est l'**Access Class Barring**. Concrètement, votre téléphone reçoit ce message et bloque lui-même votre tentative d'appel ou de connexion data, sans même envoyer la demande à la station. C'est élégant parce que ça soulage la station avant même qu'elle ne soit sollicitée. Les classes prioritaires, elles, passent sans encombre. + +Il existe une variante plus dure appelée **Extended Access Barring**, conçue pour les objets connectés et les usages non urgents. Quand une vraie crise se déclare, l'opérateur peut couper les compteurs intelligents, les alarmes domestiques et autres équipements bavards pour préserver la bande passante humaine. + +### Prioriser une fois connecté + +Là où la 4G a vraiment innové, c'est en introduisant le **QCI** — *QoS Class Identifier*. Chaque flux de données qui transite sur le réseau se voit attribuer un numéro entre 1 et 9 (et quelques valeurs au-dessus pour des cas spéciaux) qui dit à l'infrastructure comment le traiter. + +Quelques exemples concrets : + +| Usage | QCI | Traitement | +|---|---|---| +| Appel VoLTE (voix sur LTE) | 1 | Latence minimale, débit garanti | +| Signalisation réseau | 5 | Très haute priorité | +| Visioconférence | 2 | Débit garanti | +| Streaming vidéo | 6 ou 8 | Best effort prioritaire | +| Web et internet général | 9 | Best effort standard | + +Quand la cellule est encombrée, le routeur sait quoi sacrifier en premier. YouTube va ralentir, les pages web vont mettre du temps à charger, mais l'appel téléphonique de votre voisin reste audible. C'est un compromis assumé : on dégrade volontairement les usages secondaires pour préserver les usages critiques. + +## En 5G : ajouter le découpage + +### Un mécanisme d'accès refondu + +La 5G garde l'esprit du barring mais change son nom et sa mécanique. L'ancien Access Class Barring est remplacé par l'**UAC** — *Unified Access Control*, introduit dans la Release 15 du 3GPP. L'idée est d'unifier dans un seul cadre ce qui était auparavant éparpillé entre ACB, EAB et d'autres mécanismes spécifiques. + +UAC repose sur deux notions. Les **Access Identities** identifient qui vous êtes (utilisateur lambda, abonné à un service prioritaire type MPS ou MCS, personnel d'urgence, agent opérateur). Les **Access Categories** identifient ce que vous essayez de faire (appel d'urgence, connexion data normale, SMS, mise à jour de localisation). La combinaison des deux détermine si votre demande passe ou pas. + +Ce qui change vraiment, c'est la granularité. En 4G, on bloquait une classe entière. En 5G, on peut bloquer un type d'action précis pour un type d'utilisateur précis — par exemple « les abonnés grand public ne peuvent plus initier de nouveaux appels data, mais les SMS et les appels voix continuent ». L'opérateur peut aussi définir ses propres catégories d'accès, calées sur sa politique commerciale et technique. + +### Le QCI devient le 5QI + +Même logique qu'en 4G mais avec plus de finesse. Le **5QI** (*5G QoS Identifier*) propose davantage de niveaux et tient compte de cas que la 4G gérait mal, notamment les services à très basse latence pour les usines connectées ou la voiture autonome. La voix d'urgence garde son sommet, les données critiques industrielles s'intercalent juste après, le streaming et le web restent en bas de la pile. + +### La vraie nouveauté : le network slicing + +C'est l'apport majeur de la 5G en termes de gestion de crise. Au lieu de partager une seule infrastructure entre tous les usages, on peut maintenant la **découper logiciellement en tranches** — des *slices* — qui se comportent comme autant de réseaux indépendants, alors qu'ils tournent sur les mêmes antennes et les mêmes câbles. + +Un opérateur peut par exemple maintenir : + +- une tranche pour le grand public, avec ses millions d'abonnés et son trafic massif, +- une tranche pour les services d'urgence et de sécurité, dimensionnée pour rester fluide même quand le reste sature, +- une tranche pour les objets connectés industriels, avec des garanties de latence, +- une tranche pour les opérateurs critiques type SNCF, EDF, hôpitaux. + +Chaque tranche a ses propres règles d'admission, ses propres priorités, ses propres garanties de performance. Si la tranche grand public est totalement saturée, celle des secours ne le sait même pas. Cette isolation est ce qui distingue le plus fondamentalement la 5G des générations précédentes, où tout le monde se battait pour les mêmes ressources, avec juste des priorités différentes. + +## Et le forfait premium dans tout ça ? + +Question qu'on entend souvent : si je paie un forfait à 50 € au lieu d'un forfait à 10 €, est-ce que je passe avant les autres en cas de saturation ? + +Non. + +Les priorités techniques décrites au-dessus ne dépendent ni du prix du forfait, ni des options commerciales souscrites. Elles dépendent du profil réseau associé à votre SIM (lui-même fonction de votre statut : grand public, secours, opérateur, services prioritaires officiels), et des politiques de gestion de crise programmées par l'opérateur. Un cadre dirigeant avec un forfait illimité reste, du point de vue du réseau, un abonné de classe d'accès 0-9 comme tout le monde. + +Le forfait premium vous donne plus de data, parfois un meilleur débit théorique en conditions normales, des options de roaming, du cloud gratuit. Il ne vous donne pas la priorité face à un pompier ou à un préfet. + +## Pour résumer + +| Génération | Ce qui est contrôlé | Comment | +|---|---|---| +| 2G | L'accès au réseau | Classes d'accès 0-15 | +| 4G | L'accès + la priorité du trafic | ACB / EAB + QCI | +| 5G | L'accès + la priorité + l'isolation des services | UAC + 5QI + network slicing | + +Ce qui est intéressant, c'est que ces mécanismes restent invisibles tant que tout va bien. Vous ne savez pas qu'ils existent. Vous découvrez leur existence le jour où votre voisin n'arrive plus à charger ses mails alors que les pompiers, eux, continuent de communiquer normalement. Ce jour-là, ce n'est pas de la magie. C'est trente ans d'ingénierie radio qui ont anticipé que ça arriverait. \ No newline at end of file diff --git a/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0007.md b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0007.md new file mode 100644 index 0000000..fdeddc6 --- /dev/null +++ b/data/4f443bcb-b0d4-47f8-837d-61627e6c94f2/revisions/0007.md @@ -0,0 +1,87 @@ +Un attentat, un séisme, un match du Stade de France, une grande panne d'électricité. Dans ces moments-là, des centaines de milliers de gens dégainent leur téléphone au même instant. Le réseau mobile est dimensionné pour un usage moyen, pas pour un pic massif simultané, et il devrait théoriquement s'effondrer. La plupart du temps, il tient. Pas parfaitement, pas pour tout le monde, mais il tient — et surtout, les appels d'urgence continuent de passer. C'est le résultat d'une série de mécanismes empilés depuis les années 1990, que la 4G a affinés et que la 5G a élargis. Cet article les passe en revue, et termine sur une question qu'on me pose souvent : est-ce que mon forfait à 50 € me donne une place prioritaire dans cette file d'attente ? + +## Trois questions, pas une + +Quand une cellule commence à chauffer, l'opérateur doit répondre à trois questions distinctes. Qui a le droit de se connecter ? Une fois connecté, qui passe en premier ? Et quels services doivent absolument continuer à fonctionner, quoi qu'il arrive ? + +La 2G ne savait répondre qu'à la première. Elle filtrait à l'entrée et basta. La 4G a ajouté la deuxième : une fois admis sur le réseau, votre trafic est traité différemment selon son importance. La 5G ajoute la troisième : elle peut créer des réseaux virtuels parallèles dont certains sont réservés à des usages critiques, totalement isolés des autres. + +## Le filtrage à l'entrée + +Chaque carte SIM porte un numéro de classe d'accès, hérité du GSM, entre 0 et 15. Les classes 0 à 9 couvrent le grand public — autrement dit nous tous. Les classes 11 à 15 sont réservées : services de secours, autorités publiques, personnel opérateur, usages militaires selon les pays. + +Quand une cellule est surchargée, l'eNodeB (la station de base 4G) diffuse une consigne aux téléphones du secteur : « les classes 0 à 9, vous attendez ». C'est l'**Access Class Barring**. Concrètement, votre téléphone reçoit ce message et bloque lui-même votre tentative d'appel ou de connexion data, sans même envoyer la demande à la station. C'est élégant parce que ça soulage la station avant même qu'elle ne soit sollicitée. Les classes prioritaires, elles, passent sans encombre. + +Une variante plus dure, l'**Extended Access Barring**, vise les objets connectés et les usages non urgents. Quand une vraie crise se déclare, l'opérateur peut couper les compteurs intelligents, les alarmes domestiques et autres équipements bavards pour préserver la bande passante humaine. + +En 5G, ce mécanisme a été refondu sous le nom d'**UAC** — *Unified Access Control*, introduit dans la Release 15 du 3GPP. UAC unifie dans un seul cadre ce qui était auparavant éparpillé entre ACB, EAB et d'autres dispositifs spécifiques. Il repose sur deux notions complémentaires. Les *Access Identities* identifient qui vous êtes : utilisateur lambda, abonné à un service prioritaire type MPS ou MCS, personnel d'urgence, agent opérateur. Les *Access Categories* identifient ce que vous essayez de faire : appel d'urgence, connexion data normale, SMS, mise à jour de localisation. La combinaison des deux détermine si votre demande passe ou pas. La granularité gagnée par rapport à la 4G est réelle : on peut bloquer un type d'action précis pour un type d'utilisateur précis, par exemple « les abonnés grand public ne peuvent plus initier de nouveaux appels data, mais les SMS et les appels voix continuent ». + +## La priorité une fois connecté + +Là où la 4G a vraiment innové, c'est en introduisant le **QCI** — *QoS Class Identifier*. Chaque flux de données qui transite sur le réseau se voit attribuer un numéro entre 1 et 9 (avec quelques valeurs supplémentaires pour des cas spéciaux) qui dit à l'infrastructure comment le traiter. + +| Usage | QCI | Traitement | +|---|---|---| +| Appel VoLTE (voix sur LTE) | 1 | Latence minimale, débit garanti | +| Visioconférence | 2 | Débit garanti | +| Signalisation réseau | 5 | Très haute priorité | +| Streaming vidéo | 6 ou 8 | Best effort prioritaire | +| Web et internet général | 9 | Best effort standard | + +Quand la cellule est encombrée, le routeur sait quoi sacrifier en premier. YouTube va ralentir, les pages web vont mettre du temps à charger, mais l'appel téléphonique de votre voisin reste audible. C'est un compromis assumé : on dégrade volontairement les usages secondaires pour préserver les usages critiques. + +La 5G a transposé ce mécanisme sous le nom de **5QI** (*5G QoS Identifier*) avec davantage de niveaux et une meilleure prise en compte des cas que la 4G gérait mal — notamment les services à très basse latence pour les usines connectées ou la voiture autonome. La voix d'urgence garde son sommet, les données critiques industrielles s'intercalent juste après, le streaming et le web restent en bas de la pile. + +## L'isolation par tranches : le network slicing + +C'est l'apport majeur de la 5G en matière de gestion de crise. Au lieu de partager une seule infrastructure entre tous les usages, on peut maintenant la découper logiciellement en tranches — des *slices* — qui se comportent comme autant de réseaux indépendants, alors qu'ils tournent sur les mêmes antennes et les mêmes câbles. + +Un opérateur peut par exemple maintenir une tranche pour le grand public avec ses millions d'abonnés et son trafic massif, une autre pour les services d'urgence dimensionnée pour rester fluide même quand le reste sature, une troisième pour les objets connectés industriels avec des garanties de latence, et une quatrième pour des opérateurs critiques type SNCF, EDF ou hôpitaux. Chaque tranche a ses propres règles d'admission, ses propres priorités, ses propres garanties de performance. Si la tranche grand public est totalement saturée, celle des secours ne le sait même pas. + +Cette isolation est ce qui distingue le plus fondamentalement la 5G des générations précédentes. Avant, tout le monde se battait pour les mêmes ressources, avec juste des priorités différentes pour départager. Maintenant, certaines ressources sont retirées du combat dès le départ. + +## Récapitulatif + +| Génération | Ce qui est contrôlé | Comment | +|---|---|---| +| 2G | L'accès au réseau | Classes d'accès 0-15 | +| 4G | L'accès + la priorité du trafic | ACB / EAB + QCI | +| 5G | L'accès + la priorité + l'isolation des services | UAC + 5QI + network slicing | + +Tous ces mécanismes restent invisibles tant que tout va bien. Vous ne savez pas qu'ils existent. Vous découvrez leur existence le jour où votre voisin n'arrive plus à charger ses mails alors que les pompiers, eux, continuent de communiquer normalement. Ce jour-là, ce n'est pas de la magie. C'est trente ans d'ingénierie radio qui ont anticipé que ça arriverait. + +--- + +## Et mon forfait premium, alors ? + +Question logique à ce stade. Si le réseau sait techniquement prioriser certains flux par rapport à d'autres, qu'est-ce qui empêche un opérateur de faire passer ses abonnés à 50 € devant ceux à 10 € quand les antennes saturent ? La réponse honnête commence par un aveu : techniquement, rien. L'outil existe, il s'appelle **Quality of Service** (QoS), c'est exactement le mécanisme qu'on vient de décrire. Si demain Orange ou SFR voulaient créer une voie rapide pour leurs abonnés haut de gamme, ils auraient les outils dans la boîte. Pourtant, ils ne le font pas. Pour quatre raisons. + +### La loi européenne l'interdit + +Le règlement **(UE) 2015/2120**, dit « règlement internet ouvert », oblige les opérateurs à traiter tout le trafic de la même façon, sans discrimination liée à l'expéditeur, au destinataire, au contenu ou à l'application. Il a fêté ses dix ans en novembre 2025, et l'ARCEP a profité de l'anniversaire pour rappeler que c'est l'un des piliers du modèle numérique européen. Les sanctions sont sérieuses : jusqu'à **3 % du chiffre d'affaires** de l'opérateur fautif. Un opérateur français qui annoncerait demain « avec notre forfait Premium, vous passez devant les autres » se retrouverait devant l'ARCEP dans la semaine. + +Le règlement laisse quelques portes ouvertes pour les services dits « spécialisés » qui ont besoin d'une qualité garantie — téléchirurgie, voiture connectée. Mais ces exceptions sont étroitement encadrées et ne couvrent absolument pas le confort d'un client haut de gamme qui voudrait charger son Instagram plus vite à 19h. + +Aux États-Unis, l'histoire est différente. La FCC a tenté de restaurer la neutralité du net en 2024, mais en janvier 2025 la cour d'appel du sixième circuit a invalidé la décision, jugeant que la FCC n'avait pas l'autorité légale pour reclasser le haut débit comme service public. Avec l'arrivée de Brendan Carr à la tête de la FCC, ouvertement opposé à la neutralité du net, il n'y a aujourd'hui plus de règle fédérale outre-Atlantique. Quelques États (Californie, Washington, New York, Oregon) ont leurs propres lois qui maintiennent le principe, mais à l'échelle du pays, les opérateurs américains pourraient légalement faire ce que leurs homologues européens n'ont pas le droit de faire. Pourtant, ils ne le font pas ouvertement non plus, et la raison renvoie aux trois points suivants. + +### C'est commercialement intenable + +Imagine la publicité : « Forfait Premium à 50 € — passez devant les pauvres pendant les heures de pointe ». Le slogan ne se vend pas. Les directions marketing savent que dire à la moitié de leurs clients qu'ils sont des citoyens de seconde zone du réseau est le plus court chemin vers une crise de réputation. C'est pour ça qu'on vous vend « plus de Go », « 5G ultra rapide », « roaming inclus dans 110 pays » — des promesses qui sonnent positivement sans jamais dire à personne qu'il est désavantagé. + +### L'effet boule de neige serait toxique + +Imagine que ça se mette quand même en place. Les riches passent devant. Les antennes restent saturées pour les autres, qui se mettent à payer plus pour échapper à la saturation, ce qui sature encore plus les bas forfaits, ce qui pousse encore plus de gens à monter en gamme. Au bout de cinq ans, on a un réseau à deux vitesses où les forfaits modestes deviennent quasi inutilisables aux heures critiques, et où la connexion mobile correcte devient un service de luxe. Ce n'est plus un service de télécommunications, c'est un système de classes. + +C'est exactement ce que la neutralité du net cherche à empêcher. Pas par idéologie, mais parce qu'on a déjà vu où mène ce genre de spirale dans les pays où elle n'est pas protégée. Certains opérateurs proposent par exemple des forfaits où Facebook et WhatsApp sont gratuits mais où le reste est payant, ce qui revient à dire que le bon internet est celui que l'opérateur a choisi pour vous. Ce n'est plus tout à fait le même service. + +### Ça ne résoudrait rien + +Quand un réseau sature, ce n'est pas un problème de répartition entre utilisateurs, c'est un problème de **capacité totale**. Faire passer Pierre avant Paul ne crée pas un seul bit de bande passante supplémentaire. Ça déplace juste le problème de l'un vers l'autre. La vraie solution, quand une cellule sature trop souvent, c'est d'installer plus d'antennes, de densifier le réseau, de basculer sur une fréquence plus performante ou de passer à la génération suivante. C'est cher, c'est long, ça implique des autorisations administratives et des négociations foncières, mais c'est la seule réponse qui tient la route. Prioriser, c'est rapide, mais ça repousse le mur, ça ne le déplace pas. + +C'est comme si on proposait une voie réservée aux Mercedes sur l'A7 un samedi de chassé-croisé. Techniquement, on peut peindre la ligne au sol et installer les panneaux dans la matinée. Mais cette voie ne réduit pas le bouchon, elle le concentre sur les voies restantes ; elle écorne le principe d'égalité d'accès à l'infrastructure publique ; et elle ne change rien au problème de fond, qui est qu'il y a trop de voitures pour la route disponible. La vraie solution reste la même qu'avant : élargir l'autoroute, ou convaincre une partie des gens de prendre le train. + +### Le caveat 5G + +Une nuance honnête pour finir. Le *network slicing* complique le débat juridique. Un opérateur peut créer des tranches de réseau avec des qualités différenciées en toute légalité quand il s'agit d'usages spécialisés — santé, industrie, transports. La question qui agite régulateurs et juristes depuis plusieurs années est de savoir où finit le service spécialisé légitime et où commence le contournement déguisé de la neutralité du net. L'ARCEP a ouvert ce chantier, et c'est probablement là, plus que dans une revanche commerciale brutale sur les forfaits premium, que se jouera la prochaine bataille. + +Mais pour répondre simplement à la question : non, votre forfait à 50 € ne vous donne pas la priorité réseau sur celui de votre voisin à 10 €. Il vous donne plus de data, parfois un meilleur débit théorique, des options en plus. Pas une place dans la file. \ No newline at end of file diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/files/_thumb_f44a2f694f44f2a5-11682.jpg b/data/75bf96ba-e110-4a9e-8163-95890562aecf/files/_thumb_f44a2f694f44f2a5-11682.jpg new file mode 100644 index 0000000..4d165da Binary files /dev/null and b/data/75bf96ba-e110-4a9e-8163-95890562aecf/files/_thumb_f44a2f694f44f2a5-11682.jpg differ diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/files/cover.jpg b/data/75bf96ba-e110-4a9e-8163-95890562aecf/files/cover.jpg new file mode 100644 index 0000000..aea915e Binary files /dev/null and b/data/75bf96ba-e110-4a9e-8163-95890562aecf/files/cover.jpg differ diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/index.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/index.md index f62b020..988bb5a 100644 --- a/data/75bf96ba-e110-4a9e-8163-95890562aecf/index.md +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/index.md @@ -1,19 +1,17 @@ -À première vue, la situation a quelque chose de déroutant. Orange, opérateur historique français, héritier d’une longue tradition de service public et acteur stratégique des télécommunications, fait massivement appel aux infrastructures cloud d’Amazon, Microsoft ou Google. Dans un contexte où la souveraineté numérique est devenue un enjeu politique, économique et géostratégique majeur, ce choix peut apparaître comme une contradiction, voire comme un renoncement. Pourtant, il ne s’agit ni d’un abandon ni d’une naïveté, mais d’un compromis révélateur des limites actuelles de l’Europe dans la bataille du numérique. +Orange utilise massivement AWS, Azure et Google Cloud. Dit comme ça, c'est presque une blague. L'ancien France Télécom, opérateur historique, fleuron des télécoms français, héritier du service public, branché sur les serveurs de la Silicon Valley. À l'heure où on ne parle que de souveraineté numérique, on pourrait croire à une trahison. C'est plus compliqué que ça. -Le recours aux hyperscalers américains s’explique d’abord par une réalité industrielle. Ces entreprises ont construit, en une quinzaine d’années, une avance quasiment irréversible en matière d’infrastructures numériques. Leurs plateformes ne se contentent plus de fournir de la puissance de calcul ou du stockage. Elles offrent un écosystème complet qui va de l’hébergement à l’intelligence artificielle, en passant par l’analyse massive de données, l’automatisation des déploiements, la cybersécurité et la résilience globale des systèmes. Pour un groupe comme Orange, qui opère dans de nombreux pays et doit garantir des niveaux de service très élevés à des millions d’utilisateurs, cette maturité technologique est un facteur décisif. +La raison principale est bête : les Américains ont gagné la course. En quinze ans, AWS, Microsoft et Google ont construit une avance que personne ne sait combler aujourd'hui. Et ils ne vendent plus seulement du stockage ou de la puissance de calcul. Ils vendent un écosystème entier : de l'IA prête à l'emploi, des outils d'analyse de données, de l'automatisation, de la cybersécurité, des garanties de disponibilité à neuf chiffres. Pour Orange, qui doit faire tourner ses services dans une vingtaine de pays sans tomber en panne, ce niveau de maturité pèse lourd dans la balance. -Mais ce choix, rationnel sur le plan opérationnel, pose une question politique et stratégique beaucoup plus large. En confiant une part croissante de ses infrastructures numériques à des acteurs soumis au droit américain, Orange participe malgré lui à une forme de dépendance structurelle. Le Cloud Act, qui permet aux autorités américaines d’exiger l’accès à certaines données, même hébergées hors des États-Unis, symbolise cette vulnérabilité. Même si les mécanismes de chiffrement, de cloisonnement et de contrôle contractuel existent, le simple fait que la décision ultime puisse échapper aux juridictions européennes constitue une faille du point de vue de la souveraineté. +Sauf que ce choix rationnel a un prix politique. En confiant ses infrastructures à des entreprises soumises au droit américain, Orange entre dans une zone de dépendance dont on ne sort pas facilement. Le Cloud Act permet aux autorités américaines de réclamer des données hébergées par ces sociétés, même quand ces données sont physiquement en Europe. On peut chiffrer, cloisonner, négocier des clauses dans tous les sens, le fait reste que la décision finale échappe au juge européen. Pour un opérateur télécoms qui manipule des données de millions d'abonnés, ce n'est pas un détail. -Ce paradoxe est d’autant plus frappant que des alternatives européennes existent. La France et l’Europe disposent d’acteurs solides, capables de fournir des services cloud performants, sécurisés et compétitifs sur de nombreux usages. OVHcloud, Scaleway, Outscale, IONOS ou encore les initiatives portées par Deutsche Telekom en sont la preuve. Alors pourquoi ne pas construire une alliance massive entre ces acteurs et un groupe comme Orange pour bâtir une véritable alternative souveraine ? +Le plus rageant, c'est qu'on a des alternatives. OVHcloud, Scaleway, Outscale, IONOS en Allemagne, sans parler des projets autour de Deutsche Telekom. Ces acteurs existent, ils sont sérieux, ils savent faire. Alors pourquoi Orange ne s'allie pas avec eux pour construire quelque chose de crédible à l'échelle européenne ? -La réponse tient moins à la volonté qu’à l’échelle. Les hyperscalers américains investissent chaque année des dizaines de milliards d’euros dans leurs infrastructures. Ils déploient des data centers sur tous les continents, possèdent leurs propres réseaux mondiaux et attirent l’essentiel des talents du secteur. Face à cette puissance financière et industrielle, les acteurs européens, pris individuellement, peinent à rivaliser. Une alliance serait possible, mais elle nécessiterait un effort coordonné, soutenu politiquement, sur plusieurs décennies. Or l’Europe avance souvent par projets fragmentés, soumis aux cycles électoraux et aux priorités nationales parfois divergentes. +Parce que l'écart de moyens est vertigineux. AWS et Microsoft investissent chacun plus de cinquante milliards de dollars par an dans leurs infrastructures. Ils ont leurs propres câbles sous-marins, leurs propres réseaux mondiaux, et ils raflent une bonne partie des ingénieurs qui sortent des écoles. Un OVH, même bien géré, ne joue pas dans la même catégorie financière. Il faudrait une alliance européenne soutenue politiquement, financée sur vingt ou trente ans, pour espérer rattraper. On a essayé avec Gaia-X. Le résultat parle de lui-même. -Pour Orange, la situation se résume donc à un dilemme stratégique. S’en tenir strictement à des solutions européennes aujourd’hui impliquerait souvent de renoncer à certains niveaux de performance, de standardisation et de rapidité d’innovation. Dans un marché des télécoms déjà très concurrentiel, où les marges sont sous pression et où les attentes des clients sont toujours plus élevées, ce choix pourrait fragiliser l’entreprise à court et moyen terme. À l’inverse, s’appuyer sur les clouds américains permet de rester compétitif, mais au prix d’une dépendance qui pose problème à long terme. +Du coup, Orange est coincé. Tout miser sur l'européen aujourd'hui, ça veut dire accepter des services moins performants, moins riches, et perdre du terrain face à ses concurrents qui, eux, n'auront pas ces scrupules. Dans un marché où les marges fondent et où chaque innovation compte, c'est un pari risqué. Continuer avec les Américains, c'est rester dans la course mais accepter une dépendance qui peut, du jour au lendemain, devenir un problème géopolitique. -C’est dans cet entre-deux qu’émergent les stratégies hybrides. Orange, comme d’autres grands groupes européens, cherche à concilier deux impératifs contradictoires. D’un côté, tirer parti de la puissance des hyperscalers pour les usages nécessitant de la flexibilité, de l’innovation rapide et une échelle mondiale. De l’autre, développer des environnements de confiance pour les données sensibles, souvent en partenariat avec des acteurs européens, afin de garantir une maîtrise juridique et opérationnelle renforcée. Cette approche permet de limiter les risques sans renoncer totalement aux avantages technologiques des géants américains. +D'où la solution batarde que tout le monde adopte : l'hybride. On met chez Amazon ou Microsoft ce qui doit aller vite, innover, scaler. On garde en Europe, parfois sur des clouds "de confiance" labellisés SecNumCloud, ce qui touche aux données sensibles, aux clients régulés, à l'État. Ce n'est pas glorieux, mais ça permet de tenir les deux bouts. -Pour celles et ceux qui défendent activement la souveraineté numérique, ce compromis reste frustrant. Il donne l’impression d’un renoncement progressif, d’une Europe qui accepte de jouer sur un terrain défini par d’autres. Pourtant, le problème dépasse largement Orange. Il interroge la capacité collective du continent à se doter d’infrastructures numériques stratégiques, au même titre que l’énergie, la défense ou les transports. Tant que le cloud restera perçu uniquement comme un marché et non comme un enjeu de souveraineté, les décisions resteront dictées par des logiques de court terme. +Pour les défenseurs de la souveraineté numérique, ce compromis a un goût amer. On a l'impression d'une Europe qui se résigne, qui joue le match sur le terrain de l'adversaire avec ses règles. Mais en pointant Orange du doigt, on rate la cible. Le vrai problème n'est pas dans les choix d'une entreprise, il est en amont. Tant qu'on traitera le cloud comme un simple marché et pas comme une infrastructure critique, au même titre que l'électricité ou les chemins de fer, les industriels feront ce qu'ils ont toujours fait : choisir ce qui marche, là, maintenant. -La vraie question n’est donc pas de savoir pourquoi Orange utilise les clouds américains, mais pourquoi l’Europe n’a pas encore su créer un cadre suffisamment ambitieux pour rendre ce choix inutile. Tant que les alternatives souveraines resteront fragmentées, sous-financées ou cantonnées à des niches, les grands groupes continueront à faire des choix pragmatiques, même s’ils sont stratégiquement inconfortables. Défendre la souveraineté numérique, ce n’est pas seulement pointer les risques de dépendance, c’est aussi accepter que cette souveraineté a un coût, qu’elle nécessite des investissements lourds, une vision industrielle de long terme et une véritable volonté politique. - -Dans ce contexte, le combat pour la souveraineté numérique n’est pas perdu, mais il reste à mener sur un autre terrain que celui des seules décisions d’entreprise. Il se joue au niveau des États, de l’Union européenne et des grandes orientations industrielles. Tant que ce cadre n’évoluera pas, même les acteurs les plus attachés à l’indépendance technologique continueront à avancer dans ce paradoxe : défendre la souveraineté dans le discours, tout en dépendant, dans les faits, des infrastructures des géants américains. +La bonne question n'est donc pas "pourquoi Orange utilise AWS". Elle est "pourquoi, vingt ans après l'arrivée du cloud, l'Europe n'a toujours pas mis sur la table de quoi rendre ce choix évitable". La souveraineté ne se décrète pas dans des communiqués. Elle se paie. En milliards, en années, en décisions politiques qui survivent aux changements de gouvernement. Tant qu'on ne sera pas prêts à ce niveau d'engagement, on continuera à tenir un discours sur l'indépendance numérique en signant des contrats avec Seattle et Redmond. \ No newline at end of file diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/meta.json b/data/75bf96ba-e110-4a9e-8163-95890562aecf/meta.json index f918311..903d92b 100644 --- a/data/75bf96ba-e110-4a9e-8163-95890562aecf/meta.json +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/meta.json @@ -1,13 +1,149 @@ { "uuid": "75bf96ba-e110-4a9e-8163-95890562aecf", "slug": "souverainete-numerique-le-paradoxe-d-orange-face-aux-clouds-americains", - "title": "Souveraineté numérique : le paradoxe d’Orange face aux clouds américains", + "title": "Orange dans les bras d'Amazon : l'aveu d'un échec européen", "author": "cedric@abonnel.fr", "published": true, - "published_at": "2026-01-16 11:17:19", + "published_at": "2026-01-16 11:17", "created_at": "2026-01-16 11:17:19", - "updated_at": "2026-01-16 11:17:19", - "revisions": [], + "updated_at": "2026-05-11 21:44:15", + "revisions": [ + { + "n": 1, + "date": "2026-05-11 19:14:47", + "comment": "", + "title": "Souveraineté numérique : le paradoxe d’Orange face aux clouds américains" + }, + { + "n": 2, + "date": "2026-05-11 19:16:11", + "comment": "", + "title": "Souveraineté numérique : le paradoxe d’Orange face aux clouds américains" + }, + { + "n": 3, + "date": "2026-05-11 19:19:14", + "comment": "", + "title": "Souveraineté numérique : le paradoxe d’Orange face aux clouds américains" + }, + { + "n": 4, + "date": "2026-05-11 19:23:36", + "comment": "", + "title": "Souveraineté numérique : le paradoxe d’Orange face aux clouds américains" + }, + { + "n": 5, + "date": "2026-05-11 20:03:18", + "comment": "", + "title": "Souveraineté numérique : le paradoxe d’Orange face aux clouds américains" + }, + { + "n": 6, + "date": "2026-05-11 20:04:17", + "comment": "", + "title": "Souveraineté numérique : le paradoxe d’Orange face aux clouds américains" + }, + { + "n": 7, + "date": "2026-05-11 20:22:36", + "comment": "", + "title": "Souveraineté numérique : le paradoxe d’Orange face aux clouds américains" + }, + { + "n": 8, + "date": "2026-05-11 20:23:25", + "comment": "", + "title": "Souveraineté numérique : le paradoxe d’Orange face aux clouds américains" + }, + { + "n": 9, + "date": "2026-05-11 21:37:25", + "comment": "", + "title": "Orange dans les bras d'Amazon : l'aveu d'un échec européen" + }, + { + "n": 10, + "date": "2026-05-11 21:38:02", + "comment": "", + "title": "Orange dans les bras d'Amazon : l'aveu d'un échec européen" + }, + { + "n": 11, + "date": "2026-05-11 21:39:10", + "comment": "", + "title": "Orange dans les bras d'Amazon : l'aveu d'un échec européen" + }, + { + "n": 12, + "date": "2026-05-11 21:40:24", + "comment": "", + "title": "Orange dans les bras d'Amazon : l'aveu d'un échec européen" + }, + { + "n": 13, + "date": "2026-05-11 21:43:18", + "comment": "", + "title": "Orange dans les bras d'Amazon : l'aveu d'un échec européen" + }, + { + "n": 14, + "date": "2026-05-11 21:44:15", + "comment": "", + "title": "Orange dans les bras d'Amazon : l'aveu d'un échec européen" + } + ], "cover": "cover.jpg", + "files_meta": { + "cover.jpg": { + "author": "", + "source_url": "https://blog.wescale.fr/hubfs/CloudUS-Europe.jpg" + }, + "l17cenum2526028_compte-rendu.pdf": { + "author": "", + "source_url": "https://www.assemblee-nationale.fr/dyn/17/comptes-rendus/cenum/l17cenum2526028_compte-rendu.pdf" + }, + "l17cenum2526028_compte-rendu_1.pdf": { + "author": "", + "source_url": "https://www.assemblee-nationale.fr/dyn/17/comptes-rendus/cenum/l17cenum2526028_compte-rendu.pdf" + }, + "Etude-Asteres-La-dependance-technologique-aux-services-de-cloud-et-logiciels-americains-avril-2025.pdf": { + "author": "", + "source_url": "https://www.cigref.fr/wp/wp-content/uploads/2025/04/Etude-Asteres-La-dependance-technologique-aux-services-de-cloud-et-logiciels-americains-avril-2025.pdf" + } + }, + "external_links": [ + { + "url": "https://www.lemondeinformatique.fr/les-dossiers/lire-cloud-souverain-une-interpretation-a-geometrie-variable-1678.html", + "name": "Cloud souverain, une interprétation à géométrie variable", + "added_at": "2026-05-11 21:40:20", + "meta": { + "mime": "text/html", + "size": 73778, + "description": "La bataille des clouds pour la souveraineté - Cloud souverain, une interprétation à géométrie variable - ", + "og_image": "/file?uuid=75bf96ba-e110-4a9e-8163-95890562aecf&name=_thumb_f44a2f694f44f2a5-11682.jpg", + "site_name": "LeMondeInformatique", + "og_type": "article", + "canonical": "https://www.lemondeinformatique.fr/les-dossiers/lire-cloud-souverain-une-interpretation-a-geometrie-variable-1678.html" + } + }, + { + "url": "https://www.assemblee-nationale.fr/dyn/17/comptes-rendus/cenum/l17cenum2526028_compte-rendu.pdf", + "name": "Commission d’enquête sur les dépendances structurelles et les vulnérabilités systémiques dans le secteur du numérique et les risques pour l’indépendance de la France", + "added_at": "2026-05-11 21:44:12", + "meta": { + "mime": "application/pdf", + "size": 659476, + "date": "2026-05-06 16:38:24+02:00", + "creator": "pdftk 2.02 - www.pdftk.com", + "producer": "itext-paulo-155 (itextpdf.sf.net-lowagie.com)", + "pages": 26, + "pdf_version": "PDF 1.7" + } + } + ], + "seo_title": "", + "seo_description": "", + "og_image": "", "category": "actualité" } diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0001.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0001.md new file mode 100644 index 0000000..f62b020 --- /dev/null +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0001.md @@ -0,0 +1,19 @@ +À première vue, la situation a quelque chose de déroutant. Orange, opérateur historique français, héritier d’une longue tradition de service public et acteur stratégique des télécommunications, fait massivement appel aux infrastructures cloud d’Amazon, Microsoft ou Google. Dans un contexte où la souveraineté numérique est devenue un enjeu politique, économique et géostratégique majeur, ce choix peut apparaître comme une contradiction, voire comme un renoncement. Pourtant, il ne s’agit ni d’un abandon ni d’une naïveté, mais d’un compromis révélateur des limites actuelles de l’Europe dans la bataille du numérique. + +Le recours aux hyperscalers américains s’explique d’abord par une réalité industrielle. Ces entreprises ont construit, en une quinzaine d’années, une avance quasiment irréversible en matière d’infrastructures numériques. Leurs plateformes ne se contentent plus de fournir de la puissance de calcul ou du stockage. Elles offrent un écosystème complet qui va de l’hébergement à l’intelligence artificielle, en passant par l’analyse massive de données, l’automatisation des déploiements, la cybersécurité et la résilience globale des systèmes. Pour un groupe comme Orange, qui opère dans de nombreux pays et doit garantir des niveaux de service très élevés à des millions d’utilisateurs, cette maturité technologique est un facteur décisif. + +Mais ce choix, rationnel sur le plan opérationnel, pose une question politique et stratégique beaucoup plus large. En confiant une part croissante de ses infrastructures numériques à des acteurs soumis au droit américain, Orange participe malgré lui à une forme de dépendance structurelle. Le Cloud Act, qui permet aux autorités américaines d’exiger l’accès à certaines données, même hébergées hors des États-Unis, symbolise cette vulnérabilité. Même si les mécanismes de chiffrement, de cloisonnement et de contrôle contractuel existent, le simple fait que la décision ultime puisse échapper aux juridictions européennes constitue une faille du point de vue de la souveraineté. + +Ce paradoxe est d’autant plus frappant que des alternatives européennes existent. La France et l’Europe disposent d’acteurs solides, capables de fournir des services cloud performants, sécurisés et compétitifs sur de nombreux usages. OVHcloud, Scaleway, Outscale, IONOS ou encore les initiatives portées par Deutsche Telekom en sont la preuve. Alors pourquoi ne pas construire une alliance massive entre ces acteurs et un groupe comme Orange pour bâtir une véritable alternative souveraine ? + +La réponse tient moins à la volonté qu’à l’échelle. Les hyperscalers américains investissent chaque année des dizaines de milliards d’euros dans leurs infrastructures. Ils déploient des data centers sur tous les continents, possèdent leurs propres réseaux mondiaux et attirent l’essentiel des talents du secteur. Face à cette puissance financière et industrielle, les acteurs européens, pris individuellement, peinent à rivaliser. Une alliance serait possible, mais elle nécessiterait un effort coordonné, soutenu politiquement, sur plusieurs décennies. Or l’Europe avance souvent par projets fragmentés, soumis aux cycles électoraux et aux priorités nationales parfois divergentes. + +Pour Orange, la situation se résume donc à un dilemme stratégique. S’en tenir strictement à des solutions européennes aujourd’hui impliquerait souvent de renoncer à certains niveaux de performance, de standardisation et de rapidité d’innovation. Dans un marché des télécoms déjà très concurrentiel, où les marges sont sous pression et où les attentes des clients sont toujours plus élevées, ce choix pourrait fragiliser l’entreprise à court et moyen terme. À l’inverse, s’appuyer sur les clouds américains permet de rester compétitif, mais au prix d’une dépendance qui pose problème à long terme. + +C’est dans cet entre-deux qu’émergent les stratégies hybrides. Orange, comme d’autres grands groupes européens, cherche à concilier deux impératifs contradictoires. D’un côté, tirer parti de la puissance des hyperscalers pour les usages nécessitant de la flexibilité, de l’innovation rapide et une échelle mondiale. De l’autre, développer des environnements de confiance pour les données sensibles, souvent en partenariat avec des acteurs européens, afin de garantir une maîtrise juridique et opérationnelle renforcée. Cette approche permet de limiter les risques sans renoncer totalement aux avantages technologiques des géants américains. + +Pour celles et ceux qui défendent activement la souveraineté numérique, ce compromis reste frustrant. Il donne l’impression d’un renoncement progressif, d’une Europe qui accepte de jouer sur un terrain défini par d’autres. Pourtant, le problème dépasse largement Orange. Il interroge la capacité collective du continent à se doter d’infrastructures numériques stratégiques, au même titre que l’énergie, la défense ou les transports. Tant que le cloud restera perçu uniquement comme un marché et non comme un enjeu de souveraineté, les décisions resteront dictées par des logiques de court terme. + +La vraie question n’est donc pas de savoir pourquoi Orange utilise les clouds américains, mais pourquoi l’Europe n’a pas encore su créer un cadre suffisamment ambitieux pour rendre ce choix inutile. Tant que les alternatives souveraines resteront fragmentées, sous-financées ou cantonnées à des niches, les grands groupes continueront à faire des choix pragmatiques, même s’ils sont stratégiquement inconfortables. Défendre la souveraineté numérique, ce n’est pas seulement pointer les risques de dépendance, c’est aussi accepter que cette souveraineté a un coût, qu’elle nécessite des investissements lourds, une vision industrielle de long terme et une véritable volonté politique. + +Dans ce contexte, le combat pour la souveraineté numérique n’est pas perdu, mais il reste à mener sur un autre terrain que celui des seules décisions d’entreprise. Il se joue au niveau des États, de l’Union européenne et des grandes orientations industrielles. Tant que ce cadre n’évoluera pas, même les acteurs les plus attachés à l’indépendance technologique continueront à avancer dans ce paradoxe : défendre la souveraineté dans le discours, tout en dépendant, dans les faits, des infrastructures des géants américains. diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0002.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0002.md new file mode 100644 index 0000000..f62b020 --- /dev/null +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0002.md @@ -0,0 +1,19 @@ +À première vue, la situation a quelque chose de déroutant. Orange, opérateur historique français, héritier d’une longue tradition de service public et acteur stratégique des télécommunications, fait massivement appel aux infrastructures cloud d’Amazon, Microsoft ou Google. Dans un contexte où la souveraineté numérique est devenue un enjeu politique, économique et géostratégique majeur, ce choix peut apparaître comme une contradiction, voire comme un renoncement. Pourtant, il ne s’agit ni d’un abandon ni d’une naïveté, mais d’un compromis révélateur des limites actuelles de l’Europe dans la bataille du numérique. + +Le recours aux hyperscalers américains s’explique d’abord par une réalité industrielle. Ces entreprises ont construit, en une quinzaine d’années, une avance quasiment irréversible en matière d’infrastructures numériques. Leurs plateformes ne se contentent plus de fournir de la puissance de calcul ou du stockage. Elles offrent un écosystème complet qui va de l’hébergement à l’intelligence artificielle, en passant par l’analyse massive de données, l’automatisation des déploiements, la cybersécurité et la résilience globale des systèmes. Pour un groupe comme Orange, qui opère dans de nombreux pays et doit garantir des niveaux de service très élevés à des millions d’utilisateurs, cette maturité technologique est un facteur décisif. + +Mais ce choix, rationnel sur le plan opérationnel, pose une question politique et stratégique beaucoup plus large. En confiant une part croissante de ses infrastructures numériques à des acteurs soumis au droit américain, Orange participe malgré lui à une forme de dépendance structurelle. Le Cloud Act, qui permet aux autorités américaines d’exiger l’accès à certaines données, même hébergées hors des États-Unis, symbolise cette vulnérabilité. Même si les mécanismes de chiffrement, de cloisonnement et de contrôle contractuel existent, le simple fait que la décision ultime puisse échapper aux juridictions européennes constitue une faille du point de vue de la souveraineté. + +Ce paradoxe est d’autant plus frappant que des alternatives européennes existent. La France et l’Europe disposent d’acteurs solides, capables de fournir des services cloud performants, sécurisés et compétitifs sur de nombreux usages. OVHcloud, Scaleway, Outscale, IONOS ou encore les initiatives portées par Deutsche Telekom en sont la preuve. Alors pourquoi ne pas construire une alliance massive entre ces acteurs et un groupe comme Orange pour bâtir une véritable alternative souveraine ? + +La réponse tient moins à la volonté qu’à l’échelle. Les hyperscalers américains investissent chaque année des dizaines de milliards d’euros dans leurs infrastructures. Ils déploient des data centers sur tous les continents, possèdent leurs propres réseaux mondiaux et attirent l’essentiel des talents du secteur. Face à cette puissance financière et industrielle, les acteurs européens, pris individuellement, peinent à rivaliser. Une alliance serait possible, mais elle nécessiterait un effort coordonné, soutenu politiquement, sur plusieurs décennies. Or l’Europe avance souvent par projets fragmentés, soumis aux cycles électoraux et aux priorités nationales parfois divergentes. + +Pour Orange, la situation se résume donc à un dilemme stratégique. S’en tenir strictement à des solutions européennes aujourd’hui impliquerait souvent de renoncer à certains niveaux de performance, de standardisation et de rapidité d’innovation. Dans un marché des télécoms déjà très concurrentiel, où les marges sont sous pression et où les attentes des clients sont toujours plus élevées, ce choix pourrait fragiliser l’entreprise à court et moyen terme. À l’inverse, s’appuyer sur les clouds américains permet de rester compétitif, mais au prix d’une dépendance qui pose problème à long terme. + +C’est dans cet entre-deux qu’émergent les stratégies hybrides. Orange, comme d’autres grands groupes européens, cherche à concilier deux impératifs contradictoires. D’un côté, tirer parti de la puissance des hyperscalers pour les usages nécessitant de la flexibilité, de l’innovation rapide et une échelle mondiale. De l’autre, développer des environnements de confiance pour les données sensibles, souvent en partenariat avec des acteurs européens, afin de garantir une maîtrise juridique et opérationnelle renforcée. Cette approche permet de limiter les risques sans renoncer totalement aux avantages technologiques des géants américains. + +Pour celles et ceux qui défendent activement la souveraineté numérique, ce compromis reste frustrant. Il donne l’impression d’un renoncement progressif, d’une Europe qui accepte de jouer sur un terrain défini par d’autres. Pourtant, le problème dépasse largement Orange. Il interroge la capacité collective du continent à se doter d’infrastructures numériques stratégiques, au même titre que l’énergie, la défense ou les transports. Tant que le cloud restera perçu uniquement comme un marché et non comme un enjeu de souveraineté, les décisions resteront dictées par des logiques de court terme. + +La vraie question n’est donc pas de savoir pourquoi Orange utilise les clouds américains, mais pourquoi l’Europe n’a pas encore su créer un cadre suffisamment ambitieux pour rendre ce choix inutile. Tant que les alternatives souveraines resteront fragmentées, sous-financées ou cantonnées à des niches, les grands groupes continueront à faire des choix pragmatiques, même s’ils sont stratégiquement inconfortables. Défendre la souveraineté numérique, ce n’est pas seulement pointer les risques de dépendance, c’est aussi accepter que cette souveraineté a un coût, qu’elle nécessite des investissements lourds, une vision industrielle de long terme et une véritable volonté politique. + +Dans ce contexte, le combat pour la souveraineté numérique n’est pas perdu, mais il reste à mener sur un autre terrain que celui des seules décisions d’entreprise. Il se joue au niveau des États, de l’Union européenne et des grandes orientations industrielles. Tant que ce cadre n’évoluera pas, même les acteurs les plus attachés à l’indépendance technologique continueront à avancer dans ce paradoxe : défendre la souveraineté dans le discours, tout en dépendant, dans les faits, des infrastructures des géants américains. diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0003.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0003.md new file mode 100644 index 0000000..4790584 --- /dev/null +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0003.md @@ -0,0 +1,20 @@ +À première vue, la situation a quelque chose de déroutant. Orange, opérateur historique français, héritier d’une longue tradition de service public et acteur stratégique des télécommunications, fait massivement appel aux infrastructures cloud d’Amazon, Microsoft ou Google. Dans un contexte où la souveraineté numérique est devenue un enjeu politique, économique et géostratégique majeur, ce choix peut apparaître comme une contradiction, voire comme un renoncement. Pourtant, il ne s’agit ni d’un abandon ni d’une naïveté, mais d’un compromis révélateur des limites actuelles de l’Europe dans la bataille du numérique. + +Le recours aux hyperscalers américains s’explique d’abord par une réalité industrielle. Ces entreprises ont construit, en une quinzaine d’années, une avance quasiment irréversible en matière d’infrastructures numériques. Leurs plateformes ne se contentent plus de fournir de la puissance de calcul ou du stockage. Elles offrent un écosystème complet qui va de l’hébergement à l’intelligence artificielle, en passant par l’analyse massive de données, l’automatisation des déploiements, la cybersécurité et la résilience globale des systèmes. Pour un groupe comme Orange, qui opère dans de nombreux pays et doit garantir des niveaux de service très élevés à des millions d’utilisateurs, cette maturité technologique est un facteur décisif. + +Mais ce choix, rationnel sur le plan opérationnel, pose une question politique et stratégique beaucoup plus large. En confiant une part croissante de ses infrastructures numériques à des acteurs soumis au droit américain, Orange participe malgré lui à une forme de dépendance structurelle. Le Cloud Act, qui permet aux autorités américaines d’exiger l’accès à certaines données, même hébergées hors des États-Unis, symbolise cette vulnérabilité. Même si les mécanismes de chiffrement, de cloisonnement et de contrôle contractuel existent, le simple fait que la décision ultime puisse échapper aux juridictions européennes constitue une faille du point de vue de la souveraineté. + +Ce paradoxe est d’autant plus frappant que des alternatives européennes existent. La France et l’Europe disposent d’acteurs solides, capables de fournir des services cloud performants, sécurisés et compétitifs sur de nombreux usages. OVHcloud, Scaleway, Outscale, IONOS ou encore les initiatives portées par Deutsche Telekom en sont la preuve. Alors pourquoi ne pas construire une alliance massive entre ces acteurs et un groupe comme Orange pour bâtir une véritable alternative souveraine ? + +La réponse tient moins à la volonté qu’à l’échelle. Les hyperscalers américains investissent chaque année des dizaines de milliards d’euros dans leurs infrastructures. Ils déploient des data centers sur tous les continents, possèdent leurs propres réseaux mondiaux et attirent l’essentiel des talents du secteur. Face à cette puissance financière et industrielle, les acteurs européens, pris individuellement, peinent à rivaliser. Une alliance serait possible, mais elle nécessiterait un effort coordonné, soutenu politiquement, sur plusieurs décennies. Or l’Europe avance souvent par projets fragmentés, soumis aux cycles électoraux et aux priorités nationales parfois divergentes. + +Pour Orange, la situation se résume donc à un dilemme stratégique. S’en tenir strictement à des solutions européennes aujourd’hui impliquerait souvent de renoncer à certains niveaux de performance, de standardisation et de rapidité d’innovation. Dans un marché des télécoms déjà très concurrentiel, où les marges sont sous pression et où les attentes des clients sont toujours plus élevées, ce choix pourrait fragiliser l’entreprise à court et moyen terme. À l’inverse, s’appuyer sur les clouds américains permet de rester compétitif, mais au prix d’une dépendance qui pose problème à long terme. + +C’est dans cet entre-deux qu’émergent les stratégies hybrides. Orange, comme d’autres grands groupes européens, cherche à concilier deux impératifs contradictoires. D’un côté, tirer parti de la puissance des hyperscalers pour les usages nécessitant de la flexibilité, de l’innovation rapide et une échelle mondiale. De l’autre, développer des environnements de confiance pour les données sensibles, souvent en partenariat avec des acteurs européens, afin de garantir une maîtrise juridique et opérationnelle renforcée. Cette approche permet de limiter les risques sans renoncer totalement aux avantages technologiques des géants américains. + +Pour celles et ceux qui défendent activement la souveraineté numérique, ce compromis reste frustrant. Il donne l’impression d’un renoncement progressif, d’une Europe qui accepte de jouer sur un terrain défini par d’autres. Pourtant, le problème dépasse largement Orange. Il interroge la capacité collective du continent à se doter d’infrastructures numériques stratégiques, au même titre que l’énergie, la défense ou les transports. Tant que le cloud restera perçu uniquement comme un marché et non comme un enjeu de souveraineté, les décisions resteront dictées par des logiques de court terme. + +La vraie question n’est donc pas de savoir pourquoi Orange utilise les clouds américains, mais pourquoi l’Europe n’a pas encore su créer un cadre suffisamment ambitieux pour rendre ce choix inutile. Tant que les alternatives souveraines resteront fragmentées, sous-financées ou cantonnées à des niches, les grands groupes continueront à faire des choix pragmatiques, même s’ils sont stratégiquement inconfortables. Défendre la souveraineté numérique, ce n’est pas seulement pointer les risques de dépendance, c’est aussi accepter que cette souveraineté a un coût, qu’elle nécessite des investissements lourds, une vision industrielle de long terme et une véritable volonté politique. + +Dans ce contexte, le combat pour la souveraineté numérique n’est pas perdu, mais il reste à mener sur un autre terrain que celui des seules décisions d’entreprise. Il se joue au niveau des États, de l’Union européenne et des grandes orientations industrielles. Tant que ce cadre n’évoluera pas, même les acteurs les plus attachés à l’indépendance technologique continueront à avancer dans ce paradoxe : défendre la souveraineté dans le discours, tout en dépendant, dans les faits, des infrastructures des géants américains. + diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0004.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0004.md new file mode 100644 index 0000000..4790584 --- /dev/null +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0004.md @@ -0,0 +1,20 @@ +À première vue, la situation a quelque chose de déroutant. Orange, opérateur historique français, héritier d’une longue tradition de service public et acteur stratégique des télécommunications, fait massivement appel aux infrastructures cloud d’Amazon, Microsoft ou Google. Dans un contexte où la souveraineté numérique est devenue un enjeu politique, économique et géostratégique majeur, ce choix peut apparaître comme une contradiction, voire comme un renoncement. Pourtant, il ne s’agit ni d’un abandon ni d’une naïveté, mais d’un compromis révélateur des limites actuelles de l’Europe dans la bataille du numérique. + +Le recours aux hyperscalers américains s’explique d’abord par une réalité industrielle. Ces entreprises ont construit, en une quinzaine d’années, une avance quasiment irréversible en matière d’infrastructures numériques. Leurs plateformes ne se contentent plus de fournir de la puissance de calcul ou du stockage. Elles offrent un écosystème complet qui va de l’hébergement à l’intelligence artificielle, en passant par l’analyse massive de données, l’automatisation des déploiements, la cybersécurité et la résilience globale des systèmes. Pour un groupe comme Orange, qui opère dans de nombreux pays et doit garantir des niveaux de service très élevés à des millions d’utilisateurs, cette maturité technologique est un facteur décisif. + +Mais ce choix, rationnel sur le plan opérationnel, pose une question politique et stratégique beaucoup plus large. En confiant une part croissante de ses infrastructures numériques à des acteurs soumis au droit américain, Orange participe malgré lui à une forme de dépendance structurelle. Le Cloud Act, qui permet aux autorités américaines d’exiger l’accès à certaines données, même hébergées hors des États-Unis, symbolise cette vulnérabilité. Même si les mécanismes de chiffrement, de cloisonnement et de contrôle contractuel existent, le simple fait que la décision ultime puisse échapper aux juridictions européennes constitue une faille du point de vue de la souveraineté. + +Ce paradoxe est d’autant plus frappant que des alternatives européennes existent. La France et l’Europe disposent d’acteurs solides, capables de fournir des services cloud performants, sécurisés et compétitifs sur de nombreux usages. OVHcloud, Scaleway, Outscale, IONOS ou encore les initiatives portées par Deutsche Telekom en sont la preuve. Alors pourquoi ne pas construire une alliance massive entre ces acteurs et un groupe comme Orange pour bâtir une véritable alternative souveraine ? + +La réponse tient moins à la volonté qu’à l’échelle. Les hyperscalers américains investissent chaque année des dizaines de milliards d’euros dans leurs infrastructures. Ils déploient des data centers sur tous les continents, possèdent leurs propres réseaux mondiaux et attirent l’essentiel des talents du secteur. Face à cette puissance financière et industrielle, les acteurs européens, pris individuellement, peinent à rivaliser. Une alliance serait possible, mais elle nécessiterait un effort coordonné, soutenu politiquement, sur plusieurs décennies. Or l’Europe avance souvent par projets fragmentés, soumis aux cycles électoraux et aux priorités nationales parfois divergentes. + +Pour Orange, la situation se résume donc à un dilemme stratégique. S’en tenir strictement à des solutions européennes aujourd’hui impliquerait souvent de renoncer à certains niveaux de performance, de standardisation et de rapidité d’innovation. Dans un marché des télécoms déjà très concurrentiel, où les marges sont sous pression et où les attentes des clients sont toujours plus élevées, ce choix pourrait fragiliser l’entreprise à court et moyen terme. À l’inverse, s’appuyer sur les clouds américains permet de rester compétitif, mais au prix d’une dépendance qui pose problème à long terme. + +C’est dans cet entre-deux qu’émergent les stratégies hybrides. Orange, comme d’autres grands groupes européens, cherche à concilier deux impératifs contradictoires. D’un côté, tirer parti de la puissance des hyperscalers pour les usages nécessitant de la flexibilité, de l’innovation rapide et une échelle mondiale. De l’autre, développer des environnements de confiance pour les données sensibles, souvent en partenariat avec des acteurs européens, afin de garantir une maîtrise juridique et opérationnelle renforcée. Cette approche permet de limiter les risques sans renoncer totalement aux avantages technologiques des géants américains. + +Pour celles et ceux qui défendent activement la souveraineté numérique, ce compromis reste frustrant. Il donne l’impression d’un renoncement progressif, d’une Europe qui accepte de jouer sur un terrain défini par d’autres. Pourtant, le problème dépasse largement Orange. Il interroge la capacité collective du continent à se doter d’infrastructures numériques stratégiques, au même titre que l’énergie, la défense ou les transports. Tant que le cloud restera perçu uniquement comme un marché et non comme un enjeu de souveraineté, les décisions resteront dictées par des logiques de court terme. + +La vraie question n’est donc pas de savoir pourquoi Orange utilise les clouds américains, mais pourquoi l’Europe n’a pas encore su créer un cadre suffisamment ambitieux pour rendre ce choix inutile. Tant que les alternatives souveraines resteront fragmentées, sous-financées ou cantonnées à des niches, les grands groupes continueront à faire des choix pragmatiques, même s’ils sont stratégiquement inconfortables. Défendre la souveraineté numérique, ce n’est pas seulement pointer les risques de dépendance, c’est aussi accepter que cette souveraineté a un coût, qu’elle nécessite des investissements lourds, une vision industrielle de long terme et une véritable volonté politique. + +Dans ce contexte, le combat pour la souveraineté numérique n’est pas perdu, mais il reste à mener sur un autre terrain que celui des seules décisions d’entreprise. Il se joue au niveau des États, de l’Union européenne et des grandes orientations industrielles. Tant que ce cadre n’évoluera pas, même les acteurs les plus attachés à l’indépendance technologique continueront à avancer dans ce paradoxe : défendre la souveraineté dans le discours, tout en dépendant, dans les faits, des infrastructures des géants américains. + diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0005.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0005.md new file mode 100644 index 0000000..4790584 --- /dev/null +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0005.md @@ -0,0 +1,20 @@ +À première vue, la situation a quelque chose de déroutant. Orange, opérateur historique français, héritier d’une longue tradition de service public et acteur stratégique des télécommunications, fait massivement appel aux infrastructures cloud d’Amazon, Microsoft ou Google. Dans un contexte où la souveraineté numérique est devenue un enjeu politique, économique et géostratégique majeur, ce choix peut apparaître comme une contradiction, voire comme un renoncement. Pourtant, il ne s’agit ni d’un abandon ni d’une naïveté, mais d’un compromis révélateur des limites actuelles de l’Europe dans la bataille du numérique. + +Le recours aux hyperscalers américains s’explique d’abord par une réalité industrielle. Ces entreprises ont construit, en une quinzaine d’années, une avance quasiment irréversible en matière d’infrastructures numériques. Leurs plateformes ne se contentent plus de fournir de la puissance de calcul ou du stockage. Elles offrent un écosystème complet qui va de l’hébergement à l’intelligence artificielle, en passant par l’analyse massive de données, l’automatisation des déploiements, la cybersécurité et la résilience globale des systèmes. Pour un groupe comme Orange, qui opère dans de nombreux pays et doit garantir des niveaux de service très élevés à des millions d’utilisateurs, cette maturité technologique est un facteur décisif. + +Mais ce choix, rationnel sur le plan opérationnel, pose une question politique et stratégique beaucoup plus large. En confiant une part croissante de ses infrastructures numériques à des acteurs soumis au droit américain, Orange participe malgré lui à une forme de dépendance structurelle. Le Cloud Act, qui permet aux autorités américaines d’exiger l’accès à certaines données, même hébergées hors des États-Unis, symbolise cette vulnérabilité. Même si les mécanismes de chiffrement, de cloisonnement et de contrôle contractuel existent, le simple fait que la décision ultime puisse échapper aux juridictions européennes constitue une faille du point de vue de la souveraineté. + +Ce paradoxe est d’autant plus frappant que des alternatives européennes existent. La France et l’Europe disposent d’acteurs solides, capables de fournir des services cloud performants, sécurisés et compétitifs sur de nombreux usages. OVHcloud, Scaleway, Outscale, IONOS ou encore les initiatives portées par Deutsche Telekom en sont la preuve. Alors pourquoi ne pas construire une alliance massive entre ces acteurs et un groupe comme Orange pour bâtir une véritable alternative souveraine ? + +La réponse tient moins à la volonté qu’à l’échelle. Les hyperscalers américains investissent chaque année des dizaines de milliards d’euros dans leurs infrastructures. Ils déploient des data centers sur tous les continents, possèdent leurs propres réseaux mondiaux et attirent l’essentiel des talents du secteur. Face à cette puissance financière et industrielle, les acteurs européens, pris individuellement, peinent à rivaliser. Une alliance serait possible, mais elle nécessiterait un effort coordonné, soutenu politiquement, sur plusieurs décennies. Or l’Europe avance souvent par projets fragmentés, soumis aux cycles électoraux et aux priorités nationales parfois divergentes. + +Pour Orange, la situation se résume donc à un dilemme stratégique. S’en tenir strictement à des solutions européennes aujourd’hui impliquerait souvent de renoncer à certains niveaux de performance, de standardisation et de rapidité d’innovation. Dans un marché des télécoms déjà très concurrentiel, où les marges sont sous pression et où les attentes des clients sont toujours plus élevées, ce choix pourrait fragiliser l’entreprise à court et moyen terme. À l’inverse, s’appuyer sur les clouds américains permet de rester compétitif, mais au prix d’une dépendance qui pose problème à long terme. + +C’est dans cet entre-deux qu’émergent les stratégies hybrides. Orange, comme d’autres grands groupes européens, cherche à concilier deux impératifs contradictoires. D’un côté, tirer parti de la puissance des hyperscalers pour les usages nécessitant de la flexibilité, de l’innovation rapide et une échelle mondiale. De l’autre, développer des environnements de confiance pour les données sensibles, souvent en partenariat avec des acteurs européens, afin de garantir une maîtrise juridique et opérationnelle renforcée. Cette approche permet de limiter les risques sans renoncer totalement aux avantages technologiques des géants américains. + +Pour celles et ceux qui défendent activement la souveraineté numérique, ce compromis reste frustrant. Il donne l’impression d’un renoncement progressif, d’une Europe qui accepte de jouer sur un terrain défini par d’autres. Pourtant, le problème dépasse largement Orange. Il interroge la capacité collective du continent à se doter d’infrastructures numériques stratégiques, au même titre que l’énergie, la défense ou les transports. Tant que le cloud restera perçu uniquement comme un marché et non comme un enjeu de souveraineté, les décisions resteront dictées par des logiques de court terme. + +La vraie question n’est donc pas de savoir pourquoi Orange utilise les clouds américains, mais pourquoi l’Europe n’a pas encore su créer un cadre suffisamment ambitieux pour rendre ce choix inutile. Tant que les alternatives souveraines resteront fragmentées, sous-financées ou cantonnées à des niches, les grands groupes continueront à faire des choix pragmatiques, même s’ils sont stratégiquement inconfortables. Défendre la souveraineté numérique, ce n’est pas seulement pointer les risques de dépendance, c’est aussi accepter que cette souveraineté a un coût, qu’elle nécessite des investissements lourds, une vision industrielle de long terme et une véritable volonté politique. + +Dans ce contexte, le combat pour la souveraineté numérique n’est pas perdu, mais il reste à mener sur un autre terrain que celui des seules décisions d’entreprise. Il se joue au niveau des États, de l’Union européenne et des grandes orientations industrielles. Tant que ce cadre n’évoluera pas, même les acteurs les plus attachés à l’indépendance technologique continueront à avancer dans ce paradoxe : défendre la souveraineté dans le discours, tout en dépendant, dans les faits, des infrastructures des géants américains. + diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0006.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0006.md new file mode 100644 index 0000000..4790584 --- /dev/null +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0006.md @@ -0,0 +1,20 @@ +À première vue, la situation a quelque chose de déroutant. Orange, opérateur historique français, héritier d’une longue tradition de service public et acteur stratégique des télécommunications, fait massivement appel aux infrastructures cloud d’Amazon, Microsoft ou Google. Dans un contexte où la souveraineté numérique est devenue un enjeu politique, économique et géostratégique majeur, ce choix peut apparaître comme une contradiction, voire comme un renoncement. Pourtant, il ne s’agit ni d’un abandon ni d’une naïveté, mais d’un compromis révélateur des limites actuelles de l’Europe dans la bataille du numérique. + +Le recours aux hyperscalers américains s’explique d’abord par une réalité industrielle. Ces entreprises ont construit, en une quinzaine d’années, une avance quasiment irréversible en matière d’infrastructures numériques. Leurs plateformes ne se contentent plus de fournir de la puissance de calcul ou du stockage. Elles offrent un écosystème complet qui va de l’hébergement à l’intelligence artificielle, en passant par l’analyse massive de données, l’automatisation des déploiements, la cybersécurité et la résilience globale des systèmes. Pour un groupe comme Orange, qui opère dans de nombreux pays et doit garantir des niveaux de service très élevés à des millions d’utilisateurs, cette maturité technologique est un facteur décisif. + +Mais ce choix, rationnel sur le plan opérationnel, pose une question politique et stratégique beaucoup plus large. En confiant une part croissante de ses infrastructures numériques à des acteurs soumis au droit américain, Orange participe malgré lui à une forme de dépendance structurelle. Le Cloud Act, qui permet aux autorités américaines d’exiger l’accès à certaines données, même hébergées hors des États-Unis, symbolise cette vulnérabilité. Même si les mécanismes de chiffrement, de cloisonnement et de contrôle contractuel existent, le simple fait que la décision ultime puisse échapper aux juridictions européennes constitue une faille du point de vue de la souveraineté. + +Ce paradoxe est d’autant plus frappant que des alternatives européennes existent. La France et l’Europe disposent d’acteurs solides, capables de fournir des services cloud performants, sécurisés et compétitifs sur de nombreux usages. OVHcloud, Scaleway, Outscale, IONOS ou encore les initiatives portées par Deutsche Telekom en sont la preuve. Alors pourquoi ne pas construire une alliance massive entre ces acteurs et un groupe comme Orange pour bâtir une véritable alternative souveraine ? + +La réponse tient moins à la volonté qu’à l’échelle. Les hyperscalers américains investissent chaque année des dizaines de milliards d’euros dans leurs infrastructures. Ils déploient des data centers sur tous les continents, possèdent leurs propres réseaux mondiaux et attirent l’essentiel des talents du secteur. Face à cette puissance financière et industrielle, les acteurs européens, pris individuellement, peinent à rivaliser. Une alliance serait possible, mais elle nécessiterait un effort coordonné, soutenu politiquement, sur plusieurs décennies. Or l’Europe avance souvent par projets fragmentés, soumis aux cycles électoraux et aux priorités nationales parfois divergentes. + +Pour Orange, la situation se résume donc à un dilemme stratégique. S’en tenir strictement à des solutions européennes aujourd’hui impliquerait souvent de renoncer à certains niveaux de performance, de standardisation et de rapidité d’innovation. Dans un marché des télécoms déjà très concurrentiel, où les marges sont sous pression et où les attentes des clients sont toujours plus élevées, ce choix pourrait fragiliser l’entreprise à court et moyen terme. À l’inverse, s’appuyer sur les clouds américains permet de rester compétitif, mais au prix d’une dépendance qui pose problème à long terme. + +C’est dans cet entre-deux qu’émergent les stratégies hybrides. Orange, comme d’autres grands groupes européens, cherche à concilier deux impératifs contradictoires. D’un côté, tirer parti de la puissance des hyperscalers pour les usages nécessitant de la flexibilité, de l’innovation rapide et une échelle mondiale. De l’autre, développer des environnements de confiance pour les données sensibles, souvent en partenariat avec des acteurs européens, afin de garantir une maîtrise juridique et opérationnelle renforcée. Cette approche permet de limiter les risques sans renoncer totalement aux avantages technologiques des géants américains. + +Pour celles et ceux qui défendent activement la souveraineté numérique, ce compromis reste frustrant. Il donne l’impression d’un renoncement progressif, d’une Europe qui accepte de jouer sur un terrain défini par d’autres. Pourtant, le problème dépasse largement Orange. Il interroge la capacité collective du continent à se doter d’infrastructures numériques stratégiques, au même titre que l’énergie, la défense ou les transports. Tant que le cloud restera perçu uniquement comme un marché et non comme un enjeu de souveraineté, les décisions resteront dictées par des logiques de court terme. + +La vraie question n’est donc pas de savoir pourquoi Orange utilise les clouds américains, mais pourquoi l’Europe n’a pas encore su créer un cadre suffisamment ambitieux pour rendre ce choix inutile. Tant que les alternatives souveraines resteront fragmentées, sous-financées ou cantonnées à des niches, les grands groupes continueront à faire des choix pragmatiques, même s’ils sont stratégiquement inconfortables. Défendre la souveraineté numérique, ce n’est pas seulement pointer les risques de dépendance, c’est aussi accepter que cette souveraineté a un coût, qu’elle nécessite des investissements lourds, une vision industrielle de long terme et une véritable volonté politique. + +Dans ce contexte, le combat pour la souveraineté numérique n’est pas perdu, mais il reste à mener sur un autre terrain que celui des seules décisions d’entreprise. Il se joue au niveau des États, de l’Union européenne et des grandes orientations industrielles. Tant que ce cadre n’évoluera pas, même les acteurs les plus attachés à l’indépendance technologique continueront à avancer dans ce paradoxe : défendre la souveraineté dans le discours, tout en dépendant, dans les faits, des infrastructures des géants américains. + diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0007.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0007.md new file mode 100644 index 0000000..4790584 --- /dev/null +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0007.md @@ -0,0 +1,20 @@ +À première vue, la situation a quelque chose de déroutant. Orange, opérateur historique français, héritier d’une longue tradition de service public et acteur stratégique des télécommunications, fait massivement appel aux infrastructures cloud d’Amazon, Microsoft ou Google. Dans un contexte où la souveraineté numérique est devenue un enjeu politique, économique et géostratégique majeur, ce choix peut apparaître comme une contradiction, voire comme un renoncement. Pourtant, il ne s’agit ni d’un abandon ni d’une naïveté, mais d’un compromis révélateur des limites actuelles de l’Europe dans la bataille du numérique. + +Le recours aux hyperscalers américains s’explique d’abord par une réalité industrielle. Ces entreprises ont construit, en une quinzaine d’années, une avance quasiment irréversible en matière d’infrastructures numériques. Leurs plateformes ne se contentent plus de fournir de la puissance de calcul ou du stockage. Elles offrent un écosystème complet qui va de l’hébergement à l’intelligence artificielle, en passant par l’analyse massive de données, l’automatisation des déploiements, la cybersécurité et la résilience globale des systèmes. Pour un groupe comme Orange, qui opère dans de nombreux pays et doit garantir des niveaux de service très élevés à des millions d’utilisateurs, cette maturité technologique est un facteur décisif. + +Mais ce choix, rationnel sur le plan opérationnel, pose une question politique et stratégique beaucoup plus large. En confiant une part croissante de ses infrastructures numériques à des acteurs soumis au droit américain, Orange participe malgré lui à une forme de dépendance structurelle. Le Cloud Act, qui permet aux autorités américaines d’exiger l’accès à certaines données, même hébergées hors des États-Unis, symbolise cette vulnérabilité. Même si les mécanismes de chiffrement, de cloisonnement et de contrôle contractuel existent, le simple fait que la décision ultime puisse échapper aux juridictions européennes constitue une faille du point de vue de la souveraineté. + +Ce paradoxe est d’autant plus frappant que des alternatives européennes existent. La France et l’Europe disposent d’acteurs solides, capables de fournir des services cloud performants, sécurisés et compétitifs sur de nombreux usages. OVHcloud, Scaleway, Outscale, IONOS ou encore les initiatives portées par Deutsche Telekom en sont la preuve. Alors pourquoi ne pas construire une alliance massive entre ces acteurs et un groupe comme Orange pour bâtir une véritable alternative souveraine ? + +La réponse tient moins à la volonté qu’à l’échelle. Les hyperscalers américains investissent chaque année des dizaines de milliards d’euros dans leurs infrastructures. Ils déploient des data centers sur tous les continents, possèdent leurs propres réseaux mondiaux et attirent l’essentiel des talents du secteur. Face à cette puissance financière et industrielle, les acteurs européens, pris individuellement, peinent à rivaliser. Une alliance serait possible, mais elle nécessiterait un effort coordonné, soutenu politiquement, sur plusieurs décennies. Or l’Europe avance souvent par projets fragmentés, soumis aux cycles électoraux et aux priorités nationales parfois divergentes. + +Pour Orange, la situation se résume donc à un dilemme stratégique. S’en tenir strictement à des solutions européennes aujourd’hui impliquerait souvent de renoncer à certains niveaux de performance, de standardisation et de rapidité d’innovation. Dans un marché des télécoms déjà très concurrentiel, où les marges sont sous pression et où les attentes des clients sont toujours plus élevées, ce choix pourrait fragiliser l’entreprise à court et moyen terme. À l’inverse, s’appuyer sur les clouds américains permet de rester compétitif, mais au prix d’une dépendance qui pose problème à long terme. + +C’est dans cet entre-deux qu’émergent les stratégies hybrides. Orange, comme d’autres grands groupes européens, cherche à concilier deux impératifs contradictoires. D’un côté, tirer parti de la puissance des hyperscalers pour les usages nécessitant de la flexibilité, de l’innovation rapide et une échelle mondiale. De l’autre, développer des environnements de confiance pour les données sensibles, souvent en partenariat avec des acteurs européens, afin de garantir une maîtrise juridique et opérationnelle renforcée. Cette approche permet de limiter les risques sans renoncer totalement aux avantages technologiques des géants américains. + +Pour celles et ceux qui défendent activement la souveraineté numérique, ce compromis reste frustrant. Il donne l’impression d’un renoncement progressif, d’une Europe qui accepte de jouer sur un terrain défini par d’autres. Pourtant, le problème dépasse largement Orange. Il interroge la capacité collective du continent à se doter d’infrastructures numériques stratégiques, au même titre que l’énergie, la défense ou les transports. Tant que le cloud restera perçu uniquement comme un marché et non comme un enjeu de souveraineté, les décisions resteront dictées par des logiques de court terme. + +La vraie question n’est donc pas de savoir pourquoi Orange utilise les clouds américains, mais pourquoi l’Europe n’a pas encore su créer un cadre suffisamment ambitieux pour rendre ce choix inutile. Tant que les alternatives souveraines resteront fragmentées, sous-financées ou cantonnées à des niches, les grands groupes continueront à faire des choix pragmatiques, même s’ils sont stratégiquement inconfortables. Défendre la souveraineté numérique, ce n’est pas seulement pointer les risques de dépendance, c’est aussi accepter que cette souveraineté a un coût, qu’elle nécessite des investissements lourds, une vision industrielle de long terme et une véritable volonté politique. + +Dans ce contexte, le combat pour la souveraineté numérique n’est pas perdu, mais il reste à mener sur un autre terrain que celui des seules décisions d’entreprise. Il se joue au niveau des États, de l’Union européenne et des grandes orientations industrielles. Tant que ce cadre n’évoluera pas, même les acteurs les plus attachés à l’indépendance technologique continueront à avancer dans ce paradoxe : défendre la souveraineté dans le discours, tout en dépendant, dans les faits, des infrastructures des géants américains. + diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0008.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0008.md new file mode 100644 index 0000000..a4a72e5 --- /dev/null +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0008.md @@ -0,0 +1,19 @@ +## Orange dans les bras d'Amazon : l'aveu d'un échec européen + +Orange utilise massivement AWS, Azure et Google Cloud. Dit comme ça, c'est presque une blague. L'ancien France Télécom, opérateur historique, fleuron des télécoms français, héritier du service public, branché sur les serveurs de la Silicon Valley. À l'heure où on ne parle que de souveraineté numérique, on pourrait croire à une trahison. C'est plus compliqué que ça. + +La raison principale est bête : les Américains ont gagné la course. En quinze ans, AWS, Microsoft et Google ont construit une avance que personne ne sait combler aujourd'hui. Et ils ne vendent plus seulement du stockage ou de la puissance de calcul. Ils vendent un écosystème entier : de l'IA prête à l'emploi, des outils d'analyse de données, de l'automatisation, de la cybersécurité, des garanties de disponibilité à neuf chiffres. Pour Orange, qui doit faire tourner ses services dans une vingtaine de pays sans tomber en panne, ce niveau de maturité pèse lourd dans la balance. + +Sauf que ce choix rationnel a un prix politique. En confiant ses infrastructures à des entreprises soumises au droit américain, Orange entre dans une zone de dépendance dont on ne sort pas facilement. Le Cloud Act permet aux autorités américaines de réclamer des données hébergées par ces sociétés, même quand ces données sont physiquement en Europe. On peut chiffrer, cloisonner, négocier des clauses dans tous les sens, le fait reste que la décision finale échappe au juge européen. Pour un opérateur télécoms qui manipule des données de millions d'abonnés, ce n'est pas un détail. + +Le plus rageant, c'est qu'on a des alternatives. OVHcloud, Scaleway, Outscale, IONOS en Allemagne, sans parler des projets autour de Deutsche Telekom. Ces acteurs existent, ils sont sérieux, ils savent faire. Alors pourquoi Orange ne s'allie pas avec eux pour construire quelque chose de crédible à l'échelle européenne ? + +Parce que l'écart de moyens est vertigineux. AWS et Microsoft investissent chacun plus de cinquante milliards de dollars par an dans leurs infrastructures. Ils ont leurs propres câbles sous-marins, leurs propres réseaux mondiaux, et ils raflent une bonne partie des ingénieurs qui sortent des écoles. Un OVH, même bien géré, ne joue pas dans la même catégorie financière. Il faudrait une alliance européenne soutenue politiquement, financée sur vingt ou trente ans, pour espérer rattraper. On a essayé avec Gaia-X. Le résultat parle de lui-même. + +Du coup, Orange est coincé. Tout miser sur l'européen aujourd'hui, ça veut dire accepter des services moins performants, moins riches, et perdre du terrain face à ses concurrents qui, eux, n'auront pas ces scrupules. Dans un marché où les marges fondent et où chaque innovation compte, c'est un pari risqué. Continuer avec les Américains, c'est rester dans la course mais accepter une dépendance qui peut, du jour au lendemain, devenir un problème géopolitique. + +D'où la solution batarde que tout le monde adopte : l'hybride. On met chez Amazon ou Microsoft ce qui doit aller vite, innover, scaler. On garde en Europe, parfois sur des clouds "de confiance" labellisés SecNumCloud, ce qui touche aux données sensibles, aux clients régulés, à l'État. Ce n'est pas glorieux, mais ça permet de tenir les deux bouts. + +Pour les défenseurs de la souveraineté numérique, ce compromis a un goût amer. On a l'impression d'une Europe qui se résigne, qui joue le match sur le terrain de l'adversaire avec ses règles. Mais en pointant Orange du doigt, on rate la cible. Le vrai problème n'est pas dans les choix d'une entreprise, il est en amont. Tant qu'on traitera le cloud comme un simple marché et pas comme une infrastructure critique, au même titre que l'électricité ou les chemins de fer, les industriels feront ce qu'ils ont toujours fait : choisir ce qui marche, là, maintenant. + +La bonne question n'est donc pas "pourquoi Orange utilise AWS". Elle est "pourquoi, vingt ans après l'arrivée du cloud, l'Europe n'a toujours pas mis sur la table de quoi rendre ce choix évitable". La souveraineté ne se décrète pas dans des communiqués. Elle se paie. En milliards, en années, en décisions politiques qui survivent aux changements de gouvernement. Tant qu'on ne sera pas prêts à ce niveau d'engagement, on continuera à tenir un discours sur l'indépendance numérique en signant des contrats avec Seattle et Redmond. \ No newline at end of file diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0009.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0009.md new file mode 100644 index 0000000..c2c0bae --- /dev/null +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0009.md @@ -0,0 +1,17 @@ +Orange utilise massivement AWS, Azure et Google Cloud. Dit comme ça, c'est presque une blague. L'ancien France Télécom, opérateur historique, fleuron des télécoms français, héritier du service public, branché sur les serveurs de la Silicon Valley. À l'heure où on ne parle que de souveraineté numérique, on pourrait croire à une trahison. C'est plus compliqué que ça. + +La raison principale est bête : les Américains ont gagné la course. En quinze ans, AWS, Microsoft et Google ont construit une avance que personne ne sait combler aujourd'hui. Et ils ne vendent plus seulement du stockage ou de la puissance de calcul. Ils vendent un écosystème entier : de l'IA prête à l'emploi, des outils d'analyse de données, de l'automatisation, de la cybersécurité, des garanties de disponibilité à neuf chiffres. Pour Orange, qui doit faire tourner ses services dans une vingtaine de pays sans tomber en panne, ce niveau de maturité pèse lourd dans la balance. + +Sauf que ce choix rationnel a un prix politique. En confiant ses infrastructures à des entreprises soumises au droit américain, Orange entre dans une zone de dépendance dont on ne sort pas facilement. Le Cloud Act permet aux autorités américaines de réclamer des données hébergées par ces sociétés, même quand ces données sont physiquement en Europe. On peut chiffrer, cloisonner, négocier des clauses dans tous les sens, le fait reste que la décision finale échappe au juge européen. Pour un opérateur télécoms qui manipule des données de millions d'abonnés, ce n'est pas un détail. + +Le plus rageant, c'est qu'on a des alternatives. OVHcloud, Scaleway, Outscale, IONOS en Allemagne, sans parler des projets autour de Deutsche Telekom. Ces acteurs existent, ils sont sérieux, ils savent faire. Alors pourquoi Orange ne s'allie pas avec eux pour construire quelque chose de crédible à l'échelle européenne ? + +Parce que l'écart de moyens est vertigineux. AWS et Microsoft investissent chacun plus de cinquante milliards de dollars par an dans leurs infrastructures. Ils ont leurs propres câbles sous-marins, leurs propres réseaux mondiaux, et ils raflent une bonne partie des ingénieurs qui sortent des écoles. Un OVH, même bien géré, ne joue pas dans la même catégorie financière. Il faudrait une alliance européenne soutenue politiquement, financée sur vingt ou trente ans, pour espérer rattraper. On a essayé avec Gaia-X. Le résultat parle de lui-même. + +Du coup, Orange est coincé. Tout miser sur l'européen aujourd'hui, ça veut dire accepter des services moins performants, moins riches, et perdre du terrain face à ses concurrents qui, eux, n'auront pas ces scrupules. Dans un marché où les marges fondent et où chaque innovation compte, c'est un pari risqué. Continuer avec les Américains, c'est rester dans la course mais accepter une dépendance qui peut, du jour au lendemain, devenir un problème géopolitique. + +D'où la solution batarde que tout le monde adopte : l'hybride. On met chez Amazon ou Microsoft ce qui doit aller vite, innover, scaler. On garde en Europe, parfois sur des clouds "de confiance" labellisés SecNumCloud, ce qui touche aux données sensibles, aux clients régulés, à l'État. Ce n'est pas glorieux, mais ça permet de tenir les deux bouts. + +Pour les défenseurs de la souveraineté numérique, ce compromis a un goût amer. On a l'impression d'une Europe qui se résigne, qui joue le match sur le terrain de l'adversaire avec ses règles. Mais en pointant Orange du doigt, on rate la cible. Le vrai problème n'est pas dans les choix d'une entreprise, il est en amont. Tant qu'on traitera le cloud comme un simple marché et pas comme une infrastructure critique, au même titre que l'électricité ou les chemins de fer, les industriels feront ce qu'ils ont toujours fait : choisir ce qui marche, là, maintenant. + +La bonne question n'est donc pas "pourquoi Orange utilise AWS". Elle est "pourquoi, vingt ans après l'arrivée du cloud, l'Europe n'a toujours pas mis sur la table de quoi rendre ce choix évitable". La souveraineté ne se décrète pas dans des communiqués. Elle se paie. En milliards, en années, en décisions politiques qui survivent aux changements de gouvernement. Tant qu'on ne sera pas prêts à ce niveau d'engagement, on continuera à tenir un discours sur l'indépendance numérique en signant des contrats avec Seattle et Redmond. \ No newline at end of file diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0010.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0010.md new file mode 100644 index 0000000..988bb5a --- /dev/null +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0010.md @@ -0,0 +1,17 @@ +Orange utilise massivement AWS, Azure et Google Cloud. Dit comme ça, c'est presque une blague. L'ancien France Télécom, opérateur historique, fleuron des télécoms français, héritier du service public, branché sur les serveurs de la Silicon Valley. À l'heure où on ne parle que de souveraineté numérique, on pourrait croire à une trahison. C'est plus compliqué que ça. + +La raison principale est bête : les Américains ont gagné la course. En quinze ans, AWS, Microsoft et Google ont construit une avance que personne ne sait combler aujourd'hui. Et ils ne vendent plus seulement du stockage ou de la puissance de calcul. Ils vendent un écosystème entier : de l'IA prête à l'emploi, des outils d'analyse de données, de l'automatisation, de la cybersécurité, des garanties de disponibilité à neuf chiffres. Pour Orange, qui doit faire tourner ses services dans une vingtaine de pays sans tomber en panne, ce niveau de maturité pèse lourd dans la balance. + +Sauf que ce choix rationnel a un prix politique. En confiant ses infrastructures à des entreprises soumises au droit américain, Orange entre dans une zone de dépendance dont on ne sort pas facilement. Le Cloud Act permet aux autorités américaines de réclamer des données hébergées par ces sociétés, même quand ces données sont physiquement en Europe. On peut chiffrer, cloisonner, négocier des clauses dans tous les sens, le fait reste que la décision finale échappe au juge européen. Pour un opérateur télécoms qui manipule des données de millions d'abonnés, ce n'est pas un détail. + +Le plus rageant, c'est qu'on a des alternatives. OVHcloud, Scaleway, Outscale, IONOS en Allemagne, sans parler des projets autour de Deutsche Telekom. Ces acteurs existent, ils sont sérieux, ils savent faire. Alors pourquoi Orange ne s'allie pas avec eux pour construire quelque chose de crédible à l'échelle européenne ? + +Parce que l'écart de moyens est vertigineux. AWS et Microsoft investissent chacun plus de cinquante milliards de dollars par an dans leurs infrastructures. Ils ont leurs propres câbles sous-marins, leurs propres réseaux mondiaux, et ils raflent une bonne partie des ingénieurs qui sortent des écoles. Un OVH, même bien géré, ne joue pas dans la même catégorie financière. Il faudrait une alliance européenne soutenue politiquement, financée sur vingt ou trente ans, pour espérer rattraper. On a essayé avec Gaia-X. Le résultat parle de lui-même. + +Du coup, Orange est coincé. Tout miser sur l'européen aujourd'hui, ça veut dire accepter des services moins performants, moins riches, et perdre du terrain face à ses concurrents qui, eux, n'auront pas ces scrupules. Dans un marché où les marges fondent et où chaque innovation compte, c'est un pari risqué. Continuer avec les Américains, c'est rester dans la course mais accepter une dépendance qui peut, du jour au lendemain, devenir un problème géopolitique. + +D'où la solution batarde que tout le monde adopte : l'hybride. On met chez Amazon ou Microsoft ce qui doit aller vite, innover, scaler. On garde en Europe, parfois sur des clouds "de confiance" labellisés SecNumCloud, ce qui touche aux données sensibles, aux clients régulés, à l'État. Ce n'est pas glorieux, mais ça permet de tenir les deux bouts. + +Pour les défenseurs de la souveraineté numérique, ce compromis a un goût amer. On a l'impression d'une Europe qui se résigne, qui joue le match sur le terrain de l'adversaire avec ses règles. Mais en pointant Orange du doigt, on rate la cible. Le vrai problème n'est pas dans les choix d'une entreprise, il est en amont. Tant qu'on traitera le cloud comme un simple marché et pas comme une infrastructure critique, au même titre que l'électricité ou les chemins de fer, les industriels feront ce qu'ils ont toujours fait : choisir ce qui marche, là, maintenant. + +La bonne question n'est donc pas "pourquoi Orange utilise AWS". Elle est "pourquoi, vingt ans après l'arrivée du cloud, l'Europe n'a toujours pas mis sur la table de quoi rendre ce choix évitable". La souveraineté ne se décrète pas dans des communiqués. Elle se paie. En milliards, en années, en décisions politiques qui survivent aux changements de gouvernement. Tant qu'on ne sera pas prêts à ce niveau d'engagement, on continuera à tenir un discours sur l'indépendance numérique en signant des contrats avec Seattle et Redmond. \ No newline at end of file diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0011.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0011.md new file mode 100644 index 0000000..c2c0bae --- /dev/null +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0011.md @@ -0,0 +1,17 @@ +Orange utilise massivement AWS, Azure et Google Cloud. Dit comme ça, c'est presque une blague. L'ancien France Télécom, opérateur historique, fleuron des télécoms français, héritier du service public, branché sur les serveurs de la Silicon Valley. À l'heure où on ne parle que de souveraineté numérique, on pourrait croire à une trahison. C'est plus compliqué que ça. + +La raison principale est bête : les Américains ont gagné la course. En quinze ans, AWS, Microsoft et Google ont construit une avance que personne ne sait combler aujourd'hui. Et ils ne vendent plus seulement du stockage ou de la puissance de calcul. Ils vendent un écosystème entier : de l'IA prête à l'emploi, des outils d'analyse de données, de l'automatisation, de la cybersécurité, des garanties de disponibilité à neuf chiffres. Pour Orange, qui doit faire tourner ses services dans une vingtaine de pays sans tomber en panne, ce niveau de maturité pèse lourd dans la balance. + +Sauf que ce choix rationnel a un prix politique. En confiant ses infrastructures à des entreprises soumises au droit américain, Orange entre dans une zone de dépendance dont on ne sort pas facilement. Le Cloud Act permet aux autorités américaines de réclamer des données hébergées par ces sociétés, même quand ces données sont physiquement en Europe. On peut chiffrer, cloisonner, négocier des clauses dans tous les sens, le fait reste que la décision finale échappe au juge européen. Pour un opérateur télécoms qui manipule des données de millions d'abonnés, ce n'est pas un détail. + +Le plus rageant, c'est qu'on a des alternatives. OVHcloud, Scaleway, Outscale, IONOS en Allemagne, sans parler des projets autour de Deutsche Telekom. Ces acteurs existent, ils sont sérieux, ils savent faire. Alors pourquoi Orange ne s'allie pas avec eux pour construire quelque chose de crédible à l'échelle européenne ? + +Parce que l'écart de moyens est vertigineux. AWS et Microsoft investissent chacun plus de cinquante milliards de dollars par an dans leurs infrastructures. Ils ont leurs propres câbles sous-marins, leurs propres réseaux mondiaux, et ils raflent une bonne partie des ingénieurs qui sortent des écoles. Un OVH, même bien géré, ne joue pas dans la même catégorie financière. Il faudrait une alliance européenne soutenue politiquement, financée sur vingt ou trente ans, pour espérer rattraper. On a essayé avec Gaia-X. Le résultat parle de lui-même. + +Du coup, Orange est coincé. Tout miser sur l'européen aujourd'hui, ça veut dire accepter des services moins performants, moins riches, et perdre du terrain face à ses concurrents qui, eux, n'auront pas ces scrupules. Dans un marché où les marges fondent et où chaque innovation compte, c'est un pari risqué. Continuer avec les Américains, c'est rester dans la course mais accepter une dépendance qui peut, du jour au lendemain, devenir un problème géopolitique. + +D'où la solution batarde que tout le monde adopte : l'hybride. On met chez Amazon ou Microsoft ce qui doit aller vite, innover, scaler. On garde en Europe, parfois sur des clouds "de confiance" labellisés SecNumCloud, ce qui touche aux données sensibles, aux clients régulés, à l'État. Ce n'est pas glorieux, mais ça permet de tenir les deux bouts. + +Pour les défenseurs de la souveraineté numérique, ce compromis a un goût amer. On a l'impression d'une Europe qui se résigne, qui joue le match sur le terrain de l'adversaire avec ses règles. Mais en pointant Orange du doigt, on rate la cible. Le vrai problème n'est pas dans les choix d'une entreprise, il est en amont. Tant qu'on traitera le cloud comme un simple marché et pas comme une infrastructure critique, au même titre que l'électricité ou les chemins de fer, les industriels feront ce qu'ils ont toujours fait : choisir ce qui marche, là, maintenant. + +La bonne question n'est donc pas "pourquoi Orange utilise AWS". Elle est "pourquoi, vingt ans après l'arrivée du cloud, l'Europe n'a toujours pas mis sur la table de quoi rendre ce choix évitable". La souveraineté ne se décrète pas dans des communiqués. Elle se paie. En milliards, en années, en décisions politiques qui survivent aux changements de gouvernement. Tant qu'on ne sera pas prêts à ce niveau d'engagement, on continuera à tenir un discours sur l'indépendance numérique en signant des contrats avec Seattle et Redmond. \ No newline at end of file diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0012.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0012.md new file mode 100644 index 0000000..988bb5a --- /dev/null +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0012.md @@ -0,0 +1,17 @@ +Orange utilise massivement AWS, Azure et Google Cloud. Dit comme ça, c'est presque une blague. L'ancien France Télécom, opérateur historique, fleuron des télécoms français, héritier du service public, branché sur les serveurs de la Silicon Valley. À l'heure où on ne parle que de souveraineté numérique, on pourrait croire à une trahison. C'est plus compliqué que ça. + +La raison principale est bête : les Américains ont gagné la course. En quinze ans, AWS, Microsoft et Google ont construit une avance que personne ne sait combler aujourd'hui. Et ils ne vendent plus seulement du stockage ou de la puissance de calcul. Ils vendent un écosystème entier : de l'IA prête à l'emploi, des outils d'analyse de données, de l'automatisation, de la cybersécurité, des garanties de disponibilité à neuf chiffres. Pour Orange, qui doit faire tourner ses services dans une vingtaine de pays sans tomber en panne, ce niveau de maturité pèse lourd dans la balance. + +Sauf que ce choix rationnel a un prix politique. En confiant ses infrastructures à des entreprises soumises au droit américain, Orange entre dans une zone de dépendance dont on ne sort pas facilement. Le Cloud Act permet aux autorités américaines de réclamer des données hébergées par ces sociétés, même quand ces données sont physiquement en Europe. On peut chiffrer, cloisonner, négocier des clauses dans tous les sens, le fait reste que la décision finale échappe au juge européen. Pour un opérateur télécoms qui manipule des données de millions d'abonnés, ce n'est pas un détail. + +Le plus rageant, c'est qu'on a des alternatives. OVHcloud, Scaleway, Outscale, IONOS en Allemagne, sans parler des projets autour de Deutsche Telekom. Ces acteurs existent, ils sont sérieux, ils savent faire. Alors pourquoi Orange ne s'allie pas avec eux pour construire quelque chose de crédible à l'échelle européenne ? + +Parce que l'écart de moyens est vertigineux. AWS et Microsoft investissent chacun plus de cinquante milliards de dollars par an dans leurs infrastructures. Ils ont leurs propres câbles sous-marins, leurs propres réseaux mondiaux, et ils raflent une bonne partie des ingénieurs qui sortent des écoles. Un OVH, même bien géré, ne joue pas dans la même catégorie financière. Il faudrait une alliance européenne soutenue politiquement, financée sur vingt ou trente ans, pour espérer rattraper. On a essayé avec Gaia-X. Le résultat parle de lui-même. + +Du coup, Orange est coincé. Tout miser sur l'européen aujourd'hui, ça veut dire accepter des services moins performants, moins riches, et perdre du terrain face à ses concurrents qui, eux, n'auront pas ces scrupules. Dans un marché où les marges fondent et où chaque innovation compte, c'est un pari risqué. Continuer avec les Américains, c'est rester dans la course mais accepter une dépendance qui peut, du jour au lendemain, devenir un problème géopolitique. + +D'où la solution batarde que tout le monde adopte : l'hybride. On met chez Amazon ou Microsoft ce qui doit aller vite, innover, scaler. On garde en Europe, parfois sur des clouds "de confiance" labellisés SecNumCloud, ce qui touche aux données sensibles, aux clients régulés, à l'État. Ce n'est pas glorieux, mais ça permet de tenir les deux bouts. + +Pour les défenseurs de la souveraineté numérique, ce compromis a un goût amer. On a l'impression d'une Europe qui se résigne, qui joue le match sur le terrain de l'adversaire avec ses règles. Mais en pointant Orange du doigt, on rate la cible. Le vrai problème n'est pas dans les choix d'une entreprise, il est en amont. Tant qu'on traitera le cloud comme un simple marché et pas comme une infrastructure critique, au même titre que l'électricité ou les chemins de fer, les industriels feront ce qu'ils ont toujours fait : choisir ce qui marche, là, maintenant. + +La bonne question n'est donc pas "pourquoi Orange utilise AWS". Elle est "pourquoi, vingt ans après l'arrivée du cloud, l'Europe n'a toujours pas mis sur la table de quoi rendre ce choix évitable". La souveraineté ne se décrète pas dans des communiqués. Elle se paie. En milliards, en années, en décisions politiques qui survivent aux changements de gouvernement. Tant qu'on ne sera pas prêts à ce niveau d'engagement, on continuera à tenir un discours sur l'indépendance numérique en signant des contrats avec Seattle et Redmond. \ No newline at end of file diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0013.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0013.md new file mode 100644 index 0000000..988bb5a --- /dev/null +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0013.md @@ -0,0 +1,17 @@ +Orange utilise massivement AWS, Azure et Google Cloud. Dit comme ça, c'est presque une blague. L'ancien France Télécom, opérateur historique, fleuron des télécoms français, héritier du service public, branché sur les serveurs de la Silicon Valley. À l'heure où on ne parle que de souveraineté numérique, on pourrait croire à une trahison. C'est plus compliqué que ça. + +La raison principale est bête : les Américains ont gagné la course. En quinze ans, AWS, Microsoft et Google ont construit une avance que personne ne sait combler aujourd'hui. Et ils ne vendent plus seulement du stockage ou de la puissance de calcul. Ils vendent un écosystème entier : de l'IA prête à l'emploi, des outils d'analyse de données, de l'automatisation, de la cybersécurité, des garanties de disponibilité à neuf chiffres. Pour Orange, qui doit faire tourner ses services dans une vingtaine de pays sans tomber en panne, ce niveau de maturité pèse lourd dans la balance. + +Sauf que ce choix rationnel a un prix politique. En confiant ses infrastructures à des entreprises soumises au droit américain, Orange entre dans une zone de dépendance dont on ne sort pas facilement. Le Cloud Act permet aux autorités américaines de réclamer des données hébergées par ces sociétés, même quand ces données sont physiquement en Europe. On peut chiffrer, cloisonner, négocier des clauses dans tous les sens, le fait reste que la décision finale échappe au juge européen. Pour un opérateur télécoms qui manipule des données de millions d'abonnés, ce n'est pas un détail. + +Le plus rageant, c'est qu'on a des alternatives. OVHcloud, Scaleway, Outscale, IONOS en Allemagne, sans parler des projets autour de Deutsche Telekom. Ces acteurs existent, ils sont sérieux, ils savent faire. Alors pourquoi Orange ne s'allie pas avec eux pour construire quelque chose de crédible à l'échelle européenne ? + +Parce que l'écart de moyens est vertigineux. AWS et Microsoft investissent chacun plus de cinquante milliards de dollars par an dans leurs infrastructures. Ils ont leurs propres câbles sous-marins, leurs propres réseaux mondiaux, et ils raflent une bonne partie des ingénieurs qui sortent des écoles. Un OVH, même bien géré, ne joue pas dans la même catégorie financière. Il faudrait une alliance européenne soutenue politiquement, financée sur vingt ou trente ans, pour espérer rattraper. On a essayé avec Gaia-X. Le résultat parle de lui-même. + +Du coup, Orange est coincé. Tout miser sur l'européen aujourd'hui, ça veut dire accepter des services moins performants, moins riches, et perdre du terrain face à ses concurrents qui, eux, n'auront pas ces scrupules. Dans un marché où les marges fondent et où chaque innovation compte, c'est un pari risqué. Continuer avec les Américains, c'est rester dans la course mais accepter une dépendance qui peut, du jour au lendemain, devenir un problème géopolitique. + +D'où la solution batarde que tout le monde adopte : l'hybride. On met chez Amazon ou Microsoft ce qui doit aller vite, innover, scaler. On garde en Europe, parfois sur des clouds "de confiance" labellisés SecNumCloud, ce qui touche aux données sensibles, aux clients régulés, à l'État. Ce n'est pas glorieux, mais ça permet de tenir les deux bouts. + +Pour les défenseurs de la souveraineté numérique, ce compromis a un goût amer. On a l'impression d'une Europe qui se résigne, qui joue le match sur le terrain de l'adversaire avec ses règles. Mais en pointant Orange du doigt, on rate la cible. Le vrai problème n'est pas dans les choix d'une entreprise, il est en amont. Tant qu'on traitera le cloud comme un simple marché et pas comme une infrastructure critique, au même titre que l'électricité ou les chemins de fer, les industriels feront ce qu'ils ont toujours fait : choisir ce qui marche, là, maintenant. + +La bonne question n'est donc pas "pourquoi Orange utilise AWS". Elle est "pourquoi, vingt ans après l'arrivée du cloud, l'Europe n'a toujours pas mis sur la table de quoi rendre ce choix évitable". La souveraineté ne se décrète pas dans des communiqués. Elle se paie. En milliards, en années, en décisions politiques qui survivent aux changements de gouvernement. Tant qu'on ne sera pas prêts à ce niveau d'engagement, on continuera à tenir un discours sur l'indépendance numérique en signant des contrats avec Seattle et Redmond. \ No newline at end of file diff --git a/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0014.md b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0014.md new file mode 100644 index 0000000..988bb5a --- /dev/null +++ b/data/75bf96ba-e110-4a9e-8163-95890562aecf/revisions/0014.md @@ -0,0 +1,17 @@ +Orange utilise massivement AWS, Azure et Google Cloud. Dit comme ça, c'est presque une blague. L'ancien France Télécom, opérateur historique, fleuron des télécoms français, héritier du service public, branché sur les serveurs de la Silicon Valley. À l'heure où on ne parle que de souveraineté numérique, on pourrait croire à une trahison. C'est plus compliqué que ça. + +La raison principale est bête : les Américains ont gagné la course. En quinze ans, AWS, Microsoft et Google ont construit une avance que personne ne sait combler aujourd'hui. Et ils ne vendent plus seulement du stockage ou de la puissance de calcul. Ils vendent un écosystème entier : de l'IA prête à l'emploi, des outils d'analyse de données, de l'automatisation, de la cybersécurité, des garanties de disponibilité à neuf chiffres. Pour Orange, qui doit faire tourner ses services dans une vingtaine de pays sans tomber en panne, ce niveau de maturité pèse lourd dans la balance. + +Sauf que ce choix rationnel a un prix politique. En confiant ses infrastructures à des entreprises soumises au droit américain, Orange entre dans une zone de dépendance dont on ne sort pas facilement. Le Cloud Act permet aux autorités américaines de réclamer des données hébergées par ces sociétés, même quand ces données sont physiquement en Europe. On peut chiffrer, cloisonner, négocier des clauses dans tous les sens, le fait reste que la décision finale échappe au juge européen. Pour un opérateur télécoms qui manipule des données de millions d'abonnés, ce n'est pas un détail. + +Le plus rageant, c'est qu'on a des alternatives. OVHcloud, Scaleway, Outscale, IONOS en Allemagne, sans parler des projets autour de Deutsche Telekom. Ces acteurs existent, ils sont sérieux, ils savent faire. Alors pourquoi Orange ne s'allie pas avec eux pour construire quelque chose de crédible à l'échelle européenne ? + +Parce que l'écart de moyens est vertigineux. AWS et Microsoft investissent chacun plus de cinquante milliards de dollars par an dans leurs infrastructures. Ils ont leurs propres câbles sous-marins, leurs propres réseaux mondiaux, et ils raflent une bonne partie des ingénieurs qui sortent des écoles. Un OVH, même bien géré, ne joue pas dans la même catégorie financière. Il faudrait une alliance européenne soutenue politiquement, financée sur vingt ou trente ans, pour espérer rattraper. On a essayé avec Gaia-X. Le résultat parle de lui-même. + +Du coup, Orange est coincé. Tout miser sur l'européen aujourd'hui, ça veut dire accepter des services moins performants, moins riches, et perdre du terrain face à ses concurrents qui, eux, n'auront pas ces scrupules. Dans un marché où les marges fondent et où chaque innovation compte, c'est un pari risqué. Continuer avec les Américains, c'est rester dans la course mais accepter une dépendance qui peut, du jour au lendemain, devenir un problème géopolitique. + +D'où la solution batarde que tout le monde adopte : l'hybride. On met chez Amazon ou Microsoft ce qui doit aller vite, innover, scaler. On garde en Europe, parfois sur des clouds "de confiance" labellisés SecNumCloud, ce qui touche aux données sensibles, aux clients régulés, à l'État. Ce n'est pas glorieux, mais ça permet de tenir les deux bouts. + +Pour les défenseurs de la souveraineté numérique, ce compromis a un goût amer. On a l'impression d'une Europe qui se résigne, qui joue le match sur le terrain de l'adversaire avec ses règles. Mais en pointant Orange du doigt, on rate la cible. Le vrai problème n'est pas dans les choix d'une entreprise, il est en amont. Tant qu'on traitera le cloud comme un simple marché et pas comme une infrastructure critique, au même titre que l'électricité ou les chemins de fer, les industriels feront ce qu'ils ont toujours fait : choisir ce qui marche, là, maintenant. + +La bonne question n'est donc pas "pourquoi Orange utilise AWS". Elle est "pourquoi, vingt ans après l'arrivée du cloud, l'Europe n'a toujours pas mis sur la table de quoi rendre ce choix évitable". La souveraineté ne se décrète pas dans des communiqués. Elle se paie. En milliards, en années, en décisions politiques qui survivent aux changements de gouvernement. Tant qu'on ne sera pas prêts à ce niveau d'engagement, on continuera à tenir un discours sur l'indépendance numérique en signant des contrats avec Seattle et Redmond. \ No newline at end of file diff --git a/data/976fd7f0-e53d-44e2-a879-58194765f3cf/files/cover.svg b/data/976fd7f0-e53d-44e2-a879-58194765f3cf/files/cover.svg new file mode 100644 index 0000000..72cedfa --- /dev/null +++ b/data/976fd7f0-e53d-44e2-a879-58194765f3cf/files/cover.svg @@ -0,0 +1,152 @@ + +Mises à jour automatiques de sécurité sur Debian +Illustration symbolique : un bouclier protégeant un terminal Debian, entouré de paquets de mise à jour en orbite et de flux de données sécurisés. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +.deb + + + + +.deb + + + + +CVE-fix + + + + +patch + + + + +apt + + + + + + + + + + + + + + + + + + + + + + + + + + + +debian — unattended-upgrades + + +root@srv:~# +apt update + +# Reading package lists... + +root@srv:~# +unattended-upgrade + +# Checking security archive + +→ openssl 3.0.15 +→ linux-image 6.1.140 +→ libpam 1.5.2-6+ + +# 3 packages upgraded ✓ + +root@srv:~# +_ + + + + + + + + + + + + + + + + + + + Mises à jour automatiques de sécurité + + + Debian · unattended-upgrades + + + + + apt · security.debian.org · CVE patches + + + Un serveur protégé pendant que vous dormez + + \ No newline at end of file diff --git a/data/976fd7f0-e53d-44e2-a879-58194765f3cf/index.md b/data/976fd7f0-e53d-44e2-a879-58194765f3cf/index.md index 3917422..9a40f64 100644 --- a/data/976fd7f0-e53d-44e2-a879-58194765f3cf/index.md +++ b/data/976fd7f0-e53d-44e2-a879-58194765f3cf/index.md @@ -1,86 +1,155 @@ -Dans un environnement de serveur ou de poste de travail, maintenir un système à jour avec les derniers correctifs de sécurité est crucial pour éviter toute vulnérabilité. Debian, l'une des distributions Linux les plus populaires et stables, propose des mécanismes permettant d'automatiser ce processus de mise à jour, et ainsi garantir que les correctifs de sécurité sont appliqués sans nécessiter une intervention manuelle. +Maintenir un système Debian à jour, c'est un peu comme fermer ses fenêtres avant de partir en vacances : on sait qu'il faut le faire, on sait pourquoi, et pourtant ça finit régulièrement par passer à la trappe. Le problème, c'est qu'une CVE qui traîne plusieurs semaines sur un serveur exposé, ça ne pardonne pas toujours. -Comment activer les mises à jour automatiques sur une machine Debian, en se concentrant spécifiquement sur les correctifs de sécurité ? Comment configurer ce processus pour un contrôle fin et comment tester que tout fonctionne correctement ? +Heureusement, Debian fournit tout ce qu'il faut pour automatiser l'application des correctifs de sécurité, à travers un paquet qui s'appelle `unattended-upgrades`. L'idée est simple : on configure une fois, et la machine se débrouille pour appliquer les patches `-security` sans qu'on ait à y penser. Ce qui suit, c'est la marche à suivre, avec les pièges que j'ai croisés en route. -### Étapes pour activer les mises à jour automatiques +## Le principe -#### 1. Installer les paquets nécessaires +`unattended-upgrades` n'est pas un démon qui tourne en permanence. C'est un script qui est lancé une fois par jour par un timer systemd (`apt-daily-upgrade.timer`), et qui regarde dans sa configuration quelles « origines » de paquets il a le droit de mettre à jour. Par défaut, il est conservateur : il ne touche qu'aux paquets venant du dépôt de sécurité officiel. C'est exactement ce qu'on veut sur un serveur de production. -La première étape pour activer les mises à jour automatiques sur Debian consiste à installer les outils nécessaires. Cela inclut le paquet `unattended-upgrades`, qui permet de gérer les mises à jour automatiques, ainsi que `apt-listchanges` qui permet de recevoir des informations sur les paquets mis à jour. +Deux fichiers entrent en jeu : -Exécutez la commande suivante pour installer ces paquets : +- `/etc/apt/apt.conf.d/20auto-upgrades` décide *si* et *à quelle fréquence* unattended-upgrades est exécuté +- `/etc/apt/apt.conf.d/50unattended-upgrades` décide *quoi* mettre à jour et *comment* + +On va passer par les deux. + +## Installation + +Rien de très exotique : ```bash sudo apt update sudo apt install -y unattended-upgrades apt-listchanges ``` -#### 2. Configurer `unattended-upgrades` +`apt-listchanges` n'est pas strictement nécessaire, mais il est utile : il permet de recevoir un résumé des changements appliqués (notamment les entrées de `NEWS.Debian` qui annoncent parfois des changements de comportement qu'il vaut mieux ne pas découvrir un lundi matin). -Une fois le paquet installé, vous devez configurer `unattended-upgrades` pour qu'il applique automatiquement les mises à jour de sécurité. Cela se fait en modifiant certains fichiers de configuration dans `/etc/apt/apt.conf.d/`. +## Activer l'exécution automatique -Exécutez la commande suivante pour reconfigurer `unattended-upgrades` : +La commande classique pour ça : ```bash sudo dpkg-reconfigure --priority=low unattended-upgrades ``` -Lors de la configuration, vous serez invité à activer les mises à jour automatiques. Assurez-vous que l'option **"Install security updates"** est sélectionnée. Cela garantit que les mises à jour de sécurité seront appliquées automatiquement sans intervention manuelle. +L'interface te pose une question simple — « voulez-vous appliquer automatiquement les mises à jour de stabilité ? » — réponds oui. En coulisses, cette commande crée le fichier `/etc/apt/apt.conf.d/20auto-upgrades` avec ce contenu : -#### 3. Vérifier la configuration dans `/etc/apt/apt.conf.d/50unattended-upgrades` - -Une fois la configuration initiale terminée, il est important de vérifier que le fichier de configuration principal de `unattended-upgrades` permet bien l'installation des mises à jour de sécurité. - -Éditez le fichier `/etc/apt/apt.conf.d/50unattended-upgrades` avec votre éditeur de texte préféré, par exemple `nano` : - -```bash -sudo nano /etc/apt/apt.conf.d/50unattended-upgrades +``` +APT::Periodic::Update-Package-Lists "1"; +APT::Periodic::Unattended-Upgrade "1"; ``` -Dans ce fichier, vous devez vous assurer que la ligne suivante est présente et non commentée : +Le `"1"` signifie « tous les jours ». Tu peux mettre `"7"` pour hebdomadaire, mais sur un serveur exposé je ne vois pas l'intérêt de retarder. -```plaintext -"${distro_id}:${distro_codename}-security"; +Pendant qu'on y est, deux options qu'on ajoute souvent à ce fichier : + +``` +APT::Periodic::Download-Upgradeable-Packages "1"; +APT::Periodic::AutocleanInterval "7"; ``` -Cela garantit que les mises à jour de sécurité de votre version de Debian seront appliquées automatiquement. +La première télécharge les paquets en amont, ce qui rend l'installation plus rapide le moment venu. La seconde nettoie le cache `/var/cache/apt/archives` une fois par semaine, ce qui évite que ce dossier ne grossisse indéfiniment. -**Optionnel** : Si vous souhaitez également appliquer des mises à jour non critiques (par exemple des mises à jour mineures ou des corrections de bugs), vous pouvez activer les mises à jour pour tous les paquets en dé-commentant ou ajoutant cette ligne : +## Configurer le périmètre des mises à jour -```plaintext -"${distro_id}:${distro_codename}-updates"; +C'est dans `/etc/apt/apt.conf.d/50unattended-upgrades` que ça se joue. Le fichier est livré commenté et documenté, ce qui aide. La section la plus importante ressemble à ça : + +``` +Unattended-Upgrade::Origins-Pattern { + "origin=Debian,codename=${distro_codename}-updates"; + "origin=Debian,codename=${distro_codename},label=Debian"; + "origin=Debian,codename=${distro_codename},label=Debian-Security"; + "origin=Debian,codename=${distro_codename}-security,label=Debian-Security"; +}; ``` -Cependant, cette option peut introduire des mises à jour qui ne sont pas toujours aussi urgentes que celles de sécurité. Il est donc recommandé de ne l'activer que si vous êtes à l'aise avec des mises à jour supplémentaires automatiques. +Sur une Debian récente (Bookworm et au-delà), ces lignes sont décommentées par défaut et couvrent les mises à jour de sécurité. Si tu veux être strictement sécurité-seulement, garde uniquement les deux lignes contenant `Debian-Security` et commente les autres. La règle est : `label=Debian-Security` correspond aux correctifs de l'équipe sécurité, le reste correspond aux mises à jour de point release (les `12.6 → 12.7` et compagnie). -#### 4. Tester la configuration des mises à jour automatiques +Quelques options supplémentaires qui méritent qu'on s'y arrête : -Pour vous assurer que `unattended-upgrades` fonctionne comme prévu, il est utile de faire un test en mode "dry-run". Cela permet de simuler les mises à jour sans les appliquer réellement. +### Le redémarrage automatique -Exécutez la commande suivante : +``` +Unattended-Upgrade::Automatic-Reboot "false"; +Unattended-Upgrade::Automatic-Reboot-Time "02:00"; +``` + +Question politique autant que technique. Certaines mises à jour — typiquement le noyau ou la glibc — ne prennent effet qu'après reboot. Tant que la machine n'a pas redémarré, le correctif n'est pas réellement appliqué, même si le paquet est installé. Tu as deux options : laisser à `"false"` et reboot manuellement quand tu veux (en surveillant `/var/run/reboot-required`), ou passer à `"true"` avec une heure creuse. Sur un serveur isolé, le reboot auto se défend. Sur une base de données critique, beaucoup moins. + +### Les notifications + +``` +Unattended-Upgrade::Mail "admin@exemple.fr"; +Unattended-Upgrade::MailReport "on-change"; +``` + +Très utile. Tu reçois un mail uniquement quand quelque chose a été installé (ou a échoué), ce qui évite le bruit. Évidemment, il faut un MTA configuré — `msmtp` ou un postfix en relais SMTP font le boulot. + +### Le nettoyage + +``` +Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; +Unattended-Upgrade::Remove-Unused-Dependencies "true"; +``` + +Sans ça, les vieux noyaux s'accumulent dans `/boot`, qui finit par se remplir, ce qui finit par bloquer la prochaine mise à jour du noyau. Classique. + +## Tester avant de laisser tourner + +Avant de partir en weekend, vérifie que la configuration est bien comprise : ```bash sudo unattended-upgrades --dry-run --debug ``` -Cette commande simule le processus de mise à jour et affiche des informations détaillées sur les paquets qui seraient mis à jour. Cela vous permet de vérifier que la configuration fonctionne correctement et que seules les mises à jour de sécurité (ou celles que vous avez spécifiées) seront prises en compte. +Le dry-run ne touche à rien, mais il liste les paquets qui seraient installés et — surtout — il indique pourquoi un paquet est ou n'est pas retenu. Si tu vois `Checking: ` suivi de `Allowed origins are:` et que ton dépôt de sécurité apparaît bien dans la liste, c'est bon signe. -#### 5. Vérifier les logs - -Une fois les mises à jour automatiques activées et en cours d'exécution, il est important de vérifier régulièrement les logs pour vous assurer qu'aucune mise à jour n'a échoué. Les logs de `unattended-upgrades` sont stockés dans le fichier `/var/log/unattended-upgrades/unattended-upgrades.log`. - -Pour consulter les logs, utilisez la commande suivante : +Tu peux aussi vérifier que les timers systemd sont actifs : ```bash -sudo cat /var/log/unattended-upgrades/unattended-upgrades.log +systemctl list-timers apt-daily.timer apt-daily-upgrade.timer ``` -Cela vous permet de suivre les mises à jour installées automatiquement et d’identifier tout problème éventuel. +Ces deux timers sont fournis par le paquet `apt` lui-même, indépendamment de unattended-upgrades. Le premier rafraîchit la liste des paquets, le second déclenche l'upgrade. S'ils sont marqués `inactive`, c'est qu'ils sont masqués quelque part — un `systemctl unmask` règle généralement le problème. ---- +## Vérifier après coup -En activant les mises à jour automatiques sur votre machine Debian, vous vous assurez que les correctifs de sécurité sont appliqués rapidement et sans intervention manuelle, réduisant ainsi le risque de vulnérabilités exploitables. +Les logs vivent ici : -N'oubliez pas que bien que l'activation des mises à jour automatiques pour les correctifs de sécurité soit essentielle, il est également important de tester régulièrement le processus, de vérifier les logs, et de maintenir une vigilance pour toute mise à jour système majeure qui pourrait nécessiter une attention spéciale. +```bash +sudo less /var/log/unattended-upgrades/unattended-upgrades.log +sudo less /var/log/unattended-upgrades/unattended-upgrades-dpkg.log +``` -En appliquant cette configuration, vous minimisez les risques liés à des failles de sécurité tout en maintenant la stabilité et la sécurité de votre environnement Debian. +Le premier est un résumé lisible, le second contient la sortie brute de `dpkg`. Quand quelque chose se passe mal, c'est généralement dans le second qu'on trouve l'explication (un fichier de configuration modifié, un service qui refuse de redémarrer, ce genre de choses). + +Pour savoir si la machine attend un reboot après une mise à jour de noyau : + +```bash +ls /var/run/reboot-required 2>/dev/null && cat /var/run/reboot-required.pkgs +``` + +Si le fichier existe, c'est qu'au moins un paquet installé recommande un redémarrage. Le second fichier liste lesquels. + +## Quelques pièges + +**Les fichiers de configuration modifiés.** Si tu as personnalisé un `/etc/...` dont le paquet propose une nouvelle version, unattended-upgrades va voir un conflit et laisser tomber l'installation par défaut (option `--force-confdef`). C'est généralement le bon comportement, mais ça veut dire que certaines mises à jour resteront en attente jusqu'à une intervention manuelle. Les logs te le diront. + +**Les paquets blacklistés.** Tu peux exclure des paquets précis de la mise à jour automatique : + +``` +Unattended-Upgrade::Package-Blacklist { + "libc6"; + "linux-image-.*"; +}; +``` + +À utiliser avec discernement — exclure libc6 ou le noyau, c'est précisément exclure les correctifs qui comptent le plus. Mais sur une machine où un reboot coûte cher, ça permet de garder le contrôle sur les paquets sensibles tout en automatisant le reste. + +**Les dépôts tiers.** Par défaut, seuls les dépôts Debian officiels sont concernés. Si tu utilises un PPA ou un dépôt comme celui de Docker ou de PostgreSQL, il faut explicitement l'ajouter dans `Origins-Pattern`. Sinon, ces paquets ne sont jamais mis à jour automatiquement — ce qui peut être un piège silencieux. + +## Pour conclure + +L'automatisation des mises à jour de sécurité sur Debian, ce n'est pas une boîte noire : c'est un script qui tourne une fois par jour, qui lit deux fichiers texte, et qui appelle `apt` avec des règles bien définies. Une fois qu'on a compris ça, le configurer revient à éditer ces deux fichiers selon ses contraintes — niveau de risque, fenêtre de reboot acceptable, notifications souhaitées. + +Le minimum vital sur un serveur exposé tient en quatre points : `unattended-upgrades` installé, le périmètre limité aux dépôts `-security`, les notifications mail activées, et un coup d'œil régulier à `/var/run/reboot-required` pour ne pas oublier les redémarrages. Le reste, c'est de l'ajustement selon le contexte. \ No newline at end of file diff --git a/data/976fd7f0-e53d-44e2-a879-58194765f3cf/meta.json b/data/976fd7f0-e53d-44e2-a879-58194765f3cf/meta.json index 0a345f0..448eca2 100644 --- a/data/976fd7f0-e53d-44e2-a879-58194765f3cf/meta.json +++ b/data/976fd7f0-e53d-44e2-a879-58194765f3cf/meta.json @@ -1,13 +1,36 @@ { "uuid": "976fd7f0-e53d-44e2-a879-58194765f3cf", - "slug": "activer-les-mises-a-jour-automatiques-sur-debian-pour-une-gestion-simplifiee-des-correctifs-de-securite", - "title": "Activer les mises à jour automatiques sur Debian pour une gestion simplifiée des correctifs de sécurité", + "slug": "mises-a-jour-automatiques-de-securite-sur-debian", + "title": "Mises à jour automatiques de sécurité sur Debian", "author": "cedric@abonnel.fr", "published": true, - "published_at": "2026-01-06 20:45:52", + "published_at": "2026-01-06 20:45", "created_at": "2026-01-06 20:45:52", - "updated_at": "2026-01-06 20:45:52", - "revisions": [], - "cover": "cover.jpg", + "updated_at": "2026-05-12 00:22:53", + "revisions": [ + { + "n": 1, + "date": "2026-05-12 00:18:42", + "comment": "", + "title": "Mises à jour automatiques de sécurité sur Debian" + }, + { + "n": 2, + "date": "2026-05-12 00:22:53", + "comment": "", + "title": "Mises à jour automatiques de sécurité sur Debian" + } + ], + "cover": "cover.svg", + "files_meta": { + "5cfac9bc6078c2d1-31391.svg": { + "author": "Cédrix", + "source_url": "" + } + }, + "external_links": [], + "seo_title": "", + "seo_description": "", + "og_image": "", "category": "linux" } diff --git a/data/976fd7f0-e53d-44e2-a879-58194765f3cf/revisions/0001.md b/data/976fd7f0-e53d-44e2-a879-58194765f3cf/revisions/0001.md new file mode 100644 index 0000000..f3e1bc6 --- /dev/null +++ b/data/976fd7f0-e53d-44e2-a879-58194765f3cf/revisions/0001.md @@ -0,0 +1,155 @@ +Maintenir un système Debian à jour, c'est un peu comme fermer ses fenêtres avant de partir en vacances : on sait qu'il faut le faire, on sait pourquoi, et pourtant ça finit régulièrement par passer à la trappe. Le problème, c'est qu'une CVE qui traîne plusieurs semaines sur un serveur exposé, ça ne pardonne pas toujours. + +Heureusement, Debian fournit tout ce qu'il faut pour automatiser l'application des correctifs de sécurité, à travers un paquet qui s'appelle `unattended-upgrades`. L'idée est simple : on configure une fois, et la machine se débrouille pour appliquer les patches `-security` sans qu'on ait à y penser. Ce qui suit, c'est la marche à suivre, avec les pièges que j'ai croisés en route. + +## Le principe + +`unattended-upgrades` n'est pas un démon qui tourne en permanence. C'est un script qui est lancé une fois par jour par un timer systemd (`apt-daily-upgrade.timer`), et qui regarde dans sa configuration quelles « origines » de paquets il a le droit de mettre à jour. Par défaut, il est conservateur : il ne touche qu'aux paquets venant du dépôt de sécurité officiel. C'est exactement ce qu'on veut sur un serveur de production. + +Deux fichiers entrent en jeu : + +- `/etc/apt/apt.conf.d/20auto-upgrades` décide *si* et *à quelle fréquence* unattended-upgrades est exécuté +- `/etc/apt/apt.conf.d/50unattended-upgrades` décide *quoi* mettre à jour et *comment* + +On va passer par les deux. + +## Installation + +Rien de très exotique : + +```bash +sudo apt update +sudo apt install -y unattended-upgrades apt-listchanges +``` + +`apt-listchanges` n'est pas strictement nécessaire, mais il est utile : il permet de recevoir un résumé des changements appliqués (notamment les entrées de `NEWS.Debian` qui annoncent parfois des changements de comportement qu'il vaut mieux ne pas découvrir un lundi matin). + +## Activer l'exécution automatique + +La commande classique pour ça : + +```bash +sudo dpkg-reconfigure --priority=low unattended-upgrades +``` + +L'interface te pose une question simple — « voulez-vous appliquer automatiquement les mises à jour de stabilité ? » — réponds oui. En coulisses, cette commande crée le fichier `/etc/apt/apt.conf.d/20auto-upgrades` avec ce contenu : + +``` +APT::Periodic::Update-Package-Lists "1"; +APT::Periodic::Unattended-Upgrade "1"; +``` + +Le `"1"` signifie « tous les jours ». Tu peux mettre `"7"` pour hebdomadaire, mais sur un serveur exposé je ne vois pas l'intérêt de retarder. + +Pendant qu'on y est, deux options qu'on ajoute souvent à ce fichier : + +``` +APT::Periodic::Download-Upgradeable-Packages "1"; +APT::Periodic::AutocleanInterval "7"; +``` + +La première télécharge les paquets en amont, ce qui rend l'installation plus rapide le moment venu. La seconde nettoie le cache `/var/cache/apt/archives` une fois par semaine, ce qui évite que ce dossier ne grossisse indéfiniment. + +## Configurer le périmètre des mises à jour + +C'est dans `/etc/apt/apt.conf.d/50unattended-upgrades` que ça se joue. Le fichier est livré commenté et documenté, ce qui aide. La section la plus importante ressemble à ça : + +``` +Unattended-Upgrade::Origins-Pattern { + "origin=Debian,codename=${distro_codename}-updates"; + "origin=Debian,codename=${distro_codename},label=Debian"; + "origin=Debian,codename=${distro_codename},label=Debian-Security"; + "origin=Debian,codename=${distro_codename}-security,label=Debian-Security"; +}; +``` + +Sur une Debian récente (Bookworm et au-delà), ces lignes sont décommentées par défaut et couvrent les mises à jour de sécurité. Si tu veux être strictement sécurité-seulement, garde uniquement les deux lignes contenant `Debian-Security` et commente les autres. La règle est : `label=Debian-Security` correspond aux correctifs de l'équipe sécurité, le reste correspond aux mises à jour de point release (les `12.6 → 12.7` et compagnie). + +Quelques options supplémentaires qui méritent qu'on s'y arrête : + +### Le redémarrage automatique + +``` +Unattended-Upgrade::Automatic-Reboot "false"; +Unattended-Upgrade::Automatic-Reboot-Time "02:00"; +``` + +Question politique autant que technique. Certaines mises à jour — typiquement le noyau ou la glibc — ne prennent effet qu'après reboot. Tant que la machine n'a pas redémarré, le correctif n'est pas réellement appliqué, même si le paquet est installé. Tu as deux options : laisser à `"false"` et reboot manuellement quand tu veux (en surveillant `/var/run/reboot-required`), ou passer à `"true"` avec une heure creuse. Sur un serveur isolé, le reboot auto se défend. Sur une base de données critique, beaucoup moins. + +### Les notifications + +``` +Unattended-Upgrade::Mail "admin@exemple.fr"; +Unattended-Upgrade::MailReport "on-change"; +``` + +Très utile. Tu reçois un mail uniquement quand quelque chose a été installé (ou a échoué), ce qui évite le bruit. Évidemment, il faut un MTA configuré — `msmtp` ou un postfix en relais SMTP font le boulot. + +### Le nettoyage + +``` +Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; +Unattended-Upgrade::Remove-Unused-Dependencies "true"; +``` + +Sans ça, les vieux noyaux s'accumulent dans `/boot`, qui finit par se remplir, ce qui finit par bloquer la prochaine mise à jour du noyau. Classique. + +## Tester avant de laisser tourner + +Avant de partir en weekend, vérifie que la configuration est bien comprise : + +```bash +sudo unattended-upgrades --dry-run --debug +``` + +Le dry-run ne touche à rien, mais il liste les paquets qui seraient installés et — surtout — il indique pourquoi un paquet est ou n'est pas retenu. Si tu vois `Checking: ` suivi de `Allowed origins are:` et que ton dépôt de sécurité apparaît bien dans la liste, c'est bon signe. + +Tu peux aussi vérifier que les timers systemd sont actifs : + +```bash +systemctl list-timers apt-daily.timer apt-daily-upgrade.timer +``` + +Ces deux timers sont fournis par le paquet `apt` lui-même, indépendamment de unattended-upgrades. Le premier rafraîchit la liste des paquets, le second déclenche l'upgrade. S'ils sont marqués `inactive`, c'est qu'ils sont masqués quelque part — un `systemctl unmask` règle généralement le problème. + +## Vérifier après coup + +Les logs vivent ici : + +```bash +sudo less /var/log/unattended-upgrades/unattended-upgrades.log +sudo less /var/log/unattended-upgrades/unattended-upgrades-dpkg.log +``` + +Le premier est un résumé lisible, le second contient la sortie brute de `dpkg`. Quand quelque chose se passe mal, c'est généralement dans le second qu'on trouve l'explication (un fichier de configuration modifié, un service qui refuse de redémarrer, ce genre de choses). + +Pour savoir si la machine attend un reboot après une mise à jour de noyau : + +```bash +ls /var/run/reboot-required 2>/dev/null && cat /var/run/reboot-required.pkgs +``` + +Si le fichier existe, c'est qu'au moins un paquet installé recommande un redémarrage. Le second fichier liste lesquels. + +## Quelques pièges + +**Les fichiers de configuration modifiés.** Si tu as personnalisé un `/etc/...` dont le paquet propose une nouvelle version, unattended-upgrades va voir un conflit et laisser tomber l'installation par défaut (option `--force-confdef`). C'est généralement le bon comportement, mais ça veut dire que certaines mises à jour resteront en attente jusqu'à une intervention manuelle. Les logs te le diront. + +**Les paquets blacklistés.** Tu peux exclure des paquets précis de la mise à jour automatique : + +``` +Unattended-Upgrade::Package-Blacklist { + "libc6"; + "linux-image-.*"; +}; +``` + +À utiliser avec discernement — exclure libc6 ou le noyau, c'est précisément exclure les correctifs qui comptent le plus. Mais sur une machine où un reboot coûte cher, ça permet de garder le contrôle sur les paquets sensibles tout en automatisant le reste. + +**Les dépôts tiers.** Par défaut, seuls les dépôts Debian officiels sont concernés. Si tu utilises un PPA ou un dépôt comme celui de Docker ou de PostgreSQL, il faut explicitement l'ajouter dans `Origins-Pattern`. Sinon, ces paquets ne sont jamais mis à jour automatiquement — ce qui peut être un piège silencieux. + +## Pour conclure + +L'automatisation des mises à jour de sécurité sur Debian, ce n'est pas une boîte noire : c'est un script qui tourne une fois par jour, qui lit deux fichiers texte, et qui appelle `apt` avec des règles bien définies. Une fois qu'on a compris ça, le configurer revient à éditer ces deux fichiers selon ses contraintes — niveau de risque, fenêtre de reboot acceptable, notifications souhaitées. + +Le minimum vital sur un serveur exposé tient en quatre points : `unattended-upgrades` installé, le périmètre limité aux dépôts `-security`, les notifications mail activées, et un coup d'œil régulier à `/var/run/reboot-required` pour ne pas oublier les redémarrages. Le reste, c'est de l'ajustement selon le contexte. \ No newline at end of file diff --git a/data/976fd7f0-e53d-44e2-a879-58194765f3cf/revisions/0002.md b/data/976fd7f0-e53d-44e2-a879-58194765f3cf/revisions/0002.md new file mode 100644 index 0000000..9a40f64 --- /dev/null +++ b/data/976fd7f0-e53d-44e2-a879-58194765f3cf/revisions/0002.md @@ -0,0 +1,155 @@ +Maintenir un système Debian à jour, c'est un peu comme fermer ses fenêtres avant de partir en vacances : on sait qu'il faut le faire, on sait pourquoi, et pourtant ça finit régulièrement par passer à la trappe. Le problème, c'est qu'une CVE qui traîne plusieurs semaines sur un serveur exposé, ça ne pardonne pas toujours. + +Heureusement, Debian fournit tout ce qu'il faut pour automatiser l'application des correctifs de sécurité, à travers un paquet qui s'appelle `unattended-upgrades`. L'idée est simple : on configure une fois, et la machine se débrouille pour appliquer les patches `-security` sans qu'on ait à y penser. Ce qui suit, c'est la marche à suivre, avec les pièges que j'ai croisés en route. + +## Le principe + +`unattended-upgrades` n'est pas un démon qui tourne en permanence. C'est un script qui est lancé une fois par jour par un timer systemd (`apt-daily-upgrade.timer`), et qui regarde dans sa configuration quelles « origines » de paquets il a le droit de mettre à jour. Par défaut, il est conservateur : il ne touche qu'aux paquets venant du dépôt de sécurité officiel. C'est exactement ce qu'on veut sur un serveur de production. + +Deux fichiers entrent en jeu : + +- `/etc/apt/apt.conf.d/20auto-upgrades` décide *si* et *à quelle fréquence* unattended-upgrades est exécuté +- `/etc/apt/apt.conf.d/50unattended-upgrades` décide *quoi* mettre à jour et *comment* + +On va passer par les deux. + +## Installation + +Rien de très exotique : + +```bash +sudo apt update +sudo apt install -y unattended-upgrades apt-listchanges +``` + +`apt-listchanges` n'est pas strictement nécessaire, mais il est utile : il permet de recevoir un résumé des changements appliqués (notamment les entrées de `NEWS.Debian` qui annoncent parfois des changements de comportement qu'il vaut mieux ne pas découvrir un lundi matin). + +## Activer l'exécution automatique + +La commande classique pour ça : + +```bash +sudo dpkg-reconfigure --priority=low unattended-upgrades +``` + +L'interface te pose une question simple — « voulez-vous appliquer automatiquement les mises à jour de stabilité ? » — réponds oui. En coulisses, cette commande crée le fichier `/etc/apt/apt.conf.d/20auto-upgrades` avec ce contenu : + +``` +APT::Periodic::Update-Package-Lists "1"; +APT::Periodic::Unattended-Upgrade "1"; +``` + +Le `"1"` signifie « tous les jours ». Tu peux mettre `"7"` pour hebdomadaire, mais sur un serveur exposé je ne vois pas l'intérêt de retarder. + +Pendant qu'on y est, deux options qu'on ajoute souvent à ce fichier : + +``` +APT::Periodic::Download-Upgradeable-Packages "1"; +APT::Periodic::AutocleanInterval "7"; +``` + +La première télécharge les paquets en amont, ce qui rend l'installation plus rapide le moment venu. La seconde nettoie le cache `/var/cache/apt/archives` une fois par semaine, ce qui évite que ce dossier ne grossisse indéfiniment. + +## Configurer le périmètre des mises à jour + +C'est dans `/etc/apt/apt.conf.d/50unattended-upgrades` que ça se joue. Le fichier est livré commenté et documenté, ce qui aide. La section la plus importante ressemble à ça : + +``` +Unattended-Upgrade::Origins-Pattern { + "origin=Debian,codename=${distro_codename}-updates"; + "origin=Debian,codename=${distro_codename},label=Debian"; + "origin=Debian,codename=${distro_codename},label=Debian-Security"; + "origin=Debian,codename=${distro_codename}-security,label=Debian-Security"; +}; +``` + +Sur une Debian récente (Bookworm et au-delà), ces lignes sont décommentées par défaut et couvrent les mises à jour de sécurité. Si tu veux être strictement sécurité-seulement, garde uniquement les deux lignes contenant `Debian-Security` et commente les autres. La règle est : `label=Debian-Security` correspond aux correctifs de l'équipe sécurité, le reste correspond aux mises à jour de point release (les `12.6 → 12.7` et compagnie). + +Quelques options supplémentaires qui méritent qu'on s'y arrête : + +### Le redémarrage automatique + +``` +Unattended-Upgrade::Automatic-Reboot "false"; +Unattended-Upgrade::Automatic-Reboot-Time "02:00"; +``` + +Question politique autant que technique. Certaines mises à jour — typiquement le noyau ou la glibc — ne prennent effet qu'après reboot. Tant que la machine n'a pas redémarré, le correctif n'est pas réellement appliqué, même si le paquet est installé. Tu as deux options : laisser à `"false"` et reboot manuellement quand tu veux (en surveillant `/var/run/reboot-required`), ou passer à `"true"` avec une heure creuse. Sur un serveur isolé, le reboot auto se défend. Sur une base de données critique, beaucoup moins. + +### Les notifications + +``` +Unattended-Upgrade::Mail "admin@exemple.fr"; +Unattended-Upgrade::MailReport "on-change"; +``` + +Très utile. Tu reçois un mail uniquement quand quelque chose a été installé (ou a échoué), ce qui évite le bruit. Évidemment, il faut un MTA configuré — `msmtp` ou un postfix en relais SMTP font le boulot. + +### Le nettoyage + +``` +Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; +Unattended-Upgrade::Remove-Unused-Dependencies "true"; +``` + +Sans ça, les vieux noyaux s'accumulent dans `/boot`, qui finit par se remplir, ce qui finit par bloquer la prochaine mise à jour du noyau. Classique. + +## Tester avant de laisser tourner + +Avant de partir en weekend, vérifie que la configuration est bien comprise : + +```bash +sudo unattended-upgrades --dry-run --debug +``` + +Le dry-run ne touche à rien, mais il liste les paquets qui seraient installés et — surtout — il indique pourquoi un paquet est ou n'est pas retenu. Si tu vois `Checking: ` suivi de `Allowed origins are:` et que ton dépôt de sécurité apparaît bien dans la liste, c'est bon signe. + +Tu peux aussi vérifier que les timers systemd sont actifs : + +```bash +systemctl list-timers apt-daily.timer apt-daily-upgrade.timer +``` + +Ces deux timers sont fournis par le paquet `apt` lui-même, indépendamment de unattended-upgrades. Le premier rafraîchit la liste des paquets, le second déclenche l'upgrade. S'ils sont marqués `inactive`, c'est qu'ils sont masqués quelque part — un `systemctl unmask` règle généralement le problème. + +## Vérifier après coup + +Les logs vivent ici : + +```bash +sudo less /var/log/unattended-upgrades/unattended-upgrades.log +sudo less /var/log/unattended-upgrades/unattended-upgrades-dpkg.log +``` + +Le premier est un résumé lisible, le second contient la sortie brute de `dpkg`. Quand quelque chose se passe mal, c'est généralement dans le second qu'on trouve l'explication (un fichier de configuration modifié, un service qui refuse de redémarrer, ce genre de choses). + +Pour savoir si la machine attend un reboot après une mise à jour de noyau : + +```bash +ls /var/run/reboot-required 2>/dev/null && cat /var/run/reboot-required.pkgs +``` + +Si le fichier existe, c'est qu'au moins un paquet installé recommande un redémarrage. Le second fichier liste lesquels. + +## Quelques pièges + +**Les fichiers de configuration modifiés.** Si tu as personnalisé un `/etc/...` dont le paquet propose une nouvelle version, unattended-upgrades va voir un conflit et laisser tomber l'installation par défaut (option `--force-confdef`). C'est généralement le bon comportement, mais ça veut dire que certaines mises à jour resteront en attente jusqu'à une intervention manuelle. Les logs te le diront. + +**Les paquets blacklistés.** Tu peux exclure des paquets précis de la mise à jour automatique : + +``` +Unattended-Upgrade::Package-Blacklist { + "libc6"; + "linux-image-.*"; +}; +``` + +À utiliser avec discernement — exclure libc6 ou le noyau, c'est précisément exclure les correctifs qui comptent le plus. Mais sur une machine où un reboot coûte cher, ça permet de garder le contrôle sur les paquets sensibles tout en automatisant le reste. + +**Les dépôts tiers.** Par défaut, seuls les dépôts Debian officiels sont concernés. Si tu utilises un PPA ou un dépôt comme celui de Docker ou de PostgreSQL, il faut explicitement l'ajouter dans `Origins-Pattern`. Sinon, ces paquets ne sont jamais mis à jour automatiquement — ce qui peut être un piège silencieux. + +## Pour conclure + +L'automatisation des mises à jour de sécurité sur Debian, ce n'est pas une boîte noire : c'est un script qui tourne une fois par jour, qui lit deux fichiers texte, et qui appelle `apt` avec des règles bien définies. Une fois qu'on a compris ça, le configurer revient à éditer ces deux fichiers selon ses contraintes — niveau de risque, fenêtre de reboot acceptable, notifications souhaitées. + +Le minimum vital sur un serveur exposé tient en quatre points : `unattended-upgrades` installé, le périmètre limité aux dépôts `-security`, les notifications mail activées, et un coup d'œil régulier à `/var/run/reboot-required` pour ne pas oublier les redémarrages. Le reste, c'est de l'ajustement selon le contexte. \ No newline at end of file diff --git a/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_035b34dd014ac80f-635197.jpg b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_035b34dd014ac80f-635197.jpg new file mode 100644 index 0000000..ac0c81a Binary files /dev/null and b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_035b34dd014ac80f-635197.jpg differ diff --git a/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_5913d9738c966833-30567.jpg b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_5913d9738c966833-30567.jpg new file mode 100644 index 0000000..54ec9c9 Binary files /dev/null and b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_5913d9738c966833-30567.jpg differ diff --git a/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_7d6ba93f6ce840e7-13566.webp b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_7d6ba93f6ce840e7-13566.webp new file mode 100644 index 0000000..fc9ad23 Binary files /dev/null and b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_7d6ba93f6ce840e7-13566.webp differ diff --git a/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_d5dde33b48cd2761-66620.jpg b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_d5dde33b48cd2761-66620.jpg new file mode 100644 index 0000000..c15f74d Binary files /dev/null and b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_d5dde33b48cd2761-66620.jpg differ diff --git a/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_e99b946f131256b8-49943.jpg b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_e99b946f131256b8-49943.jpg new file mode 100644 index 0000000..7686c81 Binary files /dev/null and b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_e99b946f131256b8-49943.jpg differ diff --git a/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_fb5a5b1ffa000d12-30780.png b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_fb5a5b1ffa000d12-30780.png new file mode 100644 index 0000000..bcaf159 Binary files /dev/null and b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/_thumb_fb5a5b1ffa000d12-30780.png differ diff --git a/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/cover.jpg b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/cover.jpg new file mode 100644 index 0000000..3cfadc3 Binary files /dev/null and b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/files/cover.jpg differ diff --git a/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/index.md b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/index.md index d460a1e..6b9d6aa 100644 --- a/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/index.md +++ b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/index.md @@ -1,41 +1,25 @@ -À première vue, une brique LEGO reste une brique : un parallélépipède de plastique, discret et familier, qui évoque les chambres d’enfants et les châteaux improvisés sur le tapis du salon. Pourtant, depuis quelques années, certaines de ces briques ont acquis une tout autre nature. On les appelle **Smart Bricks**, et sous cette appellation presque anodine se cache une petite révolution silencieuse : celle de l’intelligence embarquée qui s’invite dans l’univers du jeu. +## La brique qui répond -La Smart Brick n’est pas seulement un élément de construction, elle est un cerveau miniature. Là où la brique traditionnelle se contente de tenir les autres ensemble, celle-ci observe, calcule, décide. Elle reçoit des informations venues de capteurs, interprète des instructions programmées par l’utilisateur, puis déclenche des actions : un moteur qui se met en marche, une lumière qui s’allume, un robot qui change de trajectoire. À travers elle, LEGO a transformé l’acte de construire en une véritable expérience de conception, où l’imagination se prolonge dans la logique et l’expérimentation. +À première vue c'est une brique LEGO comme une autre. Un parallélépipède de plastique gris, le format classique, deux par quatre tenons sur le dessus. On pourrait la prendre, l'emboîter dans un mur, et ne rien remarquer. Sauf que celle-là parle. Elle fait du bruit, elle clignote, elle sait si vous la secouez ou si vous la posez à plat. À l'intérieur, LEGO a réussi à caser un accéléromètre, un capteur de lumière, un capteur de couleur, un haut-parleur miniature et une puce sur mesure plus petite qu'un seul tenon. C'est la **LEGO Smart Brick**, et elle est arrivée en boutique le 1ᵉʳ mars 2026. -Cette mutation a ouvert la porte à une nouvelle façon de jouer. Les modèles ne sont plus figés dans une posture décorative : ils vivent, réagissent, apprennent presque. Un véhicule peut désormais éviter un obstacle, un bras mécanique saisir un objet, un automate suivre une ligne tracée au sol. L’enfant ne se contente plus d’assembler des pièces ; il devient ingénieur, programmeur, inventeur d’un monde en mouvement. Chaque erreur devient une hypothèse à tester, chaque réussite une découverte. Le jeu se transforme en terrain d’exploration scientifique, sans jamais perdre sa part de rêve. +Il faut tout de suite tordre le cou à un malentendu. La Smart Brick, ce n'est pas un Mindstorms. Ce n'est pas du LEGO éducatif, ce n'est pas une plateforme pour apprendre à coder, et on ne programme rien du tout avec. C'est un objet beaucoup plus simple dans son intention : faire en sorte qu'un set LEGO réagisse quand on joue avec. Vous prenez le X-Wing de Luke Skywalker, vous le faites basculer pour décoller, le brique embarquée détecte le mouvement et joue le bruit du moteur. Vous posez la minifigurine de Dark Vador à côté, la brique la reconnaît grâce à un Smart Tag (une petite tuile codée), et elle déclenche la respiration emblématique du Seigneur Sith. C'est tout. Mais c'est déjà beaucoup. -C’est sans doute là que réside la force la plus subtile de la Smart Brick : dans sa dimension éducative. Derrière l’apparente simplicité des interfaces de programmation, elle initie à la pensée algorithmique, à la rigueur de la logique, à la patience qu’exige toute mise au point technique. Sans discours théorique, sans tableaux noirs ni équations imposées, elle enseigne les bases de l’informatique et de la robotique comme on apprend une langue étrangère en voyageant : par immersion, par tâtonnement, par plaisir. +LEGO appelle cet écosystème **Smart Play**. Il repose sur trois éléments. La Smart Brick elle-même, qui est le cerveau et le haut-parleur. Les Smart Tags, des tuiles plates qu'on accroche aux constructions et qui disent à la brique ce qu'elle doit faire à cet endroit (« ici tu joues un bruit de tir laser », « ici tu fais le bruit du réacteur »). Et les Smart Minifigures, des figurines avec un identifiant intégré, que la brique détecte quand on les approche. Le tout communique en local, sans appli obligatoire, sans écran, via un système maison que LEGO a baptisé BrickNet. C'est important : le pari est explicitement de faire de la techno **invisible**, pas de coller un smartphone entre l'enfant et le jouet. -Au fil des années, cette brique intelligente a elle-même grandi. Des premiers modèles un peu rustiques aux hubs modernes capables de communiquer sans fil et d’exécuter des programmes complexes, elle a suivi l’évolution rapide des technologies numériques. Aujourd’hui, elle se rapproche davantage d’un véritable micro-ordinateur que d’un simple accessoire de jeu. Pourtant, son enveloppe reste la même, fidèle au format LEGO, comme pour rappeler que l’innovation la plus profonde peut parfois se glisser dans les formes les plus familières. +Côté pratique, la brique se recharge sans fil. Elle tient environ deux heures et demie en jeu actif, se met en veille au bout de trois minutes d'inactivité et se réveille quand on la secoue. Au-delà d'une dizaine d'heures de veille, il faut la remettre sur son chargeur. Une application gratuite, **LEGO SMART Assist**, sert à régler le volume, donner un nom à ses briques, gérer plusieurs appareils, et surtout mettre à jour le firmware — parce que oui, une brique LEGO peut maintenant recevoir des mises à jour logicielles. On y est. -La Smart Brick occupe ainsi une place singulière, à la frontière entre le jouet et l’outil scientifique. Dans une salle de classe, elle devient support pédagogique. Dans un atelier de passionnés, elle sert de laboratoire miniature. Dans une chambre d’enfant, elle allume peut-être la première étincelle d’une vocation future. Elle prouve surtout qu’il n’y a pas d’âge pour comprendre la technologie, et que la science peut naître d’un simple geste : emboîter deux briques, puis leur donner vie. +Pour le lancement, LEGO a choisi Star Wars, et l'offre est un peu plus subtile qu'il n'y paraît. **Huit sets** sortent le 1ᵉʳ mars, mais seulement **trois contiennent réellement une Smart Brick**. Ce sont les coffrets dits *All-In-One*, qui embarquent la brique, son chargeur, des tags et des figurines intelligentes : -Plus qu’une innovation technique, la Smart Brick est un symbole. Celui d’un monde où la créativité manuelle rencontre l’intelligence numérique, où le jeu devient apprentissage, et où une petite brique de plastique peut ouvrir, discrètement, la porte vers les grandes aventures de la science et de l’ingénierie. +- **75421 — Chasseur TIE de Dark Vador** : 69,99 €, le ticket d'entrée. +- **75423 — Le X-Wing rouge de Luke Skywalker** : 89,99 €. +- **75427 — Duel dans la salle du trône & A-Wing** : 159,99 €, le plus gros, avec **deux** Smart Bricks. -Voici **les informations connues à ce jour (janvier 2026)** sur **la disponibilité de la Smart Brick LEGO** et les modèles où elle est proposée : +Les cinq autres sets — Millennium Falcon, Mos Eisley Cantina, AT-ST Endor, hutte de Yoda, Landspeeder de Luke — sont étiquetés Smart Play mais ne contiennent **pas** de brique. Ils embarquent juste des tags et des figurines compatibles. Pour qu'ils s'animent, il faut posséder une brique achetée dans l'un des trois coffrets *All-In-One*, et la déplacer d'un set à l'autre. C'est un choix commercial qu'on peut critiquer : un parent ou un grand-parent qui voit *Smart Play* sur la boîte de la Mos Eisley Cantina à 79,99 € a de quoi être surpris en rentrant à la maison. -### 📅 Date de sortie +Géographiquement, le lancement est restreint. Six pays seulement à l'ouverture : États-Unis, Royaume-Uni, France, Allemagne, Pologne, Australie. Le reste du monde attendra. -La **Smart Brick LEGO** (élément électronique interactif intégré à une brique standard) **sera disponible à partir du **1ᵉʳ mars 2026**, avec ouverture des précommandes dès début janvier 2026. ([Toms Guide][1]) +Pourquoi est-ce intéressant au-delà du cas Star Wars ? Parce que LEGO ne fait pas ça pour vendre trois sets. La marque parle de **plus de vingt brevets** déposés sur la techno, et de la « plus grande évolution du système LEGO depuis l'introduction de la minifigurine en 1978 ». Le ton est ambitieux, et il y a déjà des rumeurs de déclinaisons sur les gammes Pokémon et Animal Crossing. Si le pari réussit, on parle d'une plateforme qui peut s'étendre à toute la production LEGO sur dix ou vingt ans. Si elle échoue, ce sera la deuxième tentative ratée après les Mindstorms et la gamme Boost, dans la longue liste des essais LEGO pour marier l'électronique au plastique. -### 🎁 Modèles / ensembles où la Smart Brick est proposée au lancement +Le point qui me semble vraiment réussi, c'est la philosophie sans écran. Là où la plupart des jouets connectés exigent une tablette pour fonctionner, où l'enfant finit en pratique à regarder un iPad plutôt qu'à jouer avec l'objet physique, LEGO a fait le choix inverse : l'application existe mais elle est facultative, toute l'interaction se passe entre les mains et les briques. C'est moins spectaculaire dans une démo marketing, mais c'est probablement plus juste pour des gamins de huit ans. -Pour son lancement, la Smart Brick est intégrée dans **trois sets LEGO Star Wars de la nouvelle gamme *SMART Play***. Ces ensembles incluent également des *Smart Tags* et des *Smart Minifigures* pour exploiter les effets interactifs (sons, lumières, réactions physiques) : ([Toms Guide][1]) - -* Un set autour du **TIE Fighter de Dark Vador** (offrant un Smart Brick et des effets interactifs). ([HOTH BRICKS][2]) -* Le **X-Wing “Red Five” de Luke Skywalker**, avec plusieurs Smart Tags et figurines intelligentes. ([HOTH BRICKS][2]) -* Un set plus complet **“Throne Room Duel & A-Wing”**, qui inclut **deux Smart Bricks** et plusieurs composants intelligents. ([HOTH BRICKS][2]) - -Ces boîtes sont commercialisées comme **ensembles “All-In-One” SMART Play** : elles contiennent tout le nécessaire (Smart Brick(s), chargeur sans fil inclus, Smart Tags, figurines) pour découvrir et utiliser la technologie. ([LEGO][3]) - -### 🛒 Disponibilité - -* **Précommandes disponibles maintenant** auprès de LEGO et de revendeurs. ([Toms Guide][1]) -* **Livraison/arrivée en boutiques : 1er mars 2026**. ([Frandroid][4]) - -Si tu souhaites, je peux te lister précisément les **références LEGO Smart Play disponibles** (numéros de set + prix indicatifs) pour comparer. - -[1]: https://www.tomsguide.fr/lego-smart-play-quels-sont-les-sets-qui-vont-profiter-des-briques-intelligentes/?utm_source=chatgpt.com "Lego Smart Play : quels sont les sets qui vont profiter des ..." -[2]: https://www.hothbricks.com/sur-le-shop-lego-ou-chez-amazon-les-nouveautes-lego-star-wars-compatibles-smart-play-sont-en-precommande/?utm_source=chatgpt.com "Les nouveautés LEGO Star Wars compatibles SMART ..." -[3]: https://www.lego.com/fr-fr/smart-play/all-sets?utm_source=chatgpt.com "Jouets LEGO® SMART Play" -[4]: https://www.frandroid.com/produits-android/maison-connectee/2902811_lego-smart-brick-tout-savoir-sur-la-brique-connectee-qui-revolutionne-la-construction?utm_source=chatgpt.com "LEGO Smart Brick : tout savoir sur la brique connectée qui ..." +Reste à voir ce que ça donne en vrai, sur le tapis du salon, après six mois d'utilisation, quand la batterie sera moins fringante et que la nouveauté se sera émoussée. C'est toujours là que se joue la vraie partie pour ce genre de produit. Mais sur le papier, et c'est rare, LEGO a sorti quelque chose qui ne ressemble à rien d'autre. \ No newline at end of file diff --git a/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/meta.json b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/meta.json index 076fee4..251bb52 100644 --- a/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/meta.json +++ b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/meta.json @@ -1,13 +1,152 @@ { "uuid": "c8fa250e-d8b5-453a-a06a-799d53c3b6d1", "slug": "la-smart-brick-de-lego-quand-la-brique-devient-intelligente", - "title": "La Smart Brick de LEGO : quand la brique devient intelligente", + "title": "LEGO : La brique qui répond", "author": "cedric@abonnel.fr", "published": true, - "published_at": "2026-01-13 20:26:53", + "published_at": "2026-01-13 20:26", "created_at": "2026-01-13 20:26:53", - "updated_at": "2026-01-13 20:26:53", - "revisions": [], + "updated_at": "2026-05-11 22:45:23", + "revisions": [ + { + "n": 1, + "date": "2026-05-11 21:54:06", + "comment": "", + "title": "LEGO : La brique qui répond" + }, + { + "n": 2, + "date": "2026-05-11 22:45:23", + "comment": "", + "title": "LEGO : La brique qui répond" + } + ], "cover": "cover.jpg", + "files_meta": { + "cover.jpg": { + "author": "", + "source_url": "https://thegadgetflow.com/wp-content/uploads/2026/01/LEGO-Interactive-smart-brick-featured-image-1.jpg" + }, + "_thumb_035b34dd014ac80f-635197.jpg": { + "author": "", + "source_url": "" + }, + "_thumb_5913d9738c966833-30567.jpg": { + "author": "", + "source_url": "" + }, + "_thumb_7d6ba93f6ce840e7-13566.webp": { + "author": "", + "source_url": "" + }, + "_thumb_d5dde33b48cd2761-66620.jpg": { + "author": "", + "source_url": "" + }, + "_thumb_e99b946f131256b8-49943.jpg": { + "author": "", + "source_url": "" + }, + "_thumb_fb5a5b1ffa000d12-30780.png": { + "author": "", + "source_url": "" + } + }, + "external_links": [ + { + "url": "https://www.begeek.fr/lego-smart-brick-les-briques-de-la-marque-danoise-deviennent-interactives-426477", + "name": "LEGO Smart Brick : les briques de la marque danoise deviennent interactives", + "added_at": "2026-05-11 21:47:32", + "meta": { + "mime": "text/html", + "size": 36385, + "description": "Avec les Smart Bricks, LEGO transforme chaque construction en une expérience connectée grâce à des capteurs, haut-parleurs et LED intégrés.", + "og_image": "/file?uuid=c8fa250e-d8b5-453a-a06a-799d53c3b6d1&name=_thumb_5913d9738c966833-30567.jpg", + "site_name": "Begeek", + "og_type": "article", + "language": "fr_FR", + "date": "2026-01-07T13:00:51+00:00", + "canonical": "https://www.begeek.fr/lego-smart-brick-les-briques-de-la-marque-danoise-deviennent-interactives-426477" + } + }, + { + "url": "https://www.mac4ever.com/divers/193948-lego-devoile-une-etonnante-brique-intelligente-au-ces-2026", + "name": "LEGO dévoile une étonnante brique intelligente au CES 2026", + "added_at": "2026-05-11 21:47:50", + "meta": { + "mime": "text/html", + "size": 121071, + "description": "Pour sa première apparition au CES de Las Vegas, LEGO frappe fort avec Smart Play, une nouvelle plateforme qui intègre de l'électronique miniaturisée…", + "og_image": "/file?uuid=c8fa250e-d8b5-453a-a06a-799d53c3b6d1&name=_thumb_7d6ba93f6ce840e7-13566.webp", + "site_name": "Mac4Ever", + "og_type": "article", + "language": "fr_FR", + "date": "2026-01-06T09:36:39+01:00", + "canonical": "https://www.mac4ever.com/divers/193948-lego-devoile-une-etonnante-brique-intelligente-au-ces-2026" + } + }, + { + "url": "https://www.clubic.com/actualite-593794-lego-devoile-smart-play-sa-plus-grosse-innovation-depuis-toujours.html", + "name": "LEGO dévoile Smart Play, sa plus grosse innovation \"depuis... toujours\" !", + "added_at": "2026-05-11 21:48:05", + "meta": { + "mime": "text/html", + "size": 251642, + "description": "Dans les couloirs du CES de Las Vegas, la marque LEGO a tenu à dévoiler une toute nouvelle brique intelligente : Smart Brick. Une brique qui va se charger de réagir de manière intelligente (et autonome) à son environnement, sans la moindre application ou écran externe.", + "og_image": "/file?uuid=c8fa250e-d8b5-453a-a06a-799d53c3b6d1&name=_thumb_d5dde33b48cd2761-66620.jpg", + "site_name": "clubic.com", + "og_type": "article", + "language": "fr_FR", + "date": "2026-01-07T09:56:00+01:00", + "canonical": "https://www.clubic.com/actualite-593794-lego-devoile-smart-play-sa-plus-grosse-innovation-depuis-toujours.html" + } + }, + { + "url": "https://www.solutions-magazine.com/lego-smart-brick/", + "name": "LEGO lance sa « smart brick » - Solutions Magazine", + "added_at": "2026-05-11 21:48:23", + "meta": { + "mime": "text/html", + "size": 582486, + "description": "Au CES, Lego a dévoilé un ensemble de nouvelles technologies insérées dans ses futurs jouets. Notamment sa « smart brick »", + "og_image": "/file?uuid=c8fa250e-d8b5-453a-a06a-799d53c3b6d1&name=_thumb_e99b946f131256b8-49943.jpg", + "site_name": "Solutions Magazine", + "og_type": "article", + "language": "fr_FR", + "date": "2026-01-10T15:56:46+00:00", + "canonical": "https://www.solutions-magazine.com/lego-smart-brick/" + } + }, + { + "url": "https://www.lesnumeriques.com/jouet/lego-smart-play-on-a-mis-nos-gros-doigts-sur-la-petite-brique-magique-et-c-est-bluffant-n249358.html", + "name": "Lego Smart Play : on a mis nos gros doigts sur la petite brique magique, et c'est bluffant ! - Les Numériques", + "added_at": "2026-05-11 21:48:38", + "meta": { + "mime": "text/html", + "size": 219016, + "description": "Présentée il y a quelques jours au CES en exclusivité, la brique Lego connectée Smart Brick s'est dévoilée un peu plus à Paris. Après quelques minutes de démonstration, avouons-le : nous regrettons de ne plus avoir 8 ans pour jouer avec sans scrupule.", + "keywords": "lego", + "og_image": "/file?uuid=c8fa250e-d8b5-453a-a06a-799d53c3b6d1&name=_thumb_035b34dd014ac80f-635197.jpg", + "og_type": "article", + "date": "2026-01-11T06:00:00Z", + "canonical": "https://www.lesnumeriques.com/jouet/lego-smart-play-on-a-mis-nos-gros-doigts-sur-la-petite-brique-magique-et-c-est-bluffant-n249358.html" + } + }, + { + "url": "https://www.lego.com/fr-fr/smart-play", + "name": "Système LEGO® SMART Play™ | Boutique LEGO® officielle FR", + "added_at": "2026-05-11 21:48:47", + "meta": { + "mime": "text/html", + "size": 1219325, + "description": "Voici le système LEGO® SMART Play™, conçu pour stimuler la créativité des enfants. Découvrez cette évolution du jeu LEGO® qui vous répond à l’infini ! Plus d’informations ici", + "canonical": "https://www.lego.com/fr-fr/smart-play", + "og_image": "/file?uuid=c8fa250e-d8b5-453a-a06a-799d53c3b6d1&name=_thumb_fb5a5b1ffa000d12-30780.png" + } + } + ], + "seo_title": "", + "seo_description": "", + "og_image": "", "category": "loisirs" } diff --git a/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/revisions/0001.md b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/revisions/0001.md new file mode 100644 index 0000000..3494d6e --- /dev/null +++ b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/revisions/0001.md @@ -0,0 +1,25 @@ +## La brique qui répond + +À première vue c'est une brique LEGO comme une autre. Un parallélépipède de plastique gris, le format classique, deux par quatre tenons sur le dessus. On pourrait la prendre, l'emboîter dans un mur, et ne rien remarquer. Sauf que celle-là parle. Elle fait du bruit, elle clignote, elle sait si vous la secouez ou si vous la posez à plat. À l'intérieur, LEGO a réussi à caser un accéléromètre, un capteur de lumière, un capteur de couleur, un haut-parleur miniature et une puce sur mesure plus petite qu'un seul tenon. C'est la **LEGO Smart Brick**, et elle est arrivée en boutique le 1ᵉʳ mars 2026. + +Il faut tout de suite tordre le cou à un malentendu. La Smart Brick, ce n'est pas un Mindstorms. Ce n'est pas du LEGO éducatif, ce n'est pas une plateforme pour apprendre à coder, et on ne programme rien du tout avec. C'est un objet beaucoup plus simple dans son intention : faire en sorte qu'un set LEGO réagisse quand on joue avec. Vous prenez le X-Wing de Luke Skywalker, vous le faites basculer pour décoller, le brique embarquée détecte le mouvement et joue le bruit du moteur. Vous posez la minifigurine de Dark Vador à côté, la brique la reconnaît grâce à un Smart Tag (une petite tuile codée), et elle déclenche la respiration emblématique du Seigneur Sith. C'est tout. Mais c'est déjà beaucoup. + +LEGO appelle cet écosystème **Smart Play**. Il repose sur trois éléments. La Smart Brick elle-même, qui est le cerveau et le haut-parleur. Les Smart Tags, des tuiles plates qu'on accroche aux constructions et qui disent à la brique ce qu'elle doit faire à cet endroit (« ici tu joues un bruit de tir laser », « ici tu fais le bruit du réacteur »). Et les Smart Minifigures, des figurines avec un identifiant intégré, que la brique détecte quand on les approche. Le tout communique en local, sans appli obligatoire, sans écran, via un système maison que LEGO a baptisé BrickNet. C'est important : le pari est explicitement de faire de la techno **invisible**, pas de coller un smartphone entre l'enfant et le jouet. + +Côté pratique, la brique se recharge sans fil. Elle tient environ deux heures et demie en jeu actif, se met en veille au bout de trois minutes d'inactivité et se réveille quand on la secoue. Au-delà d'une dizaine d'heures de veille, il faut la remettre sur son chargeur. Une application gratuite, **LEGO SMART Assist**, sert à régler le volume, donner un nom à ses briques, gérer plusieurs appareils, et surtout mettre à jour le firmware — parce que oui, une brique LEGO peut maintenant recevoir des mises à jour logicielles. On y est. + +Pour le lancement, LEGO a choisi Star Wars, et l'offre est un peu plus subtile qu'il n'y paraît. **Huit sets** sortent le 1ᵉʳ mars, mais seulement **trois contiennent réellement une Smart Brick**. Ce sont les coffrets dits *All-In-One*, qui embarquent la brique, son chargeur, des tags et des figurines intelligentes : + +- **75421 — Chasseur TIE de Dark Vador** : 69,99 €, le ticket d'entrée. +- **75423 — Le X-Wing rouge de Luke Skywalker** : 89,99 €. +- **75427 — Duel dans la salle du trône & A-Wing** : 159,99 €, le plus gros, avec **deux** Smart Bricks. + +Les cinq autres sets — Millennium Falcon, Mos Eisley Cantina, AT-ST Endor, hutte de Yoda, Landspeeder de Luke — sont étiquetés Smart Play mais ne contiennent **pas** de brique. Ils embarquent juste des tags et des figurines compatibles. Pour qu'ils s'animent, il faut posséder une brique achetée dans l'un des trois coffrets *All-In-One*, et la déplacer d'un set à l'autre. C'est un choix commercial qu'on peut critiquer : un parent ou un grand-parent qui voit *Smart Play* sur la boîte de la Mos Eisley Cantina à 79,99 € a de quoi être surpris en rentrant à la maison. + +Géographiquement, le lancement est restreint. Six pays seulement à l'ouverture : États-Unis, Royaume-Uni, France, Allemagne, Pologne, Australie. Le reste du monde attendra. + +Pourquoi est-ce intéressant au-delà du cas Star Wars ? Parce que LEGO ne fait pas ça pour vendre trois sets. La marque parle de **plus de vingt brevets** déposés sur la techno, et de la « plus grande évolution du système LEGO depuis l'introduction de la minifigurine en 1978 ». Le ton est ambitieux, et il y a déjà des rumeurs de déclinaisons sur les gammes Pokémon et Animal Crossing. Si le pari réussit, on parle d'une plateforme qui peut s'étendre à toute la production LEGO sur dix ou vingt ans. Si elle échoue, ce sera la deuxième tentative ratée après les Mindstorms et la gamme Boost, dans la longue liste des essais LEGO pour marier l'électronique au plastique. + +Le point qui me semble vraiment réussi, c'est la philosophie sans écran. Là où la plupart des jouets connectés exigent une tablette pour fonctionner, où l'enfant finit en pratique à regarder un iPad plutôt qu'à jouer avec l'objet physique, LEGO a fait le choix inverse : l'application existe mais elle est facultative, toute l'interaction se passe entre les mains et les briques. C'est moins spectaculaire dans une démo marketing, mais c'est probablement plus juste pour des gamins de huit ans. + +Reste à voir ce que ça donne en vrai, sur le tapis du salon, après six mois d'utilisation, quand la batterie sera moins fringante et que la nouveauté se sera émoussée. C'est toujours là que se joue la vraie partie pour ce genre de produit. Mais sur le papier, et c'est rare, LEGO a sorti quelque chose qui ne ressemble à rien d'autre. \ No newline at end of file diff --git a/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/revisions/0002.md b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/revisions/0002.md new file mode 100644 index 0000000..6b9d6aa --- /dev/null +++ b/data/c8fa250e-d8b5-453a-a06a-799d53c3b6d1/revisions/0002.md @@ -0,0 +1,25 @@ +## La brique qui répond + +À première vue c'est une brique LEGO comme une autre. Un parallélépipède de plastique gris, le format classique, deux par quatre tenons sur le dessus. On pourrait la prendre, l'emboîter dans un mur, et ne rien remarquer. Sauf que celle-là parle. Elle fait du bruit, elle clignote, elle sait si vous la secouez ou si vous la posez à plat. À l'intérieur, LEGO a réussi à caser un accéléromètre, un capteur de lumière, un capteur de couleur, un haut-parleur miniature et une puce sur mesure plus petite qu'un seul tenon. C'est la **LEGO Smart Brick**, et elle est arrivée en boutique le 1ᵉʳ mars 2026. + +Il faut tout de suite tordre le cou à un malentendu. La Smart Brick, ce n'est pas un Mindstorms. Ce n'est pas du LEGO éducatif, ce n'est pas une plateforme pour apprendre à coder, et on ne programme rien du tout avec. C'est un objet beaucoup plus simple dans son intention : faire en sorte qu'un set LEGO réagisse quand on joue avec. Vous prenez le X-Wing de Luke Skywalker, vous le faites basculer pour décoller, le brique embarquée détecte le mouvement et joue le bruit du moteur. Vous posez la minifigurine de Dark Vador à côté, la brique la reconnaît grâce à un Smart Tag (une petite tuile codée), et elle déclenche la respiration emblématique du Seigneur Sith. C'est tout. Mais c'est déjà beaucoup. + +LEGO appelle cet écosystème **Smart Play**. Il repose sur trois éléments. La Smart Brick elle-même, qui est le cerveau et le haut-parleur. Les Smart Tags, des tuiles plates qu'on accroche aux constructions et qui disent à la brique ce qu'elle doit faire à cet endroit (« ici tu joues un bruit de tir laser », « ici tu fais le bruit du réacteur »). Et les Smart Minifigures, des figurines avec un identifiant intégré, que la brique détecte quand on les approche. Le tout communique en local, sans appli obligatoire, sans écran, via un système maison que LEGO a baptisé BrickNet. C'est important : le pari est explicitement de faire de la techno **invisible**, pas de coller un smartphone entre l'enfant et le jouet. + +Côté pratique, la brique se recharge sans fil. Elle tient environ deux heures et demie en jeu actif, se met en veille au bout de trois minutes d'inactivité et se réveille quand on la secoue. Au-delà d'une dizaine d'heures de veille, il faut la remettre sur son chargeur. Une application gratuite, **LEGO SMART Assist**, sert à régler le volume, donner un nom à ses briques, gérer plusieurs appareils, et surtout mettre à jour le firmware — parce que oui, une brique LEGO peut maintenant recevoir des mises à jour logicielles. On y est. + +Pour le lancement, LEGO a choisi Star Wars, et l'offre est un peu plus subtile qu'il n'y paraît. **Huit sets** sortent le 1ᵉʳ mars, mais seulement **trois contiennent réellement une Smart Brick**. Ce sont les coffrets dits *All-In-One*, qui embarquent la brique, son chargeur, des tags et des figurines intelligentes : + +- **75421 — Chasseur TIE de Dark Vador** : 69,99 €, le ticket d'entrée. +- **75423 — Le X-Wing rouge de Luke Skywalker** : 89,99 €. +- **75427 — Duel dans la salle du trône & A-Wing** : 159,99 €, le plus gros, avec **deux** Smart Bricks. + +Les cinq autres sets — Millennium Falcon, Mos Eisley Cantina, AT-ST Endor, hutte de Yoda, Landspeeder de Luke — sont étiquetés Smart Play mais ne contiennent **pas** de brique. Ils embarquent juste des tags et des figurines compatibles. Pour qu'ils s'animent, il faut posséder une brique achetée dans l'un des trois coffrets *All-In-One*, et la déplacer d'un set à l'autre. C'est un choix commercial qu'on peut critiquer : un parent ou un grand-parent qui voit *Smart Play* sur la boîte de la Mos Eisley Cantina à 79,99 € a de quoi être surpris en rentrant à la maison. + +Géographiquement, le lancement est restreint. Six pays seulement à l'ouverture : États-Unis, Royaume-Uni, France, Allemagne, Pologne, Australie. Le reste du monde attendra. + +Pourquoi est-ce intéressant au-delà du cas Star Wars ? Parce que LEGO ne fait pas ça pour vendre trois sets. La marque parle de **plus de vingt brevets** déposés sur la techno, et de la « plus grande évolution du système LEGO depuis l'introduction de la minifigurine en 1978 ». Le ton est ambitieux, et il y a déjà des rumeurs de déclinaisons sur les gammes Pokémon et Animal Crossing. Si le pari réussit, on parle d'une plateforme qui peut s'étendre à toute la production LEGO sur dix ou vingt ans. Si elle échoue, ce sera la deuxième tentative ratée après les Mindstorms et la gamme Boost, dans la longue liste des essais LEGO pour marier l'électronique au plastique. + +Le point qui me semble vraiment réussi, c'est la philosophie sans écran. Là où la plupart des jouets connectés exigent une tablette pour fonctionner, où l'enfant finit en pratique à regarder un iPad plutôt qu'à jouer avec l'objet physique, LEGO a fait le choix inverse : l'application existe mais elle est facultative, toute l'interaction se passe entre les mains et les briques. C'est moins spectaculaire dans une démo marketing, mais c'est probablement plus juste pour des gamins de huit ans. + +Reste à voir ce que ça donne en vrai, sur le tapis du salon, après six mois d'utilisation, quand la batterie sera moins fringante et que la nouveauté se sera émoussée. C'est toujours là que se joue la vraie partie pour ce genre de produit. Mais sur le papier, et c'est rare, LEGO a sorti quelque chose qui ne ressemble à rien d'autre. \ No newline at end of file diff --git a/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_63b0e27c3950cfe1-993774.webp b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_63b0e27c3950cfe1-993774.webp new file mode 100644 index 0000000..17836e5 Binary files /dev/null and b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_63b0e27c3950cfe1-993774.webp differ diff --git a/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_6dea6d617384f5ed-875.gif b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_6dea6d617384f5ed-875.gif new file mode 100644 index 0000000..e594837 Binary files /dev/null and b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_6dea6d617384f5ed-875.gif differ diff --git a/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_7df96bdf1ecebb75-124286.jpg b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_7df96bdf1ecebb75-124286.jpg new file mode 100644 index 0000000..2a1cec7 Binary files /dev/null and b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_7df96bdf1ecebb75-124286.jpg differ diff --git a/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_bfd46debd51361c4-255309.jpg b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_bfd46debd51361c4-255309.jpg new file mode 100644 index 0000000..5d0bd1b Binary files /dev/null and b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_bfd46debd51361c4-255309.jpg differ diff --git a/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_c436b74420666bbb-3393394.png b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_c436b74420666bbb-3393394.png new file mode 100644 index 0000000..5b2f512 Binary files /dev/null and b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_c436b74420666bbb-3393394.png differ diff --git a/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_e58b3803bdfafdf0-360838.png b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_e58b3803bdfafdf0-360838.png new file mode 100644 index 0000000..f3c9683 Binary files /dev/null and b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/_thumb_e58b3803bdfafdf0-360838.png differ diff --git a/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/cover.jpg b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/cover.jpg new file mode 100644 index 0000000..dec1178 Binary files /dev/null and b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/files/cover.jpg differ diff --git a/data/e739bf3c-b380-4567-90aa-32da12f56bc5/index.md b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/index.md index 49f686c..a8feac6 100644 --- a/data/e739bf3c-b380-4567-90aa-32da12f56bc5/index.md +++ b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/index.md @@ -1,78 +1,61 @@ -Alors que les discussions publiques se focalisent souvent sur la 5G et les futures générations mobiles, une révolution plus discrète mais tout aussi fondamentale est en cours : **la disparition progressive du cuivre** dans les réseaux fixes. Le cuivre, utilisé depuis des décennies pour le téléphone et l’ADSL, cède la place à la fibre optique, plus rapide, plus fiable et capable de supporter les usages ultra-connectés de demain. +La fibre optique a déjà remplacé le cuivre dans la plupart des déploiements neufs, et les opérateurs ont passé la dernière décennie à généraliser le GPON puis le XGS-PON. Mais la course aux débits ne s'arrête pas là. La prochaine marche s'appelle le **50G-PON**, et elle est en train de passer du statut de standard sur le papier à celui de technologie qu'on commence à voir en démonstration chez les équipementiers. Voilà ce qu'il faut en retenir. -Parmi les technologies qui matérialisent cette transition, le **50G-PON** (Passive Optical Network à 50 Gbit/s) représente le futur de la connectivité fixe. Destiné à remplacer le GPON (1 Gbit/s) et le XGS-PON (10 Gbit/s), il illustre la manière dont la fibre prend le relais du cuivre, tant pour les particuliers que pour les entreprises. +## Ce que c'est ---- +Le 50G-PON est la dernière génération de réseau optique passif normalisée par l'ITU-T sous la référence **G.9804**. Comme ses prédécesseurs, il repose sur le principe d'une fibre unique partagée entre plusieurs abonnés via des splitters passifs — pas d'électronique active entre le central et le client. Ce qui change, c'est le débit : **50 Gbit/s symétriques** sur une seule longueur d'onde. -### Définition et principes +Pour situer la techno dans sa famille : -* **PON (Passive Optical Network)** : réseau optique passif partagé entre plusieurs abonnés. -* **50G-PON** : dernière génération standardisée par l’ITU-T (G.9804), offrant **débits symétriques jusqu’à 50 Gbit/s** par fibre partagée. -* **Évolution par rapport au cuivre :** +- **GPON** : 2,5 Gbit/s descendant / 1,25 Gbit/s montant — la base du déploiement résidentiel actuel +- **XGS-PON** : 10 Gbit/s symétriques — la génération qui prend le relais aujourd'hui +- **NG-PON2** : 40 Gbit/s, obtenus en agrégeant quatre canaux de 10 Gbit/s sur des longueurs d'onde différentes +- **50G-PON** : 50 Gbit/s symétriques sur une longueur d'onde unique - * **GPON** : 1 Gbit/s – déjà bien plus rapide que l’ADSL cuivre. - * **XGS-PON** : 10 Gbit/s – multiplié par 10 par rapport au GPON. - * **NG-PON2** : 40 Gbit/s – agrégation de 4 × 10 Gbit/s. - * **50G-PON** : 50 Gbit/s symétriques – le cuivre ne peut tout simplement pas suivre. +Le point intéressant, c'est précisément ce dernier détail. Là où NG-PON2 multipliait les canaux pour atteindre 40 Gbit/s — au prix d'une électronique plus complexe et plus chère — le 50G-PON tape les 50 Gbit/s sur **une seule porteuse**. C'est techniquement plus exigeant côté composants optiques, mais beaucoup plus simple à industrialiser et à exploiter. ---- +## Comment ça marche -### Pourquoi la fibre remplace le cuivre +L'architecture reste celle du PON classique, ce qui est un choix volontaire pour garantir la coexistence avec les générations précédentes : -1. **Débits massifs** : les lignes cuivre plafonnent à quelques centaines de Mbit/s en VDSL2, tandis que la fibre monte facilement à 50 Gbit/s. -2. **Fiabilité** : la fibre est moins sensible aux perturbations électromagnétiques et aux pertes de signal sur de longues distances. -3. **Évolutivité** : la même infrastructure peut être mise à jour par simple changement d’équipements actifs, sans remplacer les câbles. -4. **Symétrie** : le cuivre ne peut offrir des débits montants équivalents aux débits descendants, contrairement à la fibre. - ---- - -### Architecture simplifiée - -```mermaid -flowchart LR - OLT[Optical Line Terminal - central] -->|Fibre optique unique| splitter[Splitters passifs] - splitter --> ONU1[Abonné 1] - splitter --> ONU2[Abonné 2] - splitter --> ONU3[Abonné 3] +``` +OLT (central) ──── fibre ──── [Splitter passif] ─┬─── ONT abonné 1 + ├─── ONT abonné 2 + └─── ONT abonné 3 ``` -* **OLT** : équipement central chez l’opérateur. -* **Splitters passifs** : distribuent le signal à plusieurs abonnés sans amplification. -* **ONU/ONT** : terminaison optique côté abonné. +- L'**OLT** (*Optical Line Terminal*), côté opérateur, pilote le réseau et émet le signal. +- Les **splitters passifs** dupliquent le signal lumineux pour le distribuer, sans alimentation ni amplification. +- L'**ONT** (*Optical Network Terminal*), chez l'abonné, fait la conversion optique-électrique. -Cette architecture est impossible à réaliser avec le cuivre à ces débits. +L'astuce du 50G-PON, c'est qu'il utilise **des longueurs d'onde différentes** de celles du GPON et du XGS-PON. Concrètement, les trois technologies peuvent **cohabiter sur la même fibre physique** : un opérateur peut continuer à servir ses abonnés GPON existants tout en branchant des nouveaux clients en XGS-PON ou en 50G-PON, sans retoucher l'infrastructure passive. C'est un point décisif pour le déploiement, parce qu'il évite la rupture de service et étale l'investissement. ---- +## Pourquoi ça compte -### Limites et défis +À 50 Gbit/s symétriques, on n'est plus dans la logique du « plus de débit pour le particulier ». L'enjeu est ailleurs, et il est triple. -* **Coût de déploiement** : remplacer les infrastructures cuivre existantes par la fibre demande des investissements lourds. -* **Adoption progressive** : tous les foyers ne nécessitent pas 50 Gbit/s, mais la fibre prépare l’avenir. -* **Interopérabilité** : certains équipements anciens ne peuvent pas être réutilisés. -* **Maintenance et consommation** : les équipements optiques haute vitesse demandent plus de puissance et de contrôle que le cuivre. +D'abord, **les usages professionnels** qui tournent en limite sur XGS-PON. Sauvegarde cloud à l'échelle d'une entreprise, synchronisation inter-sites, stockage partagé, environnements de travail virtualisés : ces flux ont besoin de débit symétrique et constant, et 10 Gbit/s commencent à serrer dans certains contextes. ---- +Ensuite, le **transport pour le mobile**. Une antenne 5G — et a fortiori 6G — doit être raccordée au cœur de réseau par un lien capable d'encaisser le trafic agrégé de tous les utilisateurs qu'elle sert. C'est ce qu'on appelle le *fronthaul* ou le *backhaul* selon l'architecture. Le 50G-PON est un candidat sérieux pour ce rôle, parce qu'il offre les bons débits avec une infrastructure mutualisable et peu coûteuse à exploiter. -### Usages envisagés +Enfin, **l'évolutivité**. La même fibre, le même splitter, le même chemin physique pourront porter le 50G-PON aujourd'hui et la génération suivante — déjà en discussion à l'ITU-T sous le nom de 100G-PON — demain. C'est ce qui justifie qu'on déploie du 50G-PON même si tous les abonnés n'en ont pas l'usage immédiat : ce n'est pas l'équipement client qui coûte cher, c'est la fibre dans la rue, et elle est déjà là. -* **Entreprises et datacenters** : backup cloud, stockage partagé, synchronisation massive. -* **Télétravail et multimédia** : visioconférences 8K, cloud gaming, streaming multiple. -* **Futurs usages** : smart cities, IoT à grande échelle, et éventuellement fronthaul/backhaul pour la 6G fixe. +## Ce qui freine encore ---- +Le 50G-PON existe, il est standardisé, et plusieurs équipementiers proposent du matériel compatible. Pour autant, le déploiement à grande échelle prendra du temps, pour quelques raisons concrètes. -### Comparaison rapide +Le **coût des équipements** reste élevé. Les composants optiques capables de moduler proprement à 50 Gbit/s sur une seule porteuse sont à un stade industriel récent, et les volumes ne sont pas encore là pour faire baisser les prix. Pour la majorité des foyers, le XGS-PON couvre largement les besoins et coûte beaucoup moins cher. -| Technologie | Débit symétrique | Usages typiques | -| ----------- | ---------------- | ----------------------------------- | -| Cuivre ADSL | 1–20 Mbit/s | Internet basique, téléphonie | -| VDSL2 | 50–100 Mbit/s | Internet résidentiel amélioré | -| GPON | 1 Gbit/s | Internet haut débit résidentiel | -| XGS-PON | 10 Gbit/s | PME, streaming HD, cloud | -| 50G-PON | 50 Gbit/s | Ultra-HD, datacenters, smart cities | +La **consommation énergétique** est plus importante que sur les générations précédentes. Ce n'est pas rédhibitoire, mais ça compte dans le bilan d'exploitation, surtout à l'échelle d'un opérateur. ---- +Enfin, **le marché n'est pas pressé**. Les box résidentielles actuelles n'exploiteraient même pas 10 Gbit/s symétriques, et les usages qui justifient le 50G-PON sont aujourd'hui concentrés sur des segments précis — entreprises, datacenters, opérateurs mobiles. Le déploiement va donc se faire par couches, en commençant par les zones où la demande existe vraiment. -La transition **cuivre → fibre** n’est pas qu’une question de vitesse : c’est un changement structurel. Le cuivre, malgré sa robustesse historique, atteint ses limites. La fibre, à travers des technologies comme le 50G-PON, est en train de devenir le **nouveau standard universel**, prêt à supporter les besoins numériques des prochaines décennies. +## En résumé -> En résumé, si le cuivre disparaît, ce n’est pas seulement pour la vitesse, mais pour **permettre l’infrastructure du futur**, capable de répondre aux besoins toujours croissants en connectivité. +| Technologie | Débit symétrique | Cible principale | +|---|---|---| +| GPON | 1 Gbit/s | Résidentiel actuel | +| XGS-PON | 10 Gbit/s | Résidentiel haut de gamme, PME | +| NG-PON2 | 40 Gbit/s (4 × 10) | Niche, peu déployé | +| 50G-PON | 50 Gbit/s | Entreprises, datacenters, transport mobile | + +Le 50G-PON n'est pas la techno qui va arriver dans les box grand public dans les six mois. C'est la **brique d'infrastructure** qui prépare la décennie qui vient : celle qui permettra aux opérateurs de répondre à la fois aux besoins des entreprises, au raccordement des antennes mobiles de prochaine génération, et à la montée en puissance progressive du résidentiel — sans toucher à la fibre déjà tirée. Et c'est exactement ce qu'on attend d'une bonne infrastructure : qu'elle se mette en place sans bruit, et qu'elle dure. diff --git a/data/e739bf3c-b380-4567-90aa-32da12f56bc5/meta.json b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/meta.json index 8146f4d..2d0f00c 100644 --- a/data/e739bf3c-b380-4567-90aa-32da12f56bc5/meta.json +++ b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/meta.json @@ -4,10 +4,147 @@ "title": "50G-PON : la fibre optique du futur", "author": "cedric@abonnel.fr", "published": true, - "published_at": "2025-11-05 08:48:01", + "published_at": "2025-11-05 08:48", "created_at": "2025-11-05 08:48:01", - "updated_at": "2025-11-05 08:48:01", - "revisions": [], + "updated_at": "2026-05-11 23:54:38", + "revisions": [ + { + "n": 1, + "date": "2026-05-11 23:54:38", + "comment": "", + "title": "50G-PON : la fibre optique du futur" + } + ], "cover": "cover.jpg", + "files_meta": { + "cover.jpg": { + "author": "", + "source_url": "https://www.zdnet.fr/wp-content/uploads/zdnet/2025/10/fibre-1125x615.jpg" + }, + "_thumb_63b0e27c3950cfe1-993774.webp": { + "author": "", + "source_url": "" + }, + "_thumb_6dea6d617384f5ed-875.gif": { + "author": "", + "source_url": "" + }, + "_thumb_7df96bdf1ecebb75-124286.jpg": { + "author": "", + "source_url": "" + }, + "_thumb_bfd46debd51361c4-255309.jpg": { + "author": "", + "source_url": "" + }, + "_thumb_c436b74420666bbb-3393394.png": { + "author": "", + "source_url": "" + }, + "_thumb_e58b3803bdfafdf0-360838.png": { + "author": "", + "source_url": "" + } + }, + "external_links": [ + { + "url": "https://hellofuture.orange.com/fr/50g-pon-orange-ouvre-la-voie-a-la-fibre-du-futur/", + "name": "50G-PON : Orange ouvre la voie à la Fibre du futur - Hello Future", + "added_at": "2026-05-11 23:52:53", + "meta": { + "mime": "text/html", + "size": 117887, + "description": "Sur la standardisation de la triple coexistence de trois technologies PON Depuis 2006, Orange déploie la fibre jusqu’aux domiciles (FTTH-Fibre To The Home) et jusqu’aux entreprises (FTTE-Fibre To The Entreprise). Les réseaux d’accès fibre d’Orange reposent sur des infrastructures passives (fibres, câbles, connecteurs, boitiers etc.) et des systèmes de transmissions…", + "og_image": "/file?uuid=e739bf3c-b380-4567-90aa-32da12f56bc5&name=_thumb_bfd46debd51361c4-255309.jpg", + "site_name": "Hello Future", + "og_type": "article", + "language": "fr_FR", + "date": "2024-06-25T10:27:25+01:00", + "canonical": "https://hellofuture.orange.com/fr/50g-pon-orange-ouvre-la-voie-a-la-fibre-du-futur/" + } + }, + { + "url": "https://www.universfreebox.com/article/587477/orange-teste-la-fibre-du-futur-avec-la-50g-pon-a-40-gbit-s-une-premiere-en-france", + "name": "Orange teste la \"fibre du futur\" avec la 50G-PON à 40 Gbit/s, une première en France", + "added_at": "2026-05-11 23:53:22", + "author": "Lucas Musset", + "meta": { + "mime": "text/html", + "size": 118235, + "description": "Orange teste la technologie 50G-PON, une première en France pour la fibre très haut débit. Ce jeudi 23 octobre 2025, Orange a présenté à Lyon et Marseille une démonstration grandeur nature de la technologie 50G-PON, considérée comme la prochaine étape majeure dans l’évolution des réseaux fibre optique. Il s’agit, selon l’opérateur, d’une première en France. […]", + "og_image": "/file?uuid=e739bf3c-b380-4567-90aa-32da12f56bc5&name=_thumb_c436b74420666bbb-3393394.png", + "site_name": "Univers Freebox", + "og_type": "article", + "language": "fr_FR", + "date": "2025-10-23T16:00:44+00:00", + "canonical": "https://www.universfreebox.com/article/587477/orange-teste-la-fibre-du-futur-avec-la-50g-pon-a-40-gbit-s-une-premiere-en-france" + } + }, + { + "url": "https://www.generation-nt.com/actualites/orange-50g-pon-fibre-ftth-debit-2064811", + "name": "Fibre du futur : Orange teste du 50G-PON en conditions réelles", + "added_at": "2026-05-11 23:53:33", + "author": "Jérôme G.", + "meta": { + "mime": "text/html", + "size": 109809, + "description": "GNT est le portail Hi-Tech français consacré aux nouvelles technologies (internet, logiciel, matériel, mobilité, entreprise) et au jeu vidéo PC et consoles.", + "keywords": "50g-pon orange fibre optique , orange, 50g, pon, fibre, ftth, debit", + "og_image": "/file?uuid=e739bf3c-b380-4567-90aa-32da12f56bc5&name=_thumb_63b0e27c3950cfe1-993774.webp", + "site_name": "Génération NT", + "og_type": "article", + "language": "fr_FR", + "canonical": "https://www.generation-nt.com/actualites/orange-50g-pon-fibre-ftth-debit-2064811" + } + }, + { + "url": "https://www.zdnet.fr/actualites/orange-teste-la-fibre-optique-du-futur-jusqua-cinq-fois-plus-rapide-484095.htm", + "name": "Orange teste la fibre optique du futur, jusqu’à cinq fois plus ra ...", + "added_at": "2026-05-11 23:54:09", + "author": "Xavier Biseul", + "meta": { + "mime": "text/html", + "size": 236667, + "description": "Dans ses laboratoires, l’opérateur historique mène des expérimentations sur la technologie 50G-PON. Ce nouveau standard des réseaux de fibre optique permet d’atteindre des débits théoriques allant jusqu’à 50 gigabits par seconde.", + "og_image": "/file?uuid=e739bf3c-b380-4567-90aa-32da12f56bc5&name=_thumb_7df96bdf1ecebb75-124286.jpg", + "site_name": "ZDNET", + "og_type": "article", + "language": "fr_FR", + "date": "2025-10-28T15:20:02+00:00", + "canonical": "https://www.zdnet.fr/actualites/orange-teste-la-fibre-optique-du-futur-jusqua-cinq-fois-plus-rapide-484095.htm" + } + }, + { + "url": "https://www.lyon-entreprises.com/actualites/article/orange-teste-a-lyon-la-fibre-du-futur-grace-a-la-technologie-50g-pon", + "name": "Orange teste à Lyon la fibre du futur grâce à la technologie 50G-PON - Lyon Entreprises [LE]", + "added_at": "2026-05-11 23:54:21", + "meta": { + "mime": "text/html", + "size": 161762, + "description": "Un article d'actualité LE [ Lyon-Entreprises ], le portail d'information sur les entreprises pour les décideurs de Lyon et Rhône-Alpes", + "og_image": "/file?uuid=e739bf3c-b380-4567-90aa-32da12f56bc5&name=_thumb_e58b3803bdfafdf0-360838.png", + "site_name": "Lyon Entreprises [LE]", + "og_type": "article", + "language": "fr_FR", + "canonical": "https://www.lyon-entreprises.com/actualites/article/orange-teste-a-lyon-la-fibre-du-futur-grace-a-la-technologie-50g-pon" + } + }, + { + "url": "https://lafibre.info/orange-les-news/50g-pon-orange-ouvre-la-voie-a-la-fibre-du-futur/", + "name": "50G-PON : Orange ouvre la voie à la Fibre du futur", + "added_at": "2026-05-11 23:54:30", + "meta": { + "mime": "text/html", + "size": 48608, + "description": "50G-PON : Orange ouvre la voie à la Fibre du futur", + "keywords": "Fibre optique,FTTH,très haut débit,Gpon,FTTLA,FTTdp,Test débit,SpeedTest", + "canonical": "https://lafibre.info/orange-les-news/50g-pon-orange-ouvre-la-voie-a-la-fibre-du-futur/", + "og_image": "/file?uuid=e739bf3c-b380-4567-90aa-32da12f56bc5&name=_thumb_6dea6d617384f5ed-875.gif" + } + } + ], + "seo_title": "", + "seo_description": "", + "og_image": "", "category": "télécom" } diff --git a/data/e739bf3c-b380-4567-90aa-32da12f56bc5/revisions/0001.md b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/revisions/0001.md new file mode 100644 index 0000000..36b7b23 --- /dev/null +++ b/data/e739bf3c-b380-4567-90aa-32da12f56bc5/revisions/0001.md @@ -0,0 +1,61 @@ +La fibre optique a déjà remplacé le cuivre dans la plupart des déploiements neufs, et les opérateurs ont passé la dernière décennie à généraliser le GPON puis le XGS-PON. Mais la course aux débits ne s'arrête pas là. La prochaine marche s'appelle le **50G-PON**, et elle est en train de passer du statut de standard sur le papier à celui de technologie qu'on commence à voir en démonstration chez les équipementiers. Voilà ce qu'il faut en retenir. + +## Ce que c'est + +Le 50G-PON est la dernière génération de réseau optique passif normalisée par l'ITU-T sous la référence **G.9804**. Comme ses prédécesseurs, il repose sur le principe d'une fibre unique partagée entre plusieurs abonnés via des splitters passifs — pas d'électronique active entre le central et le client. Ce qui change, c'est le débit : **50 Gbit/s symétriques** sur une seule longueur d'onde. + +Pour situer la techno dans sa famille : + +- **GPON** : 2,5 Gbit/s descendant / 1,25 Gbit/s montant — la base du déploiement résidentiel actuel +- **XGS-PON** : 10 Gbit/s symétriques — la génération qui prend le relais aujourd'hui +- **NG-PON2** : 40 Gbit/s, obtenus en agrégeant quatre canaux de 10 Gbit/s sur des longueurs d'onde différentes +- **50G-PON** : 50 Gbit/s symétriques sur une longueur d'onde unique + +Le point intéressant, c'est précisément ce dernier détail. Là où NG-PON2 multipliait les canaux pour atteindre 40 Gbit/s — au prix d'une électronique plus complexe et plus chère — le 50G-PON tape les 50 Gbit/s sur **une seule porteuse**. C'est techniquement plus exigeant côté composants optiques, mais beaucoup plus simple à industrialiser et à exploiter. + +## Comment ça marche + +L'architecture reste celle du PON classique, ce qui est un choix volontaire pour garantir la coexistence avec les générations précédentes : + +``` +OLT (central) ──── fibre ──── [Splitter passif] ─┬─── ONT abonné 1 + ├─── ONT abonné 2 + └─── ONT abonné 3 +``` + +- L'**OLT** (*Optical Line Terminal*), côté opérateur, pilote le réseau et émet le signal. +- Les **splitters passifs** dupliquent le signal lumineux pour le distribuer, sans alimentation ni amplification. +- L'**ONT** (*Optical Network Terminal*), chez l'abonné, fait la conversion optique-électrique. + +L'astuce du 50G-PON, c'est qu'il utilise **des longueurs d'onde différentes** de celles du GPON et du XGS-PON. Concrètement, les trois technologies peuvent **cohabiter sur la même fibre physique** : un opérateur peut continuer à servir ses abonnés GPON existants tout en branchant des nouveaux clients en XGS-PON ou en 50G-PON, sans retoucher l'infrastructure passive. C'est un point décisif pour le déploiement, parce qu'il évite la rupture de service et étale l'investissement. + +## Pourquoi ça compte + +À 50 Gbit/s symétriques, on n'est plus dans la logique du « plus de débit pour le particulier ». L'enjeu est ailleurs, et il est triple. + +D'abord, **les usages professionnels** qui tournent en limite sur XGS-PON. Sauvegarde cloud à l'échelle d'une entreprise, synchronisation inter-sites, stockage partagé, environnements de travail virtualisés : ces flux ont besoin de débit symétrique et constant, et 10 Gbit/s commencent à serrer dans certains contextes. + +Ensuite, le **transport pour le mobile**. Une antenne 5G — et a fortiori 6G — doit être raccordée au cœur de réseau par un lien capable d'encaisser le trafic agrégé de tous les utilisateurs qu'elle sert. C'est ce qu'on appelle le *fronthaul* ou le *backhaul* selon l'architecture. Le 50G-PON est un candidat sérieux pour ce rôle, parce qu'il offre les bons débits avec une infrastructure mutualisable et peu coûteuse à exploiter. + +Enfin, **l'évolutivité**. La même fibre, le même splitter, le même chemin physique pourront porter le 50G-PON aujourd'hui et la génération suivante — déjà en discussion à l'ITU-T sous le nom de 100G-PON — demain. C'est ce qui justifie qu'on déploie du 50G-PON même si tous les abonnés n'en ont pas l'usage immédiat : ce n'est pas l'équipement client qui coûte cher, c'est la fibre dans la rue, et elle est déjà là. + +## Ce qui freine encore + +Le 50G-PON existe, il est standardisé, et plusieurs équipementiers proposent du matériel compatible. Pour autant, le déploiement à grande échelle prendra du temps, pour quelques raisons concrètes. + +Le **coût des équipements** reste élevé. Les composants optiques capables de moduler proprement à 50 Gbit/s sur une seule porteuse sont à un stade industriel récent, et les volumes ne sont pas encore là pour faire baisser les prix. Pour la majorité des foyers, le XGS-PON couvre largement les besoins et coûte beaucoup moins cher. + +La **consommation énergétique** est plus importante que sur les générations précédentes. Ce n'est pas rédhibitoire, mais ça compte dans le bilan d'exploitation, surtout à l'échelle d'un opérateur. + +Enfin, **le marché n'est pas pressé**. Les box résidentielles actuelles n'exploiteraient même pas 10 Gbit/s symétriques, et les usages qui justifient le 50G-PON sont aujourd'hui concentrés sur des segments précis — entreprises, datacenters, opérateurs mobiles. Le déploiement va donc se faire par couches, en commençant par les zones où la demande existe vraiment. + +## En résumé + +| Technologie | Débit symétrique | Cible principale | +|---|---|---| +| GPON | 1 Gbit/s | Résidentiel actuel | +| XGS-PON | 10 Gbit/s | Résidentiel haut de gamme, PME | +| NG-PON2 | 40 Gbit/s (4 × 10) | Niche, peu déployé | +| 50G-PON | 50 Gbit/s | Entreprises, datacenters, transport mobile | + +Le 50G-PON n'est pas la techno qui va arriver dans les box grand public dans les six mois. C'est la **brique d'infrastructure** qui prépare la décennie qui vient : celle qui permettra aux opérateurs de répondre à la fois aux besoins des entreprises, au raccordement des antennes mobiles de prochaine génération, et à la montée en puissance progressive du résidentiel — sans toucher à la fibre déjà tirée. Et c'est exactement ce qu'on attend d'une bonne infrastructure : qu'elle se mette en place sans bruit, et qu'elle dure. diff --git a/data/private_cats.json b/data/private_cats.json new file mode 100644 index 0000000..141462c --- /dev/null +++ b/data/private_cats.json @@ -0,0 +1 @@ +["scolaire"] \ No newline at end of file diff --git a/database/migration_001_roles_ratings.sql b/database/migration_001_roles_ratings.sql new file mode 100644 index 0000000..1437249 --- /dev/null +++ b/database/migration_001_roles_ratings.sql @@ -0,0 +1,39 @@ +-- Migration 001 : Système de rôles et notes d'articles +-- À exécuter une seule fois sur le serveur PostgreSQL + +-- Rôles disponibles +CREATE TABLE IF NOT EXISTS roles ( + id SERIAL PRIMARY KEY, + name VARCHAR(50) UNIQUE NOT NULL, + label TEXT NOT NULL +); + +INSERT INTO roles (name, label) VALUES + ('admin', 'Administrateur'), + ('editor', 'Rédacteur'), + ('reader', 'Lecteur') +ON CONFLICT (name) DO NOTHING; + +-- Association utilisateur ↔ rôle (clé : email, pour compatibilité OIDC sans FK) +CREATE TABLE IF NOT EXISTS user_roles ( + user_email TEXT NOT NULL, + role_id INTEGER NOT NULL REFERENCES roles(id) ON DELETE CASCADE, + granted_at TIMESTAMP DEFAULT NOW(), + granted_by TEXT, + PRIMARY KEY (user_email, role_id) +); + +-- Seed : cedric@abonnel.fr → admin +INSERT INTO user_roles (user_email, role_id, granted_by) +SELECT 'cedric@abonnel.fr', id, 'migration' +FROM roles WHERE name = 'admin' +ON CONFLICT DO NOTHING; + +-- Notes d'articles (1-5 étoiles, une note par utilisateur par article) +CREATE TABLE IF NOT EXISTS article_ratings ( + article_uuid VARCHAR(36) NOT NULL, + user_email TEXT NOT NULL, + rating SMALLINT NOT NULL CHECK (rating BETWEEN 1 AND 5), + rated_at TIMESTAMP DEFAULT NOW(), + PRIMARY KEY (article_uuid, user_email) +); diff --git a/public/assets/css/style.css b/public/assets/css/style.css index e929f9c..63c5349 100644 --- a/public/assets/css/style.css +++ b/public/assets/css/style.css @@ -115,13 +115,35 @@ body { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2830%2C41%2C59%2C0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); } +/* ─── Category nav in navbar ─────────────── */ +.navbar-cats { + gap: 0.15rem; +} + +.nav-cat { + font-size: 0.8rem !important; + padding: 0.25rem 0.6rem !important; + border-radius: 2rem !important; + white-space: nowrap; +} + +.nav-cat.active { + background-color: var(--vl-accent) !important; + color: #fff !important; +} + /* ─── Main ───────────────────────────────── */ -main.container { - max-width: 980px; +main.container, +main.container-xl, +main.container-fluid { padding-top: 2rem; padding-bottom: 3rem; } +main.container { + max-width: 980px; +} + /* ─── Headings ───────────────────────────── */ h1 { font-weight: 700; @@ -170,6 +192,139 @@ a:hover { display: block; } +.article-cover--gradient { + height: 160px; + position: relative; +} + +/* Hero : titre sur l'image */ +.article-cover--hero { + position: relative; +} + +.article-cover--hero img { + height: clamp(260px, 45vw, 480px); +} + +.article-cover--hero.article-cover--gradient { + height: clamp(200px, 35vw, 340px); +} + +.article-hero-text { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + justify-content: space-between; + padding: 0.9rem 1.4rem 1.25rem; + background: linear-gradient( + to top, + rgba(0,0,0,.80) 0%, + rgba(0,0,0,.32) 50%, + transparent 100% + ); +} + +.article-hero-top { + display: flex; + justify-content: flex-end; + gap: 0.4rem; + align-items: flex-start; + min-height: 2rem; +} + +.article-hero-bottom { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 1rem; +} + +.article-hero-left { flex: 1; min-width: 0; } + +.article-hero-right { + flex-shrink: 0; + display: flex; + flex-direction: column; + align-items: flex-end; + gap: 0.5rem; +} + +.article-hero-text .cover-category { + position: static; + align-self: flex-start; + margin-bottom: 0.55rem; +} + +.article-hero-text .article-title { + color: #fff; + text-shadow: 0 1px 8px rgba(0,0,0,.5); + margin-bottom: 0.3rem; +} + +.article-hero-meta { + font-size: 0.82rem; + color: rgba(255,255,255,.72); + margin: 0; +} + +/* Boutons glass sur le hero */ +.hero-btn { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.28rem 0.75rem; + font-size: 0.73rem; + font-weight: 600; + color: #fff !important; + background: rgba(0,0,0,.35); + border: 1px solid rgba(255,255,255,.22); + border-radius: 999px; + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + text-decoration: none !important; + cursor: pointer; + transition: background 0.15s; + white-space: nowrap; + line-height: 1.4; +} +.hero-btn:hover { background: rgba(0,0,0,.58); color: #fff !important; } +.hero-btn--danger { border-color: rgba(239,68,68,.5); } +.hero-btn--danger:hover { background: rgba(180,30,30,.65); } + +/* Score de notation dans le hero */ +.hero-rating-score { + font-size: 0.8rem; + font-weight: 600; + color: rgba(255,255,255,.88); +} + +/* Étoiles sur fond sombre */ +.star-rating--hero label { color: rgba(255,255,255,.4); font-size: 1.1rem; } +.star-rating--hero input:checked ~ label, +.star-rating--hero label:hover, +.star-rating--hero label:hover ~ label { color: #f5c842; } + +.card-cover { + position: relative; +} + +.cover-category { + position: absolute; + bottom: 0.6rem; + left: 0.75rem; + font-size: 0.65rem; + font-weight: 700; + letter-spacing: 0.1em; + text-transform: uppercase; + color: #fff; + background: rgba(0, 0, 0, 0.28); + padding: 0.2rem 0.55rem; + border-radius: 999px; + backdrop-filter: blur(6px); + -webkit-backdrop-filter: blur(6px); +} + .card { border: 1px solid var(--vl-border) !important; border-radius: var(--vl-radius) !important; @@ -195,6 +350,15 @@ a:hover { color: var(--vl-text); } +.article-title { + font-weight: 800; + font-size: clamp(1.6rem, 4vw, 2.4rem); + line-height: 1.2; + letter-spacing: -0.5px; + color: var(--vl-text); + margin-bottom: 0.5rem; +} + /* Override la couleur text-primary Bootstrap sur les card-title */ .card-title.text-primary { color: var(--vl-text) !important; @@ -226,7 +390,8 @@ a:hover { /* ─── Ribbons (brouillon / avant-première) ── */ .draft-ribbon, -.premiere-ribbon { +.premiere-ribbon, +.private-ribbon { position: absolute; top: 26px; right: -34px; @@ -244,8 +409,9 @@ a:hover { box-shadow: 0 1px 3px rgba(0,0,0,.18); } -.draft-ribbon { background: #f59e0b; } +.draft-ribbon { background: #f59e0b; } .premiere-ribbon { background: #6366f1; } +.private-ribbon { background: #64748b; } /* ─── Buttons ─────────────────────────────── */ .btn { @@ -349,6 +515,195 @@ textarea.form-control { color: #991b1b; } +/* ─── Left category sidebar ──────────────── */ +.left-sidebar { + position: sticky; + top: 1.5rem; +} + +.left-sidebar-section { + margin-bottom: 1.5rem; +} + +.left-sidebar-cat { + display: block; + font-size: 0.7rem; + font-weight: 700; + letter-spacing: .08em; + text-transform: uppercase; + color: var(--vl-muted); + text-decoration: none; + margin-bottom: 0.4rem; + padding: 0.2rem 0.5rem; + border-radius: 0.4rem; + transition: background 0.15s, color 0.15s; +} + +.left-sidebar-cat:hover { + background: var(--vl-accent-soft); + color: var(--vl-accent); +} + +.left-sidebar-list { + list-style: none; + padding: 0; + margin: 0; +} + +.left-sidebar-list li { + border-left: 2px solid var(--vl-border); + padding-left: 0.6rem; + margin-bottom: 0.3rem; +} + +.left-sidebar-list li a { + font-size: 0.8rem; + line-height: 1.35; + color: var(--vl-text); + text-decoration: none; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + transition: color 0.15s; +} + +.left-sidebar-list li a:hover { + color: var(--vl-accent); +} + +/* ─── Related articles sidebar ───────────── */ +.related-sidebar { + position: sticky; + top: 1.5rem; +} + +/* ─── Post layout: colonnes sidebar fixe + article flexible ── */ +@media (min-width: 992px) { + .post-sidebar-col { + flex: 0 0 260px; + width: 260px; + max-width: 260px; + } +} + +.related-sidebar-title { + font-size: 0.7rem; + font-weight: 700; + letter-spacing: .08em; + text-transform: uppercase; + color: var(--vl-muted); + margin-bottom: 1rem; +} + +.related-card { + display: flex; + gap: 0.75rem; + align-items: flex-start; + text-decoration: none; + color: var(--vl-text); + padding: 0.65rem; + border-radius: var(--vl-radius); + transition: background 0.15s; + margin-bottom: 0.25rem; +} + +.related-card:hover { + background: var(--vl-accent-soft); + color: var(--vl-accent); +} + +.related-card-thumb { + width: 64px; + height: 52px; + border-radius: 0.5rem; + flex-shrink: 0; + background-size: cover; + background-position: center; +} + +.related-card-body { + flex: 1; + min-width: 0; +} + +.related-card-title { + font-size: 0.875rem; + font-weight: 600; + line-height: 1.35; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.related-card-date { + font-size: 0.75rem; + color: var(--vl-muted); + margin-top: 0.2rem; +} + +/* ─── Source / attachment cards (sidebar) ── */ +.source-card { + display: flex; + gap: 0.65rem; + align-items: flex-start; + text-decoration: none; + color: var(--vl-text); + padding: 0.5rem 0.65rem; + border-radius: var(--vl-radius); + border: 1px solid var(--vl-border); + background: var(--vl-surface); + transition: border-color 0.15s, box-shadow 0.15s; +} + +.source-card:hover { + border-color: var(--vl-accent); + box-shadow: 0 0 0 3px rgba(79,70,229,.08); + color: var(--vl-accent); +} + +.source-card-thumb { + width: 52px; + height: 42px; + border-radius: 0.4rem; + flex-shrink: 0; + background-color: var(--vl-accent-soft); +} + +.source-card-thumb--pdf, +.source-card-thumb--link { + display: flex; + align-items: center; + justify-content: center; + font-size: 1.2rem; + color: var(--vl-accent); +} + +.source-card-body { + flex: 1; + min-width: 0; +} + +.source-card-title { + font-size: 0.82rem; + font-weight: 600; + line-height: 1.3; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.source-card-meta { + font-size: 0.72rem; + color: var(--vl-muted); + margin-top: 0.2rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + /* ─── Post content (Markdown rendu) ──────── */ .post-content { font-size: 1rem; @@ -554,6 +909,56 @@ footer { opacity: 0.75; } +/* ─── Pagination ─────────────────────────── */ +.pagination-nav { + display: flex; + align-items: center; + justify-content: center; + gap: 0.3rem; + flex-wrap: wrap; +} + +.pagination-btn { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 2.2rem; + height: 2.2rem; + padding: 0 0.5rem; + border-radius: 0.5rem; + border: 1px solid var(--vl-border); + background: var(--vl-surface); + color: var(--vl-text); + font-size: 0.875rem; + font-weight: 500; + text-decoration: none; + transition: border-color 0.15s, background 0.15s, color 0.15s; +} + +.pagination-btn:hover:not(.disabled):not(.active) { + border-color: var(--vl-accent); + color: var(--vl-accent); + background: var(--vl-accent-soft); +} + +.pagination-btn.active { + background: var(--vl-accent); + border-color: var(--vl-accent); + color: #fff; +} + +.pagination-btn.disabled { + opacity: 0.35; + cursor: default; + pointer-events: none; +} + +.pagination-ellipsis { + padding: 0 0.25rem; + color: var(--vl-muted); + font-size: 0.875rem; +} + /* ─── Footer 2 colonnes ──────────────────── */ footer { border-top: 1px solid var(--vl-border); @@ -639,3 +1044,27 @@ footer { .text-primary { color: var(--vl-accent) !important; } + +/* ─── Widget étoiles ──────────────────────── */ +.star-rating { + display: inline-flex; + flex-direction: row-reverse; + gap: 2px; +} + +.star-rating input { + display: none; +} + +.star-rating label { + font-size: 1.4rem; + color: #ccc; + cursor: pointer; + transition: color 0.1s; +} + +.star-rating input:checked ~ label, +.star-rating label:hover, +.star-rating label:hover ~ label { + color: #f5a623; +} diff --git a/public/assets/js/app.js b/public/assets/js/app.js index 603734e..42db54a 100644 --- a/public/assets/js/app.js +++ b/public/assets/js/app.js @@ -2,7 +2,7 @@ document.addEventListener('DOMContentLoaded', function () { - // Auto-resize textarea au chargement et à la saisie + // ─── Auto-resize textareas ─────────────────────────────────────────────── document.querySelectorAll('textarea.form-control').forEach(function (ta) { function resize() { ta.style.height = 'auto'; @@ -12,7 +12,7 @@ document.addEventListener('DOMContentLoaded', function () { resize(); }); - // Ctrl+Enter (ou Cmd+Enter) pour soumettre le formulaire de post + // ─── Ctrl+Enter : soumettre le formulaire ──────────────────────────────── var form = document.querySelector('form[method="POST"]'); if (form) { form.addEventListener('keydown', function (e) { @@ -22,4 +22,422 @@ document.addEventListener('DOMContentLoaded', function () { }); } + // ─── Slug auto-génération ──────────────────────────────────────────────── + const titleInput = document.getElementById('title'); + const slugField = document.getElementById('slug'); + const slugPreview = document.getElementById('slug-preview'); + + if (titleInput && slugField) { + if (slugField.value !== '') slugField._auto = false; + + titleInput.addEventListener('input', function () { + if (slugField._auto !== false) { + const generated = slugify(this.value); + slugField.value = generated; + if (slugPreview) slugPreview.textContent = generated; + } + }); + + slugField.addEventListener('input', function () { + this._auto = (this.value === ''); + if (slugPreview) slugPreview.textContent = this.value; + }); + } + + function slugify(s) { + const map = {'à':'a','â':'a','ä':'a','é':'e','è':'e','ê':'e','ë':'e','î':'i','ï':'i','ô':'o','ö':'o','ù':'u','û':'u','ü':'u','ç':'c','æ':'ae','œ':'oe'}; + return s.toLowerCase().replace(/[àâäéèêëîïôöùûüçæœ]/g, c => map[c] || c) + .replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, ''); + } + + // ─── Aperçu couleur catégorie ──────────────────────────────────────────── + const KNOWN_CATS = { + 'actualité': 10, 'travaux': 35, 'scolaire': 55, + 'linux': 120, 'domotique': 160, 'télécom': 190, + 'blog': 220, 'informatique': 255, 'réflexion': 285, + 'loisirs': 320, 'perso': 345, + }; + const FREE_HUES = [87, 140, 205, 237, 302]; + + function gradient(hue) { + return `linear-gradient(135deg,hsl(${hue},70%,88%) 0%,hsl(${hue},60%,28%) 100%)`; + } + + function hashHue(str) { + let h = 5381; + for (let i = 0; i < str.length; i++) h = (((h << 5) + h) + str.charCodeAt(i)) | 0; + return ((Math.abs(h) * 0.6180339887) * 360 | 0) % 360; + } + + function nearestKnown(hue) { + let best = null, bestDist = Infinity; + for (const [name, h] of Object.entries(KNOWN_CATS)) { + const d = Math.min(Math.abs(hue - h), 360 - Math.abs(hue - h)); + if (d < bestDist) { bestDist = d; best = name; } + } + return { name: best, dist: bestDist }; + } + + function updateCatPreview(val) { + const key = val.trim().toLowerCase(); + const swatch = document.getElementById('cat-swatch'); + const hint = document.getElementById('cat-hint'); + const freeEl = document.getElementById('cat-free-swatches'); + if (!swatch) return; + freeEl.innerHTML = ''; + + if (!key) { + swatch.style.background = '#e5e7eb'; + swatch.title = ''; + hint.textContent = ''; + return; + } + + if (KNOWN_CATS[key] !== undefined) { + const hue = KNOWN_CATS[key]; + swatch.style.background = gradient(hue); + swatch.title = `${hue}°`; + hint.textContent = `Catégorie existante · teinte fixe (${hue}°)`; + hint.className = 'text-muted d-block mt-1'; + return; + } + + const hue = hashHue(key); + const { name, dist } = nearestKnown(hue); + + swatch.style.background = gradient(hue); + swatch.title = `${hue}°`; + + if (dist < 20) { + hint.innerHTML = `⚠ Teinte proche de ${name} (${dist}° d'écart) · couleurs disponibles :`; + hint.className = 'text-warning d-block mt-1'; + FREE_HUES.forEach(h => { + const el = document.createElement('span'); + el.title = `${h}°`; + el.style.cssText = `display:inline-block;width:28px;height:20px;border-radius:4px;cursor:help;background:${gradient(h)}`; + freeEl.appendChild(el); + }); + } else { + hint.textContent = `Nouvelle catégorie · teinte libre (${hue}°)`; + hint.className = 'text-muted d-block mt-1'; + } + } + + const catInput = document.getElementById('category'); + if (catInput) { + catInput.addEventListener('input', function () { updateCatPreview(this.value); }); + updateCatPreview(catInput.value); + } + + // ─── Copier la référence Markdown ──────────────────────────────────────── + document.querySelectorAll('[data-copy-md-name]').forEach(function (btn) { + btn.addEventListener('click', function () { + const name = this.dataset.copyMdName; + const isImage = this.dataset.copyMdIsImage === '1'; + const ref = isImage ? `![](${name})` : `[${name}](${name})`; + navigator.clipboard.writeText(ref).then(() => { + const orig = this.textContent; + this.textContent = 'Copié !'; + setTimeout(() => { this.textContent = orig; }, 1500); + }); + }); + }); + + // ─── Boîtes de confirmation (suppression) ─────────────────────────────── + document.querySelectorAll('button[data-confirm], a[data-confirm]').forEach(function (el) { + el.addEventListener('click', function (e) { + if (!confirm(this.dataset.confirm)) e.preventDefault(); + }); + }); + document.querySelectorAll('form[data-confirm]').forEach(function (form) { + form.addEventListener('submit', function (e) { + if (!confirm(this.dataset.confirm)) e.preventDefault(); + }); + }); + + // ─── Insérer une référence Markdown au curseur ─────────────────────────── + const ta = document.getElementById('content'); + if (ta) { + ta._savedStart = null; + ta._savedEnd = null; + + function saveCursor() { + if (document.activeElement === ta) { + ta._savedStart = ta.selectionStart; + ta._savedEnd = ta.selectionEnd; + } + } + document.addEventListener('mousedown', saveCursor); + ta.addEventListener('keyup', saveCursor); + ta.addEventListener('mouseup', saveCursor); + + document.querySelectorAll('[data-insert-ref]').forEach(function (el) { + el.addEventListener('click', function () { + insertRef(this.dataset.insertRef); + }); + if (el.tagName === 'IMG') { + el.addEventListener('mouseenter', function () { this.style.borderColor = '#0d6efd'; }); + el.addEventListener('mouseleave', function () { this.style.borderColor = 'transparent'; }); + } + }); + } + + function insertRef(url) { + if (!ta) return; + const isImage = /\.(jpe?g|png|gif|webp|svg|avif)(\?.*)?$/i.test(url); + const label = url.startsWith('http') + ? (decodeURIComponent(url.split('/').pop().split('?')[0]) || url) + : url; + const ref = isImage ? `![](${url})` : `[${label}](${url})`; + const len = ta.value.length; + const start = ta._savedStart !== null ? ta._savedStart : len; + const end = ta._savedEnd !== null ? ta._savedEnd : len; + ta.focus(); + ta.setRangeText(ref, start, end, 'end'); + ta._savedStart = ta._savedEnd = start + ref.length; + ta.dispatchEvent(new Event('input')); + } + + // ─── Compteurs SEO ─────────────────────────────────────────────────────── + function initCounter(inputId, counterId, max) { + const input = document.getElementById(inputId); + const counter = document.getElementById(counterId); + if (!input || !counter) return; + function update() { + const len = input.value.length; + counter.textContent = `${len} / ${max}`; + counter.className = len > max ? 'text-danger' : 'text-muted'; + } + input.addEventListener('input', update); + update(); + } + initCounter('seo_title', 'seo_title_counter', 60); + initCounter('seo_description', 'seo_desc_counter', 155); + + // ─── Page catégories ───────────────────────────────────────────────────── + function catComputeGradient(val) { + const key = val.trim().toLowerCase(); + if (!key) return null; + if (KNOWN_CATS[key] !== undefined) return { hue: KNOWN_CATS[key], known: true }; + const hue = hashHue(key); + const { name, dist } = nearestKnown(hue); + return { hue, known: false, conflict: dist < 20 ? name : null }; + } + + document.querySelectorAll('form[action="/?action=rename_category"] input[name="new"]').forEach(function (input) { + input.addEventListener('input', function () { + const swatch = input.closest('form').querySelector('.rename-swatch'); + const result = catComputeGradient(input.value); + if (swatch) swatch.style.background = result ? gradient(result.hue) : '#e5e7eb'; + }); + }); + + const newCatInput = document.getElementById('new-cat-input'); + if (newCatInput) { + newCatInput.addEventListener('input', function () { + const swatch = document.getElementById('new-cat-swatch'); + const hint = document.getElementById('new-cat-hint'); + const result = catComputeGradient(this.value); + + if (!result) { + swatch.style.background = '#e5e7eb'; + hint.textContent = ''; + return; + } + + swatch.style.background = gradient(result.hue); + + if (result.known) { + hint.textContent = `Catégorie existante · teinte fixe (${result.hue}°)`; + hint.className = 'text-muted d-block mb-3'; + } else if (result.conflict) { + hint.textContent = `⚠ Teinte proche de « ${result.conflict} » — choisissez un autre nom ou une couleur disponible ci-dessous`; + hint.className = 'text-warning d-block mb-3'; + } else { + hint.textContent = `Couleur libre · teinte ${result.hue}°`; + hint.className = 'text-success d-block mb-3'; + } + }); + } + + // ─── Import image : récupérer les métadonnées ──────────────────────────── + const fetchMetaBtn = document.getElementById('fetch-meta-btn'); + if (fetchMetaBtn) { + fetchMetaBtn.addEventListener('click', async function () { + const urlInput = document.getElementById('import-url'); + const resultDiv = document.getElementById('meta-result'); + const url = urlInput ? urlInput.value.trim() : ''; + + if (!url) { + resultDiv.innerHTML = 'Saisissez une URL d\'abord.'; + return; + } + + fetchMetaBtn.disabled = true; + fetchMetaBtn.textContent = 'Chargement…'; + resultDiv.innerHTML = ''; + + try { + const res = await fetch(`/?action=fetch_file_meta&url=${encodeURIComponent(url)}`); + const data = await res.json(); + + if (!data.ok) { + resultDiv.innerHTML = `${data.error || 'Erreur lors de la récupération.'}`; + return; + } + + // Auto-remplissage dynamique des champs (si vides) + const AUTOFILL = { + img_author: { keys: ['author', 'credit'], label: 'Auteur / crédit' }, + img_source: { keys: ['canonical', 'source'], label: 'URL source' }, + }; + const autofillKeys = new Set(); + const autofillNotice = []; + for (const [fieldName, cfg] of Object.entries(AUTOFILL)) { + const f = document.querySelector(`input[name="${fieldName}"]`); + if (!f || f.value) continue; + for (const key of cfg.keys) { + if (data[key]) { + f.value = data[key]; + autofillKeys.add(key); + autofillNotice.push(`${cfg.label} : ${data[key]}`); + break; + } + } + } + + // Affichage dynamique de tous les champs retournés + const isPdf = (data.mime === 'application/pdf'); + const isHtml = (data.mime || '').startsWith('text/html'); + + const META_ORDER = ['mime','size','pages','page_size','pdf_version', + 'width','site_name','og_type','language', + 'title','description','author','subject','keywords', + 'credit','source','creator','producer','date','camera','copyright', + 'canonical','og_image']; + const META_LABELS = { + mime: 'Type', size: 'Taille', width: 'Dimensions', + pages: 'Pages', page_size: 'Format', pdf_version: 'Version PDF', + site_name: 'Site', og_type: 'Type OG', language: 'Langue', + title: isPdf || isHtml ? 'Titre' : 'Titre EXIF/IPTC', + author: isPdf || isHtml ? 'Auteur' : 'Auteur EXIF/IPTC', + date: isPdf ? 'Créé le' : isHtml ? 'Publié le' : 'Prise de vue', + description: 'Description', subject: 'Sujet', keywords: 'Mots-clés', + credit: 'Crédit', source: 'Source IPTC', + creator: 'Créé avec', producer: 'Produit par', + camera: 'Appareil', copyright: 'Copyright', + canonical: 'URL canonique', og_image: 'Image OG', + }; + + function fmtVal(key, val) { + if (key === 'size') return (val/1024).toFixed(0) + ' Ko' + (val >= 1048576 ? ` (${(val/1048576).toFixed(1)} Mo)` : ''); + if (key === 'width') return `${data.width} × ${data.height} px`; + if (key === 'og_image') return ``; + if (key === 'canonical') return `${val}`; + return String(val); + } + + const SKIP = new Set(['ok', 'height']); + const seen = new Set(); + const rows = []; + + for (const key of META_ORDER) { + const val = data[key]; + if (val == null || val === '' || key === 'height') continue; + seen.add(key); + const badge = autofillKeys.has(key) + ? ' ↓ pré-rempli' + : ''; + rows.push([META_LABELS[key] ?? key, fmtVal(key, val) + badge]); + } + for (const [key, val] of Object.entries(data)) { + if (seen.has(key) || SKIP.has(key) || val == null || val === '') continue; + rows.push([key, fmtVal(key, val)]); + } + + let html = ''; + if (rows.length > 0) { + const trs = rows.map(([k, v]) => + `${k}${v}` + ).join(''); + html = `${trs}
`; + } else { + html = 'Aucune métadonnée disponible pour ce fichier.'; + } + if (autofillNotice.length > 0) { + html += `
✓ Pré-rempli — ${autofillNotice.join(' · ')}
`; + } + resultDiv.innerHTML = html; + } catch { + resultDiv.innerHTML = 'Erreur de connexion.'; + } finally { + fetchMetaBtn.disabled = false; + fetchMetaBtn.textContent = 'Métadonnées'; + } + }); + } + + // ─── Import image : toggle mode download ──────────────────────────────── + document.querySelectorAll('input[name="mode"]').forEach(function (r) { + r.addEventListener('change', function () { + const dl = this.value === 'download'; + const ss = this.value === 'screenshot'; + const warn = document.getElementById('copyright-warning'); + const fields = document.getElementById('download-fields'); + if (warn) warn.style.display = dl ? 'block' : 'none'; + if (fields) fields.style.display = (dl || ss) ? 'block' : 'none'; + }); + }); + + // ─── Données page (mode édition uniquement) ────────────────────────────── + const pageEl = document.getElementById('vl-page'); + if (!pageEl) return; + + const uuid = pageEl.dataset.uuid; + const insertUrl = pageEl.dataset.insertUrl; + + // Auto-insertion après import d'image + if (insertUrl && ta) { + const isImage = /\.(jpe?g|png|gif|webp|svg|avif)(\?.*)?$/i.test(insertUrl); + const name = decodeURIComponent(insertUrl.split('/').pop().split('?')[0]) || 'fichier'; + const ref = isImage ? `![](${insertUrl})` : `[${name}](${insertUrl})`; + const sep = ta.value.length > 0 && !ta.value.endsWith('\n') ? '\n' : ''; + ta.value += sep + ref; + ta.focus(); + ta.selectionStart = ta.selectionEnd = ta.value.length; + ta.dispatchEvent(new Event('input')); + } + + // ─── Autosave ──────────────────────────────────────────────────────────── + const indicator = document.getElementById('autosave-indicator'); + if (!indicator || !uuid) return; + + let timer = null; + + function scheduleAutosave() { + clearTimeout(timer); + timer = setTimeout(doAutosave, 3000); + } + + async function doAutosave() { + const title = document.getElementById('title').value; + const slug = document.getElementById('slug').value; + const content = document.getElementById('content').value; + indicator.textContent = 'Sauvegarde…'; + try { + const res = await fetch(`/?action=autosave&uuid=${encodeURIComponent(uuid)}`, { + method: 'POST', + headers: {'Content-Type': 'application/x-www-form-urlencoded'}, + body: new URLSearchParams({title, slug, content}), + }); + const data = await res.json(); + indicator.textContent = data.ok ? `Brouillon sauvegardé à ${data.time}` : 'Erreur de sauvegarde'; + } catch { + indicator.textContent = 'Erreur de sauvegarde'; + } + } + + ['title', 'slug', 'content'].forEach(id => { + document.getElementById(id)?.addEventListener('input', scheduleAutosave); + }); }); diff --git a/public/index.php b/public/index.php index ec3d9a8..b9320a7 100644 --- a/public/index.php +++ b/public/index.php @@ -21,6 +21,406 @@ $action = $_GET['action'] ?? 'list'; $uuid = $_GET['uuid'] ?? ''; $slug = $_GET['slug'] ?? ''; +// ─── Extraction de métadonnées depuis une URL ──────────────────────────────── +function fetchUrlMeta(string $url): array +{ + if (!filter_var($url, FILTER_VALIDATE_URL) || !preg_match('#^https?://#i', $url)) { + return ['ok' => false, 'error' => 'URL invalide']; + } + $tmpFile = tempnam(sys_get_temp_dir(), 'vl_meta_'); + $fp = fopen($tmpFile, 'wb'); + $downloaded = 0; + $limit = 4 * 1024 * 1024; + $contentLength = null; + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 3, + CURLOPT_CONNECTTIMEOUT => 8, + CURLOPT_TIMEOUT => 20, + CURLOPT_USERAGENT => 'Mozilla/5.0 varlog-meta/1.0', + CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_ENCODING => '', // accepte gzip/deflate/br, décompresse automatiquement + CURLOPT_HEADERFUNCTION => static function ($curl, $header) use (&$contentLength): int { + if (preg_match('/^content-length:\s*(\d+)/i', $header, $m)) { + $contentLength = (int) $m[1]; + } + return strlen($header); + }, + CURLOPT_WRITEFUNCTION => static function ($curl, $chunk) use ($fp, &$downloaded, $limit): int { + $downloaded += strlen($chunk); + if ($downloaded > $limit) { + return -1; + } + fwrite($fp, $chunk); + return strlen($chunk); + }, + ]); + curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $mimeRaw = (string) curl_getinfo($ch, CURLINFO_CONTENT_TYPE); + $errno = curl_errno($ch); + curl_close($ch); + fclose($fp); + if ($httpCode < 200 || $httpCode >= 400 || ($errno !== 0 && $errno !== 23)) { + @unlink($tmpFile); + return ['ok' => false, 'error' => "Téléchargement impossible (HTTP $httpCode)"]; + } + $mime = strtok($mimeRaw ?: 'application/octet-stream', '; '); + $result = ['ok' => true, 'mime' => $mime, 'size' => $contentLength ?? $downloaded]; + + if (!str_starts_with($mime, 'text/html')) { + $etJson = @shell_exec('exiftool -json -charset utf8 -struct ' . escapeshellarg($tmpFile) . ' 2>/dev/null'); + if ($etJson) { + $et = json_decode($etJson, true)[0] ?? []; + $etVal = static function (string ...$keys) use ($et): ?string { + foreach ($keys as $key) { + $v = $et[$key] ?? null; + if (is_array($v)) { + $v = implode(', ', array_filter(array_map('trim', $v))); + } + if (is_string($v) && trim($v) !== '') { + return trim($v); + } + } + return null; + }; + if ($v = $etVal('Title', 'Headline', 'ObjectName')) { + $result['title'] = $v; + } + if ($v = $etVal('Description', 'Caption-Abstract', 'ImageDescription')) { + $result['description'] = $v; + } + if ($v = $etVal('Keywords')) { + $result['keywords'] = $v; + } + if ($v = $etVal('Copyright', 'CopyrightNotice', 'Rights')) { + $result['copyright'] = $v; + } + if ($v = $etVal('DateTimeOriginal', 'CreateDate', 'ModifyDate')) { + $result['date'] = preg_replace('/^(\d{4}):(\d{2}):(\d{2})/', '$1-$2-$3', $v); + } + if (str_starts_with($mime, 'image/')) { + if ($v = $etVal('Artist', 'Creator', 'By-line')) { + $result['author'] = $v; + } + $w = $et['ImageWidth'] ?? $et['ExifImageWidth'] ?? null; + $h = $et['ImageHeight'] ?? $et['ExifImageHeight'] ?? null; + if ($w !== null && $h !== null) { + $result['width'] = (int)$w; + $result['height'] = (int)$h; + } + $camera = trim(($et['Make'] ?? '') . ' ' . ($et['Model'] ?? '')); + if ($camera !== '') { + $result['camera'] = $camera; + } + if ($v = $etVal('Credit')) { + $result['credit'] = $v; + } + if ($v = $etVal('Source')) { + $result['source'] = $v; + } + } + if ($mime === 'application/pdf') { + if ($v = $etVal('Author')) { + $result['author'] = $v; + } + if ($v = $etVal('Subject')) { + $result['subject'] = $v; + } + if ($v = $etVal('Creator', 'CreatorTool')) { + $result['creator'] = $v; + } + if ($v = $etVal('Producer')) { + $result['producer'] = $v; + } + if (isset($et['PageCount'])) { + $result['pages'] = (int) $et['PageCount']; + } + if (isset($et['PDFVersion'])) { + $result['pdf_version'] = 'PDF ' . $et['PDFVersion']; + } + $fhPdf = fopen($tmpFile, 'rb'); + $pdfHead = fread($fhPdf, min(filesize($tmpFile), 65536)); + fclose($fhPdf); + if (preg_match('/\/MediaBox\s*\[\s*([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s*\]/', $pdfHead, $mb)) { + $wPt = (float)$mb[3] - (float)$mb[1]; + $hPt = (float)$mb[4] - (float)$mb[2]; + $wMm = (int) round($wPt * 25.4 / 72); + $hMm = (int) round($hPt * 25.4 / 72); + $landscape = $wMm > $hMm; + if ($landscape) { + [$wMm, $hMm] = [$hMm, $wMm]; + } + $paperSizes = ['A0' => [841,1189],'A1' => [594,841],'A2' => [420,594], + 'A3' => [297,420],'A4' => [210,297],'A5' => [148,210], + 'Letter' => [216,279],'Legal' => [216,356]]; + $paperName = null; + foreach ($paperSizes as $pname => [$pw, $ph]) { + if (abs($wMm - $pw) <= 2 && abs($hMm - $ph) <= 2) { + $paperName = $pname; + break; + } + } + $label = $paperName ? $paperName . ($landscape ? ' paysage' : '') : ($landscape ? 'Paysage' : 'Portrait'); + $result['page_size'] = "$label ({$wMm}×{$hMm} mm)"; + } + } + } + } + + if (str_starts_with($mime, 'text/html')) { + try { + $fhHtml = fopen($tmpFile, 'rb'); + $html = fread($fhHtml, min(filesize($tmpFile), 65536)); + fclose($fhHtml); + + // Détection du charset : 1) en-tête HTTP, 2) , 3) + $charset = null; + if (preg_match('/charset=([^\s;]+)/i', $mimeRaw, $cm)) { + $charset = trim($cm[1], '"\''); + } + if (!$charset && preg_match('/]+charset=["\']?\s*([^"\'\s;>]+)/i', $html, $cm)) { + $charset = trim($cm[1]); + } + if (!$charset && preg_match('/]+content=["\'][^"\']*charset=([^"\'\s;]+)/i', $html, $cm)) { + $charset = trim($cm[1]); + } + if ($charset && strtolower(str_replace(['-','_'], '', $charset)) !== 'utf8') { + $converted = @mb_convert_encoding($html, 'UTF-8', $charset); + if ($converted !== false && $converted !== '') { + $html = $converted; + } + } + + preg_match('/]*>(.*?)<\/head>/si', $html, $headMatch); + $headHtml = $headMatch[1] ?? $html; + if (preg_match('/]*>\s*([^<]+)\s*<\/title>/i', $headHtml, $m)) { + $result['title'] = html_entity_decode(trim($m[1]), ENT_QUOTES | ENT_HTML5, 'UTF-8'); + } + $metaMap = []; + preg_match_all('/]+)>/i', $headHtml, $metaTags); + foreach ($metaTags[1] as $attrs) { + $key = $val = null; + if (preg_match('/(?:name|property)\s*=\s*["\']([^"\']+)["\']/', $attrs, $m)) { + $key = strtolower($m[1]); + } + if (preg_match('/content\s*=\s*["\']([^"\']*)["\']/', $attrs, $m)) { + $val = html_entity_decode($m[1], ENT_QUOTES | ENT_HTML5, 'UTF-8'); + } + if ($key !== null && $val !== null && $val !== '') { + $metaMap[$key] = $val; + } + } + $result['title'] ??= $metaMap['og:title'] ?? $metaMap['twitter:title'] ?? $metaMap['title'] ?? null; + $result['description'] ??= $metaMap['og:description'] ?? $metaMap['twitter:description'] ?? $metaMap['description'] ?? null; + $result['author'] ??= $metaMap['author'] ?? $metaMap['article:author'] ?? $metaMap['dc.creator'] ?? null; + $result['keywords'] ??= $metaMap['keywords'] ?? $metaMap['news_keywords'] ?? null; + $result['og_image'] ??= $metaMap['og:image'] ?? $metaMap['twitter:image'] ?? null; + $result['site_name'] ??= $metaMap['og:site_name'] ?? null; + $result['og_type'] ??= $metaMap['og:type'] ?? null; + $result['language'] ??= $metaMap['og:locale'] ?? $metaMap['dc.language'] ?? null; + $result['date'] ??= $metaMap['article:published_time'] ?? $metaMap['dc.date'] ?? null; + if (preg_match('/]+rel=["\']canonical["\'][^>]+href=["\']([^"\']+)["\'][^>]*>/i', $headHtml, $m) + || preg_match('/]+href=["\']([^"\']+)["\'][^>]+rel=["\']canonical["\'][^>]*>/i', $headHtml, $m)) { + $result['canonical'] = $m[1]; + } + preg_match_all('/]+type=["\']application\/ld\+json["\'][^>]*>(.*?)<\/script>/si', $headHtml, $ldTags); + foreach ($ldTags[1] as $jsonStr) { + $ld = @json_decode(trim($jsonStr), true); + if (!is_array($ld)) { + continue; + } + foreach (isset($ld[0]) ? $ld : [$ld] as $item) { + if (!is_array($item)) { + continue; + } + if (empty($result['title']) && !empty($item['headline'])) { + $result['title'] = $item['headline']; + } + if (empty($result['description']) && !empty($item['description'])) { + $result['description'] = $item['description']; + } + if (empty($result['date'])) { + $d = $item['datePublished'] ?? $item['dateCreated'] ?? null; + if ($d) { + $result['date'] = $d; + } + } + if (empty($result['author'])) { + $au = $item['author'] ?? null; + if (is_array($au)) { + $au = $au['name'] ?? ($au[0]['name'] ?? null); + } + if (is_string($au) && $au !== '') { + $result['author'] = $au; + } + } + } + break; + } + $result = array_filter($result, static fn ($v) => $v !== null && $v !== ''); + $result['ok'] = true; + } catch (\Throwable) { + } + } + + @unlink($tmpFile); + return $result; +} + +// ─── Télécharge une image distante → _thumb_ local, retourne le nom du fichier ─ +function downloadImageToThumb(string $imageUrl, string $filesDir): ?string +{ + if (!filter_var($imageUrl, FILTER_VALIDATE_URL) || !preg_match('#^https?://#i', $imageUrl)) { + return null; + } + $ch = curl_init($imageUrl); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 3, + CURLOPT_TIMEOUT => 10, + CURLOPT_CONNECTTIMEOUT => 5, + CURLOPT_USERAGENT => 'Mozilla/5.0 varlog/1.0', + ]); + $body = curl_exec($ch); + $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($body === false || $code !== 200 || strlen($body) < 512) { + return null; + } + $urlPath = parse_url($imageUrl, PHP_URL_PATH) ?? ''; + $ext = strtolower(pathinfo($urlPath, PATHINFO_EXTENSION)); + if (!in_array($ext, ['jpg', 'jpeg', 'png', 'webp', 'gif', 'avif'], true)) { + $ext = 'jpg'; + } + if ($ext === 'jpeg') { + $ext = 'jpg'; + } + if (!is_dir($filesDir)) { + mkdir($filesDir, 0755, true); + } + $hash = substr(hash('sha256', $body), 0, 16); + $size = strlen($body); + $name = '_thumb_' . $hash . '-' . $size . '.' . $ext; + file_put_contents($filesDir . '/' . $name, $body); + return $name; +} + +// ─── Trouve l'URL de la plus grande image d'une page HTML ──────────────────── +function findLargestPageImage(string $pageUrl): ?string +{ + if (!filter_var($pageUrl, FILTER_VALIDATE_URL)) { + return null; + } + $ch = curl_init($pageUrl); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 3, + CURLOPT_TIMEOUT => 10, + CURLOPT_CONNECTTIMEOUT => 5, + CURLOPT_USERAGENT => 'Mozilla/5.0 varlog/1.0', + CURLOPT_ENCODING => '', + CURLOPT_WRITEFUNCTION => static function ($curl, $chunk) use (&$htmlBuf, &$htmlLen): int { + $htmlLen = ($htmlLen ?? 0) + strlen($chunk); + if ($htmlLen <= 131072) { + $htmlBuf = ($htmlBuf ?? '') . $chunk; + } + return strlen($chunk); + }, + ]); + $htmlBuf = ''; + $htmlLen = 0; + curl_exec($ch); + curl_close($ch); + if (!$htmlBuf) { + return null; + } + + $scheme = parse_url($pageUrl, PHP_URL_SCHEME) ?? 'https'; + $host = $scheme . '://' . (parse_url($pageUrl, PHP_URL_HOST) ?? ''); + + preg_match_all('/]+src=["\']([^"\']+)["\'][^>]*>/i', $htmlBuf, $m); + $candidates = []; + foreach ($m[1] as $src) { + if (preg_match('#^https?://#i', $src)) { + $candidates[] = $src; + } elseif (str_starts_with($src, '//')) { + $candidates[] = $scheme . ':' . $src; + } elseif (str_starts_with($src, '/')) { + $candidates[] = $host . $src; + } + } + // Filtre les icônes/avatars courants par leur chemin + $candidates = array_filter( + $candidates, + fn ($u) => + !preg_match('#/(icon|logo|avatar|favicon|sprite|pixel|spacer|blank|1x1|tracking)#i', $u) + && preg_match('#\.(jpe?g|png|webp|gif|avif)(\?.*)?$#i', $u) + ); + $candidates = array_slice(array_values($candidates), 0, 10); + if (empty($candidates)) { + return null; + } + + // HEAD requests pour comparer Content-Length + $best = null; + $bestSize = 0; + foreach ($candidates as $imgUrl) { + $ch = curl_init($imgUrl); + curl_setopt_array($ch, [ + CURLOPT_NOBODY => true, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_TIMEOUT => 5, + CURLOPT_CONNECTTIMEOUT => 3, + CURLOPT_USERAGENT => 'Mozilla/5.0 varlog/1.0', + ]); + curl_exec($ch); + $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); + $len = (int) curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD); + curl_close($ch); + if ($code === 200 && $len > $bestSize) { + $bestSize = $len; + $best = $imgUrl; + } + } + // Si aucun Content-Length retourné, prend le premier candidat + return $best ?? $candidates[0]; +} + +// ─── Capture d'écran via Chromium headless ────────────────────────────────── +function takeScreenshot(string $url, string $outputPath): bool +{ + $bin = ''; + foreach (['chromium-headless-shell', 'chromium', 'chromium-browser', 'google-chrome'] as $name) { + $found = trim((string) shell_exec('which ' . escapeshellarg($name) . ' 2>/dev/null')); + if ($found !== '') { + $bin = $found; + break; + } + } + if ($bin === '') { + return false; + } + + $cmd = 'timeout 20 ' . escapeshellarg($bin) + . ' --headless=new' + . ' --disable-gpu' + . ' --no-sandbox' + . ' --disable-setuid-sandbox' + . ' --hide-scrollbars' + . ' --window-size=1200,630' + . ' --screenshot=' . escapeshellarg($outputPath) + . ' --virtual-time-budget=6000' + . ' ' . escapeshellarg($url) + . ' 2>/dev/null'; + shell_exec($cmd); + return file_exists($outputPath) && filesize($outputPath) > 0; +} + switch ($action) { case 'create': @@ -34,6 +434,7 @@ switch ($action) { $seoTitle = $_POST['seo_title'] ?? ''; $seoDescription = $_POST['seo_description'] ?? ''; $ogImage = $_POST['og_image'] ?? ''; + $category = $_POST['category'] ?? ''; $errors = []; if ($_SERVER['REQUEST_METHOD'] === 'POST') { @@ -41,7 +442,7 @@ switch ($action) { $errors[] = 'Le titre est obligatoire.'; } if (empty($errors)) { - $newUuid = $articles->create($title, $content, $published, $postSlug, $published_at, currentUserEmail() ?? '', $seoTitle, $seoDescription, $ogImage); + $newUuid = $articles->create($title, $content, $published, $postSlug, $published_at, currentUserEmail() ?? '', $seoTitle, $seoDescription, $ogImage, $category); foreach ($_FILES['files']['tmp_name'] ?? [] as $i => $tmpName) { if ($_FILES['files']['error'][$i] === UPLOAD_ERR_OK) { @@ -72,19 +473,28 @@ switch ($action) { } if (!$article['published']) { - $author = $article['author'] ?? ''; - $currentEmail = currentUserEmail() ?? ''; - $canView = ($author !== '' && $currentEmail === $author) - || ($author === '' && isAdmin()); - if (!$canView) { + if (!canDoOnArticle('view_drafts', $article)) { http_response_code(404); echo 'Article introuvable.'; exit; } } - // Avant-première : publié mais date future → contenu verrouillé + // Avant-première : publié mais date future → réservé aux connectés if ($article['published'] && strtotime((string)($article['published_at'] ?? '')) > time()) { + if (!isLoggedIn()) { + http_response_code(404); + echo 'Article introuvable.'; + exit; + } + } + + // Catégorie privée → réservé aux connectés + $allCats = $articles->getCategories(); + $privateCats = $articles->getPrivateCategories(); + $articleCat = trim($article['category'] ?? ''); + $isPrivateCat = $articleCat !== '' && in_array($articleCat, $privateCats, true); + if ($isPrivateCat && !isLoggedIn()) { http_response_code(404); echo 'Article introuvable.'; exit; @@ -95,6 +505,64 @@ switch ($action) { // Résout les chemins de fichiers relatifs dans le contenu $rawContent = $articles->resolveFileUrls($article['uuid'], $article['content']); + // Ratings + $ratingStats = ['avg' => null, 'count' => 0]; + $userRating = null; + $pdo = dbPdo(); + if ($pdo) { + require_once BASE_PATH . '/src/RatingManager.php'; + $ratingMgr = new RatingManager($pdo); + $ratingStats = $ratingMgr->statsForArticle($article['uuid']); + if (isLoggedIn()) { + $userRating = $ratingMgr->userRating($article['uuid'], currentUserEmail() ?? ''); + } + } + + // Tous les articles publiés (une seule passe pour related + sidebar) + $_allPublished = $articles->getAll(true); + + // Articles liés (même catégorie) + $relatedArticles = []; + if ($articleCat !== '') { + foreach ($_allPublished as $a) { + if ($a['uuid'] === $article['uuid']) { + continue; + } + if (trim($a['category'] ?? '') !== $articleCat) { + continue; + } + if (strtotime((string)($a['published_at'] ?? '')) > time() && !isLoggedIn()) { + continue; + } + $relatedArticles[] = $a; + if (count($relatedArticles) >= 5) { + break; + } + } + } + + // Sidebar gauche : autres catégories avec leurs 5 derniers articles + $categorySidebar = []; + foreach ($_allPublished as $a) { + $aCat = trim($a['category'] ?? ''); + if ($aCat === '' || $aCat === $articleCat) { + continue; + } + if (in_array($aCat, $privateCats, true) && !isLoggedIn()) { + continue; + } + if (strtotime((string)($a['published_at'] ?? '')) > time() && !isLoggedIn()) { + continue; + } + if (!isset($categorySidebar[$aCat])) { + $categorySidebar[$aCat] = []; + } + if (count($categorySidebar[$aCat]) < 5) { + $categorySidebar[$aCat][] = $a; + } + } + unset($_allPublished); + include BASE_PATH . '/templates/post_view.php'; break; @@ -108,6 +576,12 @@ switch ($action) { exit; } + if (!canDoOnArticle('edit_articles', $article)) { + http_response_code(403); + echo 'Accès refusé.'; + exit; + } + $title = $_POST['title'] ?? $article['title']; $content = $_POST['content'] ?? $article['content']; $postSlug = $_POST['slug'] ?? $article['slug']; @@ -117,6 +591,7 @@ switch ($action) { $seoTitle = $_POST['seo_title'] ?? ($article['seo_title'] ?? ''); $seoDescription = $_POST['seo_description'] ?? ($article['seo_description'] ?? ''); $ogImage = $_POST['og_image'] ?? ($article['og_image'] ?? ''); + $category = $_POST['category'] ?? ($article['category'] ?? ''); $errors = []; if ($_SERVER['REQUEST_METHOD'] === 'POST') { @@ -134,17 +609,22 @@ switch ($action) { $_POST['revision_comment'] ?? '', $_POST['seo_title'] ?? '', $_POST['seo_description'] ?? '', - $_POST['og_image'] ?? '' + $_POST['og_image'] ?? '', + $_POST['category'] ?? '' ); - foreach ($_FILES['files']['tmp_name'] ?? [] as $i => $tmpName) { - if ($_FILES['files']['error'][$i] === UPLOAD_ERR_OK) { - $articles->addFile($uuid, [ - 'name' => $_FILES['files']['name'][$i], - 'tmp_name' => $tmpName, - 'error' => $_FILES['files']['error'][$i], - ]); - } + // Métadonnées des fichiers existants (auteur, source) + $fmetaNames = $_POST['fmeta_name'] ?? []; + $fmetaAuthors = $_POST['fmeta_author'] ?? []; + $fmetaSources = $_POST['fmeta_source'] ?? []; + foreach ($fmetaNames as $fi => $fname) { + $articles->addFileMeta($uuid, $fname, trim($fmetaAuthors[$fi] ?? ''), trim($fmetaSources[$fi] ?? '')); + } + + // Cover + $coverFile = trim($_POST['cover_file'] ?? ''); + if ($coverFile !== '') { + $articles->setCover($uuid, $coverFile); } $updated = $articles->getByUuid($uuid); @@ -156,6 +636,10 @@ switch ($action) { $formAction = '/?action=edit&uuid=' . rawurlencode($uuid); $action = 'edit'; $existingFiles = $articles->getFiles($uuid); + $insertUrl = ''; + if (isset($_GET['insert_url']) && filter_var($_GET['insert_url'], FILTER_VALIDATE_URL)) { + $insertUrl = $_GET['insert_url']; + } include BASE_PATH . '/templates/post_form.php'; break; @@ -176,6 +660,47 @@ switch ($action) { header('Location: /'); exit; + case 'categories': + requireAuth(); + $cats = $articles->getCategories(); + $privateCats = $articles->getPrivateCategories(); + include BASE_PATH . '/templates/categories.php'; + break; + + case 'rename_category': + requireAuth(); + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $old = trim($_POST['old'] ?? ''); + $new = trim($_POST['new'] ?? ''); + if ($old !== '' && $new !== '' && $old !== $new) { + $articles->renameCategory($old, $new); + } + } + header('Location: /?action=categories'); + exit; + + case 'delete_category': + requireAuth(); + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $cat = trim($_POST['category'] ?? ''); + if ($cat !== '') { + $articles->deleteCategory($cat); + } + } + header('Location: /?action=categories'); + exit; + + case 'toggle_private_category': + requireAuth(); + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $cat = trim($_POST['category'] ?? ''); + if ($cat !== '') { + $articles->togglePrivateCategory($cat); + } + } + header('Location: /?action=categories'); + exit; + case 'about': include BASE_PATH . '/templates/about.php'; break; @@ -192,17 +717,826 @@ switch ($action) { include BASE_PATH . '/templates/licenses.php'; break; + case 'diff': + requireAuth(); + $article = $articles->getByUuid($uuid); + if (!$article) { + http_response_code(404); + echo 'Article introuvable.'; + exit; + } + $revisions = $article['revisions'] ?? []; + $revN = (int)($_GET['rev'] ?? 0); + // Trouver l'index dans le tableau par numéro de révision + $revIndex = null; + foreach ($revisions as $ri => $r) { + if ((int)($r['n'] ?? 0) === $revN) { + $revIndex = $ri; + break; + } + } + if ($revIndex === null || $revN < 1) { + header('Location: /?action=edit&uuid=' . rawurlencode($uuid)); + exit; + } + $oldContent = $articles->getRevisionContent($uuid, $revN); + if ($oldContent === null) { + http_response_code(404); + echo 'Révision introuvable.'; + exit; + } + $diffLines = lineDiff($oldContent, $article['content']); + include BASE_PATH . '/templates/diff.php'; + break; + + case 'autosave': + requireAuth(); + header('Content-Type: application/json'); + if ($_SERVER['REQUEST_METHOD'] !== 'POST' || $uuid === '') { + echo json_encode(['ok' => false]); + exit; + } + $asTitle = trim($_POST['title'] ?? ''); + $asContent = $_POST['content'] ?? ''; + $asSlug = trim($_POST['slug'] ?? ''); + if ($asTitle === '') { + echo json_encode(['ok' => false]); + exit; + } + $ok = $articles->autosave($uuid, $asTitle, $asContent, $asSlug); + echo json_encode(['ok' => $ok, 'time' => date('H:i:s')]); + exit; + + case 'add_files': + requireAuth(); + $addFilesArticle = $articles->getByUuid($uuid); + if (!$addFilesArticle) { + http_response_code(404); + echo 'Article introuvable.'; + exit; + } + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + foreach ($_FILES['files']['tmp_name'] ?? [] as $i => $tmpName) { + if ($_FILES['files']['error'][$i] === UPLOAD_ERR_OK) { + $articles->addFile($uuid, [ + 'name' => $_FILES['files']['name'][$i], + 'tmp_name' => $tmpName, + 'error' => $_FILES['files']['error'][$i], + ]); + } + } + header('Location: /?action=edit&uuid=' . rawurlencode($uuid)); + exit; + } + include BASE_PATH . '/templates/add_files.php'; + break; + + case 'import_image': + requireAuth(); + $importArticle = $articles->getByUuid($uuid); + if (!$importArticle) { + http_response_code(404); + echo 'Article introuvable.'; + exit; + } + $importError = $_GET['error'] ?? ''; + include BASE_PATH . '/templates/import_image.php'; + break; + + case 'fetch_file_meta': + requireAuth(); + header('Content-Type: application/json'); + echo json_encode(fetchUrlMeta(trim($_GET['url'] ?? ''))); + exit; + + case 'import_image_step2': + requireAuth(); + if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + header('Location: /?action=import_image&uuid=' . rawurlencode($uuid)); + exit; + } + $step2Article = $articles->getByUuid($uuid); + if (!$step2Article) { + http_response_code(404); + echo 'Article introuvable.'; + exit; + } + $step2Url = trim($_POST['image_url'] ?? ''); + if (!filter_var($step2Url, FILTER_VALIDATE_URL) || !preg_match('#^https?://#i', $step2Url)) { + header('Location: /?action=import_image&uuid=' . rawurlencode($uuid) . '&error=1'); + exit; + } + $step2Meta = fetchUrlMeta($step2Url); + if (!($step2Meta['ok'] ?? false)) { + header('Location: /?action=import_image&uuid=' . rawurlencode($uuid) . '&error=1'); + exit; + } + // Capture d'écran pour prévisualisation (pages HTML uniquement) + $step2Screenshot = null; + if (str_starts_with($step2Meta['mime'] ?? '', 'text/html')) { + $filesDir = BASE_PATH . '/data/' . $uuid . '/files'; + if (!is_dir($filesDir)) { + mkdir($filesDir, 0755, true); + } + $previewPath = $filesDir . '/_preview.png'; + @unlink($previewPath); // supprime le résidu d'une analyse précédente + if (takeScreenshot($step2Url, $previewPath)) { + $step2Screenshot = '_preview.png'; + } + } + include BASE_PATH . '/templates/import_image_step2.php'; + break; + + case 'copyright_ack': + requireAuth(); + $ackArticle = $articles->getByUuid($uuid); + if (!$ackArticle) { + http_response_code(404); + echo 'Article introuvable.'; + exit; + } + $ackUrl = filter_var($_GET['image_url'] ?? '', FILTER_VALIDATE_URL) + ? $_GET['image_url'] : ''; + if ($ackUrl === '') { + header('Location: /?action=import_image&uuid=' . rawurlencode($uuid)); + exit; + } + $ackTitle = $_GET['img_title'] ?? ''; + $ackAuthor = $_GET['img_author'] ?? ''; + $ackSource = $_GET['img_source'] ?? ''; + $ackIsCover = !empty($_GET['is_cover']); + $ackMetaJson = $_GET['meta_json'] ?? ''; + include BASE_PATH . '/templates/copyright_ack.php'; + break; + + case 'add_file_from_url': + requireAuth(); + if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + header('Location: /'); + exit; + } + $urlUuid = $_GET['uuid'] ?? $_POST['uuid'] ?? ''; + $imageUrl = trim($_POST['image_url'] ?? ''); + $mode = $_POST['mode'] ?? 'link'; + $isCover = isset($_POST['is_cover']); + $imgTitle = trim($_POST['img_title'] ?? ''); + $imgAuthor = trim($_POST['img_author'] ?? ''); + $imgSource = trim($_POST['img_source'] ?? '') ?: $imageUrl; + + // Métadonnées supplémentaires (passées depuis l'étape 2) + $importedMeta = []; + $rawMetaJson = $_POST['meta_json'] ?? ''; + if ($rawMetaJson !== '') { + $dec = @json_decode($rawMetaJson, true); + if (is_array($dec)) { + foreach ($dec as $k => $v) { + if (is_string($k) && strlen($k) <= 60 && is_scalar($v)) { + $importedMeta[$k] = $v; + } + } + } + } + + $urlArticle = $articles->getByUuid($urlUuid); + if (!$urlArticle || $imageUrl === '' || !filter_var($imageUrl, FILTER_VALIDATE_URL)) { + header('Location: /?action=import_image&uuid=' . rawurlencode($urlUuid)); + exit; + } + + $screenshotFile = basename(trim($_POST['screenshot_file'] ?? '')); + + if ($mode === 'screenshot') { + if ($screenshotFile === '' || $screenshotFile !== '_preview.png') { + header('Location: /?action=import_image&uuid=' . rawurlencode($urlUuid) . '&error=1'); + exit; + } + $filesDir = BASE_PATH . '/data/' . $urlUuid . '/files'; + $previewPath = $filesDir . '/' . $screenshotFile; + if (!file_exists($previewPath)) { + header('Location: /?action=import_image&uuid=' . rawurlencode($urlUuid) . '&error=1'); + exit; + } + $hash = substr(hash_file('sha256', $previewPath), 0, 16); + $size = filesize($previewPath); + $destName = $hash . '-' . $size . '.png'; + rename($previewPath, $filesDir . '/' . $destName); + $articles->addFileMeta($urlUuid, $destName, $imgAuthor, $imgSource, $imgTitle, $importedMeta); + if ($isCover) { + $articles->setCover($urlUuid, $destName); + } + header('Location: /?action=edit&uuid=' . rawurlencode($urlUuid)); + exit; + } + + if ($mode === 'link') { + $filesDir = BASE_PATH . '/data/' . $urlUuid . '/files'; + if (!is_dir($filesDir)) { + mkdir($filesDir, 0755, true); + } + $linkMime = $importedMeta['mime'] ?? ''; + $isHtmlLink = str_starts_with($linkMime, 'text/html') || $linkMime === ''; + if ($isHtmlLink) { + $thumbSet = false; + // 1. Télécharge l'og:image distante + $extOg = $importedMeta['og_image'] ?? ''; + if (!$thumbSet && $extOg !== '' && !str_starts_with($extOg, '/')) { + $thumbName = downloadImageToThumb($extOg, $filesDir); + if ($thumbName !== null) { + $importedMeta['og_image'] = '/file?uuid=' . rawurlencode($urlUuid) . '&name=' . rawurlencode($thumbName); + $thumbSet = true; + } + } + // 2. Plus grande image trouvée sur la page + if (!$thumbSet) { + $bigImg = findLargestPageImage($imageUrl); + if ($bigImg !== null) { + $thumbName = downloadImageToThumb($bigImg, $filesDir); + if ($thumbName !== null) { + $importedMeta['og_image'] = '/file?uuid=' . rawurlencode($urlUuid) . '&name=' . rawurlencode($thumbName); + $thumbSet = true; + } + } + } + // 3. Screenshot pré-généré depuis step2 + if (!$thumbSet && $screenshotFile !== '' && file_exists($filesDir . '/' . $screenshotFile)) { + $previewPath = $filesDir . '/' . $screenshotFile; + $hash = substr(hash_file('sha256', $previewPath), 0, 16); + $size = filesize($previewPath); + $thumbName = '_thumb_' . $hash . '-' . $size . '.png'; + rename($previewPath, $filesDir . '/' . $thumbName); + $importedMeta['og_image'] = '/file?uuid=' . rawurlencode($urlUuid) . '&name=' . rawurlencode($thumbName); + $thumbSet = true; + } + // 4. Screenshot à la volée en dernier recours + if (!$thumbSet) { + $screenshotTmp = tempnam(sys_get_temp_dir(), 'vl_ss_') . '.png'; + if (takeScreenshot($imageUrl, $screenshotTmp)) { + $hash = substr(hash_file('sha256', $screenshotTmp), 0, 16); + $size = filesize($screenshotTmp); + $thumbName = '_thumb_' . $hash . '-' . $size . '.png'; + rename($screenshotTmp, $filesDir . '/' . $thumbName); + $importedMeta['og_image'] = '/file?uuid=' . rawurlencode($urlUuid) . '&name=' . rawurlencode($thumbName); + } else { + @unlink($screenshotTmp); + } + } + // Supprime le preview inutilisé si toujours présent + if ($screenshotFile !== '' && file_exists($filesDir . '/' . $screenshotFile)) { + @unlink($filesDir . '/' . $screenshotFile); + } + } elseif ($screenshotFile !== '') { + // Non-HTML : supprime le preview inutilisé + @unlink($filesDir . '/' . $screenshotFile); + } + $articles->addExternalLink($urlUuid, $imageUrl, $imgTitle, $imgAuthor, $importedMeta); + header('Location: /?action=edit&uuid=' . rawurlencode($urlUuid)); + exit; + } + + // Mode téléchargement : accusé de réception obligatoire + if (empty($_POST['copyright_acked'])) { + header('Location: /?action=copyright_ack&' . http_build_query([ + 'uuid' => $urlUuid, + 'image_url' => $imageUrl, + 'img_title' => $imgTitle, + 'img_author' => $imgAuthor, + 'img_source' => trim($_POST['img_source'] ?? ''), + 'is_cover' => $isCover ? '1' : '', + 'meta_json' => $rawMetaJson, + ])); + exit; + } + + $imported = $articles->addFileFromUrl($urlUuid, $imageUrl, $isCover, $imgAuthor, $imgSource, $imgTitle, $importedMeta); + if ($imported) { + header('Location: /?action=edit&uuid=' . rawurlencode($urlUuid)); + } else { + header('Location: /?action=import_image&uuid=' . rawurlencode($urlUuid) . '&error=1&mode=download'); + } + exit; + + case 'sources': + $article = $articles->getByUuid($uuid); + if (!$article) { + http_response_code(404); + echo 'Article introuvable.'; + exit; + } + requireAuth(); + if (!canDoOnArticle('view_sources', $article)) { + http_response_code(403); + echo 'Accès refusé.'; + exit; + } + $sourcesFiles = $articles->getFiles($uuid); + include BASE_PATH . '/templates/sources.php'; + break; + + case 'regen_thumbs': + requireAuth(); + + // Page de confirmation si pas encore lancé + if (!isset($_GET['run'])) { + ob_start(); + ?> +

Génération des aperçus de liens

+
+ + +
+
+ + +
+ Supprime et régénère les miniatures locales déjà enregistrées. +
+
+ +
+
+ ← Retour + + Génération des aperçus + + '; + $heading = $force ? 'Régénération de tous les aperçus' : 'Génération des aperçus manquants'; + echo '

' . $heading . '

    '; + @ob_flush(); + flush(); + + $done = $fail = $skip = 0; + foreach ($articles->getAll() as $article) { + $artUuid = $article['uuid']; + $filesDir = BASE_PATH . '/data/' . $artUuid . '/files'; + foreach ($article['external_links'] ?? [] as $link) { + $lMeta = $link['meta'] ?? []; + $lMime = $lMeta['mime'] ?? 'text/html'; + $lUrl = $link['url'] ?? ''; + + // Ignore si ce n'est pas du HTML + if ($lMime !== '' && !str_starts_with($lMime, 'text/html')) { + $skip++; + continue; + } + + $hasLocal = !empty($lMeta['og_image']) && str_starts_with($lMeta['og_image'], '/'); + if ($hasLocal && !$force) { + $skip++; + continue; + } + + echo '
  • '; + echo '' . htmlspecialchars($article['title']) . ''; + echo htmlspecialchars($lUrl) . ' … '; + @ob_flush(); + flush(); + + // Supprime l'ancienne miniature locale si on force + if ($force && $hasLocal) { + $oldMeta = $lMeta['og_image']; + $oldName = rawurldecode(parse_url($oldMeta, PHP_URL_QUERY) ? (explode('name=', $oldMeta)[1] ?? '') : ''); + // Extrait le paramètre name= de l'URL /file?uuid=...&name=... + parse_str(parse_url($oldMeta, PHP_URL_QUERY) ?? '', $oldQs); + $oldFile = $oldQs['name'] ?? ''; + if ($oldFile !== '' && file_exists($filesDir . '/' . $oldFile)) { + @unlink($filesDir . '/' . $oldFile); + } + } + + $thumbName = null; + $method = ''; + + // 1. og_image → téléchargement direct + // Non-force : utilise l'og_image stockée si externe + // Force : refetch la page pour récupérer l'URL d'origine + $ogToDownload = ''; + if (!$force) { + $stored = $lMeta['og_image'] ?? ''; + if ($stored !== '' && filter_var($stored, FILTER_VALIDATE_URL)) { + $ogToDownload = $stored; + } + } else { + $freshMeta = fetchUrlMeta($lUrl); + $ogToDownload = $freshMeta['og_image'] ?? ''; + if (!filter_var($ogToDownload, FILTER_VALIDATE_URL)) { + $ogToDownload = ''; + } + } + if ($ogToDownload !== '') { + $thumbName = downloadImageToThumb($ogToDownload, $filesDir); + if ($thumbName) { + $method = '✓ og:image'; + } + } + + // 2. Plus grande image de la page + if ($thumbName === null) { + $largestUrl = findLargestPageImage($lUrl); + if ($largestUrl) { + $thumbName = downloadImageToThumb($largestUrl, $filesDir); + if ($thumbName) { + $method = '✓ plus grande image'; + } + } + } + + // 3. Screenshot Chromium en dernier recours + if ($thumbName === null) { + $screenshotTmp = tempnam(sys_get_temp_dir(), 'vl_ss_') . '.png'; + if (takeScreenshot($lUrl, $screenshotTmp)) { + if (!is_dir($filesDir)) { + mkdir($filesDir, 0755, true); + } + $hash = substr(hash_file('sha256', $screenshotTmp), 0, 16); + $size = filesize($screenshotTmp); + $thumbName = '_thumb_' . $hash . '-' . $size . '.png'; + rename($screenshotTmp, $filesDir . '/' . $thumbName); + $method = '✓ screenshot'; + } else { + @unlink($screenshotTmp); + } + } + + if ($thumbName !== null) { + $ogUrl = '/file?uuid=' . rawurlencode($artUuid) . '&name=' . rawurlencode($thumbName); + $articles->updateExternalLinkMeta($artUuid, $lUrl, ['og_image' => $ogUrl]); + echo '' . $method . ''; + $done++; + } else { + echo '✗ échec'; + $fail++; + } + echo '
  • '; + @ob_flush(); + flush(); + } + } + + echo '
'; + echo '

Terminé — '; + echo $done . ' capturé' . ($done > 1 ? 's' : '') . ', '; + echo $fail . ' échec' . ($fail > 1 ? 's' : '') . ', '; + echo $skip . ' ignoré' . ($skip > 1 ? 's' : '') . '.

'; + echo '← Retour'; + echo ''; + exit; + + case 'delete_external_link': + requireAuth(); + if ($_SERVER['REQUEST_METHOD'] === 'POST' && $uuid !== '') { + $linkUrl = $_POST['url'] ?? ''; + if ($linkUrl !== '' && filter_var($linkUrl, FILTER_VALIDATE_URL)) { + $articles->removeExternalLink($uuid, $linkUrl); + } + } + header('Location: /?action=edit&uuid=' . rawurlencode($uuid)); + exit; + + case 'rate': + requireAuth(); + if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + header('Location: /'); + exit; + } + $rateUuid = $_POST['uuid'] ?? ''; + $rateValue = (int)($_POST['rating'] ?? 0); + $rateArticle = $articles->getByUuid($rateUuid); + if ($rateArticle && $rateValue >= 1 && $rateValue <= 5) { + $pdo = dbPdo(); + if ($pdo) { + require_once BASE_PATH . '/src/RatingManager.php'; + (new RatingManager($pdo))->rate($rateUuid, currentUserEmail() ?? '', $rateValue); + } + header('Location: /post/' . rawurlencode($rateArticle['slug'] ?? $rateUuid)); + } else { + header('Location: /'); + } + exit; + + case 'admin': + requireAuth(); + $tab = $_GET['tab'] ?? (isAdmin() ? 'dashboard' : 'articles'); + $adminData = []; + + if ($tab === 'dashboard') { + if (!isAdmin()) { + http_response_code(403); + exit; + } + $allArticles = $articles->getAll(); + $now = time(); + $adminData['total'] = count($allArticles); + $adminData['published'] = count(array_filter($allArticles, fn ($a) => $a['published'] && strtotime((string)($a['published_at'] ?? '')) <= $now)); + $adminData['drafts'] = count(array_filter($allArticles, fn ($a) => !$a['published'])); + $adminData['previews'] = count(array_filter($allArticles, fn ($a) => $a['published'] && strtotime((string)($a['published_at'] ?? '')) > $now)); + $adminData['recent'] = array_slice( + usort($allArticles, fn ($a, $b) => strcmp($b['updated_at'] ?? '', $a['updated_at'] ?? '')) ? $allArticles : $allArticles, + 0, + 5 + ); + // Trier par updated_at desc + usort($allArticles, fn ($a, $b) => strcmp($b['updated_at'] ?? '', $a['updated_at'] ?? '')); + $adminData['recent'] = array_slice($allArticles, 0, 5); + } + + if ($tab === 'articles') { + $allArticles = $articles->getAll(); + if (!isAdmin()) { + $me = currentUserEmail() ?? ''; + $allArticles = array_values(array_filter($allArticles, fn ($a) => ($a['author'] ?? '') === $me)); + } + usort($allArticles, fn ($a, $b) => strcmp($b['updated_at'] ?? '', $a['updated_at'] ?? '')); + $adminData['articles'] = $allArticles; + } + + if ($tab === 'roles') { + if (!isAdmin()) { + http_response_code(403); + exit; + } + $pdo = dbPdo(); + if ($pdo) { + $st = $pdo->query( + 'SELECT r.id, r.name, r.label, COUNT(ur.user_email) AS user_count + FROM roles r + LEFT JOIN user_roles ur ON ur.role_id = r.id + GROUP BY r.id, r.name, r.label + ORDER BY r.name' + ); + $roles = $st->fetchAll(PDO::FETCH_ASSOC); + // Charge les capacités par rôle + try { + $capRows = $pdo->query('SELECT role_id, capability FROM role_capabilities')->fetchAll(PDO::FETCH_ASSOC); + $capsMap = []; + foreach ($capRows as $cr) { + $capsMap[(int)$cr['role_id']][] = $cr['capability']; + } + } catch (\Throwable) { + $capsMap = []; + } + foreach ($roles as &$r) { + $r['capabilities'] = $capsMap[(int)$r['id']] ?? []; + } + unset($r); + $adminData['roles'] = $roles; + } else { + $adminData['roles'] = []; + } + } + + if ($tab === 'users') { + if (!isAdmin()) { + http_response_code(403); + exit; + } + $pdo = dbPdo(); + if ($pdo) { + // users table may not exist yet — degrade gracefully + $usersFromDb = []; + try { + $st = $pdo->query('SELECT email, is_active FROM users ORDER BY email'); + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $row) { + $v = $row['is_active']; + $usersFromDb[$row['email']] = is_bool($v) ? $v : in_array(strtolower((string)$v), ['t', '1', 'true', 'yes'], true); + } + } catch (\PDOException) { + // table absente, on continue avec la liste user_roles seulement + } + + $st = $pdo->query('SELECT ur.user_email, r.name FROM user_roles ur JOIN roles r ON r.id = ur.role_id ORDER BY ur.user_email'); + $rolesMap = []; + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $row) { + $rolesMap[$row['user_email']][] = $row['name']; + } + + $merged = []; + foreach (array_unique(array_merge(array_keys($usersFromDb), array_keys($rolesMap))) as $email) { + $merged[$email] = [ + 'email' => $email, + 'is_active' => $usersFromDb[$email] ?? null, + 'roles' => $rolesMap[$email] ?? [], + ]; + } + ksort($merged); + $adminData['users'] = array_values($merged); + + $st = $pdo->query('SELECT id, name, label FROM roles ORDER BY name'); + $adminData['roles'] = $st->fetchAll(PDO::FETCH_ASSOC); + } else { + $adminData['users'] = []; + $adminData['roles'] = []; + } + } + + include BASE_PATH . '/templates/admin.php'; + break; + + case 'admin_grant_role': + requireAuth(); + if (!isAdmin() || $_SERVER['REQUEST_METHOD'] !== 'POST') { + http_response_code(403); + exit; + } + $targetEmail = strtolower(trim($_POST['email'] ?? '')); + $roleName = trim($_POST['role'] ?? ''); + if ($targetEmail && $roleName && filter_var($targetEmail, FILTER_VALIDATE_EMAIL)) { + $pdo = dbPdo(); + if ($pdo) { + $st = $pdo->prepare( + 'INSERT INTO user_roles (user_email, role_id, granted_by) + SELECT :email, id, :by FROM roles WHERE name = :role + ON CONFLICT DO NOTHING' + ); + $st->execute([':email' => $targetEmail, ':role' => $roleName, ':by' => currentUserEmail()]); + } + } + header('Location: /?action=admin&tab=users'); + exit; + + case 'admin_revoke_role': + requireAuth(); + if (!isAdmin() || $_SERVER['REQUEST_METHOD'] !== 'POST') { + http_response_code(403); + exit; + } + $targetEmail = strtolower(trim($_POST['email'] ?? '')); + $roleName = trim($_POST['role'] ?? ''); + if ($targetEmail && $roleName) { + $pdo = dbPdo(); + if ($pdo) { + $st = $pdo->prepare( + 'DELETE FROM user_roles + WHERE user_email = :email + AND role_id = (SELECT id FROM roles WHERE name = :role)' + ); + $st->execute([':email' => $targetEmail, ':role' => $roleName]); + } + } + header('Location: /?action=admin&tab=users'); + exit; + + case 'admin_create_role': + requireAuth(); + if (!isAdmin() || $_SERVER['REQUEST_METHOD'] !== 'POST') { + http_response_code(403); + exit; + } + $roleName = preg_replace('/[^a-z0-9_-]/', '', strtolower(trim($_POST['name'] ?? ''))); + $roleLabel = trim($_POST['label'] ?? ''); + if ($roleName && $roleLabel) { + $pdo = dbPdo(); + if ($pdo) { + try { + $st = $pdo->prepare('INSERT INTO roles (name, label) VALUES (:n, :l) ON CONFLICT (name) DO NOTHING'); + $st->execute([':n' => $roleName, ':l' => $roleLabel]); + } catch (\PDOException) { + } + } + } + header('Location: /?action=admin&tab=roles'); + exit; + + case 'admin_update_role': + requireAuth(); + if (!isAdmin() || $_SERVER['REQUEST_METHOD'] !== 'POST') { + http_response_code(403); + exit; + } + $roleId = (int)($_POST['id'] ?? 0); + $roleLabel = trim($_POST['label'] ?? ''); + if ($roleId > 0 && $roleLabel) { + $pdo = dbPdo(); + if ($pdo) { + $st = $pdo->prepare('UPDATE roles SET label = :l WHERE id = :id'); + $st->execute([':l' => $roleLabel, ':id' => $roleId]); + } + } + header('Location: /?action=admin&tab=roles'); + exit; + + case 'admin_delete_role': + requireAuth(); + if (!isAdmin() || $_SERVER['REQUEST_METHOD'] !== 'POST') { + http_response_code(403); + exit; + } + $roleId = (int)($_POST['id'] ?? 0); + if ($roleId > 0) { + $pdo = dbPdo(); + if ($pdo) { + $st = $pdo->prepare('DELETE FROM roles WHERE id = :id'); + $st->execute([':id' => $roleId]); + } + } + header('Location: /?action=admin&tab=roles'); + exit; + + case 'admin_update_role_caps': + requireAuth(); + if (!isAdmin() || $_SERVER['REQUEST_METHOD'] !== 'POST') { + http_response_code(403); + exit; + } + $roleId = (int)($_POST['role_id'] ?? 0); + $newCaps = array_filter((array)($_POST['caps'] ?? []), fn ($c) => array_key_exists($c, KNOWN_CAPABILITIES)); + if ($roleId > 0) { + $pdo = dbPdo(); + if ($pdo) { + $pdo->prepare('DELETE FROM role_capabilities WHERE role_id = :id')->execute([':id' => $roleId]); + $ins = $pdo->prepare('INSERT INTO role_capabilities (role_id, capability) VALUES (:id, :cap)'); + foreach ($newCaps as $cap) { + $ins->execute([':id' => $roleId, ':cap' => $cap]); + } + // Invalide le cache de capacités en session (affecte l'utilisateur courant) + unset($_SESSION['user_capabilities']); + } + } + header('Location: /?action=admin&tab=roles'); + exit; + + case 'profile': + requireAuth(); + $profileError = ''; + $profileSuccess = false; + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $newName = trim($_POST['display_name'] ?? ''); + if ($newName === '') { + $profileError = 'Le nom ne peut pas être vide.'; + } else { + $pdo = dbPdo(); + if ($pdo) { + try { + $st = $pdo->prepare( + 'INSERT INTO user_profiles (email, display_name, updated_at) + VALUES (:e, :n, now()) + ON CONFLICT (email) DO UPDATE SET display_name = :n, updated_at = now()' + ); + $st->execute([':e' => currentUserEmail(), ':n' => $newName]); + $_SESSION['user_display_name'] = $newName; + $profileSuccess = true; + } catch (\Throwable $ex) { + $profileError = 'Erreur lors de la sauvegarde.'; + } + } + } + } + $profileCurrentName = currentUserName(); + include BASE_PATH . '/templates/profile.php'; + break; + case 'list': default: - $currentEmail = currentUserEmail() ?? ''; - $posts = array_values(array_filter($articles->getAll(), static function (array $a) use ($currentEmail): bool { - if ($a['published']) { - return true; + $privateCats = $articles->getPrivateCategories(); + $allCats = $articles->getCategories(); + $filterCat = trim($_GET['cat'] ?? ''); + $allPosts = array_values(array_filter($articles->getAll(), static function (array $a) use ($privateCats, $filterCat): bool { + if (!$a['published']) { + return canDoOnArticle('view_drafts', $a); } - $author = $a['author'] ?? ''; - return ($author !== '' && $currentEmail === $author) - || ($author === '' && isAdmin()); + $cat = trim($a['category'] ?? ''); + if ($cat !== '' && in_array($cat, $privateCats, true) && !isLoggedIn()) { + return false; + } + if ($filterCat !== '' && $cat !== $filterCat) { + return false; + } + return true; })); + $perPage = 12; + $cursor = trim($_GET['cursor'] ?? ''); + + // Trouve la position du curseur dans la liste triée + $offset = 0; + if ($cursor !== '') { + foreach ($allPosts as $i => $a) { + if ($a['uuid'] === $cursor) { + $offset = $i + 1; + break; + } + } + } + + $posts = array_slice($allPosts, $offset, $perPage); + $nextCursor = count($posts) === $perPage ? end($posts)['uuid'] : null; + $prevCursor = null; + if ($offset > 0) { + $prevOffset = max(0, $offset - $perPage); + $prevCursor = $prevOffset > 0 ? $allPosts[$prevOffset - 1]['uuid'] : ''; + } include BASE_PATH . '/templates/post_list.php'; break; } diff --git a/public/oidc/callback.php b/public/oidc/callback.php index d92855e..8a59dab 100644 --- a/public/oidc/callback.php +++ b/public/oidc/callback.php @@ -142,9 +142,20 @@ if (!$email) { exit; } +// Nom d'affichage depuis les claims SSO +$displayName = ''; +if (!empty($claims['given_name']) || !empty($claims['family_name'])) { + $displayName = trim(($claims['given_name'] ?? '') . ' ' . ($claims['family_name'] ?? '')); +} elseif (!empty($claims['name'])) { + $displayName = trim($claims['name']); +} elseif (!empty($claims['preferred_username'])) { + $displayName = trim($claims['preferred_username']); +} + // Ouvre la session authentifiée session_regenerate_id(true); -$_SESSION['user_email'] = strtolower(trim($email)); +$_SESSION['user_email'] = strtolower(trim($email)); +$_SESSION['user_display_name'] = $displayName; $_SESSION['oidc'] = [ 'issuer' => $OIDC_ISSUER, 'sub' => $claims['sub'] ?? null, @@ -153,6 +164,23 @@ $_SESSION['oidc'] = [ 'expires_at' => time() + (int)($tokens['expires_in'] ?? 3600), ]; +// Persiste le nom d'affichage en base (seulement s'il vient du SSO et que la table existe) +if ($displayName !== '') { + require_once dirname(__DIR__, 2) . '/src/auth.php'; + $pdo = dbPdo(); + if ($pdo) { + try { + $st = $pdo->prepare( + 'INSERT INTO user_profiles (email, display_name, updated_at) + VALUES (:e, :n, now()) + ON CONFLICT (email) DO NOTHING' + ); + $st->execute([':e' => strtolower(trim($email)), ':n' => $displayName]); + } catch (\Throwable) { + } + } +} + $target = $_SESSION['oidc_return_to'] ?? '/'; unset($_SESSION['oidc_return_to'], $_SESSION['oidc_flow']); if (!is_string($target) || $target === '' || $target[0] !== '/') { diff --git a/src/ArticleManager.php b/src/ArticleManager.php index a85f58b..32ea787 100644 --- a/src/ArticleManager.php +++ b/src/ArticleManager.php @@ -4,6 +4,8 @@ declare(strict_types=1); class ArticleManager { + private const MAX_REVISIONS = 50; + public function __construct(private string $dataDir) { } @@ -65,11 +67,24 @@ class ArticleManager return $this->loadArticle($dir); } + public function getRevisionContent(string $uuid, int $n): ?string + { + if (!$this->isValidUuid($uuid) || $n < 1) { + return null; + } + $path = sprintf('%s/%s/revisions/%04d.md', $this->dataDir, $uuid, $n); + if (!file_exists($path)) { + return null; + } + $c = file_get_contents($path); + return $c !== false ? $c : null; + } + // ------------------------------------------------------------------ // // Écriture // ------------------------------------------------------------------ // - public function create(string $title, string $content, bool $published, string $slug = '', string $publishedAt = '', string $author = '', string $seoTitle = '', string $seoDescription = '', string $ogImage = ''): string + public function create(string $title, string $content, bool $published, string $slug = '', string $publishedAt = '', string $author = '', string $seoTitle = '', string $seoDescription = '', string $ogImage = '', string $category = ''): string { $uuid = $this->generateUuid(); $slug = $slug !== '' ? $this->sanitizeSlug($slug) : $this->generateSlug($title); @@ -91,9 +106,13 @@ class ArticleManager 'created_at' => $now, 'updated_at' => $now, 'revisions' => [], + 'cover' => '', + 'files_meta' => [], + 'external_links' => [], 'seo_title' => $seoTitle, 'seo_description' => $seoDescription, 'og_image' => $ogImage, + 'category' => $category, ]; $this->writeMeta($dir, $meta); file_put_contents($dir . '/index.md', ltrim($content)); @@ -101,18 +120,37 @@ class ArticleManager return $uuid; } - public function update(string $uuid, string $title, string $content, bool $published, string $slug, string $publishedAt, string $revisionComment = '', string $seoTitle = '', string $seoDescription = '', string $ogImage = ''): void + public function update(string $uuid, string $title, string $content, bool $published, string $slug, string $publishedAt, string $revisionComment = '', string $seoTitle = '', string $seoDescription = '', string $ogImage = '', string $category = ''): void { $article = $this->getByUuid($uuid); if (!$article) { return; } - $slug = $slug !== '' ? $this->sanitizeSlug($slug) : $this->generateSlug($title); - $slug = $this->uniqueSlug($slug, $uuid); + $slug = $slug !== '' ? $this->sanitizeSlug($slug) : $this->generateSlug($title); + $slug = $this->uniqueSlug($slug, $uuid); + + // Snapshot de l'état courant avant écrasement $revisions = $article['revisions'] ?? []; - if ($revisionComment !== '') { - $revisions[] = ['date' => date('Y-m-d H:i:s'), 'comment' => $revisionComment]; + $revDir = $this->dataDir . '/' . $uuid . '/revisions'; + if (!is_dir($revDir)) { + mkdir($revDir, 0755, true); + } + $n = count($revisions) + 1; + $revFile = sprintf('%s/%04d.md', $revDir, $n); + file_put_contents($revFile, $article['content']); + + $revisions[] = [ + 'n' => $n, + 'date' => date('Y-m-d H:i:s'), + 'comment' => $revisionComment, + 'title' => $article['title'], + ]; + + // Limite à MAX_REVISIONS + if (count($revisions) > self::MAX_REVISIONS) { + $oldest = array_shift($revisions); + @unlink(sprintf('%s/%04d.md', $revDir, (int)($oldest['n'] ?? 0))); } $meta = [ @@ -125,15 +163,377 @@ class ArticleManager 'created_at' => $article['created_at'] ?? date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'), 'revisions' => $revisions, + 'cover' => $article['cover'] ?? '', + 'files_meta' => $article['files_meta'] ?? [], + 'external_links' => $article['external_links'] ?? [], 'seo_title' => $seoTitle, 'seo_description' => $seoDescription, 'og_image' => $ogImage, + 'category' => $category, ]; $dir = $this->dataDir . '/' . $uuid; $this->writeMeta($dir, $meta); file_put_contents($dir . '/index.md', ltrim($content)); } + public function autosave(string $uuid, string $title, string $content, string $slug): bool + { + if (!$this->isValidUuid($uuid)) { + return false; + } + $dir = $this->dataDir . '/' . $uuid; + $raw = @file_get_contents($dir . '/meta.json'); + if ($raw === false) { + return false; + } + $meta = json_decode($raw, true); + if (!is_array($meta)) { + return false; + } + + $slug = $slug !== '' ? $this->sanitizeSlug($slug) : $this->generateSlug($title); + $slug = $this->uniqueSlug($slug, $uuid); + + $meta['title'] = $title; + $meta['slug'] = $slug; + $meta['updated_at'] = date('Y-m-d H:i:s'); + + $this->writeMeta($dir, $meta); + @file_put_contents($dir . '/index.md', ltrim($content)); + return true; + } + + public function addFileMeta(string $uuid, string $filename, string $author, string $sourceUrl, string $title = '', array $extraMeta = []): void + { + if (!$this->isValidUuid($uuid)) { + return; + } + $filename = basename($filename); + $path = $this->dataDir . '/' . $uuid . '/files/' . $filename; + if (!file_exists($path)) { + return; + } + + $raw = file_get_contents($this->dataDir . '/' . $uuid . '/meta.json'); + if ($raw === false) { + return; + } + $meta = json_decode($raw, true); + if (!is_array($meta)) { + return; + } + if (!isset($meta['files_meta']) || !is_array($meta['files_meta'])) { + $meta['files_meta'] = []; + } + $entry = ['author' => $author, 'source_url' => $sourceUrl]; + if ($title !== '') { + $entry['title'] = $title; + } + if (!empty($extraMeta)) { + $clean = $extraMeta; + unset($clean['title'], $clean['author'], $clean['credit'], $clean['source']); + $entry['meta'] = $clean; + } + $meta['files_meta'][$filename] = $entry; + $this->writeMeta($this->dataDir . '/' . $uuid, $meta); + } + + public function setCover(string $uuid, string $filename): void + { + $article = $this->getByUuid($uuid); + if (!$article) { + return; + } + $filename = basename($filename); + $filesDir = $this->dataDir . '/' . $uuid . '/files'; + $targetPath = $filesDir . '/' . $filename; + if (!file_exists($targetPath)) { + return; + } + + $mime = mime_content_type($targetPath) ?: ''; + $ext = $this->extFromMime($mime) ?? strtolower(pathinfo($filename, PATHINFO_EXTENSION)) ?: 'jpg'; + $coverName = 'cover.' . $ext; + + // Rename old cover back to hash name + $oldCover = $article['cover'] ?? ''; + if ($oldCover && $oldCover !== $filename && $oldCover !== $coverName) { + $oldPath = $filesDir . '/' . basename($oldCover); + if (file_exists($oldPath)) { + $hash = substr(hash_file('sha256', $oldPath), 0, 16); + $size = filesize($oldPath); + $oldExt = strtolower(pathinfo($oldCover, PATHINFO_EXTENSION)); + rename($oldPath, $filesDir . '/' . "{$hash}-{$size}.{$oldExt}"); + } + } + + // Rename target to cover.{ext} + $newPath = $filesDir . '/' . $coverName; + if ($targetPath !== $newPath) { + rename($targetPath, $newPath); + } + + $raw = file_get_contents($this->dataDir . '/' . $uuid . '/meta.json'); + if ($raw === false) { + return; + } + $meta = json_decode($raw, true); + if (!is_array($meta)) { + return; + } + $meta['cover'] = $coverName; + $this->writeMeta($this->dataDir . '/' . $uuid, $meta); + } + + public function addFileFromUrl(string $uuid, string $url, bool $isCover = false, string $author = '', string $sourceUrl = '', string $title = '', array $extraMeta = []): ?string + { + if (!$this->isValidUuid($uuid)) { + return null; + } + if (!filter_var($url, FILTER_VALIDATE_URL) || !preg_match('#^https?://#i', $url)) { + return null; + } + + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 3, + CURLOPT_TIMEOUT => 20, + CURLOPT_CONNECTTIMEOUT => 5, + CURLOPT_USERAGENT => 'varlog/1.0', + ]); + $body = curl_exec($ch); + $info = curl_getinfo($ch); + curl_close($ch); + + if ($body === false || (int)$info['http_code'] !== 200) { + return null; + } + + $tmp = tempnam(sys_get_temp_dir(), 'vl_'); + file_put_contents($tmp, $body); + + $mime = mime_content_type($tmp) ?: 'application/octet-stream'; + $isImage = str_starts_with($mime, 'image/'); + $filesDir = $this->dataDir . '/' . $uuid . '/files'; + if (!is_dir($filesDir)) { + mkdir($filesDir, 0755, true); + } + + if ($isImage) { + $ext = $this->extFromMime($mime) ?? strtolower(pathinfo(parse_url($url, PHP_URL_PATH) ?? '', PATHINFO_EXTENSION)) ?: 'jpg'; + + if ($isCover) { + // Gérer l'ancienne cover + $article = $this->getByUuid($uuid); + $oldCover = $article['cover'] ?? ''; + if ($oldCover) { + $oldPath = $filesDir . '/' . basename($oldCover); + if (file_exists($oldPath)) { + $hash = substr(hash_file('sha256', $oldPath), 0, 16); + $size = filesize($oldPath); + $oldExt = strtolower(pathinfo($oldCover, PATHINFO_EXTENSION)); + rename($oldPath, $filesDir . '/' . "{$hash}-{$size}.{$oldExt}"); + } + } + $filename = 'cover.' . $ext; + } else { + $hash = substr(hash_file('sha256', $tmp), 0, 16); + $size = strlen($body); + $filename = "{$hash}-{$size}.{$ext}"; + } + } else { + // Non-image : nom extrait de l'URL, sanitisé, dédupliqué + $urlPath = parse_url($url, PHP_URL_PATH) ?? ''; + $filename = preg_replace('/[^a-zA-Z0-9._-]/', '_', basename($urlPath)) ?: 'file'; + $i = 1; + $info = pathinfo($filename); + while (file_exists($filesDir . '/' . $filename)) { + $filename = $info['filename'] . '_' . $i . (isset($info['extension']) ? '.' . $info['extension'] : ''); + $i++; + } + } + + rename($tmp, $filesDir . '/' . $filename); + + if ($author !== '' || $sourceUrl !== '' || $title !== '' || !empty($extraMeta)) { + $this->addFileMeta($uuid, $filename, $author, $sourceUrl, $title, $extraMeta); + } + + if ($isCover && $isImage) { + $raw = file_get_contents($this->dataDir . '/' . $uuid . '/meta.json'); + if ($raw !== false) { + $meta = json_decode($raw, true); + if (is_array($meta)) { + $meta['cover'] = $filename; + $this->writeMeta($this->dataDir . '/' . $uuid, $meta); + } + } + } + + return $filename; + } + + public function addExternalLink(string $uuid, string $url, string $title = '', string $author = '', array $extraMeta = []): bool + { + if (!$this->isValidUuid($uuid) || !filter_var($url, FILTER_VALIDATE_URL)) { + return false; + } + $dir = $this->dataDir . '/' . $uuid; + $raw = file_get_contents($dir . '/meta.json'); + if ($raw === false) { + return false; + } + $meta = json_decode($raw, true); + if (!is_array($meta)) { + return false; + } + if (!isset($meta['external_links']) || !is_array($meta['external_links'])) { + $meta['external_links'] = []; + } + foreach ($meta['external_links'] as $link) { + if ($link['url'] === $url) { + return true; // already exists + } + } + $urlPath = parse_url($url, PHP_URL_PATH) ?? ''; + $name = $title !== '' ? $title : (rawurldecode(basename($urlPath)) ?: $url); + $entry = ['url' => $url, 'name' => $name, 'added_at' => date('Y-m-d H:i:s')]; + $resolvedAuthor = $author !== '' ? $author : ($extraMeta['author'] ?? ''); + if ($resolvedAuthor !== '') { + $entry['author'] = $resolvedAuthor; + } + if (!empty($extraMeta)) { + $clean = $extraMeta; + unset($clean['title'], $clean['author'], $clean['credit']); + $entry['meta'] = $clean; + } + $meta['external_links'][] = $entry; + $this->writeMeta($dir, $meta); + return true; + } + + public function updateExternalLinkMeta(string $uuid, string $url, array $metaUpdates): bool + { + if (!$this->isValidUuid($uuid)) { + return false; + } + $dir = $this->dataDir . '/' . $uuid; + $raw = file_get_contents($dir . '/meta.json'); + if ($raw === false) { + return false; + } + $meta = json_decode($raw, true); + if (!is_array($meta)) { + return false; + } + $found = false; + foreach ($meta['external_links'] as &$link) { + if ($link['url'] === $url) { + $link['meta'] = array_merge($link['meta'] ?? [], $metaUpdates); + $found = true; + break; + } + } + unset($link); + if (!$found) { + return false; + } + $this->writeMeta($dir, $meta); + return true; + } + + public function removeExternalLink(string $uuid, string $url): bool + { + if (!$this->isValidUuid($uuid)) { + return false; + } + $dir = $this->dataDir . '/' . $uuid; + $raw = file_get_contents($dir . '/meta.json'); + if ($raw === false) { + return false; + } + $meta = json_decode($raw, true); + if (!is_array($meta)) { + return false; + } + $meta['external_links'] = array_values(array_filter( + $meta['external_links'] ?? [], + static fn ($l) => $l['url'] !== $url + )); + $this->writeMeta($dir, $meta); + return true; + } + + public function getCategories(): array + { + $cats = []; + foreach ($this->getAll() as $article) { + $cat = trim($article['category'] ?? ''); + if ($cat !== '') { + $cats[$cat] = ($cats[$cat] ?? 0) + 1; + } + } + ksort($cats); + return $cats; + } + + public function renameCategory(string $old, string $new): void + { + if (!is_dir($this->dataDir)) { + return; + } + foreach (scandir($this->dataDir) as $entry) { + if ($entry === '.' || $entry === '..') { + continue; + } + $metaPath = $this->dataDir . '/' . $entry . '/meta.json'; + if (!file_exists($metaPath)) { + continue; + } + $raw = file_get_contents($metaPath); + if ($raw === false) { + continue; + } + $meta = json_decode($raw, true); + if (!is_array($meta) || trim($meta['category'] ?? '') !== $old) { + continue; + } + $meta['category'] = $new; + $this->writeMeta($this->dataDir . '/' . $entry, $meta); + } + } + + public function deleteCategory(string $name): void + { + $this->renameCategory($name, ''); + } + + public function getPrivateCategories(): array + { + $path = $this->dataDir . '/private_cats.json'; + if (!file_exists($path)) { + return []; + } + $data = json_decode((string)file_get_contents($path), true); + return is_array($data) ? $data : []; + } + + public function togglePrivateCategory(string $cat): void + { + $cats = $this->getPrivateCategories(); + if (in_array($cat, $cats, true)) { + $cats = array_values(array_filter($cats, fn ($c) => $c !== $cat)); + } else { + $cats[] = $cat; + } + file_put_contents( + $this->dataDir . '/private_cats.json', + json_encode(array_values($cats), JSON_UNESCAPED_UNICODE) + ); + } + public function delete(string $uuid): void { if (!$this->isValidUuid($uuid)) { @@ -205,6 +605,24 @@ class ArticleManager mkdir($dir, 0755, true); } + $mime = mime_content_type($uploadedFile['tmp_name']) ?: 'application/octet-stream'; + + if (str_starts_with($mime, 'image/')) { + $ext = $this->extFromMime($mime) + ?? strtolower(pathinfo($uploadedFile['name'], PATHINFO_EXTENSION)) + ?: 'jpg'; + $hash = substr(hash_file('sha256', $uploadedFile['tmp_name']), 0, 16); + $size = $uploadedFile['size'] ?? filesize($uploadedFile['tmp_name']); + $name = "{$hash}-{$size}.{$ext}"; + $dest = $dir . '/' . $name; + // Même hash = même contenu : pas de collision réelle + if (!move_uploaded_file($uploadedFile['tmp_name'], $dest)) { + return null; + } + return $name; + } + + // Non-image : nom sanitisé + déduplication $name = preg_replace('/[^a-zA-Z0-9._-]/', '_', basename($uploadedFile['name'])); $dest = $dir . '/' . $name; $i = 1; @@ -213,7 +631,6 @@ class ArticleManager $dest = $dir . '/' . $info['filename'] . '_' . $i . (isset($info['extension']) ? '.' . $info['extension'] : ''); $i++; } - if (!move_uploaded_file($uploadedFile['tmp_name'], $dest)) { return null; } @@ -221,7 +638,7 @@ class ArticleManager } // ------------------------------------------------------------------ // - // Rendu : résout les chemins relatifs dans le contenu Markdown + // Rendu // ------------------------------------------------------------------ // public function resolveFileUrls(string $uuid, string $markdown): string @@ -241,6 +658,18 @@ class ArticleManager // Helpers privés // ------------------------------------------------------------------ // + private function extFromMime(string $mime): ?string + { + return match($mime) { + 'image/jpeg' => 'jpg', + 'image/png' => 'png', + 'image/webp' => 'webp', + 'image/gif' => 'gif', + 'image/avif' => 'avif', + default => null, + }; + } + private function loadArticle(string $dir): ?array { $metaPath = $dir . '/meta.json'; @@ -255,8 +684,17 @@ class ArticleManager return null; } - $meta['content'] = file_exists($contentPath) ? (string)file_get_contents($contentPath) : ''; - $meta['published'] = (bool)($meta['published'] ?? false); + $meta['content'] = file_exists($contentPath) ? (string)file_get_contents($contentPath) : ''; + $meta['published'] = (bool)($meta['published'] ?? false); + $meta['files_meta'] = $meta['files_meta'] ?? []; + $meta['external_links'] = $meta['external_links'] ?? []; + + if (!empty($meta['cover'])) { + $coverPath = $dir . '/files/' . basename((string)$meta['cover']); + if (!file_exists($coverPath)) { + $meta['cover'] = ''; + } + } return $meta; } diff --git a/src/RatingManager.php b/src/RatingManager.php new file mode 100644 index 0000000..b73eb99 --- /dev/null +++ b/src/RatingManager.php @@ -0,0 +1,46 @@ +pdo->prepare( + 'INSERT INTO article_ratings (article_uuid, user_email, rating) + VALUES (:uuid, :email, :r) + ON CONFLICT (article_uuid, user_email) + DO UPDATE SET rating = :r, rated_at = NOW()' + ); + $st->execute([':uuid' => $uuid, ':email' => strtolower($email), ':r' => $rating]); + } + + /** @return array{avg: float|null, count: int} */ + public function statsForArticle(string $uuid): array + { + $st = $this->pdo->prepare( + 'SELECT ROUND(AVG(rating)::numeric, 1) as avg, COUNT(*) as count + FROM article_ratings WHERE article_uuid = :uuid' + ); + $st->execute([':uuid' => $uuid]); + $row = $st->fetch(PDO::FETCH_ASSOC); + return [ + 'avg' => $row && $row['avg'] !== null ? (float)$row['avg'] : null, + 'count' => $row ? (int)$row['count'] : 0, + ]; + } + + public function userRating(string $uuid, string $email): ?int + { + $st = $this->pdo->prepare( + 'SELECT rating FROM article_ratings WHERE article_uuid = :uuid AND user_email = :email' + ); + $st->execute([':uuid' => $uuid, ':email' => strtolower($email)]); + $v = $st->fetchColumn(); + return $v !== false ? (int)$v : null; + } +} diff --git a/src/auth.php b/src/auth.php index 7ddc607..2d2eccf 100644 --- a/src/auth.php +++ b/src/auth.php @@ -21,15 +21,186 @@ function currentUserEmail(): ?string return $_SESSION['user_email'] ?? null; } +function currentUserName(): string +{ + if (!isLoggedIn()) { + return ''; + } + if (isset($_SESSION['user_display_name']) && $_SESSION['user_display_name'] !== '') { + return $_SESSION['user_display_name']; + } + $name = authorDisplayName(currentUserEmail() ?? ''); + $_SESSION['user_display_name'] = $name; + return $name; +} + +function authorDisplayName(string $email): string +{ + static $cache = []; + $key = strtolower(trim($email)); + if ($key === '') { + return ''; + } + if (array_key_exists($key, $cache)) { + return $cache[$key]; + } + $pdo = dbPdo(); + if ($pdo) { + try { + $st = $pdo->prepare('SELECT display_name FROM user_profiles WHERE email = :e'); + $st->execute([':e' => $key]); + $name = $st->fetchColumn(); + $cache[$key] = ($name !== false && $name !== '') ? $name : explode('@', $key)[0]; + return $cache[$key]; + } catch (\Throwable) { + } + } + $cache[$key] = explode('@', $key)[0]; + return $cache[$key]; +} + +function dbPdo(): ?PDO +{ + static $pdo = null; + static $failed = false; + if ($failed) { + return null; + } + if ($pdo !== null) { + return $pdo; + } + $dsn = $_ENV['DB_DSN'] ?? (getenv('DB_DSN') ?: ''); + $user = $_ENV['DB_USER'] ?? (getenv('DB_USER') ?: ''); + $pass = $_ENV['DB_PASS'] ?? (getenv('DB_PASS') ?: ''); + if (!$dsn) { + $failed = true; + return null; + } + try { + $pdo = new PDO($dsn, $user ?: null, $pass ?: null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); + } catch (\Throwable) { + $failed = true; + return null; + } + return $pdo; +} + +function currentUserRoles(): array +{ + if (!isLoggedIn()) { + return []; + } + if (isset($_SESSION['user_roles'])) { + return $_SESSION['user_roles']; + } + $pdo = dbPdo(); + if (!$pdo) { + $_SESSION['user_roles'] = []; + return []; + } + try { + $st = $pdo->prepare( + 'SELECT r.name FROM roles r + JOIN user_roles ur ON ur.role_id = r.id + WHERE ur.user_email = :e' + ); + $st->execute([':e' => strtolower(currentUserEmail() ?? '')]); + $_SESSION['user_roles'] = $st->fetchAll(PDO::FETCH_COLUMN) ?: []; + } catch (\Throwable) { + $_SESSION['user_roles'] = []; + } + return $_SESSION['user_roles']; +} + +function hasRole(string $role): bool +{ + return in_array($role, currentUserRoles(), true); +} + +// Capacités connues — clé => label affiché dans l'admin +const KNOWN_CAPABILITIES = [ + 'view_sources_own' => 'Voir les sources de ses propres articles', + 'view_sources_all' => 'Voir les sources de tous les articles', + 'view_drafts_own' => 'Voir ses articles non publiés', + 'view_drafts_all' => 'Voir tous les articles non publiés', + 'edit_articles_own' => 'Modifier ses propres articles', + 'edit_articles_all' => 'Modifier tous les articles', + 'rate_articles' => 'Noter des articles', +]; + +// Groupes pour l'interface d'administration +// 'single' => pas de variante own/all +const CAPABILITY_GROUPS = [ + ['label' => 'Sources & métadonnées', 'own' => 'view_sources_own', 'all' => 'view_sources_all'], + ['label' => 'Articles non publiés', 'own' => 'view_drafts_own', 'all' => 'view_drafts_all'], + ['label' => 'Modification', 'own' => 'edit_articles_own', 'all' => 'edit_articles_all'], + ['label' => 'Noter des articles', 'single' => 'rate_articles'], +]; + +function currentUserCapabilities(): array +{ + if (!isLoggedIn()) { + return []; + } + if (isset($_SESSION['user_capabilities'])) { + return $_SESSION['user_capabilities']; + } + $pdo = dbPdo(); + if (!$pdo) { + $_SESSION['user_capabilities'] = []; + return []; + } + try { + $st = $pdo->prepare( + 'SELECT DISTINCT rc.capability + FROM role_capabilities rc + JOIN user_roles ur ON ur.role_id = rc.role_id + WHERE ur.user_email = :e' + ); + $st->execute([':e' => strtolower(currentUserEmail() ?? '')]); + $_SESSION['user_capabilities'] = $st->fetchAll(PDO::FETCH_COLUMN) ?: []; + } catch (\Throwable) { + $_SESSION['user_capabilities'] = []; + } + return $_SESSION['user_capabilities']; +} + +function hasCapability(string $cap): bool +{ + if (isAdmin()) { + return true; + } + return in_array($cap, currentUserCapabilities(), true); +} + +function canDoOnArticle(string $baseCap, array $article): bool +{ + if (isAdmin()) { + return true; + } + if (hasCapability($baseCap . '_all')) { + return true; + } + if (hasCapability($baseCap . '_own')) { + $owner = strtolower($article['author'] ?? ''); + return $owner !== '' && $owner === strtolower(currentUserEmail() ?? ''); + } + return false; +} + function isAdmin(): bool { $email = currentUserEmail(); if (!$email) { return false; } + // Fallback bootstrap : var d'env $rawAdmin = $_ENV['ADMIN_EMAIL'] ?? (getenv('ADMIN_EMAIL') ?: ''); $allowed = array_filter(array_map('trim', explode(',', (string)$rawAdmin))); - return in_array(strtolower($email), array_map('strtolower', $allowed), true); + if (in_array(strtolower($email), array_map('strtolower', $allowed), true)) { + return true; + } + return hasRole('admin'); } function ssoLogoutUrl(): string diff --git a/src/helpers.php b/src/helpers.php index 3a6c03b..2cc9e00 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -9,3 +9,118 @@ function vd($var, ...$moreVars) $output = ob_get_clean(); echo "
$output
"; } + +/** + * Diff ligne-à-ligne via LCS. Retourne un tableau de [op, line] où + * op est '=' (inchangé), '-' (supprimé), '+' (ajouté). + */ +function lineDiff(string $old, string $new): array +{ + $a = explode("\n", $old); + $b = explode("\n", $new); + $n = count($a); + $m = count($b); + + if ($n * $m > 300000) { + return [['!', "Diff trop grand ({$n}×{$m} lignes), affichage brut."], ['-', $old], ['+', $new]]; + } + + $dp = array_fill(0, $n + 1, array_fill(0, $m + 1, 0)); + for ($i = $n - 1; $i >= 0; $i--) { + for ($j = $m - 1; $j >= 0; $j--) { + $dp[$i][$j] = $a[$i] === $b[$j] + ? 1 + $dp[$i + 1][$j + 1] + : max($dp[$i + 1][$j], $dp[$i][$j + 1]); + } + } + + $diff = []; + $i = 0; + $j = 0; + while ($i < $n || $j < $m) { + if ($i < $n && $j < $m && $a[$i] === $b[$j]) { + $diff[] = ['=', $a[$i]]; + $i++; + $j++; + } elseif ($j < $m && ($i >= $n || $dp[$i][$j + 1] >= $dp[$i + 1][$j])) { + $diff[] = ['+', $b[$j++]]; + } else { + $diff[] = ['-', $a[$i++]]; + } + } + return $diff; +} + +// 16 couleurs RGB de base — distribuées sur le spectre, visuellement distinctes +const COLOR_PALETTE_16 = [ + [220, 38, 38], // rouge + [234, 88, 12], // orange + [217, 119, 6], // ambre + [161, 142, 14], // jaune-olive + [77, 124, 15], // citron + [22, 163, 74], // vert + [4, 120, 87], // émeraude + [15, 118, 110], // sarcelle + [8, 145, 178], // cyan + [3, 105, 161], // ciel + [37, 99, 235], // bleu + [79, 70, 229], // indigo + [109, 40, 217], // violet + [147, 51, 234], // pourpre + [192, 38, 211], // fuchsia + [219, 39, 119], // rose +]; + +/** + * Génère un dégradé CSS pour une catégorie. + * Avec $allCats, l'assignation est séquentielle (par ordre alpha) ; + * au-delà de 16, un décalage de teinte et d'angle différencie les palettes. + * Sans $allCats, fallback par hachage sur la palette. + */ +function coverGradient(string $seed, array $allCats = []): string +{ + $key = strtolower(trim($seed)); + + if (!empty($allCats)) { + $keys = array_map(fn ($k) => strtolower(trim((string)$k)), array_keys($allCats)); + $pos = array_search($key, $keys, true); + if ($pos !== false) { + $idx = (int) $pos; + $tier = (int) floor($idx / 16); + $ci = $idx % 16; + return _paletteGradient(COLOR_PALETTE_16[$ci], $tier); + } + } + + // Hachage déterministe en l'absence de liste + $ci = abs(crc32($key)) % 16; + return _paletteGradient(COLOR_PALETTE_16[$ci], 0); +} + +function _paletteGradient(array $rgb, int $tier): string +{ + [$r, $g, $b] = $rgb; + + // Tier 0 : dégradé standard clair → foncé, 135° + // Tier 1 : plus saturé, angle inversé, 315° + // Tier 2+ : plus sombre encore, 225° + $tintMix = match ($tier) { + 0 => 0.65, 1 => 0.48, default => 0.35 + }; + $shadeK = match ($tier) { + 0 => 0.35, 1 => 0.25, default => 0.18 + }; + $angle = match ($tier) { + 0 => 135, 1 => 315, default => 225 + }; + + $tr = (int) round($r * (1 - $tintMix) + 255 * $tintMix); + $tg = (int) round($g * (1 - $tintMix) + 255 * $tintMix); + $tb = (int) round($b * (1 - $tintMix) + 255 * $tintMix); + + $sr = (int) round($r * $shadeK); + $sg = (int) round($g * $shadeK); + $sb = (int) round($b * $shadeK); + + return "linear-gradient({$angle}deg,rgb($tr,$tg,$tb) 0%,rgb($sr,$sg,$sb) 100%)"; +} diff --git a/templates/add_files.php b/templates/add_files.php new file mode 100644 index 0000000..b8ba4cd --- /dev/null +++ b/templates/add_files.php @@ -0,0 +1,87 @@ +getFiles($addFilesArticle['uuid']); +?> + +
+ ← Retour +

Ajouter des fichiers

+
+ +

+ Article : +

+ +
+ + +
+
+
+
+ +
+ + +
+ Images → nommées sha256-taille.ext
+ Vidéos, PDF, autres → nom sanitisé +
+
+ +
+ + Annuler +
+ +
+
+
+
+ + + +
+
Fichiers existants
+
+ + +
+ + + + + + + '🎬', + str_starts_with($f['mime'], 'audio/') => '🎵', + $f['mime'] === 'application/pdf' => '📑', + default => '📄', + } ?> + + +
+ + Ko +
+ + cover + +
+ +
+
+ + +
+ +Brouillon'; + } + if (strtotime((string)($a['published_at'] ?? '')) > $now) { + return 'Avant-première'; + } + return 'Publié'; +} +?> + +
+

Administration

+ + Nouvel article +
+ + + + + + + +
+ 'Publiés', 'value' => $adminData['published'], 'color' => 'success'], + ['label' => 'Avant-premières', 'value' => $adminData['previews'], 'color' => 'warning'], + ['label' => 'Brouillons', 'value' => $adminData['drafts'], 'color' => 'secondary'], + ['label' => 'Total', 'value' => $adminData['total'], 'color' => 'primary'], + ]; + foreach ($stats as $s): ?> +
+
+
+
+
+
+
+
+ +
+ +
Activité récente
+ + + + + + + + + + + + + + + + + + + +
TitreAuteurStatutModifié le
+ + + + + +
+ + + + + +

Aucun article.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
TitreAuteurCatégorieStatutDate
+ + + + + + + Modifier +
+ + + + + + +
+
Attribuer un rôle
+
+
+
+ + +
+
+ + +
+
+ +
+
+
+
+ + + +

Aucun utilisateur.

+ + + + + + + + + + + + + + + + + + + + +
EmailStatutRôles
+ + Pré-inscrit + + Actif + + Inactif + + + + +
+ + + +
+ + + + +
+ + !in_array($r['name'], $currentRoles, true)); + ?> + +
+ + + +
+ +
+ + + + + +
+ + +
+
Rôles existants
+ +

Aucun rôle défini.

+ + + + + + + + + + + + + + + + + + + + +
Nom techniqueLabel affichéUtilisateurs
+
+ + + +
+
+ + +
+ + +
+
+ +
+ + +
+
+
Nouveau rôle
+
+
+
+ + +
Utilisé dans le code — ne change pas.
+
+
+ + +
+ +
+
+
+
+ + + +
+
Permissions par rôle
+

Le rôle admin a toutes les permissions implicitement.

+
+ +
+
+
+ + +
+
+
+ + + + +
+ > + +
+ +
+
+
+ 'Propres articles', 'all' => 'Tous'] as $scope => $scopeLabel): + $cap = $group[$scope]; ?> +
+ > + +
+ +
+
+ + + +
+
+
+
+ +
+
+ + +
+ + + + + +
+

Catégories

+ ← Retour +
+ +
+ + +
+
Catégories existantes
+ + +

Aucune catégorie définie.

+ +
+ $count): + $gradient = coverGradient($cat, $cats); ?> +
+
+ + +
+ + +
+ + article 1 ? 's' : '' ?> +
+ + +
+ + + +
+ + + +
+ + +
+ + +
+ + +
+ +
+
+ +
+ +
+ + +
+
Nouvelle catégorie
+
+
+

+ Créez une catégorie en l'assignant à un article. + La prochaine reçoit la couleur n°. +

+ + +
+ $rgb): + $g = _paletteGradient($rgb, 0); + $active = $i === $nextIdx; + ?> +
+
+ +
+
+
+
+ +
+ + + +
+
+ +
+ ← Retour +

Confirmation — droits d'auteur

+
+ +
+ +
+ Vous êtes sur le point de copier ce fichier sur votre serveur : + +
+
+ + +
+
Ce que dit la loi française
+
+

En France, toute œuvre de l'esprit est protégée dès sa création sans + formalité d'enregistrement (art. L.111-1 CPI). Cela inclut les photographies, illustrations, + textes, vidéos et musiques.

+ +

Reproduire ou diffuser publiquement une œuvre sans l'autorisation de son auteur constitue + une contrefaçon (art. L.335-2 CPI), passible de :

+
    +
  • 3 ans d'emprisonnement
  • +
  • 300 000 € d'amende
  • +
+ +

L'exception d'usage privé (art. L.122-5 1° CPI) est strictement + personnelle et ne couvre pas la publication sur un blog, même non commercial + et même à audience restreinte.

+
+
+ + +
+
+ ✓ Cas où vous pouvez légalement télécharger ce fichier +
+
    +
  • + Vous êtes l'auteur ou co-auteur du fichier +
  • +
  • + Le fichier est distribué sous une licence libre compatible avec la + reproduction publique : CC0, + CC BY, + CC BY-SA, + CC BY-ND, + domaine public, etc.
    + ⚠ CC BY-NC ne suffit pas si le blog génère des revenus, + même indirects. +
  • +
  • + Vous disposez d'une autorisation écrite explicite de l'auteur ou + du titulaire des droits patrimoniaux +
  • +
  • + L'œuvre est dans le domaine public : 70 ans révolus après le décès + de l'auteur en Union Européenne (art. L.123-1 CPI) +
  • +
+
+ + +
+ + + + + + + + + + + +
+
+
+ + +
+
+
+ +
+ + Annuler +
+
+ +
+
+ + + +
+ ← Retour +
+ + — révision # + + du + + +
+
+ +
+ − Supprimé + + Ajouté + = Inchangé +
+ + +
Aucune différence — le contenu est identique.
+ + + +
+ + + + +
+ + + +
+ +
− 
+ +
+ +
  
+ + +
+ + + + + + + +
+ ← Retour +

Importer un fichier depuis une URL

+
+ +

+ Article : +

+ + +
+ URL invalide ou inaccessible — vérifiez que le lien est correct et que le serveur peut y accéder. +
+ + +
+
+
+
+ + +
Les métadonnées seront récupérées automatiquement à l'étape suivante.
+
+
+ + Annuler +
+
+
+
+ + 'Type', + 'size' => 'Taille', + // PDF + 'pages' => 'Pages', + 'page_size' => 'Format', + 'pdf_version' => 'Version PDF', + // Image + 'width' => 'Dimensions', + 'camera' => 'Appareil', + // HTML + 'site_name' => 'Site', + 'og_type' => 'Type', + 'language' => 'Langue', + // Commun + 'author' => $isHtml ? 'Auteur' : ($isPdf ? 'Auteur' : 'Auteur EXIF'), + 'date' => $isPdf ? 'Créé le' : ($isHtml ? 'Publié le' : 'Prise de vue'), + 'description' => 'Description', + 'subject' => 'Sujet', + 'keywords' => 'Mots-clés', + 'copyright' => 'Copyright', + // PDF logiciel + 'creator' => 'Créé avec', + 'producer' => 'Produit par', + // HTML liens + 'canonical' => 'URL canonique', + 'og_image' => 'Image OG', +]; + +$hasTitle = !empty($step2Meta['title']); +$preAuthor = $step2Meta['author'] ?? $step2Meta['credit'] ?? ''; +$preSource = $step2Meta['canonical'] ?? $step2Meta['source'] ?? $step2Url; +?> + +
+ ← Retour +

Importer un fichier

+
+ +

+ Article : +

+ + + +
+

Aperçu de la page

+ + Aperçu +
+ + + + !empty($step2Meta[$key]), ARRAY_FILTER_USE_BOTH); +if ($visibleRows): ?> +
+
Métadonnées du fichier
+
+ + + $label): ?> + htmlspecialchars(round($val / 1024) . ' Ko'), + 'width' => htmlspecialchars($val . ' × ' . ($step2Meta['height'] ?? '?') . ' px'), + 'og_image' => '', + 'canonical' => '' . htmlspecialchars((string)$val) . '', + default => htmlspecialchars((string)$val), + }; + ?> + + + + + + +
+
+
+ + + +
+
+
+ + + + + $v !== null && $v !== '' + ); +?> + + + +
+ + + +
+ Titre non trouvé dans les métadonnées — saisie requise. +
+ +
+ + +
+

Mode

+
+ + +
+
+ + +
+ +
+ + +
+ + +
+ + +
> + +
+ + +
+ + +
+ + +
Laissé vide → URL du fichier utilisée comme source.
+
+ + +
+
+ + +
+
+ +
+ +
+ + Annuler +
+
+
+
+ + + + + - -
- Modifier - Supprimer + +
+ +
+ +
Brouillon
+ +
Privé
+ + +
> + + <?= htmlspecialchars($article['title']) ?> + +
+ + +
+ ← Retour + + ✎ Modifier + 🗑 Supprimer + +
+ + +
+
+ + + +

+

+ + + · + + +

+
+
+ + ℹ Sources + + +
+ + 0): ?> + + / 5 + + +
+ = 1; $s--): ?> + + onchange="this.form.submit()"> + + +
+
+ 0): ?> + + ★ + () + + +
+
+ +
+
+
+ text($rawContent) ?> +
+
+
+ + 0): ?> +

+ Note : /5 + — Connectez-vous pour noter. +

+
+ + + +
+ + +
+

Mon profil

+
+ +
+
+
+
+ +
Profil mis à jour.
+ + +
+ + +
+
+ + +
Affiché comme auteur sur vos articles.
+
+
+ + +
+ +
+
+
+
+
+ + 'Type MIME', + 'size' => 'Taille originale', + 'pages' => 'Pages', + 'page_size' => 'Format', + 'pdf_version' => 'Version PDF', + 'width' => 'Dimensions', + 'camera' => 'Appareil photo', + 'site_name' => 'Site', + 'og_type' => 'Type OG', + 'language' => 'Langue', + 'date' => 'Date', + 'description' => 'Description', + 'subject' => 'Sujet', + 'keywords' => 'Mots-clés', + 'copyright' => 'Copyright', + 'credit' => 'Crédit', + 'creator' => 'Créé avec', + 'producer' => 'Produit par', + 'canonical' => 'URL canonique', + 'og_image' => 'Image OG', +]; + +function renderMetaCell(string $key, mixed $val, array $row = []): string +{ + return match($key) { + 'size' => htmlspecialchars(number_format((float)$val / 1024, 1)) . ' Ko', + 'width' => htmlspecialchars((string)$val) . ' × ' . htmlspecialchars((string)($row['height'] ?? '?')) . ' px', + 'og_image' => str_starts_with((string)$val, '/') + ? '' + : '' . htmlspecialchars((string)$val) . '', + 'canonical' => '' . htmlspecialchars((string)$val) . '', + default => htmlspecialchars((string)$val), + }; +} +?> + +
+ ← Modifier +

Sources & médias

+
+

+ + +
+

+ Liens & sources externes + +

+ + +

Aucun lien externe enregistré.

+ +
+ +
+
+
+ + + + + +
+ +
+ + +
+ +
+ + + + + +
+ + Auteur : + + + Ajouté le + +
+ + + isset($metaLabels[$k]) && $v !== null && $v !== '' && $k !== 'height', ARRAY_FILTER_USE_BOTH); + ?> + + + + $label): + if (!isset($lMeta[$key]) || $lMeta[$key] === '' || $lMeta[$key] === null) { + continue; + } + ?> + + + + + + +
+ + +
+
+
+
+ +
+ +
+ + !str_starts_with($f['name'], '_thumb_'))); +?> +
+

+ Pièces jointes + +

+ + +

Aucun fichier joint.

+ +
+ +
+
+
+ + + + + + + +
+ '🎬', + str_starts_with($f['mime'], 'audio/') => '🎵', + $f['mime'] === 'application/pdf' => '📑', + default => '📄', + } ?> +
+ + +
+ +
+ + + + + + + + cover + +
+ + +
+ Ko + + Auteur : + + + + Source : + + + + + +
+ + + isset($metaLabels[$k]) && $v !== null && $v !== '' && $k !== 'height', ARRAY_FILTER_USE_BOTH); + ?> + + + + $label): + if (!isset($fExtra[$key]) || $fExtra[$key] === '' || $fExtra[$key] === null) { + continue; + } + ?> + + + + + + +
+ + + + Pas de métadonnées enregistrées. + +
+
+
+
+ +
+ +
+ +