Options -Indexes -MultiViews

RewriteEngine On

# ─── Routes spécifiques ───────────────────────────────────────────────────────

RewriteRule ^feed/?$          feed.php     [L,QSA]
RewriteRule ^webmention/?$    index.php?module=webmention [L,QSA]

# Sitemap et LLMs — servis par PHP même si les fichiers statiques existent
RewriteRule ^robots\.txt$            robots.php    [L]
RewriteRule ^sitemap\.xml$           sitemap.php   [L]
RewriteRule ^opensearch\.xml$        opensearch.php [L]
RewriteRule ^manifest\.webmanifest$  manifest.php  [L]
RewriteRule ^llms\.txt$              llms.php      [L]
RewriteRule ^llms-full\.txt$         llms-full.php [L]

# ─── Routing URL propres (slugs) ──────────────────────────────────────────────
#
# Toute la navigation passe par /slug/ — jamais de ?module= visible
# Exemple : /contact/ → index.php?module=contact (interne, transparent)
#
# En production, ces règles seront déplacées dans la config Apache (VirtualHost)
# pour éviter la lecture du .htaccess à chaque requête (gain de performances)

# Trailing slash canonique — /slug → /slug/ (301 permanent)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI}      !/$
RewriteRule ^([a-z0-9][a-z0-9_-]*)$ /$1/ [R=301,L]

# Routing — /slug/ → index.php?module=slug
RewriteRule ^([a-z0-9][a-z0-9_-]*)/?$ index.php?module=$1 [L,QSA]

# ─── Catch-all ────────────────────────────────────────────────────────────────

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]

# ─── Protection des répertoires sensibles ─────────────────────────────────────

RewriteRule ^(classes|config|blocs|modules|templates|cache|data)(/|$) - [F,L]

# ─── Compression ─────────────────────────────────────────────────────────────

<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
    AddOutputFilterByType DEFLATE application/javascript application/x-javascript
    AddOutputFilterByType DEFLATE application/json application/ld+json
    AddOutputFilterByType DEFLATE application/rss+xml application/atom+xml
    AddOutputFilterByType DEFLATE image/svg+xml application/xml
    AddOutputFilterByType DEFLATE font/ttf font/otf font/woff font/woff2
    SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|webp|avif|woff2|gz|br)$ no-gzip dont-vary
</IfModule>

<IfModule mod_brotli.c>
    AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/xml text/css
    AddOutputFilterByType BROTLI_COMPRESS application/javascript application/x-javascript
    AddOutputFilterByType BROTLI_COMPRESS application/json application/ld+json
    AddOutputFilterByType BROTLI_COMPRESS application/rss+xml application/atom+xml
    AddOutputFilterByType BROTLI_COMPRESS image/svg+xml application/xml
    AddOutputFilterByType BROTLI_COMPRESS font/ttf font/otf font/woff font/woff2
</IfModule>

# ─── Cache navigateur ─────────────────────────────────────────────────────────

<IfModule mod_expires.c>
    ExpiresActive On

    <FilesMatch "\.[a-f0-9]{8}\.(css|js)$">
        ExpiresDefault "access plus 1 year"
        Header set Cache-Control "public, max-age=31536000, immutable"
    </FilesMatch>

    ExpiresByType image/jpeg        "access plus 6 months"
    ExpiresByType image/png         "access plus 6 months"
    ExpiresByType image/webp        "access plus 6 months"
    ExpiresByType image/avif        "access plus 6 months"
    ExpiresByType image/svg+xml     "access plus 6 months"
    ExpiresByType image/gif         "access plus 6 months"
    ExpiresByType image/x-icon      "access plus 1 year"
    ExpiresByType image/vnd.microsoft.icon "access plus 1 year"
    ExpiresByType font/woff         "access plus 1 year"
    ExpiresByType font/woff2        "access plus 1 year"
    ExpiresByType font/ttf          "access plus 1 year"
    ExpiresByType font/otf          "access plus 1 year"
    ExpiresByType application/font-woff  "access plus 1 year"
    ExpiresByType application/font-woff2 "access plus 1 year"
    ExpiresByType text/html         "access plus 0 seconds"
    ExpiresByType application/rss+xml  "access plus 1 hour"
    ExpiresByType application/manifest+json "access plus 1 week"
    ExpiresByType application/xml   "access plus 1 day"
    ExpiresByType text/xml          "access plus 1 day"
</IfModule>

# ─── En-têtes ─────────────────────────────────────────────────────────────────

<IfModule mod_headers.c>
    Header unset X-Powered-By
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Content-Type-Options "nosniff"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set X-DNS-Prefetch-Control "on"
    Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=()"
    Header append Vary Accept-Encoding
</IfModule>

# ─── HTTPS — à activer par l'ERP ──────────────────────────────────────────────
# RewriteCond %{HTTPS} off
# RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
# RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]

# ─── Protection des fichiers sensibles ────────────────────────────────────────

<Files "cron.php">
    Require all denied
</Files>

<FilesMatch "^(composer\.json|composer\.lock|database\.php|\.git)$">
    Require all denied
</FilesMatch>

# ─── Type MIME ────────────────────────────────────────────────────────────────

<IfModule mod_mime.c>
    AddType image/webp              .webp
    AddType image/avif              .avif
    AddType font/woff               .woff
    AddType font/woff2              .woff2
    AddType application/manifest+json .webmanifest
    AddType application/rss+xml     .rss
    AddType text/plain              .txt
</IfModule>
