# =====================================================================
# E-Venz Africa Event Hub — public/ web root
#
# On cPanel, point the domain's document root at this directory so that
# config/, lib/, includes/, sql/ and storage/ sit above the web root and
# cannot be requested over HTTP.
# =====================================================================

Options -Indexes
DirectoryIndex index.php

# The Authorization header, which Apache does not pass to PHP on its own
# under CGI or FastCGI. Without this, "Authorization: Bearer <key>" — the
# way every HTTP client on earth sends a token — arrives empty, and the
# API answers "send your key" to a caller that did. The API also accepts
# X-Evenz-Key for hosts where even this is stripped, but that is a
# fallback, not the documented way in.
<IfModule mod_setenvif.c>
  SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
</IfModule>
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{HTTP:Authorization} .
  RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>
<IfModule mod_fcgid.c>
  FcgidPassHeader Authorization
</IfModule>

# This directory IS the web root, so undo anything a parent .htaccess denies.
# Without this, a broad <FilesMatch> upstairs is inherited here and every
# page returns 403 — which is exactly what happened once already.
<FilesMatch "\.(php|css|js|json|jpg|jpeg|png|gif|webp|svg|ico|woff2?|ttf)$">
    Require all granted
</FilesMatch>

<IfModule mod_rewrite.c>
    RewriteEngine On

    # No RewriteBase on purpose. Substitutions below are relative, so
    # Apache resolves them against whichever directory this .htaccess
    # lives in. That means the same file works unchanged at a domain
    # root on cPanel and under a subdirectory such as
    # /evenz/public/ on XAMPP.

    # Pretty event URLs: /events/my-event-slug -> event.php?slug=my-event-slug
    RewriteRule ^events/([a-z0-9-]+)/?$ event.php?slug=$1 [L,QSA]

    # Widgets for other people's websites: /embed/<kind>/<slug>
    RewriteRule ^embed/([a-z]+)/([a-z0-9-]+)/?$ embed.php?kind=$1&slug=$2 [L,QSA]

    # The same widget as bare HTML, for a site to print into its own page.
    RewriteRule ^fragment/([a-z]+)/([a-z0-9-]+)/?$ fragment.php?kind=$1&slug=$2 [L,QSA]

    # A calendar feed to subscribe to, rather than a file to download.
    RewriteRule ^calendar/([a-z0-9-]+)\.ics$ calendar.php?slug=$1 [L,QSA]

    # oEmbed: consumers discover this from a <link> and call it themselves.
    RewriteRule ^oembed/?$ oembed.php [L,QSA]

    # Blog posts: /blog/my-post-slug -> blog-post.php?slug=my-post-slug
    RewriteRule ^blog/([a-z0-9-]+)/?$ blog-post.php?slug=$1 [L,QSA]

    # Ticket download links: /tickets/download/<token>
    RewriteRule ^tickets/download/([A-Za-z0-9_-]+)/?$ ticket-download.php?token=$1 [L,QSA]

    # Ticket verification: /tickets/verify/<code>
    RewriteRule ^tickets/verify/([A-Za-z0-9-]+)/?$ ticket-verify.php?code=$1 [L,QSA]

    # Certificates. /certificate/<code> hands over the PDF; /verify/<code>
    # is the page an employer lands on, and is kept short deliberately —
    # it gets typed off a printed page.
    RewriteRule ^certificate/([A-Za-z0-9-]+)/?$ certificate.php?code=$1 [L,QSA]
    RewriteRule ^verify/([A-Za-z0-9-]+)/?$ certificate-verify.php?code=$1 [L,QSA]
    RewriteRule ^verify/?$ certificate-verify.php [L,QSA]

    # RSVP. /rsvp?event=<slug> to reply, /rsvp/<token> to change it.
    RewriteRule ^rsvp/([A-Za-z0-9]+)/?$ rsvp.php?token=$1 [L,QSA]

    # A speaker filling in their own details: /speaker/<token>
    RewriteRule ^speaker/([A-Za-z0-9]+)/?$ speaker-form.php?token=$1 [L,QSA]

    # The public call for speakers: /speak/<event-slug>
    RewriteRule ^speak/([a-z0-9-]+)/?$ speak.php?slug=$1 [L,QSA]

    # Resuming a stalled payment: /pay/<token>
    RewriteRule ^pay/([A-Za-z0-9]+)/?$ pay.php?token=$1 [L,QSA]

    # XML sitemap and robots.txt (both need the absolute site URL)
    RewriteRule ^sitemap\.xml$ sitemap.php [L]
    RewriteRule ^robots\.txt$ robots.php [L]

    # Google OAuth. The redirect URI registered with Google is a fixed,
    # tidy path; these map it onto the real scripts.
    RewriteRule ^auth/google/callback/?$ google-callback.php [L,QSA]
    RewriteRule ^auth/google/?$          google-start.php    [L,QSA]

    # The public photo portal — a short, memorable URL for a link an
    # attendee is going to be sent in an email or read off a slide.
    RewriteRule ^photo/?$ photo.php [L,QSA]

    # Two-step verification after a password or a Google sign-in.
    RewriteRule ^two-factor/?$ two-factor.php [L,QSA]

    # Ticket lookup: /tickets/lookup
    # Needed explicitly — the extensionless fallback below would look for
    # tickets/lookup.php, which does not exist.
    RewriteRule ^tickets/lookup/?$ ticket-lookup.php [L,QSA]

    # Allow real files and directories through untouched.
    RewriteCond %{REQUEST_FILENAME} -f [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^ - [L]

    # Extensionless URLs: /pricing -> pricing.php
    RewriteCond %{REQUEST_FILENAME}.php -f
    RewriteRule ^(.+?)/?$ $1.php [L,QSA]

    # Everything left over goes to the MVC front controller. A page
    # written as a controller has no file in this directory, so without
    # this it would 404 in Apache before PHP ran. Anything the router
    # does not claim gets the 404 page from route.php.
    #
    # Purely additive: every URL above already matched and stopped, so
    # this only affects requests that used to be a bare Apache 404.
    # Missing assets are excluded — they should stay a cheap 404 rather
    # than booting the application to render HTML nobody will read.
    RewriteCond %{REQUEST_URI} !\.(jpg|jpeg|png|gif|webp|svg|ico|css|js|map|woff2?|ttf|eot|pdf|zip|txt|xml)$ [NC]
    RewriteRule ^ route.php [L,QSA]
</IfModule>

# Never serve dotfiles or backups.
<FilesMatch "^\.|\.(sql|log|md|json|lock|sample|bak|old|dist)$">
    Require all denied
</FilesMatch>

# config.php must never be reachable even if it is moved here by mistake.
<Files "config.php">
    Require all denied
</Files>

<IfModule mod_headers.c>
    Header set X-Content-Type-Options "nosniff"
    Header set X-Frame-Options "SAMEORIGIN"
    Header set Referrer-Policy "strict-origin-when-cross-origin"
    Header unset X-Powered-By

    # Widgets exist to be framed by other people's sites, so the blanket
    # ban above cannot apply to them. mod_headers runs after PHP, which is
    # why this has to be undone here rather than with header_remove().
    # embed.php sends frame-ancestors in its place.
    <If "%{REQUEST_URI} =~ m#/embed(/|\.php)#">
        Header unset X-Frame-Options
    </If>
</IfModule>

# Cache static assets. Uploads are content-addressed by UUID filename,
# so they can be cached aggressively.
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpeg   "access plus 1 year"
    ExpiresByType image/png    "access plus 1 year"
    ExpiresByType image/webp   "access plus 1 year"
    ExpiresByType image/svg+xml "access plus 1 year"
    ExpiresByType text/css     "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
</IfModule>

<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/css text/plain application/javascript application/json
</IfModule>
